C语言宽字符命令行参数问题:传入进程名无法获取PID
问题描述
我编写了一个程序,功能是获取首个命令行参数(应为进程名)并查找对应进程的PID。核心代码如下:
在main函数中调用:
DWORD PID = FindProcessId(argv[1]);
PID查找函数定义:
DWORD FindProcessId(PWCHAR processname) { NTSTATUS status; PVOID buffer; PSYSTEM_PROCESS_INFORMATION spi; DWORD pid = 0; buffer = VirtualAlloc(NULL, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); spi = (PSYSTEM_PROCESS_INFORMATION)buffer; status = NtQuerySystemInformation(SystemProcessInformation, spi, 1024 * 1024, NULL); while (spi->NextEntryOffset) // 遍历进程列表直到找到目标PID或到末尾 { if (wcsncmp(spi->ImageName.Buffer, processname, spi->ImageName.Length) == 0) { pid = spi->UniqueProcessId; break; } spi = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)spi + spi->NextEntryOffset); // 计算下一个进程条目地址 } return pid; }
直接在代码中传入L"notepad.exe"时,程序可正常获取PID;但通过命令行运行find_pid.exe notepad.exe时,FindProcessId返回0,明明notepad.exe正在运行却无法找到。我想用main而非wmain来让程序接收宽字符参数,为什么命令行传入时会失效?
原因分析
- 字符编码不匹配:
main函数的argv参数是char*类型的窄字符数组,而FindProcessId接收的是PWCHAR(宽字符指针)。直接把char*强转为PWCHAR会导致编码混乱——命令行传入的ASCII字符串被当成UTF-16宽字符解析,内容完全错误,自然匹配不到进程名。 wcsncmp长度参数错误:spi->ImageName.Length是宽字符的字节数(比如notepad.exe是12个字符,字节数为24),而你传入的"伪宽字符"实际长度只有12字节,wcsncmp用24作为比较长度时会读取内存垃圾数据,导致匹配失败。
解决方案
有两种可靠的修复方式:
方式一:改用wmain接收宽字符参数
这是Windows平台处理宽字符命令行参数的标准做法,系统会自动将命令行参数转换为UTF-16宽字符:
int wmain(int argc, wchar_t* argv[]) { if (argc < 2) return 1; DWORD PID = FindProcessId(argv[1]); // 后续逻辑 return 0; }
方式二:在main中手动转码窄字符为宽字符
如果坚持使用main,需要将argv[1]的窄字符转换为宽字符后再传入FindProcessId,同时修正wcsncmp的长度参数:
#include <stdlib.h> // 包含mbstowcs_s int main(int argc, char* argv[]) { if (argc < 2) return 1; wchar_t wideName[256]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wideName, sizeof(wideName)/sizeof(wchar_t), argv[1], _TRUNCATE); DWORD PID = FindProcessId(wideName); // 后续逻辑 return 0; }
修正FindProcessId中的比较逻辑:
// 原长度参数是字节数,替换为宽字符个数 if (wcsncmp(spi->ImageName.Buffer, processname, spi->ImageName.Length / sizeof(wchar_t)) == 0)
内容的提问来源于stack exchange,提问作者nortain32
相关产品推荐
相关产品推荐

