进程间通信,通过SendMessage向另一进程发送WM_COPYDATA消息,实现不同进程间的消息通信。
需求:已写好一个工具软件,想在不更改当前的软件开发的前提下,实现为后面新开发的软件提供数据推送任务。原先想到使用,WCF以实现通信级别的调用,但对于后续新开发的软件来说,所需实现的东西太多(相当于需要实现一个既定接口的服务端)。所以选择使用SendMessage,发送一个WM_COPYDATA以实现对新软件的通知任务。其中主要是需要对传输一个对象级的处理,需要进行序列化及反序列货处理,这是比较重要的一点。其他方面都比较简单,只是单独发一条WM_COPYDATA消息。

一、找到新软件需被通知的窗口(一般是以配置的形式实现)

  而在原有软件(即主消息推送方)通过既定的扩展软件名称通过:FindWindow函数进行查找对象句柄,以待后续发送消息。

二、发送消息

  需要创建WM_COPYDATA消息所需的传参结构,默认情况下可以传递字符串,所以如只单独传输字符串,那就没什么问题的,直接简单调用即可。但在此,需要传输的为对象,所以,需要将对象先进行一系列处理,以便格式化为字符串进行传输。在接收方再以逆运算得出传输过来的对象。

三、将对象序列化为字符串及反序列化的操作,通过一个帮助类实现

Demo代码:

传输类:
 using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace Dralee.AppTransferMsg.Common
{
[Serializable]
public class Msg
{
public string SentBy { get; set; }
public string RcvBy { get; set; }
public string Message { get; set; }
public DateTime SentOn { get; set; }
public Msg()
{
}
public Msg(string sentBy, string rcvBy, string msg, DateTime sentOn)
{
SentBy = sentBy;
RcvBy = rcvBy;
Message = msg;
SentOn = sentOn;
}
public static byte[] Serialize(Msg msg)
{
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, msg);
byte[] buffer = ms.GetBuffer();
ms.Close();
return buffer;
//return Encoding.Unicode.GetString(buffer);
}
public static Msg Deserialize(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer);
BinaryFormatter bf = new BinaryFormatter();
Msg msg = (Msg)bf.Deserialize(ms);
return msg;
}
}
/// <summary>
/// 传输结构
/// </summary>
public struct CopyDataStruct
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
}

转换帮助类:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dralee.AppTransferMsg.Common
{
// CreatedBy: Jackie Lee
// CreatedOn: 2016-08-17
/// <summary>
/// 字节数组与字符串互转
/// </summary>
public class HexConverter
{
/// <summary>
/// 字节数组转
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public string ByteToString(byte[] buffer)
{
StringBuilder sb = new StringBuilder();
for(int i = ; i < buffer.Length; ++i)
{
sb.AppendFormat("{0:X2}", buffer[i]);
}
return sb.ToString();
}
/// <summary>
/// 字符串转字节数组
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public byte[] StringToByte(string str)
{
if(string.IsNullOrEmpty(str) || str.Length % != )
{
return null;
}
byte[] buffer = new byte[str.Length / ];
string hex;
int j = ;
for(int i = ; i < buffer.Length;++i)
{
hex = new string(new char[] { str[j], str[j + ]});
buffer[i] = HexToByte(hex);
j += ;
}
return buffer;
}
/// <summary>
/// 双字节字符转byte
/// </summary>
/// <param name="hex"></param>
/// <returns></returns>
public byte HexToByte(string hex)
{
if (hex.Length > )
return ;
char[] hexs = hex.ToArray();
if(hexs.Length == )
{
return (byte)NumByChar(hexs[]);
}
else
{
return (byte)(NumByChar(hexs[]) * + NumByChar(hexs[]));
}
}
private byte NumByChar(char ch)
{
switch(ch)
{
case '': return ;
case '': return ;
case '': return ;
case '': return ;
case '': return ;
case '': return ;
case '': return ;
case '': return ;
case '': return ;
case '': return ;
case 'A': return ;
case 'B': return ;
case 'C': return ;
case 'D': return ;
case 'E': return ;
case 'F': return ;
default:
return ;
}
}
}
}

API类:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Dralee.AppTransferMsg.Common
{
public static class API
{
public const int WM_COPYDATA = 0x004A;
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// 发送消息
/// </summary>
/// <param name="hwnd">目标句柄</param>
/// <param name="msg"></param>
/// <param name="wParam">参数1</param>
/// <param name="lParam">参数2</param>
/// <returns></returns>
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(int hwnd, int msg, int wParam, ref CopyDataStruct lParam);
}
}

发送端:

 private void btnSend_Click(object sender, EventArgs e)
{
Msg msg = new Msg { SentBy = txtSentBy.Text.Trim(), RcvBy = txtRcvBy.Text.Trim(), Message = txtMsg.Text.Trim(), SentOn = DateTime.Parse(txtSentOn.Text) };
//long size = GC.GetTotalMemory(true);
int hwnd = API.FindWindow(null, "(测试)->接收者");
if (hwnd == )
return;
string msgStr = new HexConverter().ByteToString(Msg.Serialize(msg));
CopyDataStruct cds;
cds.dwData = (IntPtr);
cds.cbData = (int)msgStr.Length + ;
cds.lpData = msgStr; API.SendMessage(hwnd, API.WM_COPYDATA, ,ref cds);
}

