我有一个GUI程序,它是一个"包装器"到cmd.exe。 从这个GUI程序,我可以通过cmd.exe发送和接收命令
我正在使用管道重定向,并且已经阅读了各种引用:
Creating a Child Process with Redirected Input and Output
Redirect Input and Output of Powershell.exe to Pipes in C++
windows cmd pipe not unicode even with /U switch
首先,我启动" cmd.exe / U"的实例,以便我告诉cmd.exe生成Unicode输出 然后我使用ReadFile / WriteFile来读取和写入管道。
如果我使用ANSI,一切正常,但我遇到了与Unicode相关的2个问题:
1)如果我想使用WriteFile将数据传递给管道,我必须先将它从Unicode转换为Ansi。以Unicode格式传递数据不起作用:具体来说,在我的WriteFile之后读取输出时,cmd会输出一个"更多?"串。 如果我用ANSI编写输入,它工作正常,cmd正确输出命令的结果。 已使用/ U开关启动cmd。
2)当我从cmd启动一个外部程序(如ping,netstat,ipconfig等)时,控制台输出成功地为内部命令(如cd,dir等)启用了unicode。我收到的输出是ANSI,所以我收到了损坏的数据。 我想当外部程序通过cmd运行时/ U开关没有效果?是否有可能的解决方案,并使cmd中的所有内容都以Unicode格式输出?
以下是我的代码示例,我在错误所在的行上放置了注释:
bool StartCmdPipe()
{
static SECURITY_ATTRIBUTES SA;
static STARTUPINFOW SI;
static PROCESS_INFORMATION PI;
static HANDLE StdInPipeRead;
static HANDLE StdInPipeWrite;
static HANDLE StdOutPipeRead;
static HANDLE StdOutPipeWrite;
static wstring sWorkDir;
WCHAR* pBuffer;
unsigned long BytesRead;
sWorkDir = _wgetenv(L"SystemDrive");
sWorkDir += L"\\";
bJustOpened = true;
SA.nLength = sizeof(SA);
SA.bInheritHandle = true;
SA.lpSecurityDescriptor = NULL;
if (!CreatePipe(&StdInPipeRead, &StdInPipeWrite, &SA, 0) || !CreatePipe(&StdOutPipeRead, &StdOutPipeWrite, &SA, 0))
{
return false;
}
// Set Pipe for process to create
ZeroMemory(&SI, sizeof(SI));
SI.cb = sizeof(SI);
SI.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
SI.wShowWindow = SW_HIDE;
SI.hStdInput = StdInPipeRead; //GetStdHandle(STD_INPUT_HANDLE);
SI.hStdOutput = StdOutPipeWrite;
SI.hStdError = StdOutPipeWrite;
// Launch cmd process
g_bCreateProcessSuccess = CreateProcessW(
NULL,
L"cmd.exe /U",
NULL,
NULL,
true,
0,
NULL,
(WCHAR*)sWorkDir.c_str(),
&SI,
&PI);
g_sCommandLineInput = L"";
g_bkeepCmdRunning = true;
if (g_bCreateProcessSuccess)
{
do
{
DWORD TotalBytesAvail = 0;
PeekNamedPipe(StdOutPipeRead, 0, 0, 0, &TotalBytesAvail, 0);
pBuffer = (WCHAR*)malloc(TotalBytesAvail);
if (TotalBytesAvail > 0)
{
// First problem is: while internal commands work fine (dir, cd, etc.) and return output in unicode format,
// when I launch another process (ipconfig, netstat, ping, etc.), output is returned in ANSI format.
// Even if I launched cmd.exe with /U switch
ReadFile(StdOutPipeRead, pBuffer, TotalBytesAvail, &BytesRead, NULL);
}
else BytesRead = 0;
if (BytesRead > 0)
{
wprintf(pBuffer);
}
free(pBuffer);
// g_sCommandLineInput is a global wstring variable which gets filled each time user wants to send new command.
if (g_sCommandLineInput.length() > 0)
{
DWORD numberofbyteswritten = 0;
g_sCommandLineInput += L"\n"; //Append /n to make the cmd process interpret the data as a command to launch
// Second problem is, why do I have to send command in ANSI format, even if I launched cmd with the /U switch?
string sCommndLineAnsi = WStringToString(g_sCommandLineInput);
WriteFile(StdInPipeWrite, sCommndLineAnsi.c_str(), sCommndLineAnsi.length() * sizeof(CHAR), &numberofbyteswritten, NULL);
//Reset command
g_sCommandLineInput = L"";
}
Sleep(100);
}
while (g_bkeepCmdRunning);
TerminateProcess(PI.hProcess, 0);
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
}
CloseHandle(StdOutPipeRead);
CloseHandle(StdOutPipeWrite);
return true;
}