【问题标题】:Issues with CreateProcess and incorrect parametersCreateProcess 的问题和不正确的参数
【发布时间】:2021-04-12 15:49:24
【问题描述】:

这可能是 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 是一个 LPSTR,即它需要是一个可写指针。不知道是不是你的情况,看起来好像是这样想的。我的最后一个调试技巧:编写一个简单的 C++ 程序,调用 GetCommandLine 并将其转储到一个文件中,使用它代替 7zip/DirHash,看看它是否达到了您的预期。
  • 另一个调试思路:在 cmd.exe 上调用 CreateProcess,并带有启动运行 7zip/DirHash 的批处理文件的参数。看看这是否会改变任何东西,这可能会导致您遇到问题。

标签: c++ hash 7zip createprocess


【解决方案1】:

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

如果lpApplicationNamelpCommandLine都不是NULL,则lpApplicationName指向的以null结尾的字符串指定要执行的模块,lpCommandLine指向的以null结尾的字符串指定命令行.新进程可以使用GetCommandLine 检索整个命令行。 用 C 编写的控制台进程可以使用 argcargv 参数来解析命令行。因为argv[0]是模块名,所以C程序员一般会重复模块名作为命令行中的第一个记号。

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

如果lpApplicationName 为NULL,则命令行的第一个空格分隔标记指定模块名称。如果您使用包含空格的长文件名,请使用带引号的字符串来指示文件名的结束位置和参数的开始位置(请参阅lpApplicationName 参数的说明)...

此外,您可以使用 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);

【讨论】:

  • 就是这样,谢谢!一个小提示,您必须将 STARTUPINFO 变量更改为 STARTUPINFOA 才能使 CreateProcessA 工作,但除此之外,这很好用。
猜你喜欢
  • 2012-04-07
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多