接收端,通过重写以实现对消息监控:

 protected override void DefWndProc(ref Message m)
{
switch(m.Msg)
{
case API.WM_COPYDATA:
CopyDataStruct cds = (CopyDataStruct)m.GetLParam(typeof(CopyDataStruct));
//Msg msg = (Msg)m.GetLParam(typeof(Msg));
byte[] buffer = new HexConverter().StringToByte(cds.lpData);
Msg msg = Msg.Deserialize(buffer);
txtMsg.Text = msg.Message;
txtRcvBy.Text = msg.RcvBy;
txtSentBy.Text = msg.SentBy;
txtSentOn.Text = msg.SentOn.ToLongDateString();
break;
default:
base.DefWndProc(ref m);
break;
}
}

效果:

WM_COPYDATA实现的不同进程间通信的更多相关文章

  1. WM_COPYDATA+BHO+Qt实现进程间通信

    最近项目有一个需求:点击网页上某个按钮,通知Qt客户端.网页相关操作使用了BHO,BHO与Qt通信通过WB_COPYDATA,为什么这么麻烦呢,因为项目正好用到了BHO,可能还有其他方式,能直接通过网 ...

  2. WM_COPYDATA进程间通信方案

    连续在两个公司使用WM_COPYDATA实现进程间通信了,整理一下 具体步骤: 一.   进程A通过ShellExecute启动进程B, 将用于通信的窗口句柄hWndA(已强转为int值)通过命令行参 ...

  3. 【IPC进程间通信之四】数据复制消息WM_COPYDATA

    IPC进程间通信+数据复制消息WM_COPYDATA                IPC(Inter-Process Communication,进程间通信).         数据复制消息WM_C ...

  4. 利用WM_COPYDATA消息实现进程间通信

    进程间通信最简单的方式就是发送WM_COPYDATA消息,下面通过例子来实现. 发送WM_COPYDATA消息: SendMessage(hRecvWnd, WM_COPYDATA, (WPARAM) ...

  5. 进程间通信之WM_COPYDATA方式反思,回顾和总结

    许多Windows程序开发者喜欢使用WM_COPYDATA来实现一些进程间的简单通信(笔者也正在学习共享内存的一些知识来实现一些更高级的通信),这篇文章描述了笔者在使用这项技术时候的一些总结以及所遇到 ...

  6. 进程间通信的WM_COPYDATA的使用

    http://blog.csdn.net/ao929929fei/article/details/6316174 接收数据的一方 ON_WM_COPYDATA() afx_msg BOOL OnCop ...

  7. 利用WM_COPYDATA进行进程间通信

    发信消息 void CControlDlg::OnBnClickedButtonSend() { // TODO: 在此添加控件通知处理程序代码 CString strWindowTitle = _T ...

  8. CE 进程间通信

    WINCE下进程间通信常用的方式有:剪贴板(Clipboard),网络套接字(Socket),WM_COPYDATA消息,共享内存,管道(消息队列),注册表等 剪贴板 //////////////// ...

  9. [转]Windows进程间通信的各种方法

    http://www.cnblogs.com/songQQ/archive/2009/06/03/1495764.html 道相似,不过它传输数据是通过不可靠的数据报(如TCP/IP协议中的UDP包) ...

随机推荐

  1. PowerShell Notes

    1.  概要 - PowerShell 是cmdlet(command-let)的指令集合,类似unix的bash. - IDE: Windows PowerShell ISE,不区分大小写,可以用命 ...

  2. XSS的防御

    基于代码修改的防御 和SQL注入防御一样,XSS攻击也是利用了Web页面的编写疏忽,所以还有一种方法就是从Web应用开发的角度来避免: 步骤1.对所有用户提交内容进行可靠的输入验证,包括对URL.查询 ...

  3. 解决自定义leftBarButtonItem返回手势失效的方法

    考虑到interactivePopGestureRecognizer也有delegate属性,替换默认的self.navigationController.interactivePopGestureR ...

  4. 室内定位系列(三)——位置指纹法的实现(KNN)

    位置指纹法中最常用的算法是k最近邻(kNN):选取与当前RSS最邻近的k个指纹的位置估计当前位置,简单直观有效.本文介绍kNN用于定位的基本原理与具体实现(matlab.python). 基本原理 位 ...

  5. 吐槽贴:百度地图 api 封装 的实用功能 [源码下载]

    ZMap 类 功能介绍 ZMap 是学习百度地图 api 接口,开发基本功能后整的一个脚本类,本类方法功能大多使用 prototype 原型 实现: 包含的功能有:轨迹回放,圈画区域可编辑,判断几个坐 ...

  6. 利用beans.xml进行简单的Spring应用上下文创建与使用

    继上次配置Spring完成后,我们来创建一个简单的例程来理解Spring中利用beans.xml创建应用上下文的方法. 程序路径包为:com.spring.kinghts(kinght单词拼写错误,怕 ...

  7. Hibernate简易原生DAO的实现

    写在最前: 初学Hibernate,在尝试把JDBC项目移植到Hibernate的过程中,碰到了不少的麻烦,最让人心烦意乱的自然是SQL语句改动造成的代码混乱.其实不难,网上的解决方案有很多, 不过. ...

  8. secureCRT The remote system refused the connection.

    转 http://blog.csdn.net/lifengxun20121019/article/details/13627757 我在实践远程登录工具SecureCRT的时候遇到了这个问题 Ubun ...

  9. 耿丹CS16-2班第七次作业汇总

    Deadline: 2016-11-27 11:59pm 作业内容 第七次作业总结 01.每次成绩发布,麻烦没交作业的同学(暂定得分为-5的),请及时补交: 02.想不出来可以,代码乱成一团不行,命名 ...

  10. mysql的enum和set数据类型

    定义一个ENUM或者SET类型,可以约束存入的数值. ENUM中的值必须是定义过数值列中的一个,比如ENUM('a','b','c'),存入的只能是'a'或者'b'或者'c',如果存入'','d'或者 ...