VC 模擬CMD 匿名管道

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

int Call(char Cmd[])
{
	SECURITY_ATTRIBUTES sa;
	HANDLE Hread,Hwrite;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;
	if (!CreatePipe(&Hread,&Hwrite,&sa,0))
	{
		printf("Create Pipe in error\r\n");
		return 0;
	}

	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si,sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);
	GetStartupInfo(&si);
	si.hStdError = Hwrite;
	si.hStdOutput = Hwrite;
	si.wShowWindow = SW_HIDE;
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	memset(&pi,0,sizeof(PROCESS_INFORMATION));
	char cmdline[1024 ] = "cmd /c";
	strcat(cmdline,Cmd);
	if (!CreateProcessA(NULL,cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))
	{
		printf("Create process error\r\n");
		return 0;
	}

	CloseHandle(Hwrite);

	char buff[1024] = {0};
	//char cres[MAX_PATH] = {0};
	DWORD bytesread;
	while (true)
	{
		if (ReadFile(Hread,buff,1024,&bytesread,NULL) == NULL)
		{
			break;
		}

		int ilen = strlen(buff);
		for (int i =0;i<ilen;i++)
		{
			if (buff[i] == '\n' || buff[i] == '\r')
			{
				buff[i] = '\0';
			}
		}
		printf(buff);
	}
	CloseHandle(Hread);
	//sprintf()

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	char* Cmd = argv[1];
	Call(Cmd);
	return 0;
}

使用管道CREATEPIPE,來進行進程間的相互通訊,而後在進行數據的讀取。

什麼是管道,管道就是一種通訊機制,也就是內存共享,一個進程向管道寫入數據後,由另一個管道讀出。

 匿名管道是在父進程和子進程間單向傳輸數據的一種未命名的管道,只能在本地計算機中使用,而不可用於網絡間的通訊。

匿名管道由CreatePipe()函數建立,該函數在建立匿名管道的同時返回兩個句柄:管道讀句柄和管道寫句緩存

柄。CreatePipe()的函數原型爲:
BOOL CreatePipe(
      PHANDLE hReadPipe,    // 指向讀句柄的指針
   PHANDLE hWritePipe, &nb sp;  // 指向寫句柄的指針
   LPSECURITY_ATTRIBUTES lpPipeAttributes,  // 指向安全屬性的指針
   DWORD nSize     // 管道大小
  );   
返回值   
Long,非零表示成功,零表示失敗。會設置GetLastError
安全

 

在調用CreatePipe()函數時,若是管道服務器將lpPipeAttributes 指向的SECURITY_ATTRIBUTES數據結構的數據成員bInheritHandle設置爲TRUE,那麼CreatePipe()建立的管道讀、寫句柄將會被繼承。
    在用WriteFile()函數向管道寫入數據時,只有在向管道寫完指定字節的數據後或是在有錯誤發生時函數纔會返回。如管道緩衝已滿而數據尚未寫完,WriteFile()將要等到另外一進程對管道中數據讀取以釋放出更多可用空間後纔可以返回。管道服務器在調用CreatePipe()建立管道時以參數nSize對管道的緩衝大小做了設定。
  匿名管道並不支持異步讀、寫操做,這也就意味着不能在匿名管道中使用ReadFileEx()和WriteFileEx(),並且ReadFile()和WriteFile()中的lpOverLapped參數也將被忽略。匿名管道將在讀、寫句柄都被關閉後退出,也能夠在進程中調用CloseHandle()函數來關閉此句柄。
服務器

 

程序具體實現過程:
(1) 初始化安全屬性的指針 //建立匿名管道前期,就得初始化安全屬性的指針。
 SECURITY_ATTRIBUTES sa;
 sa.nLength = sizeof(sa);
 sa.lpSecurityDescriptor = 0;
 sa.bInheritHandle = TRUE;
網絡

 

(2) 建立匿名管道 //開始建立匿名管道
 HANDLE hReadPipe1,hWritePipe1;
 CreatePipe(&hReadPipe1,&hWritePipe1,&sa,0);
數據結構

 

(3) 建立cmd進程
BOOL CreateProcess(   
 LPCTSTR lpApplicationName,      //可執行模塊的字符串 
 LPTSTR lpCommandLine,      //執行的命令行字符串
 LPSECURITY_ATTRIBUTES lpProcessAttributes, 
 LPSECURITY_ATTRIBUTES lpThreadAttributes,   
 BOOL bInheritHandles,      //新進程是否從調用進程處繼承了句柄
 DWORD dwCreationFlags,      //標誌
 LPVOID lpEnvironment,      //新進程的環境塊
 LPCTSTR lpCurrentDirectory,     //子進程的工做路徑
 LPSTARTUPINFO lpStartupInfo,     //決定新進程的主窗體如何顯示
 LPPROCESS_INFORMATION lpProcessInformation  //接收新進程的識別信息
  );
app

 

在建立進程前,先初始化兩個結構體:LPSTARTUPINFO 和LPPROCESS_INFORMATION異步

STARTUPINFO結構用於指定新進程的主窗口特性,應用程序必須將cb初始化爲sizeof(STARTUPINFO)
STARTF_USESHOWWINDOW使用wShowWindow成員:wShowWindow用於設定若是子應用程序初次調用的
ShowWindows將SW_SHOWDEFAULT做爲nCmdShow參數傳遞時,該應用程序的第一個重疊窗口應該如何出現。
STARTF_USESTDHANDLES使用hstdInput、hstdOutput和hstdError成員:HANDLE hStdInput用於設定供控制檯
輸入和輸出用的緩存的句柄。按照默認設置,hstdInput 用於標識鍵盤緩存,hstdOutput和hstdError用於標識控制檯窗口的緩存。函數

STARTUPINFO si;
 memset(&si,0,sizeof(si));
 GetStartupInfo(&si);  //該函數返回進程在啓動時被指定的STARTUPINFO 結構
 si.cb = sizeof(si);
 si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
 si.wShowWindow = SW_HIDE;
 si.hStdOutput = si.hStdError = hWritePipe1;
spa

PROCESS_INFORMATION pInfo;
 memset(&pInfo,0,sizeof(PROCESS_INFORMATION));
命令行

 

建立進程
 char szCmd[MAXLENGTH] = "cmd.exe /c";
 //接收遠程傳入的進程執行參數
 int dwSize = ((RatProto*)szRecvCmd)->RatLen - sizeof(RatProto);
 strncat(szCmd,szRecvCmd+sizeof(RatProto),dwSize);
 CreateProcessA(NULL,szCmd,NULL,NULL,1,0,NULL,NULL,&si,&pInfo);

 

(3) 經過管道通訊,獲得進程執行結果
 memset(szCmd,0,MAXLENGTH);
 int dwRead;
 //判斷管道內是否有傳入數據
 int nRet = PeekNamedPipe(hReadPipe1,szCmd,MAXLENGTH,(LPDWORD)&dwRead,NULL,NULL);
 for (int i=0;i<5&&dwRead==0;i++)
 {
  Sleep(100);
  nRet = PeekNamedPipe(hReadPipe1,szCmd,MAXLENGTH,(LPDWORD)&dwRead,NULL,NULL);
 }

 if (dwRead)
 {
  nRet = ReadFile(hReadPipe1,szCmd,dwRead,(LPDWORD)&dwRead,0);
  if (!nRet)
  {
   sprintf(szCmd,"%s","CMD COMMAND EXCUTE ERROR!");
  }  
 }


 

(4) 將執行結果傳給客戶端 .......

相關文章
相關標籤/搜索