文着重讲述了如果用WM_COPYDATA消息来实现两个进程之间传递数据.

进程之间通讯的几种方法:
在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。常用的方法有

  1、使用内存映射文件 
  2、通过共享内存DLL共享内存 
  3、使用SendMessage向另一进程发送WM_COPYDATA消息

比起前两种的复杂实现来,WM_COPYDATA消息无疑是一种经济实惠的一中方法.
WM_COPYDATA消息的主要目的是允许在进程间传递只读数据。Windows在通过WM_COPYDATA消息传递期间,不提供继承同步方式。SDK文档推荐用户使用SendMessage函数,接受方在数
据拷贝完成前不返回,这样发送方就不可能删除和修改数据:
这个函数的原型及其要用到的结构如下:
SendMessage(hwnd,WM_COPYDATA,wParam,lParam); 
其中,WM_COPYDATA对应的十六进制数为0x004A
wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构: 
typedef struct tagCOPYDATASTRUCT{ 
    DWORD dwData;//用户定义数据 
    DWORD cbData;//数据大小 
    PVOID lpData;//指向数据的指针 
}COPYDATASTRUCT; 
该结构用来定义用户数据。
具体过程如下:
首先,在发送方,用FindWindow找到接受方的句柄,然后向接受方发送WM_COPYDATA消息.
接受方在DefWndProc事件中,来处理这条消息.由于中文编码是两个字节,所以传递中文时候字节长度要搞清楚.
代码中有适量的解释,大家请自己看吧.
用WM_COPYDATA的前提:

1,知道接收消息进程的句柄。

2,接收消息进程重载了WM_COPYDATA消息映射,能对其做出反应(否则不是发送端自作多情了?)

看过前提,的出结论:在自己写的两个进程间用WM_COPYDATA再好不过。

下面CODE几行就说明了一切。

获得句柄的方法,最简单的方法就是使用FindWindow,找窗口类,或者名,如果你觉得这样不把握,那就利用SetProp个窗口做个记号....(不说这些,跑踢儿了都)

OK,开始写发送端代码:

HWND hWnd = FindWindow(NULL,"MyApp");

if(hWnd!=NULL)
{
      COPYDATASTRUCT cpd; /*给COPYDATASTRUCT结构赋值*/
      cpd.dwData = 0;
      cpd.cbData = strlen("字符串");
      cpd.lpData = (void*)"字符串";
      ::SendMessage(hWnd,WM_COPYDATA,NULL,(LPARAM)&cpd);//发送!
      /*完事儿了!!*/
}

接收端重载ON_WM_COPYDATA消息映射函数(下面是手工所要加的,你最好还是用ClassWizard)

afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);
ON_WM_COPYDATA()/*消息映射*/
BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 
{
        AfxMessageBox((LPCSTR)(pCopyDataStruct->lpData));/*利用对话框表示收到消息*/
        return CWnd::OnCopyData(pWnd, pCopyDataStruct);
}

进程通信还有其他一些手段,相对来说比较麻烦,但局限性要比WM_COPYDATA小。当然你也可以两端都注册一个消息来通信。
使用WM_COPYDATA进行进程间通信的一个问题
开发中有时需要进程间传递数据,比如对于只允许单实例运行的程序,当已有实例运行时,再次打开程序,可能需要向当前运行的实例传递信息进行特殊处理。对于传递少量数据

的情况,最简单的就是用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结构的指针为空的话,流程是无法进行的,所以接收方也

理所当然收不到消息。
  进程间通信的方法有多种,其中,对于少量数据可以用WM_COPYDATA方便的实现通信(如果对于大量数据的话,由于SendMessage是阻塞的,只有接收方响应了消息,SendMessage才
能返回,否则则一直阻塞,所以,对于大量数据来说,用SendMessage就容易造成窗口假死) 。

MSDN帮助里面有该消息的例子,说的也很清楚。

