小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

VC++ 中WM_COPYDATA 怎么樣應(yīng)用來(lái)實(shí)現(xiàn)兩個(gè)進(jìn)程間的數(shù)據(jù)傳輸[轉(zhuǎn)]

 Jugg_Bug 2013-04-19

本文著重講述了如果用WM_COPYDATA消息來(lái)實(shí)現(xiàn)兩個(gè)進(jìn)程之間傳遞數(shù)據(jù).

進(jìn)程之間通訊的幾種方法:

在Windows程序中,各個(gè)進(jìn)程之間常常需要交換數(shù)據(jù),進(jìn)行數(shù)據(jù)通訊。常用的方法有

  使用內(nèi)存映射文件
  通過(guò)共享內(nèi)存DLL共享內(nèi)存
  使用SendMessage向另一進(jìn)程發(fā)送WM_COPYDATA消息

比起前兩種的復(fù)雜實(shí)現(xiàn)來(lái),WM_COPYDATA消息無(wú)疑是一種經(jīng)濟(jì)實(shí)惠的一中方法.

WM_COPYDATA消息的主要目的是允許在進(jìn)程間傳遞只讀數(shù)據(jù)。Windows在通過(guò)WM_COPYDATA消息傳遞期間,不提供繼承同步方式。SDK文檔推薦用戶使用SendMessage函數(shù),接受方在數(shù)據(jù)拷貝完成前不返回,這樣發(fā)送方就不可能刪除和修改數(shù)據(jù):

這個(gè)函數(shù)的原型及其要用到的結(jié)構(gòu)如下:

SendMessage(hwnd,WM_COPYDATA,wParam,lParam);
其中,WM_COPYDATA對(duì)應(yīng)的十六進(jìn)制數(shù)為0x004A

wParam設(shè)置為包含數(shù)據(jù)的窗口的句柄。lParam指向一個(gè)COPYDATASTRUCT的結(jié)構(gòu):
typedef struct tagCOPYDATASTRUCT{
    DWORD dwData;//用戶定義數(shù)據(jù)
    DWORD cbData;//數(shù)據(jù)大小
    PVOID lpData;//指向數(shù)據(jù)的指針
}COPYDATASTRUCT;
該結(jié)構(gòu)用來(lái)定義用戶數(shù)據(jù)。

具體過(guò)程如下:


首先,在發(fā)送方,用FindWindow找到接受方的句柄,然后向接受方發(fā)送WM_COPYDATA消息.

接受方在DefWndProc事件中,來(lái)處理這條消息.由于中文編碼是兩個(gè)字節(jié),所以傳遞中文時(shí)候字節(jié)長(zhǎng)度要搞清楚.

代碼中有適量的解釋,大家請(qǐng)自己看吧.

用WM_COPYDATA的前提:

1,知道接收消息進(jìn)程的句柄。

2,接收消息進(jìn)程重載了WM_COPYDATA消息映射,能對(duì)其做出反應(yīng)(否則不是發(fā)送端自作多情了?)

看過(guò)前提,的出結(jié)論:在自己寫(xiě)的兩個(gè)進(jìn)程間用WM_COPYDATA再好不過(guò)。

下面CODE幾行就說(shuō)明了一切。

獲得句柄的方法,最簡(jiǎn)單的方法就是使用FindWindow,找窗口類,或者名,如果你覺(jué)得這樣不把握,那就利用SetProp個(gè)窗口做個(gè)記號(hào)....(不說(shuō)這些,跑踢兒了都)

OK,開(kāi)始寫(xiě)發(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 OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);

ON_WM_COPYDATA()/*消息映射*/

BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
        AfxMessageBox((LPCSTR)(pCopyDataStruct->lpData));/*利用對(duì)話框表示收到消息*/

        return CWnd::OnCopyData(pWnd, pCopyDataStruct);
}

進(jìn)程通信還有其他一些手段,相對(duì)來(lái)說(shuō)比較麻煩,但局限性要比WM_COPYDATA小。當(dāng)然你也可以兩端都注冊(cè)一個(gè)消息來(lái)通信。

使用WM_COPYDATA進(jìn)行進(jìn)程間通信的一個(gè)問(wèn)題

 

