MFC匿名管道原理详解、函数总结、调用实例(用MFC的匿名管道读取CMD输出内容)(C++语言)
本博客主要總結(jié)MFC中匿名管道的原理和具體調(diào)用實(shí)例,以及調(diào)用匿名管道三個(gè)核心函數(shù)各個(gè)參數(shù)用法詳解,具體的如下所述。
博主在做項(xiàng)目時(shí),遇到一個(gè)問(wèn)題。用程序調(diào)用一個(gè)進(jìn)程,然后讀取進(jìn)程輸出信息。但是,博主用Qt的QProcess無(wú)法讀取標(biāo)準(zhǔn)輸出,所以只能考慮管道技術(shù)。
由于博主的開(kāi)發(fā)環(huán)境是Windows10 64位,Qt的QProcess并沒(méi)有找到類似的功能(可能博主對(duì)Qt研究不夠深入,希望知道的大神告知一下),所以打算用MFC的匿名管道。
經(jīng)過(guò)資料的查找和驗(yàn)證,博主發(fā)現(xiàn),MFC的匿名管道技術(shù)可以實(shí)現(xiàn)讀取CMD進(jìn)程輸出的內(nèi)容,所以特定將MFC匿名管道用法記錄下來(lái),學(xué)習(xí)和總結(jié)。
?
匿名管道概念解釋:
匿名管道主要用于進(jìn)程間通信,進(jìn)程的關(guān)系為父進(jìn)程和子進(jìn)程。具體原理如下圖所示:
父進(jìn)程和子進(jìn)程都有讀端口和寫(xiě)端口。通信方式可以從父進(jìn)程寫(xiě)數(shù)據(jù),子進(jìn)程讀數(shù)據(jù)?;蛘咦舆M(jìn)程寫(xiě)數(shù)據(jù),父進(jìn)程讀數(shù)據(jù)。
其中,本文下面的例子是用圖二的從子進(jìn)程寫(xiě)數(shù)據(jù),從父進(jìn)程讀取數(shù)據(jù)。即子進(jìn)程通過(guò)cmd命令執(zhí)行程序,然后程序輸入的內(nèi)容通過(guò)寫(xiě)句柄hWritePipe,寫(xiě)入內(nèi)核(直接調(diào)用CrateProcess()函數(shù),設(shè)置對(duì)應(yīng)參數(shù)就可以寫(xiě)數(shù)據(jù)到內(nèi)核。而不用調(diào)用WriteFile()函數(shù))。父進(jìn)程根據(jù)子進(jìn)程管道的讀句柄hReadPipe,調(diào)用ReadFile()函數(shù)讀取內(nèi)核數(shù)據(jù)。
?
一、MFC創(chuàng)建管道主要步驟
用MFC編寫(xiě)匿名管道的核心函數(shù)有三個(gè),分別是CreatePipe(),CreateProcess(),ReadFile()三個(gè)核心函數(shù)。其中,函數(shù)CreatePipe()主要功能是創(chuàng)建一個(gè)管道通信,函數(shù)CreateProcess()主要功能是創(chuàng)建一個(gè)進(jìn)程,函數(shù)ReadFile()讀取進(jìn)程輸出的內(nèi)容。下面是對(duì)創(chuàng)建管道通信步驟的總結(jié):
?
1.1先創(chuàng)建調(diào)用函數(shù)CreatePipe()創(chuàng)建一個(gè)管道通信。關(guān)鍵代碼為:
CreatePipe(&hReadPipe, &hWritePipe, &safety, 0);
?
1.2調(diào)用函數(shù)CreateProcess()創(chuàng)建一個(gè)進(jìn)程,該進(jìn)程輸出的內(nèi)容作為管道的寫(xiě)端口,向管道寫(xiě)數(shù)據(jù)。關(guān)鍵代碼為:(其中寫(xiě)的句柄hWritePipe在結(jié)構(gòu)體startInfo里的參數(shù)設(shè)置)
CreateProcess(NULL, cmdStr, NULL, NULL, TRUE, NULL, NULL, NULL, &startupInfo, &pinfo);
?
1.3調(diào)用函數(shù)ReadFile()作為管道的讀端口,讀取進(jìn)程寫(xiě)入管道的內(nèi)容。關(guān)鍵代碼為:(其中讀取內(nèi)存存在緩沖區(qū)buffer)
ReadFile(hReadPipe, buffer, 4095, &byteRead, NULL);
?
1.4下面是博主封裝的一個(gè)函數(shù)。該函數(shù)的功能是輸入cmd命令,返回cmd輸出內(nèi)容。
具體代碼如下所示:
CString executeCmd(CString command)
{
?? ?//創(chuàng)建匿名管道
?? ?HANDLE hReadPipe, hWritePipe;
?? ?SECURITY_ATTRIBUTES safety;?? ??? ??? ??? ??? ??? ?//安全屬性?? ?
?? ?safety.nLength = sizeof(SECURITY_ATTRIBUTES);?? ?//結(jié)構(gòu)體大小
?? ?safety.lpSecurityDescriptor = NULL;?? ??? ??? ??? ?//安全描述符,NULL;使用默認(rèn)的
?? ?safety.bInheritHandle = TRUE;?? ??? ??? ??? ??? ?//安全描述符的對(duì)象能否被子進(jìn)程繼承
?? ?if (!CreatePipe(&hReadPipe, &hWritePipe, &safety, 0))
?? ?{
?? ??? ?//創(chuàng)建管道錯(cuò)誤
?? ??? ?return _T("創(chuàng)建管道錯(cuò)誤!");
?? ?}
?? ?//創(chuàng)建進(jìn)程
?? ?TCHAR *cmdStr = StringToChar(command);
?? ?STARTUPINFO startupInfo = { sizeof(startupInfo) };?? ??? ??? ??? ??? ?//進(jìn)程信息?? ?
?? ?startupInfo.hStdError = hWritePipe;?? ??? ??? ??? ??? ??? ??? ??? ??? ?//標(biāo)志控制臺(tái)窗口緩存
?? ?startupInfo.hStdOutput = hWritePipe;?? ??? ??? ??? ??? ??? ??? ??? ?//標(biāo)志控制臺(tái)窗口緩存
?? ?startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;?? ?//使用wSHOWWIndows成員
?? ?startupInfo.wShowWindow = SW_HIDE;
?? ?PROCESS_INFORMATION pinfo;
?? ?if (!CreateProcess(NULL, cmdStr, NULL, NULL, TRUE, NULL, NULL, NULL, &startupInfo, &pinfo))
?? ?{
?? ??? ?//創(chuàng)建進(jìn)程錯(cuò)誤
?? ??? ?return _T("創(chuàng)建進(jìn)程錯(cuò)誤!");
?? ?}
?? ?CloseHandle(hWritePipe);
?? ?//獲取管道信息
?? ?char buffer[4096];?? ?
?? ?DWORD byteRead;
?? ?CString output;?? ??? ??? ??? ??? ??? ??? ??? ??? ?//返回值
?? ?while (true)
?? ?{
? ? ? ? memset(buffer, 0, 4096); ? ? ? ? ? ? ? ? ? ?//要放在循環(huán)里面,否則接收數(shù)據(jù)錯(cuò)亂
? ? ? ? if (ReadFile(hReadPipe, buffer, 4095, &byteRead, NULL) == NULL)
?? ??? ?{
?? ??? ??? ?break;
?? ??? ?}
?? ??? ?output += buffer;
?? ?}
?? ?CloseHandle(hReadPipe);
?? ?return output;
}
TCHAR* StringToChar(CString& str)
{
?? ?int len = str.GetLength();
?? ?TCHAR* tr = str.GetBuffer(len);
?? ?str.ReleaseBuffer();
?? ?return tr;
}
?
1.5函數(shù)調(diào)用的一個(gè)實(shí)例
? ? CString cmdString = _T("ipconfig.exe /?");
? ? CString output = executeCmd(cmdString);
? ? AfxMessageBox(output);
?
1.6運(yùn)行結(jié)果如下圖所示:
二、關(guān)鍵函數(shù)參數(shù)講解
2.1函數(shù)CreatePipe()各個(gè)參數(shù)如下所示:
BOOL CreatePipe(
?? ?_Out_ PHANDLE hReadPipe,?? ?//管道讀端口句柄
?? ?_Out_ PHANDLE hWritePipe,?? ?//管道寫(xiě)端口句柄
?? ?_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,?? ?//安全描述符,通過(guò)設(shè)置參數(shù),可以設(shè)置能否被支線程繼承
?? ?_In_ DWORD nSize ? ?//0表示管道緩沖設(shè)置為系統(tǒng)默認(rèn)值
?? ?);
?
2.2函數(shù)CreateProcess()各個(gè)參數(shù)如下所示:
BOOL CreateProcess(
_In_opt_ LPCWSTR lpApplicationName,?? ??? ??? ??? ??? ?//指向要調(diào)用的程序路徑
_Inout_opt_ LPWSTR lpCommandLine,?? ??? ??? ??? ??? ?//輸入的命令行TCHAR*字符串
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,?? ?//結(jié)構(gòu)體SECURTY_ATTRIBUTE,指向進(jìn)程安全描述符
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,?? ?//結(jié)構(gòu)體SECURITY_ATTRIBUTE,指向線程安全描述符
_In_ BOOL bInheritHandles,?? ??? ??? ??? ??? ??? ??? ?//新進(jìn)程是否從調(diào)用進(jìn)程處繼承了句柄
_In_ DWORD dwCreationFlags,?? ??? ??? ??? ??? ??? ??? ?//附加的、用來(lái)控制優(yōu)先類和進(jìn)程的創(chuàng)建標(biāo)志。設(shè)置為CREATE_NEW_CONSOLE可顯示子窗口。
_In_opt_ LPVOID lpEnvironment,?? ??? ??? ??? ??? ??? ?//指向使用父類的環(huán)境
_In_opt_ LPCWSTR lpCurrentDirectory,?? ??? ??? ??? ?//使用父類的當(dāng)前目錄
_In_ LPSTARTUPINFOW lpStartupInfo,?? ??? ??? ??? ??? ?//結(jié)構(gòu)體STARTUPINFO,指向一個(gè)用于決定新進(jìn)程的主窗體如何顯示
_Out_ LPPROCESS_INFORMATION lpProcessInformation?? ?//結(jié)構(gòu)體PROCESS_INFORMATION,指向一個(gè)用來(lái)接收新進(jìn)程的識(shí)別信息
);
?
2.3函數(shù)ReadFile()各個(gè)參數(shù)如下所示:
BOOL ReadFile(
_In_ HANDLE hFile,?? ??? ??? ??? ??? ??? ?//文件句柄
_Out_writes_bytes_to_opt_(nNumberOfBytesToRead, *lpNumberOfBytesRead) __out_data_source(FILE) LPVOID lpBuffer,?? ?//讀緩沖區(qū)
_In_ DWORD nNumberOfBytesToRead,?? ??? ?//要讀取的字節(jié)數(shù)
_Out_opt_ LPDWORD lpNumberOfBytesRead,?? ?//實(shí)際讀取到的字節(jié)數(shù)
_Inout_opt_ LPOVERLAPPED lpOverlapped?? ?//指向結(jié)構(gòu)體OVERLAPPED,一般設(shè)為NULL
);
?
?
參考內(nèi)容:
https://blog.csdn.net/it2153534/article/details/79064643(參考:重點(diǎn)函數(shù)各個(gè)參數(shù)講解)
https://blog.csdn.net/qq61394323/article/details/39829631(參考:MFC讀取CMD輸出內(nèi)容代碼)
https://blog.csdn.net/qq61394323/article/details/39253193?utm_source=blogxgwz2(參考:匿名管道讀寫(xiě)句柄用法)
https://blog.csdn.net/whynottrythis/article/details/39828395(參考:STARTUPINFO結(jié)構(gòu)體各個(gè)參數(shù)講解)
https://blog.csdn.net/jeanphorn/article/details/44982273(參考:函數(shù)ReadFile()參數(shù)講解和調(diào)用實(shí)例,主要參考)
https://blog.csdn.net/virtualdesk/article/details/4379965(參考:函數(shù)ReadFile()參數(shù)講解和調(diào)用實(shí)例)
原文:https://blog.csdn.net/naibozhuan3744/article/details/83142860?
?
總結(jié)
以上是生活随笔為你收集整理的MFC匿名管道原理详解、函数总结、调用实例(用MFC的匿名管道读取CMD输出内容)(C++语言)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ARM MOV和 LDR指令关系
- 下一篇: [C++] 匿名管道的理解与实现