如何将 wstring 缓冲区发送到子进程的标准输入?

How to send wstring buffer to stdin of a child process?

我在将 WString 写入子进程的 STDIN 时遇到问题。如果我只有 acii 字符串(例如:@WSX3edc),代码工作正常,但如果它包含非 ascii 字符(例如:@WSX3edcß),它将失败。

子进程是 7zr.exe(7Zip 命令行版本)。我写入 STDIN 的输入是提取文件的密码。

// inject password
wPassword.append(password);
wPassword.append(L"\n"); \For carriage return
...
DWORD dwBytesToWrite = wPassword.length()*sizeof(wchar_t);
DWORD dwBytesWritten = 0;
char szBuffer[1024] = "[=10=]";
wcstombs(szBuffer, wPassword.c_str(),wcslen(wPassword.c_str())+1);
dwBytesToWrite = strlen(szBuffer);
if (!WriteFile(hInput, szBuffer, dwBytesToWrite, &dwBytesWritten, NULL)) {
    std::cout<<"write file failed"<<GetLastError()<<std::endl;
    goto Cleanup;
}

writefile 总是成功,但由于错误的密码注入机制导致文件提取不成功。

为此创建过程看起来像:(si 对象具有使用 CreatePipe 之前设置的 STDIN 和 STDOUT 流)

if(!CreateProcess((LPWSTR)cmd, (LPWSTR)cmdArgs, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS,
        NULL, NULL, &si, &pi)) {
         std::cout<<"7zr.exe process creation failed "<<GetLastError()<<std::endl;
         goto Cleanup;
}

注意:7zr.exe 使用此特定密码 效果很好,如果我们 运行 在命令行上粘贴此密码。提取工作正常。

如果窄字符集中没有相关的密码字符,则不能使用此方法。而是找到 7zr 用于指定密码的选项。我没有名为 7zr 的可执行文件,但我有 7z,并且命令 7z | find /i "pass" 运行良好。


在其他新闻中:

  • 变量dwBytesToWrite初始化为一个值,只是在几行之后被重新赋值,没有被使用。

  • goto Cleanup 在 C++ 中通常不好。如果你想保证清理使用析构函数(称为 RAII 的技术,请继续阅读)。

  • Microsoft 的匈牙利表示法带有 szdw 等前缀,通常令人厌恶。它曾在 1980 年代支持 Microsoft 的 Programmer's Workbench 中的帮助系统。据我所知,该产品在过去 30 年左右不存在。

  • (LPWSTR)cmd 中的 C 转换很容易引入错误。使用 const_cast 在你想要转换常量的地方。那么这个转换是不正确的会更清楚:你需要一个可变缓冲区。

  • 与其通过 std::cout 向标准输出流报告故障,不如考虑通过 std::cerrstd::clog 使用标准错误流。更好的是,在检测到失败的地方不要做i/o,而是抛出异常让调用代码处理。调用代码无法删除已经存在的输出,呃,输出。

wcslen(wide) returns 其参数 宽字符数 wide (see).

wcstombs(narrow,wide,len) 写入不超过 len 字节 narrow (see).

现在如果我们总是有一个宽字符 = 一个窄字符 = 一个字节,那么有两种不同的字符就没有多大意义了,对吗?

一旦您将宽字符转换为多个窄字符,就会出现未定义的行为。

因为你的szBuffer是固定大小的,你也可以这样写

wcstombs(szBuffer, wPassword.c_str(), sizeof(szBuffer));