本文著重講述了如果用WM_COPYDATA消息來實(shí)現(xiàn)兩個(gè)進(jìn)程之間傳遞數(shù)據(jù). 進(jìn)程之間通訊的幾種方法: 在Windows程序中,各個(gè)進(jìn)程之間常常需要交換數(shù)據(jù),進(jìn)行數(shù)據(jù)通訊。常用的方法有 使用內(nèi)存映射文件 比起前兩種的復(fù)雜實(shí)現(xiàn)來,WM_COPYDATA消息無疑是一種經(jīng)濟(jì)實(shí)惠的一中方法. WM_COPYDATA消息的主要目的是允許在進(jìn)程間傳遞只讀數(shù)據(jù)。Windows在通過WM_COPYDATA消息傳遞期間,不提供繼承同步方式。SDK文檔推薦用戶使用SendMessage函數(shù),接受方在數(shù)據(jù)拷貝完成前不返回,這樣發(fā)送方就不可能刪除和修改數(shù)據(jù): 這個(gè)函數(shù)的原型及其要用到的結(jié)構(gòu)如下: SendMessage(hwnd,WM_COPYDATA,wParam,lParam); wParam設(shè)置為包含數(shù)據(jù)的窗口的句柄。lParam指向一個(gè)COPYDATASTRUCT的結(jié)構(gòu): 具體過程如下:
接受方在DefWndProc事件中,來處理這條消息.由于中文編碼是兩個(gè)字節(jié),所以傳遞中文時(shí)候字節(jié)長度要搞清楚. 代碼中有適量的解釋,大家請(qǐng)自己看吧. 用WM_COPYDATA的前提: 1,知道接收消息進(jìn)程的句柄。 2,接收消息進(jìn)程重載了WM_COPYDATA消息映射,能對(duì)其做出反應(yīng)(否則不是發(fā)送端自作多情了?) 看過前提,的出結(jié)論:在自己寫的兩個(gè)進(jìn)程間用WM_COPYDATA再好不過。 下面CO 獲得句柄的方法,最簡單的方法就是使用FindWindow,找窗口類,或者名,如果你覺得這樣不把握,那就利用SetProp個(gè)窗口做個(gè)記號(hào)....(不說這些,跑踢兒了都) OK,開始寫發(fā)送端代碼: HWND hWnd = FindWindow(NULL,"MyApp"); if(hWnd!=NULL) { COPYDATASTRUCT cpd; /*給COPYDATASTRUCT結(jié)構(gòu)賦值*/ cpd.dwData = 0; cpd.cbData = strlen("字符串"); cpd.lpData = (void*)"字符串"; ::SendMessage(hWnd,WM_COPYDATANULL,(LPARAM)&cpd);//發(fā)送! /*完事兒了??!*/ } 接收端重載ON_WM_COPYDATA消息映射函數(shù)(下面是手工所要加的,你最好還是用ClassWizard) afx_msg BOOL On ON_WM_COPYDATA()/*消息映射*/ return CWnd::On 進(jìn)程通信還有其他一些手段,相對(duì)來說比較麻煩,但局限性要比WM_COPYDATA小。當(dāng)然你也可以兩端都注冊(cè)一個(gè)消息來通信。 使用WM_COPYDATA進(jìn)行進(jìn)程間通信的一個(gè)問題
開發(fā)中有時(shí)需要進(jìn)程間傳遞數(shù)據(jù),比如對(duì)于只允許單實(shí)例運(yùn)行的程序,當(dāng)已有實(shí)例運(yùn)行時(shí),再次打開程序,可能需要向當(dāng)前運(yùn)行的實(shí)例傳遞信息進(jìn)行特殊處理。對(duì)于傳遞少量數(shù)據(jù)的情況,最簡單的就是用SendMessage發(fā)送WM_COPYDATA消息,所帶參數(shù)wParam和lParam可以攜帶相關(guān)數(shù)據(jù)。由于SendMessage是阻塞的,在接收數(shù)據(jù)進(jìn)程處理完數(shù)據(jù)之前不會(huì)返回,發(fā)送方不會(huì)刪除或修改數(shù)據(jù),因此這種方法是簡單且安全的,不過數(shù)據(jù)量不能太大,否則會(huì)由于處理時(shí)間過長造成阻塞假死。
WM_COPYDATA使用的一個(gè)例子: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 進(jìn)程間通信的方法有多種,其中,對(duì)于少量數(shù)據(jù)可以用WM_COPYDATA方便的實(shí)現(xiàn)通信(如果對(duì)于大量數(shù)據(jù)的話,由于SendMessage是阻塞的,只有接收方響應(yīng)了消息,SendMessage才能返回,否則則一直阻塞,所以,對(duì)于大量數(shù)據(jù)來說,用SendMessage就容易造成窗口假死) 。 本例子分別用WM_COPYDATA 實(shí)現(xiàn)了兩種數(shù)據(jù)類型的發(fā)送,一種為Cstring,另外一種為自定義的結(jié)構(gòu)體Student: //********************************************************** #pragma pack(1) struct Student { char ID[10]; TCHAR Name[20]; UINT Age; UINT Grade; char Room[5]; char Tel[12]; }; #pragma pack() //********************************************************** 因?yàn)樾枰诮邮辗降腛n #define STRING 1 #define STUDENT 2 發(fā)送方: void CSendDataDlg::On { UpdateData(TRUE); if (m_szData.IsEmpty()) { m_szData = _T("Hello"); UpdateData(FALSE); } // m_szData += '\0'; HWND hWndRcv = ::FindWindow(NULL,"Receiver"); if (hWndRcv == NULL) { AfxMessageBox(_T("找不到接收窗口,發(fā)送不成功")); return ; } COPYDATASTRUCT cpd; cpd.dwData = STRING; //標(biāo)志為CString類型 cpd.cbData = m_szData.GetLength() + 1; //GetLength()只是取得實(shí)際字符的長度,沒有包括'\0'. cpd.lpData = (void*)m_szData.GetBuffer(cpd.cbData); ::SendMessage(hWndRcv,WM_COPYDATA,(WPARAM)this->m_hWnd,(LPARAM)&cpd); m_szData.ReleaseBuffer(); AfxMessageBox(_T("發(fā)送成功")); } void CSendDataDlg::On { UpdateData(); m_szID += '\0'; m_szName += '\0'; m_szRoom += '\0'; m_szTel += '\0'; m_pStu = new Student(); strcpy(m_pStu->ID,m_szID.GetBuffer(m_szID.GetLength())); _tcscpy(m_pStu->Name,m_szName.GetBuffer(m_szName.GetLength())); strcpy(m_pStu->Room,m_szRoom.GetBuffer(m_szRoom.GetLength())); strcpy(m_pStu->Tel,m_szTel.GetBuffer(m_szTel.GetLength())); m_szID.ReleaseBuffer();m_szName.ReleaseBuffer(); m_szRoom.ReleaseBuffer();m_szTel.ReleaseBuffer(); m_pStu->Age = m_nAge; m_pStu->Grade = m_nGrade; HWND hWndRcv = ::FindWindow(NULL,"Receiver"); if (hWndRcv == NULL) { AfxMessageBox(_T("找不到接收窗口,發(fā)送不成功")); return ; } COPYDATASTRUCT cpd; cpd.dwData = STUDENT; // 標(biāo)志為Student類型 cpd.cbData = sizeof(Student); cpd.lpData = (PVOID)m_pStu; ::SendMessage(hWndRcv,WM_COPYDATA,(WPARAM)this->m_hWnd,(LPARAM)&cpd); delete m_pStu; AfxMessageBox(_T("發(fā)送成功")); } 接收方: 在On //*************************************************************** //初始化ListCtrl控件 LVCOLUMN column; column.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; column.cx = 80; column.iSubItem = 0; column.pszText = _T("ID"); m_ListCtl.InsertColumn(0,&column); column.cx = 80; column.pszText = _T("Name"); column.iSubItem = 1; m_ListCtl.InsertColumn(1,&column); column.cx = 55; column.pszText = _T("Age"); column.iSubItem = 2; m_ListCtl.InsertColumn(2,&column); column.cx = 55; column.pszText = _T("Grade"); column.iSubItem = 3; m_ListCtl.InsertColumn(3,&column); column.cx = 55; column.pszText = _T("Room"); column.iSubItem = 4; m_ListCtl.InsertColumn(4,&column); column.cx = 80; column.pszText = _T("Tel"); column.iSubItem = 5; m_ListCtl.InsertColumn(5,&column);
BOOL CReceiverDlg::On { switch (pCopyDataStruct->dwData) { // 接收到的是CString類型 case STRING: m_szData += (LPCSTR)(pCopyDataStruct->lpData); UpdateData(FALSE); break; case STUDENT: // 接收到的是Student類型 CString id,name,room,tel; UINT age,grade; CString str; Student* pStu = (Student*)(pCopyDataStruct->lpData); id = pStu->ID; name = pStu->Name; room = pStu->Room; tel = pStu->Tel; age = pStu->Age; grade = pStu->Grade; LVITEM item; // 把接收到的數(shù)據(jù)顯示到ListCtrl控件上 item.mask = LVIF_TEXT; int n = m_ListCtl.GetItemCount(); item.iItem = n; item.iSubItem = 0; item.pszText = id.GetBuffer(id.GetLength()); id.ReleaseBuffer(); m_ListCtl.InsertItem(&item); m_ListCtl.SetItemText(n,1,name); str.Format("%d",age); m_ListCtl.SetItemText(n,2,str); str.Format("%d",grade); m_ListCtl.SetItemText(n,3,str); m_ListCtl.SetItemText(n,4,room); m_ListCtl.SetItemText(n,5,tel); UpdateData(FALSE); //delete pStu; break; } // return CDialog::On return TRUE; }
MSDN幫助里面有該消息的例子,說的也很清楚。 |
|