用WM_COPYDATA消息来实现两个进程之间传递数据的更多相关文章

  1. 使用RandomAccessFile在两个java进程之间传递数据

    大部分情况下,我们面对在两个java进程只见传递数据的问题时,第一个想到的就是开server,然后通过socket收发消息.这方面有大量的框架可用,就不细说了.但如果两个进程是在一台机器上,那么还可以 ...

  2. 两个activity之间传递数据用startActivityForResult方法。

    package com.example.testactivityresquest; import android.app.Activity; import android.content.Intent ...

  3. WinForm 中两个窗口之间传递数据

    方法有很多种,这里介绍项目中使用的两种 一.通过委托+事件的方法进行传值 (点击Form2中的button1按钮,将会把Form2中的textbox.text 传给Form1中的 lable.text ...

  4. 两个Fragment之间传递数据

    1.第一个Fragment BlankFragment blankFragment = new BlankFragment();Bundle bundle = new Bundle();bundle. ...

  5. python进程之间修改数据[Manager]与进程池[Pool]

    #前面的队列Queue和管道Pipe都是仅仅能再进程之间传递数据,但是不能修改数据,今天我们学习的东西就可以在进程之间同时修改一份数据 #Mnager就可以实现 import multiprocess ...

  6. C#中使用SendMessage在进程间传递数据的实例

    原文:C#中使用SendMessage在进程间传递数据的实例 1 新建解决方案SendMessageExample 在解决方案下面新建三个项目:CopyDataStruct,Receiver和Send ...

  7. VC++共享数据段实现进程之间共享数据

    当我写了一个程序,我希望当这个程序同时运行两遍的时候,两个进程之间能共享一些全局变量,怎么办呢?很简单,使用VC\VC++的共享数据段.; #pragma data_seg()//恢复到正常段继续编程 ...

  8. Python 进程之间共享数据

    最近遇到多进程共享数据的问题,到网上查了有几篇博客写的蛮好的,记录下来方便以后查看. 一.Python multiprocessing 跨进程对象共享  在mp库当中,跨进程对象共享有三种方式,第一种 ...

  9. 进程队列(Queue),Pipe(管道), Manager 进行进程之间的数据传递和传输

    进程Queue,实现进程传输的队列 1.Queue from multiprocessing import Process, Queue def f(q): q.put('1') q.put('2') ...

随机推荐

  1. linux命令(38):traceroute命令

    1.命令格式: traceroute[参数][主机] 2.命令功能: traceroute指令让你追踪网络数据包的路由途径,预设数据包大小是40Bytes,用户可另行设置. 具体参数格式:tracer ...

  2. POJ-2594

    Treasure Exploration Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 7035   Accepted: 2 ...

  3. hdu 1041(递推,大数)

    Computer Transformation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/ ...

  4. SEO如何写好文章标题

    近一半网民只看标题不点内容,许多网站有个标题和内容摘要,而这个摘要基本概括了整篇新闻的大致内容,所以的互联网信息泛滥的今天,看标题看摘要成了最快阅读新闻资讯的一种有效方式. 如何写好标题?我一直愁这事 ...

  5. Linus 谈软件开发管理经验

    原文出处: linuxtoday   译文出处:CSDN // 伯乐在线转注:英文原文写于 2011 年 导读:没有人比Linus Torvalds更了解软件开发项目管理中的酸甜苦辣了.作为Linux ...

  6. hdu5731

    先求出不考虑分割线的n*m棋盘的覆盖方案数记为f[n][m] 然后枚举列分割线的状态(状压),计算此时不存在行分割线的方案数 求出这个我们就可以用容斥原理算出答案了 怎么算在列分割线确定的情况下,不存 ...

  7. 处理form表单提交后返回值的处理办法【html5】

    同事朋友ajax,最近在弄公司业务电话机,自主搭建,买的设备. 其中最主要功能是前端发起呼叫,通过浏览器触发设备进行呼叫功能,走后台呼叫还不行. 需求是这样的: 前端给设备ip发送特定的一段xml信息 ...

  8. 洛谷P1392 取数 [堆]

    题目传送门 取数 题目描述 在一个n行m列的数阵中,你须在每一行取一个数(共n个数),并将它们相加得到一个和.对于给定的数阵,请你输出和前k小的取数方法. 输入输出格式 输入格式: 第一行,三个数n, ...

  9. XJTUOJ wmq的队伍(树状数组求 K 元逆序对)

    题目链接:http://oj.xjtuacm.com/problem/14/[分析]二元的逆序对应该都会求,可以用树状数组.这个题要求K元,我们可以看成二元的.我们先从后往前求二元逆序对数, 然后对于 ...

  10. 27、Flask实战第27天:cms后台登录

    cms后台登录界面 后台登录页面,我们不用自己写,只需要去Bootstrap中文网去找一个模板改一下就行 这里使用的模板是:https://v3.bootcss.com/examples/signin ...