如何将 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 的匈牙利表示法带有 sz
和 dw
等前缀,通常令人厌恶。它曾在 1980 年代支持 Microsoft 的 Programmer's Workbench 中的帮助系统。据我所知,该产品在过去 30 年左右不存在。
(LPWSTR)cmd
中的 C 转换很容易引入错误。使用 const_cast
在你想要转换常量的地方。那么这个转换是不正确的会更清楚:你需要一个可变缓冲区。
与其通过 std::cout
向标准输出流报告故障,不如考虑通过 std::cerr
或 std::clog
使用标准错误流。更好的是,在检测到失败的地方不要做i/o,而是抛出异常让调用代码处理。调用代码无法删除已经存在的输出,呃,输出。
wcslen(wide)
returns 其参数 宽字符数 wide
(see).
wcstombs(narrow,wide,len)
写入不超过 len
字节 到 narrow
(see).
现在如果我们总是有一个宽字符 = 一个窄字符 = 一个字节,那么有两种不同的字符就没有多大意义了,对吗?
一旦您将宽字符转换为多个窄字符,就会出现未定义的行为。
因为你的szBuffer
是固定大小的,你也可以这样写
wcstombs(szBuffer, wPassword.c_str(), sizeof(szBuffer));
我在将 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 的匈牙利表示法带有
sz
和dw
等前缀,通常令人厌恶。它曾在 1980 年代支持 Microsoft 的 Programmer's Workbench 中的帮助系统。据我所知,该产品在过去 30 年左右不存在。(LPWSTR)cmd
中的 C 转换很容易引入错误。使用const_cast
在你想要转换常量的地方。那么这个转换是不正确的会更清楚:你需要一个可变缓冲区。与其通过
std::cout
向标准输出流报告故障,不如考虑通过std::cerr
或std::clog
使用标准错误流。更好的是,在检测到失败的地方不要做i/o,而是抛出异常让调用代码处理。调用代码无法删除已经存在的输出,呃,输出。
wcslen(wide)
returns 其参数 宽字符数 wide
(see).
wcstombs(narrow,wide,len)
写入不超过 len
字节 到 narrow
(see).
现在如果我们总是有一个宽字符 = 一个窄字符 = 一个字节,那么有两种不同的字符就没有多大意义了,对吗?
一旦您将宽字符转换为多个窄字符,就会出现未定义的行为。
因为你的szBuffer
是固定大小的,你也可以这样写
wcstombs(szBuffer, wPassword.c_str(), sizeof(szBuffer));