利用匿名管道在父子進(jìn)程間傳遞數(shù)據(jù)
進(jìn)程間傳遞數(shù)據(jù)有很多種方法,常用到的有命令行、共享內(nèi)存、內(nèi)存映射文件、剪貼板、windows消息、socket等。
命令行的缺點(diǎn)是數(shù)據(jù)長(zhǎng)度限制。Windows2000只能傳遞256個(gè)字節(jié),內(nèi)存映射文件、共享內(nèi)存都需要一些進(jìn)程同步才能很好的配合讀寫數(shù)據(jù),剪貼板可能會(huì)被其他進(jìn)程擦數(shù)數(shù)據(jù)。當(dāng)多開的時(shí)候很難控制進(jìn)程間的對(duì)應(yīng)關(guān)系。
一種解決方案是生成隨機(jī)命名的同步控制對(duì)象,然后利用命令行傳遞名字。同步控制對(duì)象可以通過唯一的名字再另一個(gè)進(jìn)程中獲取其引用。
相對(duì)來說用同步對(duì)象會(huì)稍有些麻煩,匿名管道可以很好的解決這些問題。子進(jìn)程可以繼承父進(jìn)程中創(chuàng)建的句柄,父子進(jìn)程一一對(duì)應(yīng)的關(guān)系不會(huì)被打亂。而且使用簡(jiǎn)單,父子進(jìn)程可以雙向通信。
用法:
1. 首先創(chuàng)建兩條匿名管道,一條用于發(fā)送數(shù)據(jù)給子進(jìn)程,一條用于從子進(jìn)程接收數(shù)據(jù),安全描述符中指定可繼承性 saAttr.bInheritHandle = TRUE;
2. 每條匿名管道包括兩個(gè)句柄,一個(gè)讀一個(gè)寫,可以理解為管道的兩端,從寫端寫出的數(shù)據(jù)可以從讀端讀取。所以父進(jìn)程需要一條管道來接收數(shù)據(jù),一條發(fā)送數(shù)據(jù)。
3. windows的IO操作都可以用WriteFile 和ReadFile來完成,默認(rèn)模式下數(shù)據(jù)發(fā)送和接收是阻塞的,管道的數(shù)據(jù)發(fā)送與接收也可以用重疊模式來進(jìn)行。
4. CreateProcess子進(jìn)程時(shí)參數(shù).bInheritHandle需要傳真,保證句柄的可繼承性。
5. 利用STARTUPINFO傳遞管道端口給子進(jìn)程,父窗口發(fā)送數(shù)據(jù)的管道的讀端口,和父窗口等待接收數(shù)據(jù)的管道的寫端口,利用STDHANDLES來傳遞。

STARTUPINFO starinfo =
{0};

starinfo.cb = sizeof(starinfo);

starinfo.hStdInput = hSendReadPipe;

starinfo.hStdOutput= hRecvWritePipe;

starinfo.hStdError = hRecvWritePipe;

starinfo.dwFlags |= STARTF_USESTDHANDLES;

6. 子進(jìn)程從STDHANDLES獲得兩個(gè)句柄用來讀寫。
HANDLE hRead = GetStdHandle(STD_INPUT_HANDLE);

HANDLE hWrite = GetStdHandle(STD_OUTPUT_HANDLE);

下面是完整代碼:


BOOL CreatePipe()



{

SECURITY_ATTRIBUTES saAttr;

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);

saAttr.bInheritHandle = TRUE;

saAttr.lpSecurityDescriptor = NULL;


/**//*'創(chuàng)建匿名管道*/

if (!CreatePipe(&hSendReadPipe,&hSendWritePipe, &saAttr, 0))


{

::LogMsg("CreatePipe failed!");

return FALSE;

}


/**//*'構(gòu)造寫句柄的復(fù)制體*/

if(!DuplicateHandle(GetCurrentProcess(), hSendWritePipe,

GetCurrentProcess(), &hSendWritePipeDup, 0,FALSE,DUPLICATE_SAME_ACCESS))


{

::LogMsg("DuplicateHandle Handle!");

return FALSE;

}

CloseHandle(hSendWritePipe);


//////////////////////////////////////////////////////////////////////////

if (!CreatePipe(&hRecvReadPipe,&hRecvWritePipe, &saAttr, 0))


{

::LogMsg("CreatePipe failed!");

return FALSE;

}


/**//*'構(gòu)造寫句柄的復(fù)制體*/

if(!DuplicateHandle(GetCurrentProcess(), hRecvReadPipe,

GetCurrentProcess(), &hRecvReadPipeDup, 0,FALSE,DUPLICATE_SAME_ACCESS))


{

::LogMsg("DuplicateHandle Handle!");

return FALSE;

}

CloseHandle(hRecvReadPipe);

return TRUE;

}





BOOL ReadFromPipe()



{

DWORD dwReaded =0;

char szBuf[255];

return ReadFile(hRecvReadPipeDup, szBuf, sizeof(szBuf), &dwReaded, NULL); ;

}


void WaitForReply()



{


while ( !ReadFromPipe())
{};

}


BOOL WriteToPipe()



{

char szData[1024];

int nSize = sizeof(g_cmdData);

CompressData((char*)&g_cmdData,nSize,szData);



/**//*'對(duì)管道進(jìn)行寫操作*/

DWORD dwWrited =0;

BOOL bSuccess = TRUE;

bSuccess &= WriteFile(hSendWritePipeDup, (LPCVOID)szData, nSize, &dwWrited, NULL);


CloseHandle(hSendWritePipeDup);

if ( !bSuccess )


{

::LogMsg("WriteFile failed!");

return FALSE;

}

return TRUE;

}


BOOL CreateGameProcess()



{


char strDir[MAX_PATH] =
{0};


char strPath[MAX_PATH]=
{0};


GetCurrentDirectory(MAX_PATH,strDir);

strcpy(strPath,strDir);


#ifdef _DEBUG

const char* pszFileName = "\\main_debug.exe";

#else

const char* pszFileName = "\\main.exe";

#endif

strcat(strPath,pszFileName);


if ( !CreatePipe() )


{

::LogMsg("CreatePipe failed!");

return FALSE;

}



STARTUPINFO starinfo =
{0};

starinfo.cb = sizeof(starinfo);

starinfo.hStdInput = hSendReadPipe;

starinfo.hStdOutput= hRecvWritePipe;

starinfo.hStdError = hRecvWritePipe;

starinfo.dwFlags |= STARTF_USESTDHANDLES;



PROCESS_INFORMATION processinfo =
{0};


BOOL bRet =::CreateProcess(strPath, " fromlogin", NULL,NULL,TRUE,NULL,NULL,strDir,&starinfo,&processinfo);

if(bRet)


{

// WaitForInputIdle(processinfo.hProcess,INFINITE);

dwGameProcessID = processinfo.dwProcessId;

CloseHandle(processinfo.hProcess);

CloseHandle(processinfo.hThread);

return TRUE;

}

::LogMsg("CreateProcess failed!");



return FALSE;

}


子進(jìn)程中接收數(shù)據(jù):


DWORD dwReaded =0;

HANDLE hRead = GetStdHandle(STD_INPUT_HANDLE);

HANDLE hWrite = GetStdHandle(STD_OUTPUT_HANDLE);


if( hRead )


{


/**//*'從管道接收數(shù)據(jù)*/

const int nBufSize = 2048;

char szBuf[nBufSize];

if(ReadFile(hRead, &szBuf,nBufSize, &dwReaded, NULL))


{

}

}
