开发中有时需要进程间传递数据,比如对于只允许单实例运行的程序,当已有实例运行时,再次打开程序,可能需要向当前运行的实例传递信息进行特殊处理。对于传递少量数据的情况,最简单的就是用SendMessage发送WM_COPYDATA消息,所带参数wParam和lParam可以携带相关数据。由于SendMessage是阻塞的,在接收数据进程处理完数据之前不会返回,发送方不会删除或修改数据,因此这种方法是简单且安全的,不过数据量不能太大,否则会由于处理时间过长造成阻塞假死。

用SendMessage发送WM_COPYDATA的方法如下:

      lResult = SendMessage((HWND) hWndControl,
                    (UINT) WM_COPYDATA, // message ID
                   (WPARAM) wParam, // = (WPARAM) () wParam;
                   (LPARAM) lParam // = (LPARAM) () lParam;
                  );

其中,hWndControl为接收数据方的窗口句柄,wParam为发送数据方的窗口句柄,lParam为指向一个COPYDATASTRUCT类型结构体的指针


在用MFC AppWizard(exe)创建接收数据的对话框程序后,生成对话框类CDataRecvDlg。在这个类中,首先要定义接收WM_COPYDATA消息的映射,可以用ClassWizard工具来增加,也可以手动增加,但手动增加需要修改三个地方:①在消息映射表中增加ON_WM_COPYDATA();②增加成员函数BOOL CDataRecvDlg::OnCopyData();③在CDataRecvDlg类中增加WM_COPYDATA消息映射函数的定义。

消息作用:
在进程间共享数据(内部通过创建内存映射文件) 消息介绍:
需要用到的数据结构/类型:
typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT; 结构体参数说明:
dwData(ULONG) 保存一个数值, 可以用来作标志等
lpData(void*) 待发送的数据的起始地址(可以为NULL)
cbData(DWORD) 待发送的数据的长度 消息的参数:
hWnd: 接收数据的窗口的句柄
wParam: 传送该数据的窗口句柄(NULL也无所谓)
lParam: COPYDATASTRUCT类型变量的地址 使用示例:
COPYDATASTRUCT cds;
char msg[] = "女孩不哭";
cds.dwData = ;
cds.lpData = msg;
cds.cbData = strlen(msg)+; //字符串请记得把'\0'加上, 不然就错了, 这里是ANSI字符串
SendMessage(FindWindow("nbsg_class", NULL), WM_COPYDATA, , (LPARAM)&cds); 接收端对该消息的一种可能处理:
case WM_COPYDATA:
{
//这里的消息应该是以 '\0' 结尾的字符串
COPYDATASTRUCT* pCDS = (COPYDATASTRUCT*)lParam;
MessageBox(hWnd, pCDS->lpData, "", MB_OK);
return TRUE;
} 说明:  
    发送的数据可以是任意的, 我上面只是为了用MessageBox做测试, 所以发送的是以'\0'的字符串.
    如果接收消息的应用程序处理了该消息, 它应该返回 TRUE , 否则返回 FALSE.
lpData 指向的内存应该是一段"数据", 就是说里面不应该有指向该程序某数据的指针. 因为 SendMessage 在处理 WM_COPYDATA 时, 只是把 lpData 指向的 cbData 个字节复制到共享内存中. 当前进程私有的指针就算是被发送到接收程序, 其也是无法访问的.
当该消息正当发送时, 该进程的其它线程不能修改其中的数据.
接收端应用程序应该把这段共享内存作为只读内存来访问. 请不要尝试修改其中的内容.
lParam 指向的数据只有在该消息处理时有效, 消息返回后无效(共享内存已被释放). 且接收端也不能释放该内存. 如果要在消息返回后继续取得数据, 可以把它复制到当前进程的某个位置. 另一种接收消息的相应方式:

WM_COPYDATA消息的映射如下:

BEGIN_MESSAGE_MAP(CDataRecvDlg, CDialog)

//{{AFX_MSG_MAP(CDataRecvDlg)

ON_WM_COPYDATA()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

CDataRecvDlg::OnCopyData()函数的定义如下:

BOOL CDataRecvDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)

{

m_strCopyData=(LPSTR)pCopyDataStruct->lpData;

// 获得实际长度的字符串

m_strCopyData=m_strCopyData.Left(pCopyDataStruct->cbData);

// 更新数据

UpdateData(FALSE);

return CDialog::OnCopyData(pWnd, pCopyDataStruct);

}

  其中m_strCopyData为接收到的字符串,pCopyDataStruct为COPYDATASTRUCT结构指针。注意由pCopyDataStruct直接得到的m_strCopyData字符串长度可能不是实际发送的字符串长度,需要用发送字符串时所给定的字符串长度来进一步确定,其长度由pCopyDataStruct ->cbData来得到。


   用到WM_COPYDATA进行进程间通信,但是接收方怎么也收不到消息。调试发现找到的窗口句柄是没有问题的,查看MSDN也没有什么提示,百思不得其解。后来看了一些示例代码,发现不同之处是我的SendMessage调用中wParam和lParam参数都是0,因为我只是需要通过WM_COPYDATA消息通知一下接收程序即可,不用传递任何数据。试着将这两个参数改为非空,接收方就可以收到消息了。总结结论为:wParam参数是否为0没有影响,但是lParam参数必须为非空,即必须指向一个有效的COPYDATASTRUCT结构体。

