自从几天以来我一直坚持这一点,我疯了。 基本上我试图在一个线程中打开cmd.exe,并从父节点给它输入和读取输出。比如,在linux中分配一个tty,因为在Windows中没有这样的东西。我对linux系统有很好的理解,但对于windows不能说同样的事情。
所以,这里"我的"代码:
#undef UNICODE
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
//using namespace std;
#define BUFFER_SIZE 99
// handles for cmd thread pipes
HANDLE cmd_in_rd = NULL;
HANDLE cmd_in_wr = NULL;
HANDLE cmd_out_rd = NULL;
HANDLE cmd_out_wr = NULL;
HANDLE cmd_thread_handle;
void PrintError(char *text, int err) {
DWORD retSize;
LPTSTR pTemp = NULL;
if (!err) return;
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
err,
LANG_NEUTRAL,
(LPTSTR)&pTemp,
0,
NULL);
if (pTemp) printf("%s: %s\n", text, pTemp);
LocalFree((HLOCAL)pTemp);
return;
}
int pipewrite(char *command) {
DWORD dwRead, dwWritten;
BOOL bSuccess = FALSE;
SetLastError(0);
WriteFile(cmd_in_wr, command, strlen(command), &dwWritten, NULL);
bSuccess = GetLastError();
PrintError("WriteToPipe", bSuccess);
return (bSuccess == 0) || (bSuccess == ERROR_IO_PENDING);
}
int __stdcall cmd_thread(int arg) {
// this function only prints when data is ready
DWORD dwRead, dwWritten;
CHAR chBuf[BUFFER_SIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
int rf_ret, wf_ret;
//CloseHandle(cmd_out_wr); makes readfile fail!!
SetLastError(0);
while (1) { // only executes once!!!!!!!
(rf_ret = ReadFile(cmd_out_rd, chBuf, BUFFER_SIZE, &dwRead, NULL))
&&
(wf_ret = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL));
printf("ReadFile returned: %d\nWriteFile returned: %d\n", rf_ret, wf_ret);
bSuccess = GetLastError();
PrintError("ReadingFromPipe", bSuccess);
}
bSuccess = GetLastError();
return (bSuccess == 0) || (bSuccess == ERROR_IO_PENDING);
}
int main(void) {
char buffer[BUFFER_SIZE];
// init the pipes
SECURITY_ATTRIBUTES cmd_sa;
cmd_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
cmd_sa.bInheritHandle = TRUE;
cmd_sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&cmd_out_rd, &cmd_out_wr, &cmd_sa, 0)) {
printf("%s\n", "Error creating pipes");
return 1;
}
if (!SetHandleInformation(cmd_out_rd, HANDLE_FLAG_INHERIT, 0)) {
printf("%s\n", "Error setting handle infos");
return 1;
}
if (!CreatePipe(&cmd_in_rd, &cmd_in_wr, &cmd_sa, 0)) {
printf("%s\n", "Error creating pipes");
return 1;
}
if (!SetHandleInformation(cmd_in_rd, HANDLE_FLAG_INHERIT, 0)) {
printf("%s\n", "Error setting handle infos");
return 1;
}
// create the cmd thread
PROCESS_INFORMATION cmd_pi;
STARTUPINFO cmd_si;
ZeroMemory(&cmd_pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&cmd_si, sizeof(STARTUPINFO));
cmd_si.cb = sizeof(STARTUPINFO);
cmd_si.hStdError = cmd_out_wr;
cmd_si.hStdOutput = cmd_out_wr;
cmd_si.hStdInput = cmd_in_rd;
cmd_si.dwFlags |= STARTF_USESTDHANDLES;
TCHAR comm[] = TEXT("cmd.exe");
BOOL th = CreateProcess(NULL,
comm,
NULL,
NULL,
TRUE, // handles are inherited
0,
NULL,
NULL,
&cmd_si,
&cmd_pi);
if (th) {
CloseHandle(cmd_pi.hProcess);
CloseHandle(cmd_pi.hThread);
}
cmd_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)cmd_thread, NULL, 0, NULL);
// read commands from shell and send them to cmd
ZeroMemory(&buffer, BUFFER_SIZE);
while (1) {
fgets(buffer, BUFFER_SIZE, stdin);
if (!pipewrite(buffer)) break;
}
printf("Program terminated\n");
return 0;
}
实际上,出于测试目的,我从stackoverflow和MSDN上的另一个问题中复制了很多,因为我无法让它在我的主程序上工作。我不明白的事情是:
为什么cmd_thread中的while循环在启动时执行,然后在那里挂起等待世界末日?我试图在阅读之前从父级关闭管道out_write句柄,但这会使其他部分无效。
pipewrite()似乎工作,但我不能确定cmd.exe线程接收并处理输入...因为我没有输出:/ 我想过stracing / ltracing程序或运行它到调试器,但我知道没有工具... 奇怪的是original有效(我得到代码的那个)。我试图发现两者之间的差异,但即使我并排看待它们,它们似乎都做了完全相同的事情。
答案 0 :(得分:0)
子进程一旦尝试从标准输入读取就会死亡,因为:
if (!SetHandleInformation(cmd_in_rd, HANDLE_FLAG_INHERIT, 0)) {
这应该是:
if (!SetHandleInformation(cmd_in_wr, HANDLE_FLAG_INHERIT, 0)) {
就像在原始代码中一样。
此外,您的错误处理在很大程度上是错误的;您没有始终检查错误,有时在没有发生错误时调用GetLastError()。 (这些问题也在原始代码中。)
您还需要重新拨打CloseHandle(cmd_out_wr);
,否则您将无法判断孩子何时退出。
哦,顺便说一下,cmd.exe
是一个进程,而不是一个帖子。