查找进程HWND (MSDN Magazine C++ Q&A)

Question:

How can I find the name of the program file (EXE) associated with another process? I've tried various combinations of GetModuleFileName, GetModuleInstance, and GetModuleHandle, but nothing seems to work.

Frank Weston


Answer:

Download the code for this article: CQA0207.exe (72KB)

 The problem with these calls is that they work only for modules loaded within the current running process, not modules in a different process. For that, you need something else, and here the road forks. If you're writing for Windows NT® 4.0, Windows 2000, or Windows XP, you can use PSAPI, a relatively new DLL with functions to get information about processes and modules. If you're writing for Windows 95, Windows 98, or Windows Me, you'll have to use ToolHelp. Since I'm so modern, I'll show you how to do it the PSAPI way. For help with ToolHelp, see Article Q175030, "HOWTO: Enumerate Applications in Win32" on MSDN®.
One of the functions in PSAPI is GetModuleFileNameEx. It takes a process and module handle and gets the name of the module. How do you know which module in a process is the EXE that started it? There's another PSAPI function, EnumProcessModules, that stuffs an array with module handles for all the modules in a process. The first entry is always the main module, so you can write

DWORD count;
HMODULE hm[1];
EnumProcessModules(hProcess, hm, 1, &count);
to get the first HMODULE, then call GetModuleFileNameEx. To show how it works in practice, I wrote a little program, lp, that lists processes with their module names and main windows (see Figure 2 ). Figure 3 shows a sample run. (Note that Windows Explorer and Outlook both have two "main" windows.)

Figure 3 Sample Run
Figure 3 Sample Run

The lp program uses a third PSAPI function, EnumProcesses, to enumerate all the running processes, but following the same idea as CWindowIterator and CMainWindowIterator from the previous question, I encapsulated the gory aspects of EnumProcesses and EnumProcessModules in two iterator classes, CProcessIterator and CProcessModuleIterator .With these classes in hand, lp is pretty straightforward. To iterate the processes, try the following:
CProcessIterator itp;
for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
// handle each process
}
And here's how to get the name of the EXE that created the process:
CProcessModuleIterator itm(pid);
HMODULE hModule = itm.First(); // .EXE
TCHAR modname[_MAX_PATH];
GetModuleBaseName(itm.GetProcessHandle(),
hModule, modname, _MAX_PATH);
Since lp displays just the base module file name, not the full path name, I use another PSAPI function, GetModuleBaseName, instead of GetModuleFileNameEx. And since CProcessModuleIterator opens the process to enumerate the modules, I don't have to call OpenProcess. Instead, I can use CProcessModuleIterator::GetProcessHandle to get the already open process handle. Then lp uses CMainWindowIterator with each process to display the HWNDs of all the main windows. The bulk of lp is the logic to interpret command-line switches. For example, -c lists the window class names, and -t the titles.
Since that was so easy, I wrote lp again just for fun, this time in C# .Not surprisingly, things are a lot easier with .NET. There's no need for PSAPI or home-grown iterator classes; .NET already has all the classes you need to navigate processes and modules. Process.GetProcesses returns an array of Process objects, all the processes in the system. From each Process object you can get its main module and window handle.
Process[] procs = Process.GetProcesses();
int len = procs.GetLength(0);
for (int i=0; i<len; i++) {
Process p = procs[i];
if (p.Id!=0) {
int hwnd = p.MainWindowHandle.ToInt32();
if (hwnd!=0) { // if has a main window:
ProcessModule pm = p.MainModule;
String modname = pm.ModuleName;
•••
}
}
}
p.MainModule is the main (EXE) module (to get all of them, use p.Modules, a ProcessModuleCollection) and p.MainWindowHandle is the main window handle. (See my comments at the end of the preceding question about this strange but useful property.) While lp is a lot simpler in C#, all that ease-of-programming comes at a cost. When I run the C++ version of lp, the response is instantaneous. From the moment I press Enter to the moment the output appears, there's no delay I can humanly perceive. With .NET, it takes a long second—even with 768MB. C# and .NET just can't deliver the speed of C/C++ and native APIs. This should come as no surprise, knowing all that goes on behind the magic curtain. Of course, no programmer in his right mind would use .NET to write a console app, except as a learning exercise. That would be like firing up the space shuttle to get groceries. Did you ever notice the "net" in .NET? That means .NET is aimed at Web apps, where a few bazillion extra CPU cycles is nothing among friends, and gigabyte servers can be preloaded up the wazoo.

Update
In my
May column , Destin Szelong asked a question about function hiding. This happens when you have a base class with overloaded virtual functions and you override one in a derived class. The other functions are not automatically inherited, because once the compiler finds the function name in the derived scope, it looks no further. In May, I showed how to get around the function hiding problem by defining a derived class function that explicitly calls the base class.
class D : public B {
public:
virtual void test(int x) {
B::test(x); // call base explicitly
}
};
As several readers including guru Scott Meyers pointed out, there's another way.
class D : public B {
public:
using B::test;
// other test overrides
};
This brings B::test into the scope of D. It has the advantage that you don't have to rewrite D if someone expands B with more overloaded test functions. Not to mention it requires less typing! When you use using, all overloaded B::test functions come into D's scope and are thus inherited. This may be an advantage or disadvantage, depending on what you're trying to do. If you want to keep some test functions hidden from consumers of D, you can use my first method (call base explicitly), or make the functions you want to hide private or protected. If you read Scott's book More Effective C++ (Addison-Wesley, 1995), you'll learn on pages 143-144 that you can even use using to circumvent the privacy of base classes.
class B { // some class
public:
func1();
func2(double d);
virtual test();
virtual test(int x);
};

// D is privately derived from B
class D : private B {
public:
// make all B::test fns public!
using B::test;
};
This trick is expedient when B should properly be hidden, but has one or two functions you want to expose. All of which goes to prove that in C++, there's never only one way to skin a cat.
Happy programming!
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值