博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用 WM_COPYDATA 在进程间共享数据
阅读量:5798 次
发布时间:2019-06-18

本文共 3218 字,大约阅读时间需要 10 分钟。

   开发中有时需要进程间传递数据,比如对于只允许单实例运行的程序,当已有实例运行时,再次打开程序,可能需要向当前运行的实例传递信息进行特殊处理。对于传递少量数据的情况,最简单的就是用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 = 0;    cds.lpData = msg;    cds.cbData = strlen(msg)+1; //字符串请记得把'\0'加上, 不然就错了, 这里是ANSI字符串    SendMessage(FindWindow("nbsg_class", NULL), WM_COPYDATA, 0, (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中接收信息的窗口句柄如何获取???

 

转载地址:http://qvifx.baihongyu.com/

你可能感兴趣的文章
oracle中以dba_、user_、v$_、all_、session_、index_开头的常...
查看>>
leetcode 116- Populating Next Right Pointers in Each Node
查看>>
spring项目启动错误——java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext...
查看>>
iOS开发网络篇—GET请求和POST请求
查看>>
字典dict
查看>>
游戏名词解释
查看>>
mongodb数据的导出和导入
查看>>
白话算法(7) 生成全排列的几种思路(二) 康托展开
查看>>
d3 v4实现饼状图,折线标注
查看>>
微软的云策略
查看>>
Valid Parentheses
查看>>
【ES6】数值的扩展
查看>>
性能测试之稳定性测试
查看>>
ES6的 Iterator 遍历器
查看>>
2019届高二(下)半期考试题(文科)
查看>>
【REDO】删除REDO LOG重做日志组后需要手工删除对应的日志文件(转)
查看>>
nginx 301跳转到带www域名方法rewrite(转)
查看>>
AIX 配置vncserver
查看>>
windows下Python 3.x图形图像处理库PIL的安装
查看>>
【IL】IL生成exe的方法
查看>>