CreateProcess 的问题和不正确的参数

Issues with CreateProcess and incorrect parameters

这可能是 2 个问题,但它们大体上都是围绕 CreateProcess 展开的,而且它运行不正常。

我一直在开发一个应用程序,该应用程序收集文件、处理它们,然后将它们压缩作为最后一步,使用我压缩的目录的哈希值重命名压缩文件。为此,我使用了 7zip (7za.exe) 的独立副本,通过使用 CreateProcess 来创建/压缩存档,以及一个名为 DirHash 的单独程序来生成我要制作的存档的名称.

我遇到的问题是这两个程序都不能正常工作。我目前 运行 使用标志 -t "temp.txt" -nowait -quiet -overwrite" 宁 DirHash,它确实创建了一个名为 temp.txt 的文件,但是,当使用 CreateProcess 运行宁它时,该文件始终为空.当我在标准命令行上使用完全相同的参数时,它会产生正确的输出。

另一个问题是 7zip 在尝试压缩我的目录时似乎出错。当 运行 通过我的 CreateProcess 时,我收到“不支持的命令”错误,并且文件没有被压缩。但是,当我在命令行上使用完全相同的参数时,存档创建成功。

这里是DirHash的相关代码,同样的代码也用于7za。我已经确认给CreateProcess的值是正确的,而且参数和我在命令行中使用的一样。

auto hashLocation = searchPath + "\" + DIRHASH_NAME;
auto params = "\"" + targetDir + "\" MD5" + " -quiet -t \"temp.txt\" -nowait -overwrite";


// I know this part is gross and if there's any suggestions for how to do it better I'm willing to hear it.        
std::wstring intermediate;
intermediate.assign(params.begin(), params.end());
LPWSTR trueParams = &intermediate[0];

std::wstring intermediate_ex;
intermediate_ex.assign(hashLocation.begin(), hashLocation.end());
LPCWSTR trueLocation = intermediate_ex.c_str();

STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);


// Ripped from stack overflow
bool success = CreateProcess(
    trueLocation,
    trueParams,
    NULL,
    NULL,
    TRUE,
    0,              // No creation flags
    NULL,           // Use parent's environment block
    NULL,           // Use parent's starting directory 
    &si,            // Pointer to STARTUPINFO structure
    &pi             // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
    );
    // Close process and thread handles. 
WaitForSingleObject(pi.hProcess, INFINITE);
if (!success)
{
    addLog("Failed to run DirHash process.", ErrorLevel::ERROR_MESSAGE);
    return ERROR_STR;
}

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

当同时使用 CreateProcess()lpApplicationNamelpCommandLine 参数时,lpCommandLine 应该包括 EXE 路径作为命令行中的第一个标记。这甚至在 CreateProcess() 文档中有说明:

If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.

因此,如果您要在命令行中包含 EXE 路径,则根本不需要使用 lpApplicationName 参数:

If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter )...

此外,而不是将 char 字符串转换为 std::wstring(你做的不正确)只是为了调用 CreateProcess()(它被映射到 CreateProcessW()这种情况),你可以使用 CreateProcessA() 代替。

试试这个:

std::string hashLocation = searchPath + "\" + DIRHASH_NAME;
std::string cmd = "\"" + hashLocation + "\" \"" + targetDir + "\" MD5 -quiet -t \"temp.txt\" -nowait -overwrite";

STARTUPINFOA si = {};
si.cb = sizeof(si);

PROCESS_INFORMATION pi = {};

bool success = CreateProcessA(
    NULL,
    &cmd[0], // or const_cast<char*>(cmd.c_str()), or params.data() in C++17...
    NULL,
    NULL,
    FALSE,
    0,              // No creation flags
    NULL,           // Use parent's environment block
    NULL,           // Use parent's starting directory 
    &si,            // Pointer to STARTUPINFO structure
    &pi             // Pointer to PROCESS_INFORMATION structure
);
if (!success)
{
    addLog("Failed to run DirHash process.", ErrorLevel::ERROR_MESSAGE);
    return ERROR_STR;
}

// Close process and thread handles. 
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

或者这个:

// change searchPath, DIRHASH_NAME, and targetDir to wide strings... 
std::wstring hashLocation = searchPath + L"\" + DIRHASH_NAME;
std::wstring cmd = L"\"" + hashLocation + L"\" \"" + targetDir + L"\" MD5 -quiet -t \"temp.txt\" -nowait -overwrite";

STARTUPINFOW si = {};
si.cb = sizeof(si);

PROCESS_INFORMATION pi = {};

bool success = CreateProcessW(
    NULL,
    &cmd[0], // or params.data() in C++17...
    NULL,
    NULL,
    FALSE,
    0,              // No creation flags
    NULL,           // Use parent's environment block
    NULL,           // Use parent's starting directory 
    &si,            // Pointer to STARTUPINFO structure
    &pi             // Pointer to PROCESS_INFORMATION structure
);
if (!success)
{
    addLog("Failed to run DirHash process.", ErrorLevel::ERROR_MESSAGE);
    return ERROR_STR;
}

// Close process and thread handles. 
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);