进程间通信最简单的方式就是发送WM_COPYDATA消息。
发送WM_COPYDATA消息:
SendMessage(接收窗口句柄,WM_COPYDATA, (WPARAM)发送窗口句柄, (LPARAM)&CopyData);
其中的CopyData为COPYDATASTRUCT结构类型,该结构定义如下:
typedef struct tagCOPYDATASTRUCT {
开发中有时需要进程间传递数据,比如对于只允许单实例运行的程序,当已有实例运行时,再次打开程序,可能需要向当前运行的实例传递信息进行特殊处理。对于传递少量数据的情况,最简单的就是用SendMessage发送WM_COPYDATA消息,所带参数wParam和lParam可以携带相关数据。由于SendMessage是阻塞的,在接收数据进程处理完数据之前不会返回,发送方不会删除或修改数据,因此这种方法是简单且安全的,不过数据量不能太大,否则会由于处理时间过长造成阻塞假死。
用SendMessage发送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为发送数据方的窗口句柄,lParam为指向一个COPYDATASTRUCT类型结构体的指针,该结构体中包含了传递的数据信息。COPYDATASTRUCT定义如下:
typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
其中,dwData为自定义的数据,cbData指定lpData指向数据的大小,lpData为指向数据的指针。按照前面所说,在使用WM_COPYDATA时要保证数据的只读属性,即不能有发送方的其他线程对传递数据进行改写。(这也解释了为什么不允许用PostMessage发送WM_COPYDATA,因为PostMessage函数是异步的。还有一点需要注意的是由于SendMessage是阻塞的,所以容易引起死锁,可以考虑用SendMessageTimeout代替。)另外,如果传递数据中涉及到对象或系统资源,必须确保接收方可以对其进行处理,比如HDC、HBITMAP之类的资源是无效的,他们属于不同的进程。
在使用的时候,要用FindWindow等API找到接收方的窗口句柄;接收方的程序中要添加对WM_COPYDATA消息的响应。
前几天写程序用到WM_COPYDATA进行进程间通信,但是接收方怎么也收不到消息。调试发现找到的窗口句柄是没有问题的,查看MSDN也没有什么提示,百思不得其解。
后来看了一些示例代码,发现不同之处是我的SendMessage调用中wParam和lParam参数都是0,因为我只是需要通过WM_COPYDATA消息通知一下接收程序即可,不用传递任何数据。试着将这两个参数改为非空,接收方就可以收到消息了。总结结论为:wParam参数是否为0没有影响,但是lParam参数必须为非空,即必须指向一个有效的COPYDATASTRUCT结构体。
原因是什么呢?查了一些资料发现,SendMessage(WM_COPYDATA)底层是通过文件映射(File Mapping)完成的,大概流程是发送方线程根据COPYDATASTRUCT结构体中的传递数据信息,在共享内存中进行数据复制,接收方线程则会到共享内存中读取数据进行处理。因此如果指向COPYDATASTRUCT结构的指针为空的话,流程是无法进行的,所以接收方也理所当然收不到消息。
前面这段是转载的.自己最近再次去深究核心编程,这里给出的例子也是父进程与子进程之间进行通讯的方式:
父进程:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include "CString.h"
using namespace std;
void main()
{
STARTUPINFO si = {sizeof(STARTUPINFO)};
SECURITY_ATTRIBUTES saProcess,saThread;
PROCESS_INFORMATION poProcessChild;
DWORD dProcessID = GetCurrentProcessId();
TCHAR str[100];
wsprintf( str,TEXT("%s %ld"),TEXT("E:\\测试程序\\2012-8-5\\RecvProcess\\Debug\\RecvProcess.exe"),dProcessID );
saThread.lpSecurityDescriptor = NULL;
saThread.bInheritHandle = TRUE;
saThread.nLength = sizeof( SECURITY_ATTRIBUTES );
saProcess.lpSecurityDescriptor = NULL;
saProcess.bInheritHandle = TRUE;
saProcess.nLength = sizeof( SECURITY_ATTRIBUTES );
BOOL bCreate = CreateProcess( NULL,str,&saProcess,&saThread,TRUE,CREATE_SUSPENDED,NULL,NULL,&si,&poProcessChild );
HWND hWnd = FindWindow( NULL,TEXT("RecvProcess") );
ResumeThread( poProcessChild.hThread );
COPYDATASTRUCT cpd; /*给COPYDATASTRUCT结构赋值*/
cpd.dwData = 0;
cpd.cbData = dProcessID;
cpd.lpData = NULL;
SendMessage( hWnd,WM_COPYDATA,NULL,(LPARAM)&cpd );
Sleep( 1000 );
}
接收端:
DWORD ProcessID = pCopyDataStruct->cbData;
或者使用命令行:
CString strCommandLine = GetCommandLine();
MessageBox( strCommandLine );