http://blog.youkuaiyun.com/windless0530/article/details/5496879
原贴也是转帖,只不过此人没给原链接……
http://pegasus827.bokee.com/6213525.html
P.S. 在98系统上,估计只有第一种方法有效。
方法一
第一种方法是大家比较熟悉的通过ToolHelp Service提供的API函数来实现。这里用到了3个关键的函数:CreateToolhelp32Snapshot(),Process32First()和Process32Next()。下面给出了关于这三个函数的原形和参数说明;
- HANDLE WINAPI CreateToolhelp32Snapshot(
- DWORD dwFlags, //系统快照要查看的信息类型
- DWORD th32ProcessID //值0表示当前进程
- );
- BOOL WINAPI Process32First(
- HANDLE hSnapshot, //CreateToolhelp32Snapshot()创建的快照句柄
- LPPROCESSENTRY32 lppe //指向进程入口结构
- );
- BOOL WINAPI Process32Next(
- HANDLE hSnapshot, //这里参数同Process32First
- LPPROCESSENTRY32 lppe //同上
- );
首先使用CreateToolhelp32Snapshot()创建系统快照句柄(hprocess是我们声明用来保存创建的快照句柄),
然后调用Process32First()获得系统快照中的第一个进程信息(Report是BOOL型作为判断系统快照中下一条进程记录):
- hProcess=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
- report=Process32First(hProcess,pinfo);
接着用一个循环调用来遍历系统中所有运行的进程:
- while(report) {
- hModule=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,pinfo->th32ProcessID);
- Module32First(hModule, minfo);
- GetShortPathName(minfo->szExePath,shortpath,256);
- printf("%s --- %s ",pinfo->szExeFile,shortpath);
- report=Process32Next(hProcess, pinfo);
- }
笔者曾通过对Pstools工具包里的Pslist.exe反编译,发现该工具用的就是这种方法。如果你查询MSDN,可以找到一个比这个功能更加完善的源程序。
方法二
(EnumProcesses、EnumProcessModules、GetModuleBaseName……本人略去……见本人另一贴“遍历进程、杀进程‘)
方法三
也许你会说前两种方法全世界都知道了,没什么大不了的!呵呵,那么笔者现在介绍的第三种方法,你就未必知道了。本方法利用了Windows NT/2000下终端服务API函数WTSOpenServer()和WTSEnumerateProcess()来实现,这两个函数都定义在Wtsapi32.dll里。具体的关于终端服务方面的知识,大家可以查询MSDN。
首先,我们来显示申明这两个函数原形:
- typedef HANDLE (_stdcall *WTSOPENSERVER)(
- LPTSTR pServerName //NetBios指定的终端服务名,如果我们查看本地终端所有进程信息我们可以通过在控制台命令行下用nbtstat –an来获取本机NetBios名。如图3所示。
- );
和前面一样,要先装载Wtsapi32.dll模块,获取关键函数地址,通过Argv[1]给终端服务名(这里我们赋本机NetBios名)赋一个值并打开这项服务:
- hWtsApi32 = LoadLibrary("wtsapi32.dll");
- pWtsOpenServer = (WTSOPENSERVER)GetProcAddress(hWtsApi32, "WTSOpenServerA");
- pWtsEnumerateProcesses = (WTSENUMERATEPROCESSES)GetProcAddress(hWtsApi32,"WTSEnumerateProcessesA");
通过Argv[1]给终端服务名(这里我们赋本机NetBios名)赋一个值并打开这项服务,然后开始遍历终端服务器上的所有进程,这里我们是指本机的所有进程
- if(!pWtsEnumerateProcesses(hWtsServer, 0, 1, &pWtspi, &dwCount)) {
- printf("enum processes error: %d ", GetLastError());
- return;
- };
- for (int i = 0; i < dwCount; i++) {
- // ...
- }
怎么样,酷吧,跟前面两种方法效果一样!
方法四
最后笔者介绍一种最少人用的方法,本方法是从“幻影旅团”论坛上看到的。后面给出的源代码也是从他们那拷贝过来的。呵呵,这种方法也提供给我们一种很好的思路。
这第四种方法利用了Native Api的NtQuerySystemInformation函数来实现。同样没有该函数的导入库,也要自己定义原形。整个实现不难,可是有点烦,因为在该函数参数结构上,笔者通查MSDN查了很久才找到这些相关的结构,下面我们来看看这个方法的实现吧。
先是自定义函数原形:
- typedef NTSTATUS (__stdcall *PZWQUERYSYSTEMINFORMATION)
- (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
- IN OUT PVOID SystemInformation,
- IN ULONG SystemInformationLength,
- OUT PULONG ReturnLength);
然后,还是和前面一样,要找到ZwQuerySystemInformation在Ntdll.dll模块里的入口地址,获得指向进程信息数组链的第一条进程信息:
- hModule = GetModuleHandle((LPCTSTR)"ntdll.dll");
- pZwQuerySystemInformation =(PZWQUERYSYSTEMINFORMATION)
- GetProcAddress(hModule, (LPCTSTR)"ZwQuerySystemInformation");
- pSystemProcessInformation = (SYSTEM_PROCESS_INFORMATION *)pvProcessList;
和方法一方法二一样,在获得第一条进程信息后,开始循环遍历,列出其余的进程:
- while (TRUE)
- {
- if (pSystemProcessInformation->NextEntryDelta == 0) //如果是最后一条,则终止循环。
- break;
- pSystemProcessInformation=(SYSTEM_PROCESS_INFORMATION*)((PCHAR)pSystemProcessInformation+ pSystemProcessInformation->NextEntryDelta);
- pProcessName = (char *)malloc(pSystemProcessInformation->ProcessName.Length + 2);
- }
特别注意的是,这里SYSTEM_PROCESS_INFORMATION结构里进程名的类型为UNICODE_STRING, 而UNICODE_STRING里的成员Buffer定义的是Unicode类型。
- typedef struct _SYSTEM_PROCESS_INFORMATION
- {
- DWORD NextEntryDelta;
- DWORD dThreadCount;
- DWORD dReserved01;
- DWORD dReserved02;
- DWORD dReserved03;
- DWORD dReserved04;
- DWORD dReserved05;
- DWORD dReserved06;
- FILETIME ftCreateTime; /* relative to 01-01-1601 */
- FILETIME ftUserTime; /* 100 nsec units */
- FILETIME ftKernelTime; /* 100 nsec units */
- UNICODE_STRING ProcessName; //这就是进程名
- DWORD BasePriority;
- DWORD dUniqueProcessId; //进程ID
- DWORD dParentProcessID;
- DWORD dHandleCount;
- DWORD dReserved07;
- DWORD dReserved08;
- DWORD VmCounters;
- DWORD dCommitCharge;
- PVOID ThreadInfos[1];
- } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
- typedef struct _UNICODE_STRING {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer; //注意,这里为Unicode类型
- } UNICODE_STRING, *PUNICODE_STRING;
所以,最后我们要调用WideCharToMultiByte()来还原成ANSI字符串以便输出:
- WideCharToMultiByte(CP_ACP,
- 0,
- pSystemProcessInformation->ProcessName.Buffer,
- pSystemProcessInformation->ProcessName.Length + 1,
- pProcessName,
- pSystemProcessInformation->ProcessName.Length + 1,
- NULL,
- NULL);