MFC匿名管道原理詳解、函數總結、調用實例(用MFC的匿名管道讀取CMD輸出內容)(C++語言)

本博客主要總結MFC中匿名管道的原理和具體調用實例,以及調用匿名管道三個核心函數各個參數用法詳解,具體的如下所述。

博主在做項目時,遇到一個問題。用程序調用一個進程,然後讀取進程輸出信息。但是,博主用Qt的QProcess無法讀取標準輸出,所以只能考慮管道技術。

由於博主的開發環境是Windows10 64位,Qt的QProcess並沒有找到類似的功能(可能博主對Qt研究不夠深入,希望知道的大神告知一下),所以打算用MFC的匿名管道。

經過資料的查找和驗證,博主發現,MFC的匿名管道技術可以實現讀取CMD進程輸出的內容,所以特定將MFC匿名管道用法記錄下來,學習和總結。

 

匿名管道概念解釋:

匿名管道主要用於進程間通信,進程的關係爲父進程和子進程。具體原理如下圖所示:

父進程和子進程都有讀端口和寫端口。通信方式可以從父進程寫數據,子進程讀數據。或者子進程寫數據,父進程讀數據。

其中,本文下面的例子是用圖二的從子進程寫數據,從父進程讀取數據。即子進程通過cmd命令執行程序,然後程序輸入的內容通過寫句柄hWritePipe,寫入內核(直接調用CrateProcess()函數,設置對應參數就可以寫數據到內核。而不用調用WriteFile()函數)。父進程根據子進程管道的讀句柄hReadPipe,調用ReadFile()函數讀取內核數據。

 

一、MFC創建管道主要步驟

用MFC編寫匿名管道的核心函數有三個,分別是CreatePipe(),CreateProcess(),ReadFile()三個核心函數。其中,函數CreatePipe()主要功能是創建一個管道通信,函數CreateProcess()主要功能是創建一個進程,函數ReadFile()讀取進程輸出的內容。下面是對創建管道通信步驟的總結:

 

1.1先創建調用函數CreatePipe()創建一個管道通信。關鍵代碼爲:

CreatePipe(&hReadPipe, &hWritePipe, &safety, 0);

 

1.2調用函數CreateProcess()創建一個進程,該進程輸出的內容作爲管道的寫端口,向管道寫數據。關鍵代碼爲:(其中寫的句柄hWritePipe在結構體startInfo裏的參數設置)

CreateProcess(NULL, cmdStr, NULL, NULL, TRUE, NULL, NULL, NULL, &startupInfo, &pinfo);

 

1.3調用函數ReadFile()作爲管道的讀端口,讀取進程寫入管道的內容。關鍵代碼爲:(其中讀取內存存在緩衝區buffer)

ReadFile(hReadPipe, buffer, 4095, &byteRead, NULL);

 

1.4下面是博主封裝的一個函數。該函數的功能是輸入cmd命令,返回cmd輸出內容。

具體代碼如下所示:

CString executeCmd(CString command)
{
	//創建匿名管道
	HANDLE hReadPipe, hWritePipe;
	SECURITY_ATTRIBUTES safety;						//安全屬性	
	safety.nLength = sizeof(SECURITY_ATTRIBUTES);	//結構體大小
	safety.lpSecurityDescriptor = NULL;				//安全描述符,NULL;使用默認的
	safety.bInheritHandle = TRUE;					//安全描述符的對象能否被子進程繼承
	if (!CreatePipe(&hReadPipe, &hWritePipe, &safety, 0))
	{
		//創建管道錯誤
		return _T("創建管道錯誤!");
	}

	//創建進程
	TCHAR *cmdStr = StringToChar(command);
	STARTUPINFO startupInfo = { sizeof(startupInfo) };					//進程信息	
	startupInfo.hStdError = hWritePipe;									//標誌控制檯窗口緩存
	startupInfo.hStdOutput = hWritePipe;								//標誌控制檯窗口緩存
	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))
	{
		//創建進程錯誤
		return _T("創建進程錯誤!");
	}
	CloseHandle(hWritePipe);

	//獲取管道信息
	char buffer[4096];
	memset(buffer, 0, 4096);
	DWORD byteRead;
	CString output;									//返回值
	while (true)
	{
		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函數調用的一個實例

    CString cmdString = _T("ipconfig.exe /?");
    CString output = executeCmd(cmdString);

    AfxMessageBox(output);

 

1.6運行結果如下圖所示:

 

 

二、關鍵函數參數講解

2.1函數CreatePipe()各個參數如下所示:

BOOL CreatePipe(
	_Out_ PHANDLE hReadPipe,	//管道讀端口句柄
	_Out_ PHANDLE hWritePipe,	//管道寫端口句柄
	_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,	//安全描述符,通過設置參數,可以設置能否被支線程繼承
	_In_ DWORD nSize    //0表示管道緩衝設置爲系統默認值
	);

 

2.2函數CreateProcess()各個參數如下所示:

BOOL CreateProcess(
_In_opt_ LPCWSTR lpApplicationName,					//指向要調用的程序路徑
_Inout_opt_ LPWSTR lpCommandLine,					//輸入的命令行TCHAR*字符串
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,	//結構體SECURTY_ATTRIBUTE,指向進程安全描述符
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,	//結構體SECURITY_ATTRIBUTE,指向線程安全描述符
_In_ BOOL bInheritHandles,							//新進程是否從調用進程處繼承了句柄
_In_ DWORD dwCreationFlags,							//附加的、用來控制優先類和進程的創建標誌。設置爲CREATE_NEW_CONSOLE可顯示子窗口。
_In_opt_ LPVOID lpEnvironment,						//指向使用父類的環境
_In_opt_ LPCWSTR lpCurrentDirectory,				//使用父類的當前目錄
_In_ LPSTARTUPINFOW lpStartupInfo,					//結構體STARTUPINFO,指向一個用於決定新進程的主窗體如何顯示
_Out_ LPPROCESS_INFORMATION lpProcessInformation	//結構體PROCESS_INFORMATION,指向一個用來接收新進程的識別信息
);

 

2.3函數ReadFile()各個參數如下所示:

BOOL ReadFile(
_In_ HANDLE hFile,						//文件句柄
_Out_writes_bytes_to_opt_(nNumberOfBytesToRead, *lpNumberOfBytesRead) __out_data_source(FILE) LPVOID lpBuffer,	//讀緩衝區
_In_ DWORD nNumberOfBytesToRead,		//要讀取的字節數
_Out_opt_ LPDWORD lpNumberOfBytesRead,	//實際讀取到的字節數
_Inout_opt_ LPOVERLAPPED lpOverlapped	//指向結構體OVERLAPPED,一般設爲NULL
);

 

 

參考內容:

https://blog.csdn.net/it2153534/article/details/79064643(參考:重點函數各個參數講解)

https://blog.csdn.net/qq61394323/article/details/39829631(參考:MFC讀取CMD輸出內容代碼)

https://blog.csdn.net/qq61394323/article/details/39253193?utm_source=blogxgwz2(參考:匿名管道讀寫句柄用法)

https://blog.csdn.net/whynottrythis/article/details/39828395(參考:STARTUPINFO結構體各個參數講解)

https://blog.csdn.net/jeanphorn/article/details/44982273(參考:函數ReadFile()參數講解和調用實例,主要參考)

https://blog.csdn.net/virtualdesk/article/details/4379965(參考:函數ReadFile()參數講解和調用實例)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章