摆脱DLL"地狱"的困扰之获取进程信息

windows:加载dll时的DLLMain介绍 在实际开发中,通常情况下,系统自带的初始化和清理机制(如全局变量初始化和析构、自动内存管理等)已经足够。然而,有些特定场景下,需要开发者自己在DllMain中处理和。以下是一些可能的情况:线程本地存储(TLS)当需要在每个线程中维护独立的数据(如线程本地存储),必须手动进行线程初始化和清理。例如,多线程日志记录、线程特定的配置等。示例:每个线程都有独立的日志文件句柄或配置对象。资源管理当需要在DLL加载时分配全局资源(如文件句柄、网络连接)并在卸载时释放这些资源时,必须手动进行初始化和清理。示例。 阅读详情

摆脱DLL"地狱"的困扰之获取进程信息

2006-01-09 09:48 作者: NorthTibet编译 出处: VCKBASE 责任编辑:方舟
  摘要

  本文讨论用各种不同的方法来获取系统中运行的进程信息,比如,进程列表,枚举列表中的进程,然后获取关于进程的详细信息。

  如何获取运行进程列表

  有三种方法来获取Win32运行进程的信息,参见表一:

  (表一)
方法平台备注
PSAPIWindows NT,Windows2000,Windows XP获取进程,驱动器,模块,内存和工作集信息
性能计数器Windows NT,Windows2000,Windows XP提供除进程清单以外的关于进程的更多信息,可在远程机器上使用。
TOOLHELP32Windows 9x,Windows2000,Windows XP获取进程,线程,模块和堆信息

  本文不打算讨论 TOOLHELP32,因为 MSDN 中提供了很多使用 TOOLHELP32 函数的例子代码。性能计数器提供的信息更多,不仅仅是进程清单。如果你想获取远程机器的信息,那么性能计数器是再好不过的工具了。如果你总是想得到另外一台机器的进程列表信息,那么就用性能计数器吧!

  进程状态 API(PSAPI 全称是 Process Status API)是微软 SDK 中一个很有用的工具,在例子程序中有一个类 CProcessList,其实现文件 Process.cpp 对 PSAPI 进行了打包,用这个类可以获取进程清单。只要 Refresh 一被调用,通过某个进程的ID便可获得此进程的描述信息,并很容易用 GetFirst 和 GetNext 列举出其它进程:

   //用 CProcessList 列出运行进程 
   // 一个挨一个获取进程
   CProcess* pProcess = NULL;
   POSITION  Pos = 0;
   for (
         pProcess = ProcessList.GetFirst(Pos); 
         (pProcess != NULL); 
         pProcess = ProcessList.GetNext(Pos)
       )
   {
      if (pProcess != NULL)
      {
      // 对进程信息进行处理
      }
   }		
  Refresh 的实现用到了 EnumProcesses 函数(在PSAPI中):
