为什么不提供CreateProcessW()执行命令?

时间:2020-03-17 22:15:52

标签: c++ windows createprocess

为了显示最小的可复制代码,我编写了一个代码,使用CreateProcessW()从给定位置删除文件。该文件不会被删除。知道为什么为什么不起作用时,一些帮助将非常有用。

dprintf(("Error %d", GetLastError()));
STARTUPINFO si = { sizeof(STARTUPINFO), 0 };
si.cb = sizeof(si);
PROCESS_INFORMATION pi = { 0 };
LPWSTR AppName = L"C:\\Windows\\System32\\cmd.exe";
string bstr = "C:\\Windows\\System32\\cmd.exe /C del"+trans_loc+"a.rtf";
LPWSTR Command = new WCHAR[bstr.length()];
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, NULL, 0);
MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, Command, wchars_num);
DWORD res = CreateProcessW(AppName, Command, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);

WaitForSingleObject(pi.hProcess, INFINITE);

定义TRANSCRIPT_LOCATION“ C:\ Users \ Administrator \ Desktop \”,这是要删除的文件的位置

GetLastError()继续返回50(ERROR_NOT_SUPPORTED),并且res的值= 1

2 个答案:

答案 0 :(得分:2)

我首先想到的是

LPWSTR Command = new WCHAR[bstr.length()];

不正确。也许

LPWSTR Command = new WCHAR[bstr.length() + 1];

将起作用。更好的选择是使用wchars_num分配内存。

代替

LPWSTR Command = new WCHAR[bstr.length()];
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, NULL, 0);
MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, Command, wchars_num);
DWORD res = CreateProcessW(AppName, Command, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);

使用

int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, NULL, 0);
LPWSTR Command = new WCHAR[wchars_num];
MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, Command, wchars_num);
DWORD res = CreateProcessW(AppName, Command, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);

第二个问题是,在编写del命令时,您可能错过了空格字符。

string bstr = "C:\\Windows\\System32\\cmd.exe /C del " + trans_loc + "a.rtf";
//                                                  ^^

答案 1 :(得分:1)

我发现您的代码存在许多问题:

  • LPWSTR AppName = L"C:\\Windows\\System32\\cmd.exe";在C ++ 11和更高版本中无法编译。您需要(并且应该)改为使用LPCWSTR,因为字符串文字是const数据,并且LPCWSTR是指向const WCHAR的指针数据,但LPWSTR是指向非const WCHAR数据的指针。

  • string bstr = "C:\\Windows\\System32\\cmd.exe /C del"+trans_loc+"a.rtf";中,del命令和要删除的文件名之间缺少必需的空格字符。

  • LPWSTR Command = new WCHAR[bstr.length()];中,您没有为空终止符分配足够的空间。另外,无论如何都不要将bstr.length()用于转换后的长度,因为不能保证转换后的字符串不会大于原始字符串。您应该使用MultiByteToWideChar()输出缓冲区调用NULL一次来计算实际的转换长度(您正在执行的操作),然后分配内存(您没有执行的操作-您分配得太早了!) ,然后再次调用MultiByteToWideChar()进行实际转换。

  • 您正在泄漏已分配的内存(您未在调用delete[] Command;)。我建议使用std::wstringstd::vector<WCHAR>代替new WCHAR[]

  • 您说res设置为1,这意味着CreateProcessW()在运行cmd.exe时实际上成功(现在,是否{{ 1}}成功执行命令是另一回事-使用GetExitCodeProcess()找出来),因此cmd.exe的返回值毫无意义!在致电GetLastError()

  • 之前先致电GetLastError() 当然很有意义
  • 无论CreateProcessW()是成功还是失败,您都在呼叫WaitForSingleObject()

尝试以下方法:

CreateProcessW()

或者,如果您使用的是Windows 10 build 17035或更高版本,并且在Windows设置中启用了“测试版:使用Unicode UTF-8进行全球语言支持”选项(或者,如果STARTUPINFO si = {}; si.cb = sizeof(si); PROCESS_INFORMATION pi = {}; std::string bstr = "C:\\Windows\\System32\\cmd.exe /C del \"" + trans_loc + "a.rtf\""; int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), NULL, 0); if (wchars_num == 0) { dprintf(("MultiByteToWideChar Error %d", GetLastError())); } else { std::vector<WCHAR> Command(wchars_num + 1); MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), Command.data(), wchars_num); if (!CreateProcessW(nullptr, Command.data(), nullptr, nullptr, FALSE, DETACHED_PROCESS, nullptr, nullptr, &si, &pi)) { dprintf(("CreateProcessW Error %d", GetLastError())); } else { WaitForSingleObject(pi.hProcess, INFINITE); DWORD dwExitCode = 0; GetExitCodeProcess(pi.hProcess, &dwExitCode); dprintf(("cmd.exe Exit Code %d", dwExitCode)); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } } 不包含任何内容非ASCII,非用户区域设置字符),则根本不需要trans_loc转换:

MultiByteToWideChar()

话虽如此,一个更好的选择是简单地使用STARTUPINFO si = {}; si.cb = sizeof(si); PROCESS_INFORMATION pi = {}; std::string Command = "C:\\Windows\\System32\\cmd.exe /C del \"" + trans_loc + "a.rtf\""; if (!CreateProcessA(nullptr, const_cast<char*>(Command.c_str()), nullptr, nullptr, FALSE, DETACHED_PROCESS, nullptr, nullptr, &si, &pi)) { dprintf(("CreateProcessA Error %d", GetLastError())); } else { WaitForSingleObject(pi.hProcess, INFINITE); DWORD dwExitCode = 0; GetExitCodeProcess(pi.hProcess, &dwExitCode); dprintf(("cmd.exe Exit Code %d", dwExitCode)); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } 而不是std::wstring来开始:

std::string

当然,最简单的解决方案是根本不使用STARTUPINFO si = {}; si.cb = sizeof(si); PROCESS_INFORMATION pi = {}; // make sure trans_loc is std::wstring instead of std::string... std::wstring bstr = L"C:\\Windows\\System32\\cmd.exe /C del \"" + trans_loc + L"a.rtf\""; if (!CreateProcessW(nullptr, Command.data(), nullptr, nullptr, FALSE, DETACHED_PROCESS, nullptr, nullptr, &si, &pi)) { dprintf(("CreateProcessW Error %d", GetLastError())); } else { WaitForSingleObject(pi.hProcess, INFINITE); DWORD dwExitCode = 0; GetExitCodeProcess(pi.hProcess, &dwExitCode); dprintf(("cmd.exe Exit Code %d", dwExitCode)); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } ,而要使用DeleteFileW()

cmd.exe / C del

或者,如果您坚持使用UTF-8编码的// make sure trans_loc is std::wstring instead of std::string... std::wstring bstr = trans_loc + L"a.rtf"; if (!DeleteFileW(bstr.c_str())) { dprintf(("DeleteFileW Error %d", GetLastError())); }

std::string

或者,如果您使用的是启用了UTF-8支持的Windows 10(或者std::string bstr = trans_loc + "a.rtf"; int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), NULL, 0); if (wchars_num == 0) { dprintf(("MultiByteToWideChar Error %d", GetLastError())); } else { std::vector<WCHAR> wstr(wchars_num + 1); MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), wstr.data(), wchars_num); if (!DeleteFileW(wstr.c_str())) { dprintf(("DeleteFileW Error %d", GetLastError())); } } 不包含任何非ASCII,非用户区域设置的字符):

trans_loc