天天看點

Windows管道技術

關于Windows管道技術:

API函數(主要):

CreatePipe()用于建立管道

ReadFile() 用于讀管道

WriteFile()用于寫管道

變量類型(主要):

HANDLE

Windows管道技術

然後直接上代碼

注意:這裡我是用管道讀取CMD的資料用CreateProcess()函數建立的程序用TerminateProcess()終止程序

用下面的結構體的幾個成員指定輸入輸出流的流向

s_info.hStdError = hwcmd;

s_info.hStdInput = hrcmd;

s_info.hStdOutput = hwcmd;>

// win_pipe.cpp : 此檔案包含 "main" 函數。程式執行将在此處開始并結束。
//

#include "pch.h"
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <string>
#include <tchar.h>

constexpr auto SEND_BUFF_SIZE = 1024;

using namespace std;

inline void winerr(void);		//用于列印windows錯誤代碼

int main()
{
	HANDLE hrcmd = NULL;
	HANDLE hwcmd = NULL;
	HANDLE hrexe = NULL;
	HANDLE hwexe = NULL;
	HANDLE hpro = NULL;

	SECURITY_ATTRIBUTES sa;		//Windows安全設定:此結構為各種函數建立的對象提供安全設定
	PROCESS_INFORMATION pro_info;

	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = true;

	if (!CreatePipe(&hrexe, &hwcmd, &sa, 0))
	{
		winerr();
		return 1;
	}
	else
	{
		cout << "creat pipe1 noerror" << endl;
	}
	if (!CreatePipe(&hrcmd, &hwexe, &sa, 0))
	{
		winerr();
		return 1;
	}
	else
	{
		cout << "creat pipe2 noerror" << endl;
	}

	//啟動資訊

	STARTUPINFO s_info;		//指定建立時程序的視窗工作站,桌面,标準句柄和主視窗的外觀
	GetStartupInfo(&s_info);
	s_info.cb = sizeof(STARTUPINFO);
	s_info.lpReserved = NULL;
	s_info.wShowWindow = SW_HIDE;
	s_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	s_info.hStdError = hwcmd;
	s_info.hStdInput = hrcmd;
	s_info.hStdOutput = hwcmd;

	cout << "初始化完成" << endl;

	WCHAR cmdpath[1024] = _T("\n");
	GetSystemDirectory(cmdpath, sizeof(cmdpath));
	wcsncat_s(cmdpath, _T("\\cmd.exe"), 9);	//寬字元串連接配接。。

	wcout << "path:" << cmdpath << endl;

		//建立cmd程序
	if (!CreateProcess(cmdpath, NULL, NULL, NULL, TRUE, NULL, NULL, NULL, &s_info, &pro_info))
	{
		winerr();
		CloseHandle(hwexe);
		CloseHandle(hrexe);
		return 1;
	}

	cout << "開始讀寫管道...." << endl;
	cout << "注意:為了完整讀取例如 ping等需要等待時間的指令的傳回資料在輸入資料後會有5秒延遲" << endl 
		 << "輸入END即退出該程式" << endl;

	//---注意!!!  CMD是ASCII編碼用WCHAR(UNICODE編碼)會亂碼
	char rbuf[2048];
	unsigned long rn = 0, wn = 0;
	//----------------------------讀寫管道----------------------------
	do
	{
		do
		{
			if (!PeekNamedPipe(hrexe, NULL, NULL, NULL, &rn, 0))	//管道是否有資料可讀
			{
				cout << "nodata" << endl;
				winerr();
				break;
			}
			if ((rn>0)&&(rn<2048))
			{
				memset(rbuf, 0, 2048);
				if (!ReadFile(hrexe, rbuf, rn, NULL, NULL))
				{
					cout << "讀管道錯誤" << endl;
					winerr();
					break;
				}
				else
				{
					cout << rbuf;
				}
			}
			Sleep(1000);
		} while (rn!=0);
		//---------寫管道---------
		string wbuf;
		getline(cin, wbuf);
		if (wbuf=="END")
		{
			break;
		}
		wbuf += "\r\n";
		if (!WriteFile(hwexe, wbuf.c_str(), strlen(wbuf.c_str()), &wn, NULL))
		{
			cout << "寫管道錯誤" << endl;
			winerr();
			break;
		}
		else
		{
			cout << wbuf;
		}
		Sleep(500);
	} while (true);
	
	TerminateProcess(pro_info.hProcess, 0);		//用于關閉cmd程序
	return 0;

}

inline void winerr(void)
{
	cout << "win error:" << GetLastError() << endl;
}

// 運作程式: Ctrl + F5 或調試 >“開始執行(不調試)”菜單
// 調試程式: F5 或調試 >“開始調試”菜單

// 入門提示: 
//   1. 使用解決方案資料總管視窗添加/管理檔案
//   2. 使用團隊資料總管視窗連接配接到源代碼管理
//   3. 使用輸出視窗檢視生成輸出和其他消息
//   4. 使用錯誤清單視窗檢視錯誤
//   5. 轉到“項目”>“添加新項”以建立新的代碼檔案,或轉到“項目”>“添加現有項”以将現有代碼檔案添加到項目
//   6. 将來,若要再次打開此項目,請轉到“檔案”>“打開”>“項目”并選擇 .sln 檔案

           

!!!最後我其實也不是特别懂,如果有錯誤歡迎指出。

繼續閱讀