WEB开发网
开发学院软件开发VC 如何获取某个进程的主窗口以及创建进程的程序名 阅读

如何获取某个进程的主窗口以及创建进程的程序名

 2010-08-22 20:47:15 来源:WEB开发网   
核心提示:一般来讲,如果隶属于某个进程的窗口没有可见的父窗口,如何获取某个进程的主窗口以及创建进程的程序名(3),那么这个窗口就可以认为是此进程的主窗口,对WS_VISIBLE的检查很重要,用CProcessModuleIterator::GetProcessHandle可以得到已打开进程的句柄,lp程序还用CMainWindo

一般来讲,如果隶属于某个进程的窗口没有可见的父窗口,那么这个窗口就可以认为是此进程的主窗口。对WS_VISIBLE的检查很重要,因为有些应用创建多个不可见的顶层窗口。关于CMainWindowIterator类的使用细节请参见本文的例子源代码。

接下来我们来讨论如何获取创建进程的程序文件名。有人用各种方法尝试过,比如:GetModuleFileName,GetModuleInstance 和 GetModuleHandle,好像都不行。为什么呢?其实,方法是没错,但调用这些函数得到的只是当前正在运行的这个进程已经加载的模块名(modules),不能用于获取其它进程所加载的模块。因此,必须想别的办法,首先要考虑两种情况,一种是如果你写的程序在Windows NT,Windows 2000,Windows XP环境运行,则可以使用PSAPI,这是一个Windows操作系统中比较新的DLL,利用其中输出的API函数可以获取进程和模块的详细信息。另一种是如果你写的程序在Windows 9x或者Windows Me中运行,则必须借助于ToolHelp,限于本文的篇幅,我在这里不介绍如何使用ToolHelp,如果你感兴趣的话可以参考,MSDN的技术支持文章Q175030,题目为“如何在Win32中枚举应用程序”。

PSAPI中有一个函数是GetModuleFileNameEx。它通过某个进程和模块句柄作为参数来获得模块名。那么对于某个进程来说,你怎么知道哪个模块是启动进程的执行文件呢呢?PSAPI中的另一个函数EnumProcessModules将某个进程中所有模块的模块句柄填充到一个数组中。这个数组的第一个元素便是主模块的句柄,所以你用下面的代码来得到第一个HMODULE:

DWORD count;
HMODULE hm[1];
EnumProcessModules(hProcess, hm, 1, &count);

然后调用GetModuleFileNameEx。

实际上从前面的图一中可以看到,在lp.exe程序中我们已经实现了罗列进程及其对应的模块名。程序的实现细节中还用到了PSAPI输出的API函数EnumProcesses来枚举所有运行进程,为了对具体的细节进行封装,我如法炮制编写了与CWindowIterator 和CMainWindowIterator类似的两个C++类:CProcessIterator 和 CProcessModuleIterator ,它们分别对EnumProcesses 和EnumProcessModules API函数进行了封装。有了这两个打包类,一切都变得如此简单。

CProcessIterator itp;
for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
 // 处理每一个进程
}

下面是获取创建进程的EXE文件名的方法:

CProcessModuleIterator itm(pid);
HMODULE hModule = itm.First(); // .EXE
TCHAR modname[_MAX_PATH];
GetModuleBaseName(itm.GetProcessHandle(), hModule, modname, _MAX_PATH);

因为lp显示出来的并不是一个含全路径的模块文件名,所以我用另外一个PSAPI函数GetModuleBaseName来代替GetModuleFileNameEx从而获取全路径名。此外,由于CProcessModuleIterator自己会打开进程枚举模块,所以不必调用OpenProcess。用CProcessModuleIterator::GetProcessHandle可以得到已打开进程的句柄。lp程序还用CMainWindowIterator来显示每个特定进程的所有主窗口。下面是CProcessIterator 和 CProcessModuleIterator的定义:

////////////////////////////////////////////////////////////////////////////////////////
// 进程列举类 -- 列举出系统中的所有进程,但总是跳过第一个PID=0的进程,即空闲进程(IDLE)
//
class CProcessIterator {
protected:
  DWORD*  m_pids; // 包含进程IDs的数祖
  DWORD    m_count; // 数组大小
  DWORD    m_current; // 当前数组项
public:
  CProcessIterator();
  ~CProcessIterator();
  DWORD GetCount() { return m_count; }
  DWORD First();
  DWORD Next() {
    return m_pids && m_current <m_count ? m_pids[m_current++] : 0;
  }
};
/////////////////////////////////////////////////////////////////
// 列举某个进程的模块,第一个模块就是创建此进程的主exe程序
//
class CProcessModuleIterator {
protected:
  HANDLE  m_hProcess; // 进程句柄
  HMODULE*  m_hModules; // 模块句柄数组
  DWORD    m_count; // 数组大小
  DWORD    m_current; // 当前模块的句柄
public:
  CProcessModuleIterator(DWORD pid);
  ~CProcessModuleIterator();
  HANDLE GetProcessHandle()  { return m_hProcess; }
  DWORD GetCount()        { return m_count; }
  HMODULE First();
  HMODULE Next() {
    return m_hProcess && m_current < m_count ? m_hModules[m_current++] : 0;
  }
};

本文配套源码

上一页  1 2 3 

Tags:如何 获取 某个

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接