进程间通信,通过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. git gui 还原部分提交文件

    有时候用git提交文件的时候会一起提交了多个文件,但是突然后悔了,想把其中一个文件撤销提交,其他文件不做修改.这个时候该怎么办呢? 我觉得有很多办法,比如可以先checkout到上次的提交,然后复制要 ...

  2. 使用 Weinre 调试移动网站及 PhoneGap 应用

    在 PC 端,我们可以使用 Firebug 或者 Chrome 开发人员工具方便的调试网站或者 Web 应用.但是,当我们想在移动端调试站点或者应用的时候,这些工具就派不上用场了.因此,移动开发人员都 ...

  3. shell 计算2

    转载 http://www.th7.cn/system/lin/201309/44683.shtml expr bc 在Linux下做算术运算时你是如何进行的呢?是不是还在用expr呢?你会说我还会b ...

  4. iOS中如何监测来电

    http://blog.csdn.net/liujinlongxa/article/details/44207587

  5. 记录下WIN下配置LINUX虚拟机及PYTHON环境

    因为听说服务器端大多都是LINUX/UNIX,LINUX是程序员必须适应的编程环境,所以今天折腾了一下,给笔记本装了个LINUX虚拟机,并顺便给WINDOWS和LINUX都配置了PYTHON环境. 这 ...

  6. Google的Protobuf协议分析

    protobuf和thrift类似,也是一个序列化的协议实现,简称PB(下文出现的PB代表protobuf). Github:https://github.com/google/protobuf 上图 ...

  7. (转)winform(C#)里几种弹出对话框

    //消息框中需要显示哪些按钮,此处显示“确定”和“取消” MessageBoxButtons messButton = MessageBoxButtons.OKCancel; //"确定要退 ...

  8. 数据库阿里连接池 druid配置详解

    http://blog.csdn.net/hj7jay/article/details/51686418 http://lj6684.iteye.com/blog/1770093 http://www ...

  9. JS验证只能输入数字,数字和字母等的正则表达式

    JS判断只能是数字和小数点 0.不能输入中文1)<input onpaste="return false;" type="text" name=" ...

  10. 参数名ASCII码从小到大排序(字典序)

    /// <summary> /// Hashtable字典排序 /// </summary> /// <param name="parameters" ...