WM_COPYDATA是一个非常特殊的消息,此消息可能携带一个比较大的消息参数,而其他消息都只能携带两个固定大小的参数(WPARAM和LPARAM)。
WM_COPYDATA的两个参数如下:
wParam //发送或传递这个消息的窗口
lParam //指向包含要发送的数据的COPYDATASTRUCT结构的指针
在发送WM_COPYDATA消息时,WM_COPYDATA的wParam参数应该赋值为发送此消息的窗口,而lParam消息参数指向一个COPYDATASTRUCT结构类型的变量:
typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData; //可以是任意值
DWORD cbData; //lpData内存区域的字节数
PVOID lpData; //需要发送给目标窗口所在进程的数据
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
在消息发送时,系统会将整个COPYDATASTRUCT及lpData所指向的内容全部发送给目标进程。目标进程窗口在收到WM_COPYDATA后,可以从lParam参数中提取出数据。
数据发送端代码片段:
// ************ Globals ************
//
#define ASCEDISPLAY 1
typedef struct tagASCEREC //将用户输入的消息封装在这个结构中
{
wchar_t s1[80];
wchar_t s2[80];
DWORD n;
} ASCEREC;
COPYDATASTRUCT AsceCDS;
ASCEREC AsceRec;
HRESULT hResult;
BOOL CALLBACK InfoDlgProc( HWND, UINT, WPARAM, LPARAM );
// ************ Code fragment ****************
// Get data from user. InfoDlgProc stores the information in AsceRec.
//
DialogBox( ghInstance, TEXT("InfoDlg"), hWnd, (DLGPROC) InfoDlgProc );
//
// Copy data into structure to be passed via WM_COPYDATA.
// Also, we assume that truncation of the data is acceptable.
//
hResult = StringCbCopy(AsceRec.s1, sizeof(AsceRec.s1), szFirstName );
if (hResult != S_OK)
return False;
hResult = StringCbCopy(AsceRec.s2, sizeof(AsceRec.s2), szLastName );
if (hResult != S_OK)
return False;
AsceRec.n = nAge;
//
// Fill the COPYDATA structure
//
AsceCDS.dwData = ASCEDISPLAY; // function identifier
AsceCDS.cbData = sizeof( AsceRec ); // size of data
AsceCDS.lpData = &AsceRec; // data structure
//
// Call function, passing data in &AsceCDS
//此处假设接收进程具有一个类名为Disp32Class的标题为"Hidden Window"的窗口
hwDispatch = FindWindow( TEXT("Disp32Class"), TEXT("Hidden Window"));
if( hwDispatch != NULL )
SendMessage( hwDispatch, //接收消息的窗口的句柄
WM_COPYDATA, //要发送的消息
(WPARAM)(HWND) hWnd, //发送或传递这个消息的窗口
(LPARAM) (LPVOID) &AsceCDS ); //指向包含要发送的数据的
//COPYDATASTRUCT结构的指针
else
MessageBox( hWnd, TEXT("Can't send WM_COPYDATA"), TEXT("ASCEApp"), MB_OK );
数据接收端代码片段:
// ************ Globals ************
//
#define ASCEDISPLAY 1
typedef struct tagASCEREC
{
wchar_t s1[80];
wchar_t s2[80];
DWORD n;
} ASCEREC;
PCOPYDATASTRUCT pAsceCDS;
void WINAPI AsceDisplay( LPTSTR, LPTSTR, DWORD );
//
// ************ Code fragment ****************
//
case WM_COPYDATA:
pAsceCDS = (PCOPYDATASTRUCT) lParam;
switch( pAsceCDS->dwData )
{
case ASCEDISPLAY:
AsceDisplay( (LPTSTR) ((ASCEREC *)(pAsceCDS->lpData))->s1,
(LPTSTR) ((ASCEREC *)(pAsceCDS->lpData))->s2,
(DWORD) ((ASCEREC *)(pAsceCDS->lpData))->n );
}
break;
WM_COPYDATA消息的不足之处:
1)必须要有一个窗体来接收消息和数据(缺乏灵活性),数据在使用之前先得拷贝到一个映射文件(浪费资源);
2)只能是本机内的进程间通信;
3)必须让两个进程在启动后,相互知道主窗口的HWND(至少一方);
4)使用WM_COPYDATA消息时,只能用SendMessage()函数发送而不能使用PostMessage(),而这两个函数的区别是SendMessage()发出消息后不是立即返回,而是在接收方的消息响应函数处理完之后才返回,并能够得到返回结果,在此期间发送方程序将被阻塞,即SendMessage()函数后面的语句不能被继续执行;而PostMessage()函数在发出消息后将立即返回,且无法获得消息的执行结果。
由此可见,在交换数据量较大的情况下实现数据频繁而快速地交换时,使用WM_COPYDATA消息的方法不合适,因为当数据传输过于频繁时,容易导致数据的丢失。