進程間通訊的四種方式:剪貼板、匿名管道、命名管道和郵槽
第一種:剪貼板
(1)新建一個基於對話框的應用程序,並設置好如下界面:
(2)分別編輯發送按鈕和接收按鈕的代碼:
[cpp] ?void CClipboardDlg::OnBtnSend()
{
// TODO: Add your control notification handler code here
if(OpenClipboard())
{
CString str;
HANDLE hClip;
char *pBuf;
EmptyClipboard();//將剪貼板擁有權設置為當前窗口
GetDlgItemText(IDC_EDIT_SEND,str);
hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//多分配一個字節,用於放置回車
pBuf=(char *)GlobalLock(hClip);//對一個內存對象加鎖並返回內存對象句柄
strcpy(pBuf,str);
GlobalUnlock(hClip);//解鎖
SetClipboardData(CF_TEXT,hClip);//放置數據
CloseClipboard();//關閉剪貼板
}
}
void CClipboardDlg::OnBtnRecv()
{
// TODO: Add your control notification handler code here
if(OpenClipboard())
{
//The IsClipboardFormatAvailable function determines whether the clipboard contains data in the specified format
if(IsClipboardFormatAvailable(CF_TEXT))
{
HANDLE hClip;
char *pBuf;
hClip=GetClipboardData(CF_TEXT);
pBuf=(char *)GlobalLock(hClip);//The GlobalLock function locks a global memory object and returns a pointer to the first byte of the object's memory block
GlobalUnlock(hClip);
SetDlgItemText(IDC_EDIT_RECV,pBuf);
CloseClipboard();
}
}
}
void CClipboardDlg::OnBtnSend()
{
// TODO: Add your control notification handler code here
if(OpenClipboard())
{
CString str;
HANDLE hClip;
char *pBuf;
EmptyClipboard();//將剪貼板擁有權設置為當前窗口
GetDlgItemText(IDC_EDIT_SEND,str);
hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//多分配一個字節,用於放置回車
pBuf=(char *)GlobalLock(hClip);//對一個內存對象加鎖並返回內存對象句柄
strcpy(pBuf,str);
GlobalUnlock(hClip);//解鎖
SetClipboardData(CF_TEXT,hClip);//放置數據
CloseClipboard();//關閉剪貼板
}
}
void CClipboardDlg::OnBtnRecv()
{
// TODO: Add your control notification handler code here
if(OpenClipboard())
{
//The IsClipboardFormatAvailable function determines whether the clipboard contains data in the specified format
if(IsClipboardFormatAvailable(CF_TEXT))
{
HANDLE hClip;
char *pBuf;
hClip=GetClipboardData(CF_TEXT);
pBuf=(char *)GlobalLock(hClip);//The GlobalLock function locks a global memory object and returns a pointer to the first byte of the object's memory block
GlobalUnlock(hClip);
SetDlgItemText(IDC_EDIT_RECV,pBuf);
CloseClipboard();
}
}
}
第二種:匿名管道
<1>新建一個基於單文檔的工程,工程名為"Parent"
(1)添加如下菜單項,並添加命令響應函數 CChildView::OnPipeRead()、CChildView::OnPipeWrite();
(2)在CParentView類中添加兩個句柄HANDLE hRead 和 HANDLE hWrite,屬性設為私有,並在構造函數中進行初始化,在析構函數中釋放該句柄
[cpp]
CParentView::CParentView()
{
// TODO: add construction code here
hRead=NULL;
hWrite=NULL;
}
CParentView::~CChildView()
{
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
}
CParentView::CParentView()
{
// TODO: add construction code here
hRead=NULL;
hWrite=NULL;
}
CParentView::~CChildView()
{
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
}
(3)編寫CParentView::OnPipeCreate() 函數,注意用到兩個函數CreatePipe(...)和CreateProcess(...)分別用於創建管道和啟動子進程。代碼如下:
[cpp]
void CParentView::OnPipeCreate()
{
// TODO: Add your command handler code here
SECURITY_ATTRIBUTES sa;//定義一個安全屬性結構圖
sa.bInheritHandle=TRUE;//TRUE表示可以被子進程繼承
sa.lpSecurityDescriptor=NULL;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
if(CreatePipe(&hRead,&hWrite,&sa,0))//創建匿名管道
{
MessageBox("匿名管道創建失敗!");
return ;
}
//如果創建成功則啟動子進程,將匿名管道的讀寫句柄傳遞給子進程
STARTUPINFO sui;
PROCESS_INFORMATION pi;
ZeroMemory(&sui,sizeof(STARTUPINFO));//將這個結構體內的所有成員設為0
sui.cb=sizeof(STARTUPINFO);
sui.dwFlags=STARTF_USESTDHANDLES;
sui.hStdInput=hRead;
sui.hStdOutput=hWrite;
sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,
TRUE,0,NULL,NULL,&sui,&pi))
{
CloseHandle(hRead);
CloseHandle(hWrite);
hRead=NULL;
hWrite=NULL;
MessageBox("創建子進程失敗!");
return;
}
else
{
CloseHandle(pi.hProcess);//關閉主進程句柄
CloseHandle(pi.hThread);//關閉主進程線程句柄
}
}
void CParentView::OnPipeCreate()
{
// TODO: Add your command handler code here
SECURITY_ATTRIBUTES sa;//定義一個安全屬性結構圖
sa.bInheritHandle=TRUE;//TRUE表示可以被子進程繼承
sa.lpSecurityDescriptor=NULL;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
if(CreatePipe(&hRead,&hWrite,&sa,0))//創建匿名管道
{
MessageBox("匿名管道創建失敗!");
return ;
}
//如果創建成功則啟動子進程,將匿名管道的讀寫句柄傳遞給子進程
STARTUPINFO sui;
PROCESS_INFORMATION pi;
ZeroMemory(&sui,sizeof(STARTUPINFO));//將這個結構體內的所有成員設為0
sui.cb=sizeof(STARTUPINFO);
sui.dwFlags=STARTF_USESTDHANDLES;
sui.hStdInput=hRead;
sui.hStdOutput=hWrite;
sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,
TRUE,0,NULL,NULL,&sui,&pi))
{
CloseHandle(hRead);
CloseHandle(hWrite);
hRead=NULL;
hWrite=NULL;
MessageBox("創建子進程失敗!");
return;
}
else
{
CloseHandle(pi.hProcess);//關閉主進程句柄
CloseHandle(pi.hThread);//關閉主進程線程句柄
}
}(4)編寫OnPipeRead()和OnPipeWrite()的具體實現:
[cpp]
void CParentView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("讀取數據失敗!");
return;
}
MessageBox(buf);
}
void CParentView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[]="http://www.sunxin.org";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("寫入數據失敗!");
return;
}
}
void CParentView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("讀取數據失敗!");
return;
}
MessageBox(buf);
}
void CParentView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[]="http://www.sunxin.org";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("寫入數據失敗!");
return;
}
}
<2>在該工程中再添加一個項目,同樣是基於單文檔的,項目名為"Child",於"Parent"保持平級即可。
(1)添加如下菜單項,並添加命令響應函數 CChildView::OnPipeRead()、CChildView::OnPipeWrite();
(2)首先我們要獲得子進程的標准輸入和標准輸出句柄,這個可以在CChildView類的窗口完全創建的時候去獲取,此時我們可以用一個CChildView::OnInitialUpdate()的虛函數去獲取,OnInitialUpdate()是在窗口完全創建之後第一個執行的函數。
(3)在CChildView類中添加兩個句柄 HANDLE hRead 和 HANDLE hWrite,屬性設為私有,並在構造函數中進行初始化,在析構函數中釋放該句柄
[cpp]
CChildView::CChildView()
{
// TODO: add construction code here
hRead=NULL;
hWrite=NULL;
}
CChildView::~CChildView()
{
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
}
CChildView::CChildView()
{
// TODO: add construction code here
hRead=NULL;
hWrite=NULL;
}
CChildView::~CChildView()
{
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
}(4)在OnInitialUpdate()函數中通過 GetStdHandle(STD_INPUT_HANDLE)、GetStdHandle(STD_OUTPUT_HANDLE)得到標准輸入輸出句柄
[cpp]
hRead=GetStdHandle(STD_INPUT_HANDLE);//得到管道的讀取句柄
hWrite=GetStdHandle(STD_OUTPUT_HANDLE);//得到管道的寫入句柄
hRead=GetStdHandle(STD_INPUT_HANDLE);//得到管道的讀取句柄
hWrite=GetStdHandle(STD_OUTPUT_HANDLE);//得到管道的寫入句柄(5)接著編寫讀取進程OnPipeRead()和寫入進程OnPipeWrite()代碼的具體實現:
[cpp]
void CChildView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("讀取數據失敗!");
return;
}
MessageBox(buf);
}
void CChildView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[]="匿名管道測試程序";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("寫入數據失敗!");
return;
}
}
void CChil
dView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("讀取數據失敗!");
return;
}
MessageBox(buf);
}
void CChildView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[]="匿名管道測試程序";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("寫入數據失敗!");
return;
}
}