開(kāi)發(fā)中有時(shí)需要進(jìn)程間傳遞數(shù)據(jù),比如對(duì)于只允許單實(shí)例運(yùn)行的程序,當(dāng)已有實(shí)例運(yùn)行時(shí),再次打開(kāi)程序,可能需要向當(dāng)前運(yùn)行的實(shí)例傳遞信息進(jìn)行特殊處理。對(duì)于傳遞少量數(shù)據(jù)的情況,最簡(jiǎn)單的就是用SendMessage發(fā)送WM_COPYDATA消息,所帶參數(shù)wParam和lParam可以攜帶相關(guān)數(shù)據(jù)。由于SendMessage是阻塞的,在接收數(shù)據(jù)進(jìn)程處理完數(shù)據(jù)之前不會(huì)返回,發(fā)送方不會(huì)刪除或修改數(shù)據(jù),因此這種方法是簡(jiǎn)單且安全的,不過(guò)數(shù)據(jù)量不能太大,否則會(huì)由于處理時(shí)間過(guò)長(zhǎng)造成阻塞假死。

    用SendMessage發(fā)送WM_COPYDATA的方法如下:

   

 

    lResult SendMessage(     // returns LRESULT in lResult
       (HWND) hWndControl,     // handle to destination control
       (UINT) WM_COPYDATA,     // message ID
       (WPARAM) wParam,     // (WPARAM) () wParam;
       (LPARAM) lParam     // (LPARAM) () lParam;

    );

   

 

    其中,wParam為發(fā)送數(shù)據(jù)方的窗口句柄,lParam為指向一個(gè)COPYDATASTRUCT類型結(jié)構(gòu)體的指針,該結(jié)構(gòu)體中包含了傳遞的數(shù)據(jù)信息。COPYDATASTRUCT定義如下:

    typedef struct tagCOPYDATASTRUCT {
        ULONG_PTR dwData;
        DWORD cbData;
        PVOID lpData;
    } COPYDATASTRUCT, *PCOPYDATASTRUCT;

    其中,dwData為自定義的數(shù)據(jù),cbData指定lpData指向數(shù)據(jù)的大小,lpData為指向數(shù)據(jù)的指針。按照前面所說(shuō),在使用WM_COPYDATA時(shí)要保證數(shù)據(jù)的只讀屬性,即不能有發(fā)送方的其他線程對(duì)傳遞數(shù)據(jù)進(jìn)行改寫(xiě)。(這也解釋了為什么不允許用PostMessage發(fā)送WM_COPYDATA,因?yàn)镻ostMessage函數(shù)是異步的。還有一點(diǎn)需要注意的是由于SendMessage是阻塞的,所以容易引起死鎖,可以考慮用SendMessageTimeout代替。)另外,如果傳遞數(shù)據(jù)中涉及到對(duì)象或系統(tǒng)資源,必須確保接收方可以對(duì)其進(jìn)行處理,比如HDC、HBITMAP之類的資源是無(wú)效的,他們屬于不同的進(jìn)程。

    在使用的時(shí)候,要用FindWindow等API找到接收方的窗口句柄;接收方的程序中要添加對(duì)WM_COPYDATA消息的響應(yīng)。

   

    前幾天寫(xiě)程序用到WM_COPYDATA進(jìn)行進(jìn)程間通信,但是接收方怎么也收不到消息。調(diào)試發(fā)現(xiàn)找到的窗口句柄是沒(méi)有問(wèn)題的,查看MSDN也沒(méi)有什么提示,百思不得其解。

    后來(lái)看了一些示例代碼,發(fā)現(xiàn)不同之處是我的SendMessage調(diào)用中wParam和lParam參數(shù)都是0,因?yàn)槲抑皇切枰ㄟ^(guò)WM_COPYDATA消息通知一下接收程序即可,不用傳遞任何數(shù)據(jù)。試著將這兩個(gè)參數(shù)改為非空,接收方就可以收到消息了。總結(jié)結(jié)論為:wParam參數(shù)是否為0沒(méi)有影響,但是lParam參數(shù)必須為非空,即必須指向一個(gè)有效的COPYDATASTRUCT結(jié)構(gòu)體。

    原因是什么呢?查了一些資料發(fā)現(xiàn),SendMessage(WM_COPYDATA)底層是通過(guò)文件映射(File Mapping)完成的,大概流程是發(fā)送方線程根據(jù)COPYDATASTRUCT結(jié)構(gòu)體中的傳遞數(shù)據(jù)信息,在共享內(nèi)存中進(jìn)行數(shù)據(jù)復(fù)制,接收方線程則會(huì)到共享內(nèi)存中讀取數(shù)據(jù)進(jìn)行處理。因此如果指向COPYDATASTRUCT結(jié)構(gòu)的指針為空的話,流程是無(wú)法進(jìn)行的,所以接收方也理所當(dāng)然收不到消息。

WM_COPYDATA使用的一個(gè)例子:

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

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

進(jìn)程間通信的方法有多種,其中,對(duì)于少量數(shù)據(jù)可以用WM_COPYDATA方便的實(shí)現(xiàn)通信(如果對(duì)于大量數(shù)據(jù)的話,由于SendMessage是阻塞的,只有接收方響應(yīng)了消息,SendMessage才能返回,否則則一直阻塞,所以,對(duì)于大量數(shù)據(jù)來(lái)說(shuō),用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)樾枰诮邮辗降腛nCopyData()函數(shù)中區(qū)分發(fā)送的兩種不同類型數(shù)據(jù)。所以就定義了以下兩個(gè)常量:

#define STRING 1

#define STUDENT 2

發(fā)送方:

void CSendDataDlg::OnBtSend() //實(shí)現(xiàn)CString類型數(shù)據(jù)的發(fā)送

{

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í)際字符的長(zhǎng)度,沒(méi)有包括'\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::OnBtStu() //實(shí)現(xiàn)Student類型數(shù)據(jù)的發(fā)送

{

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ā)送成功"));

}

接收方:

在OnInitDialog方法中:

//***************************************************************

//初始化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::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)

{

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::OnCopyData(pWnd, pCopyDataStruct);

return TRUE;

}

 

MSDN幫助里面有該消息的例子,說(shuō)的也很清楚。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多