c++ - CreateProcess 的问题和不正确的参数
问题描述
这可能是 2 个问题,但它们都广泛地围绕着 CreateProcess 并且运行不正常。
我一直在开发一个应用程序,它将文件收集在一起,处理它们,然后将它们压缩作为最后一步,用我压缩的目录的哈希重命名压缩文件。为此,我使用了 7zip (7za.exe) 的独立副本,通过使用 CreateProcess 创建/压缩存档,以及一个名为 DirHash 的单独程序来生成我正在尝试制作的存档的名称。
我遇到的问题是这些程序都不能正常工作。我目前正在使用 flags 运行 DirHash -t "temp.txt" -nowait -quiet -overwrite"
,它确实创建了一个名为 的文件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);
解决方案
当同时使用lpApplicationName
和的lpCommandLine
参数时CreateProcess()
,lpCommandLine
应将 EXE 路径作为命令行中的第一个标记。这甚至在CreateProcess()
文档中都有说明:
如果
lpApplicationName
和lpCommandLine
都是非NULL,则指向的以空结尾的字符串lpApplicationName
指定要执行的模块,指向的以空结尾的字符串lpCommandLine
指定命令行。新进程可用于GetCommandLine
检索整个命令行。用 C 编写的控制台进程可以使用argc
和argv
参数来解析命令行。因为argv[0]
是模块名,所以C程序员一般会重复模块名作为命令行中的第一个记号。
因此,如果您要在命令行中包含 EXE 路径,则根本不需要使用该lpApplicationName
参数:
如果
lpApplicationName
为 NULL,则命令行的第一个空格分隔标记指定模块名称。如果您使用包含空格的长文件名,请使用带引号的字符串来指示文件名的结束位置和参数的开始位置(请参阅lpApplicationName
参数说明)...
此外,您可以使用而不是将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);
推荐阅读
- c# - 是否可以使用 C# 将 Tempdata 限制为 ASP.NET MVC 中的其他控制器
- python - 如果我将此文本作为脚本运行,它运行良好。关于 Tkinter 环境,这种语法有什么问题?
- kql - 如何从 KQL 中的列中提取日期时间?
- c# - Azure 函数应用 (C#) 中的计时器触发函数
- python - 如何将我自己的 Cython 模块导入到 jupyter notebook
- php - 如何在本地和远程服务器上使用相同的图像和文件链接
- mongodb - 如何将 JSON 导入 MongoDB Atlas 并从 Realm 函数中设置字段类型?
- javascript - 用javascript计算金字塔中炮弹的数量
- python - 搜索特定字符并过滤
- post - DIVI 全角后滑块延迟启动