在Windows下獲取控制檯(DOS)下可執行檔案的標準輸入輸出
阿新 • • 發佈:2019-02-08
我們在開發軟體時,常常會用到控制檯下的程式,比如make,link,ftp等等。除此之外,還有一些開源的軟體都是在控制檯下使用的,這樣,如果我們想方便的在Windows程式中直接呼叫這些程序和他們進行互動,那麼就需要獲取它們的標準輸入輸出。
在Windows下獲取這種輸出最常用的方法是通過建立子程序和管道。
例子如下:
首先,我們先建立一個用來測試的console程式。
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("hello world!/n");
return 0;
}
編譯為可執行檔案hello.exe
接下來,可以通過如下示例程式碼對其標準輸出進行讀出。
1.首先創立子程序,並創立管道附加到子程序上(注意管道流向)
2.讀出子程序的標準輸出(直接使用ReadFile讀取管道),存入緩衝
3.把緩衝列印到螢幕上
我用的是C++的編譯器,C編譯器可能會報錯。
#include <stdio.h> #include <windows.h> typedef struct { HANDLE hRead; /* stdout */ HANDLE hWrite; /* stdin */ HANDLE hError; /* stderr */ HANDLE hReadU; HANDLE hWriteU; HANDLE hErrorU; HANDLE hProcess; /* child process handle */ HANDLE hThread; /* child main thread handle */ }CPWP_STRUCT; int DestroyProcessWithPipe(CPWP_STRUCT* pcs) { int nResult = 0; if(pcs->hError) CloseHandle(pcs->hError) ? TRUE : nResult--; if(pcs->hErrorU) CloseHandle(pcs->hErrorU) ? TRUE : nResult--; if(pcs->hProcess) CloseHandle(pcs->hProcess) ? TRUE : nResult--; if(pcs->hRead) CloseHandle(pcs->hRead) ? TRUE : nResult--; if(pcs->hReadU) CloseHandle(pcs->hReadU) ? TRUE : nResult--; if(pcs->hThread) CloseHandle(pcs->hThread) ? TRUE : nResult--; if(pcs->hWrite) CloseHandle(pcs->hWrite) ? TRUE : nResult--; if(pcs->hWriteU) CloseHandle(pcs->hWriteU) ? TRUE : nResult--; return nResult; } int CreateProcessWithPipe(char* szCmdLine, CPWP_STRUCT* pcs) { if(!pcs) return -1; /* init */ memset(pcs, 0, sizeof(CPWP_STRUCT)); /* create pipes for read, write and error */ SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; if(!CreatePipe(&pcs->hRead, &pcs->hReadU, &saAttr, 0)) /* create stdout pipe failed */ return -2; if(!CreatePipe(&pcs->hWriteU, &pcs->hWrite, &saAttr, 0)) /* create stdin pipe failed */ return -3; if(!CreatePipe(&pcs->hError, &pcs->hErrorU, &saAttr, 0)) /* create error pipe failed */ return -4; /* create child process */ PROCESS_INFORMATION pi; STARTUPINFO si; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdError = pcs->hErrorU; si.hStdInput = pcs->hWriteU; si.hStdOutput = pcs->hReadU; if(!CreateProcess(0, szCmdLine, 0, 0, TRUE, 0, 0, 0, &si, &pi)) { DestroyProcessWithPipe(pcs); return -5; } pcs->hProcess = pi.hProcess; pcs->hThread = pi.hThread; /* success */ return 0; } int ShowHelp() { printf("usage: SuperPipe [command file path]/n" "example: SuperPipe hello.exe/n" ); return -1; } int main(int argc, char *argv[]) { CPWP_STRUCT cs = {0}; char szBuffer[0x400] = {0}; DWORD dwWrite = 0, dwRead = 0; if(argc != 2) return ShowHelp(); /* start child process */ if(CreateProcessWithPipe(argv[1], &cs) < 0) return -3; /* read data stream from the pipe */ if(!::ReadFile(cs.hRead, szBuffer, 0x400, &dwRead, NULL)) exit(0); if(!dwRead) exit(0); printf(szBuffer); /* kill child process */ ::TerminateProcess(cs.hProcess, 0); /* close pipe and handle */ DestroyProcessWithPipe(&cs); return 0; }
只要建立了子程序我們就可以通過使用ReadFile來讀取cs.hRead獲取標準輸出。通過WirteFile寫入cs.hWrite進行標準輸入:)