原因是什么呢?查了一些资料发现,SendMessage(WM_COPYDATA)底层是通过文件映射(File Mapping)完成的,大概流程是发送方线程根据COPYDATASTRUCT结构体中的传递数据信息,在共享内存中进行数据复制,接收方线程则会到共享内存中读取数据进行处理。因此如果指向COPYDATASTRUCT结构的指针为空的话,流程是无法进行的,所以接收方也理所当然收不到消息。

SendMessage中接收信息的窗口句柄如何获取???

使用 WM_COPYDATA 在进程间共享数据的更多相关文章

  1. python 进程间共享数据 (二)

    Python中进程间共享数据,除了基本的queue,pipe和value+array外,还提供了更高层次的封装.使用multiprocessing.Manager可以简单地使用这些高级接口. Mana ...

  2. 【转】VC 利用DLL共享区间在进程间共享数据及进程间广播消息

    1.http://blog.csdn.net/morewindows/article/details/6702342 在进程间共享数据有很多种方法,剪贴板,映射文件等都可以实现,这里介绍用DLL的共享 ...

  3. 使用DLL在进程间共享数据

    0x01 DLL在进程间共享数据理论 1.可以在Dll中使用#pragma data_seg建立共享类型的数据段将需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享,从而实现不 ...

  4. 进程间共享数据Manager

    一.前言 进程间的通信Queue()和Pipe(),可以实现进程间的数据传递.但是要使python进程间共享数据,我们就要使用multiprocessing.Manager. Manager()返回的 ...

  5. 【C++】DLL内共享数据区在进程间共享数据(重要)

    因项目需要,需要在DLL中共享数据,即DLL中某一变量只执行一次,在运行DLL中其他函数时该变量值不改变:刚开始想法理解错误,搜到了DLL进程间共享数据段,后面发现直接在DLL中定义全局变量就行,当时 ...

  6. windows核心编程之进程间共享数据

    有时候我们会遇到window进程间共享数据的需求,例如说我想知道系统当前有多少某个进程的实例. 我们能够在程序中定义一个全局变量.初始化为0.每当程序启动后就加1.当然我们我们能够借助第三方介质来储存 ...

  7. Python multiprocessing.Manager介绍和实例(进程间共享数据)

    Python中进程间共享数据,处理基本的queue,pipe和value+array外,还提供了更高层次的封装.使用multiprocessing.Manager可以简单地使用这些高级接口. Mana ...

  8. Swoole 中使用 Table 内存表实现进程间共享数据

    背景 在多进程模式下进程之间的内存是相互隔离的,在一个工作进程中的全局变量和超全局变量,在另一个工作进程中是无法读取和操作的. 如果只有一个工作进程,则不存在进程隔离问题,可以使用全局变量和超全局变量 ...

  9. python 进程间共享数据 (一)

    def worker(num, mystr, arr): num.value *= 2 mystr.value = "ok" for i in range(len(arr)): a ...

随机推荐

  1. Graph 卷积神经网络:概述、样例及最新进展

    http://www.52ml.net/20031.html [新智元导读]Graph Convolutional Network(GCN)是直接作用于图的卷积神经网络,GCN 允许对结构化数据进行端 ...

  2. 条件随机场(CRF)理论及应用

    http://x-algo.cn/index.php/2016/02/15/conditional-random-field-crf-theory-and-implementation/ 条件随机场( ...

  3. Struts2的Action继承ActionSupport时,利用AOP来拦截Action出现NoSuchMethodException

    参考:http://zhanghua.1199.blog.163.com/blog/static/46449807201111139501298/ 做项目的时候,由于要用到在Struts2的Actio ...

  4. Discuz常见小问题-_如何修改网站LOGO

    1 界面-风格管理,点击编辑 2 默认的LOGO图片叫做logo.png,存放在X:\PHPNow\htdocs\Discuz\upload\static\image\common文件夹下面,其中X是 ...

  5. 【Linux】好玩的linux命令

    Linux里面有很多有趣的东西,这篇文章整理了一些.摘录一下: 1. sl 命令 你会看到一辆火车从屏幕右边开往左边...... 安装  $ sudo apt-get install sl 运行  $ ...

  6. 很好的vmware目录

    http://www.globalknowledge.com/training/course.asp?pageid=9&courseid=18023&country=United+St ...

  7. intel vt

    EPT和VPID技术是内存虚拟化技术, 是页表扩充技术Extended Page Table (EPT) 的缩写, 是VT-x技术的一部分. 内存虚拟化的主要任务是实现地址空间的虚拟化,内存虚拟化是通 ...

  8. 004-Go iris 接收post json数据

    package main import( "github.com/kataras/iris" "github.com/kataras/iris/middleware/lo ...

  9. WebViewJavascriptBridge源代码分析

    近期抽时间看了一遍WebViewJavascriptBridge这个开源框架,把看到的内容记录下来 源代码地址:https://github.com/marcuswestin/WebViewJavas ...

  10. Linux文件权限与目录

    1:文件操作者的身份 owner:创建文件.拥有文件的登录用户. group:同一群组内的用户. others:其他登录用户. [系统账户与密码信息保存在/etc/passwd:个人账户与密码信息保存 ...