進程通信之一使用WM_COPYDATA

http://www.cnblogs.com/morewindows/archive/2011/09/23/2186294.html

進程間通信最簡單的方式就是發送WM_COPYDATA消息。

 

發送WM_COPYDATA消息:

SendMessage(接收窗口句柄WM_COPYDATA, (WPARAM)發送窗口句柄, (LPARAM)&CopyData);

 

其中的CopyDataCOPYDATASTRUCT結構類型,該結構定義如下:

typedef struct tagCOPYDATASTRUCT {

DWORD dwData;  // Specifies data to be passed to the receiving application.

DWORD cbData;  //Specifies the size, in bytes, of the data pointed to by the lpData member.

 PVOID lpData;    // Pointer to data to be passed to the receiving application. can be NULL.

COPYDATASTRUCT, *PCOPYDATASTRUCT;

注意:該消息只能由SendMessage()來發送,而不能使用PostMessage()。因爲系統必須管理用以傳遞數據的緩衝區的生命期,如果使用了PostMessage(),數據緩衝區會在接收方(線程)有機會處理該數據之前,就被系統清除和回收。此外如果lpData指向一個帶有指針或某一擁有虛函數的對象時,也要小心處理。

 

如果傳入的句柄不是一個有效的窗口或當接收方進程意外終止時,SendMessage()會立即返回,因此發送方在這種情況下不會陷入一個無窮的等待狀態中。

 

返回值問題,MSDN上說如果接收方處理了,返回TRUE,否則返回FALSE,但是本人在實驗時,都是返回0(接收方已經處理)。

 

接收WM_COPYDATA消息:

只要用COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)lParam;就可以了。接收方應認爲這些數據是隻讀的。

 

由於發送方在接收方處理WM_COPYDATA消息完畢前都是處於等待中,所以接收方應當儘快處理WM_COPYDATA消息。

 

 

 

以一個簡單的例子來說明如何使用WM_COPYDATA消息,有二個程序,一個用來發送表示當前時間信息的字符串,另一個接收數據後顯示到編輯框中。例子中有幾點要注意:

1.如何得到當前控制檯窗口句柄?VS2008下可以直接使用HWND GetConsoleWindow(void);函數。

2.使用char *ctime(const time_t *timer);將一個time_t類型轉化成一個字符串時,函數會在字符串末尾加下'\n',因爲發送前要將這個'\n'去掉。

 

發送消息的程序代碼(VS2008下編譯通過):

#include <windows.h>

#include <time.h>

#include <conio.h>

#include <stdio.h>

int main()

{

       const char szDlgTitle[] = "RecvMessage";

 

       HWND hSendWindow = GetConsoleWindow ();

       if (hSendWindow == NULL)

              return -1;

       HWND hRecvWindow = FindWindow(NULLszDlgTitle);

       if (hRecvWindow == NULL)

              return -1;

 

       char szSendBuf[100];

       time_t  timenow;

       COPYDATASTRUCT CopyData;

 

       for (int i = 0; i < 10; i++)

       {

              time(&timenow);

              sprintf(szSendBuf"%s"ctime(&timenow));//注意,ctime()返回的字符串後面帶了'\n'

              CopyData.dwData = i;

              CopyData.cbData = strlen(szSendBuf);

              szSendBuf[CopyData.cbData - 1] = '\0';

              CopyData.lpData = szSendBuf;

 

              SendMessage(hRecvWindowWM_COPYDATA, (WPARAM)hSendWindow, (LPARAM)&CopyData);

              printf("%s\n"szSendBuf);

              Sleep(1000);

       }

       return 0;

}

 

接收消息程序代碼(VC6.0下編譯通過):

程序中的IDC_EDIT_RECVMESSAGE爲編輯框的ID

#include "stdafx.h"

#include "resource.h"

#include <stdio.h>

BOOL CALLBACK DlgProc(HWND hDlgUINT messageWPARAM wParamLPARAM lParam);

int APIENTRY WinMain(HINSTANCE hInstance,

                     HINSTANCE hPrevInstance,

                     LPSTR     lpCmdLine,

                     int       nCmdShow)

{

      // TODO: Place code here.

       DialogBox(hInstanceMAKEINTRESOURCE(IDD_DIALOG1), NULLDlgProc);

       return 0;

}

BOOL CALLBACK DlgProc(HWND hDlgUINT messageWPARAM wParamLPARAM lParam)

{

       const char szDlgTitle[] = "RecvMessage";

       static HWND s_hEditShowRecv;

 

       switch (message)

       {

       case WM_INITDIALOG:

              SetWindowText(hDlgszDlgTitle);

              s_hEditShowRecv = GetDlgItem(hDlgIDC_EDIT_RECVMESSAGE);

              return TRUE;

 

       case WM_COMMAND:

              switch (LOWORD(wParam))

              {

              case IDOK:

              case IDCANCEL:

                     EndDialog(hDlgLOWORD(wParam));

                     return TRUE;

              }

              break;

 

       case WM_COPYDATA:

              {

                     COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)lParam;

                     char szBuffer[300];

 

                     memset(szBuffer, 0, sizeof(szBuffer));

                     sprintf(szBuffer"dwData:%d cbData:%d\r\nlpData:0x%08x = %s\r\n\r\n",

                            pCopyData->dwDatapCopyData->cbData,

                            (PVOID)pCopyData->lpData, (char*)pCopyData->lpData);

                     //在編輯框中追加數據

                     SendMessage(s_hEditShowRecvEM_SETSEL, (WPARAM)-1, (LPARAM)-1); // (0, -1)表示全選, (-1,任意)表示全不選

                     SendMessage(s_hEditShowRecvEM_REPLACESELFALSE, (LPARAM)szBuffer);

                     SendMessage(s_hEditShowRecvEM_SCROLLCARET, 0, 0);

              }

              return TRUE;

       }

       return FALSE;

}

運行結果如下:

 

 

 

 

轉載請標明出處,原文地址:http://www.cnblogs.com/morewindows/archive/2011/09/23/2186294.html




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章