//刷新进程列表 
void CProcessList::Refresh()
{
// 不要忘了重置和释放当前的进程列表
   DefaultReset();

// 存储当前进程列表
   DWORD aProcesses[MAX_PROCESS];
   DWORD cbNeeded = 0;

// 获取进程快照
   if (!g_PSAPI.EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
      return;
    
// 计算返回了多少个进程IDs
   DWORD cProcesses = cbNeeded / sizeof(DWORD);

// 将CProcess 对象捆绑到每一个进程ID
   DWORD     dwProcessID;
   CProcess* pProcess;
   for (
         DWORD dwCurrentProcess = 0; 
         dwCurrentProcess < cProcesses; 
         dwCurrentProcess++
       )
   {
      dwProcessID = aProcesses[dwCurrentProcess];

   // 将进程信息添加到映射
      pProcess = new CProcess(TRUE);
      if (pProcess != NULL)
      {
      // 填写当前进程ID的进程信息--捆绑
         if (!pProcess->AttachProcess(aProcesses[dwCurrentProcess]))
            delete pProcess;
         else
         // 存到映射表中
            m_ProcessMap[(LPVOID)dwProcessID] = pProcess;
      }
   }

// 第二次循环需要知道此进程的子进程清单
   SetChildrenList();
}		
  如果你至今还在支持 Windows 的 16 位代码,比如在任务管理器的 ntvdm.exe 项下列出的应用程序就属于此列,那么枚举进程更棘手。有关细节参见本文 参考资料中的知识库文章,以及 Matt Pietrek 的专栏文章:August 1998 和 September 1998。

  如何获取进程信息

  有了运行进程的列表,接下来就是根据 EnumProcesses 返回的进程IDs尽可能多的获取每一个进程的详细信息,然后根据这些信息建立有用的工具。用PROCESS_QUERY_INFORMATION | PROCESS_VM_READ作为参数,调用OpenProcess获取进程句柄,然后用AttachProcess(参见Process.cpp文件中的CProcess类实现)方法创建进程描述。表二中列出的是CProcess用于获取进程细节信息的函数:

  (表二)
方法描述
GetName以NULL作为参数,调用 GetModuleBaseName ,最后去掉扩展名 “.EXE”
GetFileName以NULL作为参数,调用 GetModuleFileNameEx
GetMainWindowHandle参见GetMainWindowHandle
GetMainWindowTitle
GetParentProcessID用ProcessBasicInformation作为参数调用NtQueryInformationProcess
GetKERNELHandleCount用ProcessHandleCount作为参数调用NtQueryInformationProcess
GetUSERHandleCount用GR_USEROBJECTS作为参数调用GetGuiResources
GetGDIHandleCount用GR_GDIOBJECTS作为参数调用GetGuiResources
GetWorkingSet调用GetProcessMemoryInfo
GetCmdLine参见GetProcessCmdLine
GetOwner参见GetProcessOwner的细节
GetSessionIDProcessIdToSessionId (参见对快速用户转换的讨论部分——Windows XP的一个新特性)
GetModuleListCModuleList是一个对EnumProcessModules 和GetModuleFileNameEx的打包类
GetChildrenCount 以及子进程清单要获取某个进程的子进程列表,目前还没这样的API(即便有也未公开)可供使用。但是,因为某个进程的父进程是已知的,所以将某个进程加到其父进程的子进程列表中不难(参见SetChildrenList的实现)

  这里有几个关于AttachProcess的细节问题需要解释一下。首先,为了避免与PSAPI或 NTDLL这样的操作系统特有的DLLs进行静态链接,编写一个类对我们需要的从这些DLLs中输出的函数进行打包是值的得--有关细节可以参考例子代码中的Wrappers.h和Wrappers.cpp文件。这样的话,你只需要定义一个CPSAPIWrapper对象并调用它的GetModuleFileNameEx方法即可,不用链接到PSAPI库。另外,你应该调用IsValid方法来检查这些DLLs在你运行系统中是可用的。如此一来你的代码便可以运行在任何Windows平台而不会产生诸如某某函数未定义之类的链接错误。注意在使用某个专门的特性之前,你应该检查一下Windows的版本或IsValid的返回结果(参见DllSpy例子代码中的DllSpyApp::InitInstance部分)。

  注意PSAPI中的GetModuleFileNameEx函数返回的文件名很奇怪:如:"/SystemRoot/ System32/ smss.exe"或者"/??/C:/WINNT/system32/winlogon.exe"等等。谁知道这是什么意思?在Helper.cpp中有一个函数TranslateFilename专门对此进行转换,将这些文件名转换成更容易理解的名字。稍候会我们还会谈到这个函数。

  接下来我们讨论如何寻找某个进程的主窗口,EnumWindows有一个参数是回调函数,此回调函数的作用是接收顶层窗口句柄,在这个问调函数中,我们要调用GetWindowThreadProcessId来获取创建相应窗口的进程ID,如果找到这个窗口(可见的)便停止枚举(详情请参见GetMainWindow实现)。函数GetWindowText可以被用来获取某个不同进程的窗口标题。

  在Windows NT 和Windows 2000里,为了获取与创建某个特定窗口的进程对应的文件名字,不能像以前那样用GetWindowModuleFileName函数,你会毫无所获,这个函数总是返回当前运行进程的路径名。

  获取某个进程主窗口的详细过程描述可以参考Jeff Prosise在MSJ Aug99上的Wicked Code专栏文章。现在你已经知道了如何通过某个已知的进程ID,调用PSAPI函数来获取全路径名。然后利用这个路径名并调用GetWindowThreadProcessID函数获取创建某个特定窗口的进程文件名。

  在AttachProcess中必须调用OpenProcess来获取大多数的进程信息,但是有可能出现拒绝访问的错误。如果出现这种情况,我用了一个Keith Brown给出的方法,参见他在MSJ Aug99中的"Security Briefs"专栏文章,其中详细讨论了如何用高级别权限获取进程句柄。细节请参见例子代码的Helpers.cpp文件,其中有一个函数名叫GetProcessHandleWithEnoughRights,就是出自Keith Brown之手。

  当某个进程是作为另外一个用户账号计划任务而运行的时候,就会出现上述提到的拒绝访问问题。即便是Windows任务管理器都无法终止这样的进程,它只显示一个象下面这样的对话框。如图九:



图九 无法终止的进程

  如果你在ProcessSpy例子程序里的某个进程上双击鼠标按键,它将终止这个进程。你看一下在例子代码中的SlayProcess函数就会知道。此辅助函数调用了GetProcessHandleWithEnoughRights来获取进程句柄,但访问权限参数是PROCESS_TERMINATE,而不是在AttachProcess里所用的PROCESS_QUERY_INFORMATION | PROCESS_VM_READ。

  最后是用GetProcessOwner获取进程运行的用户账号(格式为//Domain/User),通过用TokenUser作为参数调用GetTokenInformation,然后用LookupAccountSid将返回的用户SID转换为人可读的域名和用户名。有时OpenProcessToken会因为遇到象System这样的进程而调用失败,甚至是Windows 2000 资源开发包中的PULIST.EXE遇到这种情况都无法显示出拥有进程的用户。只有ProcessExplorer(Sysinterals公司开发的一个工具软件)能成功找到此"安全的"应用的所有者。本文稍后会讨论Windows XP中如何用WTS APIs(也就是Windows Terminal Services API--Windows终端服务API)来获取进程的宿主。

 
从DLL地狱到进程侦探:WinAPI文件占用排查的进化史 本文探讨了Windows系统中文件占用排查技术的演进历程,从早期的进程快照扫描到现代的重启管理器API。文章详细分析了DLL文件被占用问题的解决方案,包括WinAPI的使用技巧和性能优化策略,帮助开发者高效解决文件锁定问题。 阅读详情

相关推荐

Unity游戏开发客户端Unity基础

Unity游戏开发客户端面经 之 Unity 篇

Sea3752的博客 2万+

powershell 问题之一Get-Help使用问题

powershell的使用过程中,我们经常用到Get-Help 函数,但是我本地的(XP系统)总是报以下的错误: PS C:/> get-help get-help -Detailed Get-Help : Error loading help content for Get-Help from file "System.Management.Automation.dll-Help

Wayne的成长 1359

【国民技术N32项目移植】基于 Windows 的 ARM GCC 开发环境

【国民技术N32项目移植】基于 Windows 的 ARM GCC 开发环境

weixin_42150032的博客 1361

Dll被加载到进程空间后如何获取进程名

这种方法可以获取进程对应的可执行文件的绝对路径。一般情况下可执行文件名就是进程名。需要进程名只要切除掉路径部分即可。 LPTSTR GetCurrentProcessName() { HMODULE hMod = NULL; PCHAR pszBuf = NULL; DWORD dwRet = 0; hMod = GetModuleHandle(NULL); pszBuf = new CHAR[MAX_PATH]; if (NULL == pszBuf) { return(NULL)

輚至消亡 1196

AltiumDesigner 09安装过程破解问题 .

首先分享一下破解文件,网上总是下载不到,好不容易下载到了,放在网盘上,有需要的自取。AltiumDesigner 09破解文件。链接:https://pan.baidu.com/s/1ZGvbR_6T51hpcaFbQiMX5w 密码:qwvaAltiumDesigner 09安装安装文件,比较大,包含破解文件:链接:https://pan.baidu.com/s/1mfgragB519jpGfR...

xiaoxiao_rabbit的博客 3万+

YOLOv11火焰识别:从环境搭建到GUI部署的完整工程实践

目标检测是计算机视觉的核心任务之一,它通过定位和分类图像中的物体,为机器赋予“看懂”世界的能力。其原理通常基于深度学习模型,如YOLO系列,通过卷积神经网络提取特征并预测边界框与类别。这项技术的价值在于将算法能力转化为实际生产力,广泛应用于安防监控、工业质检、自动驾驶等场景。在工程实践中,环境配置的稳定性与数据质量往往决定项目成败,而模型部署的易用性直接影响最终用户体验。本文以火焰识别这一具体应用为切入点,详细解析了如何利用YOLOv11完成从零到产品化的全链路流程,其中涉及Conda虚拟环境管理、PyTo

weixin_29483277的博客 236

为什么你的内存修改总被反作弊抓包?CheatEngine-DMA 插件 5 步上手指南

数值刚改完,游戏下一秒就把你踢回桌面,日志里躺着一行"检测到异常进程"。玩内存修改的人,多半都经历过这种挫败——问题常常不在手法,而在读写方式。CheatEngine-DMA(Cheat Engine Plugin for DMA users)就是冲这个痛点来的开源插件:它把 Cheat Engine 的内存操作全部转交给 FPGA 硬件,走物理内存通道读写,让你的修改在操作系统眼里"查无此人"。

gitblog_00262的博客 154

【DAY11】超参数调整专题1

核心优势: 它不是随机选择下一个点,而是根据先前评估的结果建立一个概率模型(通常是高斯过程),预测哪些参数组合可能产生更好的结果,并据此选择下一个评估点。这使得它在寻找最优解方面通常比随机搜索更高效(用更少的迭代次数达到相似或更好的性能),特别是当模型训练(单次评估)非常耗时的时候。实际上,有着非常多的方式可以实现贝叶斯优化,上面的代码比较简洁美观,贝叶斯优化和网格搜索的代码书写风格高度一致。- 需要定义参数的搜索空间,与随机搜索类似,当搜索空间非常大时,它通常比网格搜索和随机搜索更有效。

daomingwu1的博客 747

摆脱DLL"地狱"的困扰之获取进程的命令行

摆脱DLL"地狱"的困扰之获取进程的命令行2006-03-03 10:11 作者: NorthTibet编译 出处: vckbase 责任编辑:方舟 方法 描述 GetName 以

JamesXing的专栏 1463

深信服AC1000-B1200到手第一步:从开箱到激活上网的保姆级图文指南

本文提供深信服AC1000-B1200企业级行为管理设备的详细开局使用指南,涵盖从开箱验机、物理连接到网络配置、安全加固及设备激活的全流程。通过图文并茂的步骤解析,帮助用户快速完成设备初始化并实现安全上网,特别适合初次接触该设备的网络管理员参考。

weixin_42546392的博客 548

基于imx6ull平台opencv的图像采集、ffmpeg推流和Windows端拉流(多线程)

本文档是针对imx6ull平台`opencv`的图像采集、ffmpeg推流和Windows端拉流。首先创建一个线程`opencv`通过摄像头采集视频图像,接着再创建两个线程,其中一个线程获取采集的视频图像送给ffmpeg服务,另一个线程用于获取采集的视频图像并处理,处理完并在显示屏上显示,详细的流程请参看如下。

程小二的博客 1607

摆脱DLL"地狱"困扰之目前的困境

  在 Windows 系统中,动态库版本冲突实在是一个老大难的问题了,为了解决这个问题,除了使用大量现有的工具外,你还可以利用丰富的 Windows APIs 函数构造自己的调试工具和实用程序。作为例子,本文将提供三个这种类型的工具,讨论如何利用它们来解决动态库的冲突问题。这三个工具分别是: DllSpy——列出加载到系统中的所有 Dlls 以及所有使用这些 Dlls 的进程; ProcessS

fxpopboy的博客 858

电磁兼容(EMC)整改案例(七):EFT测试失败都是IC悬空引脚惹的祸

无论任何时候,为了避免这些问题,通常建议对悬空的IO口进行适当的配置,比如设置为强推挽输出低电平、输入带上拉或下拉电阻等,以减少外部电路对IO管脚状态的影响,并提高系统的稳定性和可靠性.

linkking27的博客 1032

DLL地狱问题

    上班第一天郁闷的事情

armsnow的专栏 2722

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

.net Assembly—治愈“DLL地狱”的良方?

微软Windows应用程序经常受到动态链接库的拖累,这就是“DLL地狱”问题,在遇到此类麻烦的时候,应用程序的某一个组件会被其他应用程序的不兼容组件覆盖,结果令受到干扰的应用程序完全不能正确工作。这些问题很难诊断出来,因为它们只有在问题组件安装一段时间之后才会突然冒出来。Visual Basic应用程序的DLL地狱问题更是臭名昭著,因为用Visual Basic语言开发的应用程序相比其他编程语言开

蓝昊天——.net之旅 514

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

VisualCppRedist AIO:Windows系统运行库的终极解决方案,告别DLL地狱的困扰

你是否曾在安装新游戏或专业软件时,突然遭遇"应用程序无法启动,因为计算机中丢失MSVCP140.dll"这样的错误提示?这种令人沮丧的体验被称为"DLL地狱",而VisualCppRedist AIO正是为终结这种困境而生的技术利器。这个开源项目巧妙地将微软从2005年到2022年所有Visual C++运行库整合到一个智能安装包中,让用户无需再为繁琐的版本匹配而烦恼。 ## 揭开DLL缺失的神

gitblog_00469的博客 828

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

告别DLL地狱:VC++运行库管理新方案

这个VC++运行库管理系统有效解决了传统管理方式的痛点,特别适合企业IT部门使用。增加云端同步功能,统一管理多机房环境集成更多运行时组件管理(如.NET Framework)提供REST API接口,支持与其他运维系统集成如果你也在为VC++运行库管理头疼,不妨试试InsCode(快马)平台来快速构建类似工具。它的可视化编辑器和一键部署功能让开发过程变得简单高效,我实际使用时发现从构思到实现比传统方式快很多。

BlackironPanther23的博客 735

告别DLL地狱:Visual C++ Redistributable管理新方案

过去处理VC++运行库问题基本靠手动操作:先查日志确定缺失的dll,再去微软官网下载对应版本的Redistributable安装包,安装时还可能遇到版本冲突需要先卸载旧版。整个过程繁琐不说,最头疼的是不同软件可能依赖相互冲突的版本,比如A程序需要2015版而B程序必须用2013版。每次遇到"DLL地狱"——那些因为运行时库版本冲突导致的崩溃、报错,都让人抓狂。最惊喜的是部署体验——完成开发后一键就能生成可分发的安装包,还能自动处理依赖项打包,这对需要交付给客户使用的工具类软件太重要了。

GoldenleafRaven13的博客 621

告别DLL地狱:现代开发如何避免输入点定位问题

以前开发Windows程序时,经常遇到用户反馈程序无法运行,大多数情况都是因为缺少某个DLL文件,或者DLL版本不匹配。为了解决这个问题,我决定开发一个打包工具,能够将程序及其所有依赖打包成一个独立的可执行文件。使用这个工具后,我们的程序部署变得非常简单。最大的挑战是处理一些特殊情况,比如延迟加载的DLL,或者运行时动态加载的库。我实际使用后发现,从开发到部署的整个流程都变得非常顺畅,省去了很多繁琐的配置工作。对于Windows开发者来说,告别DLL地狱不仅能提升开发效率,更能给用户带来更好的体验。

RubyLion28的博客 609

突破DLL地狱:JNA实现动态链接库多版本并行加载的终极指南

🔍 **DLL地狱**是Windows开发者最头疼的问题之一,当应用程序依赖多个不同版本的动态链接库时,版本冲突和加载失败就成了家常便饭。今天,我们将介绍如何利用**Java Native Access (JNA)** 这一强大的Java库,轻松实现DLL多版本并行加载,彻底告别版本兼容性困扰! ## 什么是JNA?为什么它能解决DLL地狱? **JNA (Java Native Acces

gitblog_00272的博客 410

还在为Visual C++运行库烦恼吗?这个AIO工具能让你告别DLL地狱

想象一下这样的场景:你刚下载了一个心仪已久的游戏或专业软件,满心期待地双击运行,结果弹出一个冰冷的错误提示——"无法启动此程序,因为计算机中丢失MSVCR140.dll"。是不是很熟悉?这种被称为"DLL地狱"的依赖问题,困扰着无数Windows用户。今天,我要介绍一个能让你彻底摆脱这种烦恼的工具:VisualCppRedist AIO。 ## 痛点分析:为什么我们需要一个AIO解决方案? W

gitblog_00490的博客 188

告别DLL地狱:智能管理OPENAL32.DLL的5种方法

现在通过工具可以一键扫描全盘,自动识别所有OPENAL32.DLL的版本号和存放位置,生成清晰的列表。在Windows开发中,DLL文件管理一直是个让人头疼的问题,尤其是像OPENAL32.DLL这样的音频相关动态链接库。最实用的是"虚拟化"功能,让不同程序看到各自需要的DLL版本而互不干扰,这招解决了我长期困扰的游戏兼容性问题。工具虽小,但对于需要处理多版本DLL的开发者来说,绝对是提升效率的利器。这个平台最让我惊喜的是部署功能,点几下就能把工具发布到测试环境,省去了配置IIS和打包的麻烦。

RubyLion28的博客 865

告别DLL地狱:C++运行库管理新方案

不同版本的DLL冲突、缺失的依赖项、系统兼容性问题,这些都会消耗我们大量的调试时间。传统的运行库安装方式往往会导致版本冲突,新安装的版本可能会覆盖旧版本,导致原有程序无法运行。我们的系统采用沙箱机制,可以让不同版本的运行库并存,应用程序可以指定使用特定版本,彻底解决了版本冲突问题。Qt的图形界面组件让我们能够快速构建直观的用户界面,而其底层的跨平台抽象层则简化了系统功能的实现。在部署应用程序时,系统可以生成详细的兼容性报告,列出所有需要的运行库及其版本要求。如果你也想体验这种高效的开发方式,可以试试。

BlackironLynx23的博客 945
上一篇: 应用程序之间互相通讯的几种方法
下一篇: Visual C++进程间数据通信的实现
JamesXing
博客等级 码龄20年 30粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值