C# 两个exeh程序通讯(包括对象传递)

简介

在使用中发现原文章中WendMessageToTargetWindow函数(如图)
在这里插入图片描述
调用这个函数传的int类型和string 类型数据,int可以接收但是string接收到的是一个句柄值,尝试对句柄取值得到的是一个空,想到作者上面有一个函数是传string字符串,这里我就改成了传两个int类型数据类似坐标。

修改后的代码

首先是MsgHandler类(在发送端NetFramework4._0Demo项目中创建)

using System;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace NetFramework4._0Demo
{
    /// <summary>  
    /// 发送消息处理程序类
    /// 调用该方法“SendMessageToTargetWindow”发送  
    /// </summary>  
    public class MsgHandler
    {
        /// <summary>  
        /// 系统定义的消息
        /// </summary>  
        private const int WM_COPYDATA = 0x004A;


        /// <summary>  
        /// 用户己定义消息
        /// </summary>  
        private const int WM_DATA_TRANSFER = 0x0437;


        // 使用Windows API的FindWindow方法
        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        private static extern int FindWindow(string lpClassName, string lpWindowName);


        //使用Windows API的IsWindow方法
        [DllImport("User32.dll", EntryPoint = "IsWindow")]
        private static extern bool IsWindow(int hWnd);


        // 使用Windows API的SendMessage方法
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);


        // 使用Windows API的SendMessage方法
        [DllImport("User32.dll", EntryPoint = "SendMessageA")]
        private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);


        /// <summary>  
        /// 要发信息数据结构 
        /// </summary>  
        private struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;//信息的长度
            public IntPtr lpData;
        }


        /// <summary>  
        /// 向目标窗口发送消息
        /// </summary>  
        /// <param name="wndName">查找目标窗体名称</param>  
        /// <param name="msg">要发送的消息,字符串</param>  
        /// <returns>返回的数据是否成功或则失败</returns>  
        public static bool SendMessageToTargetWindow(string wndName, string msg)
        {
            int iHWnd = FindWindow(null, wndName);
            if (iHWnd == 0)
            {
                
#if DEBUG
                string strError = string.Format("SendMessageToTargetWindow: 没有发现{0}窗体!", wndName);
                MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Debug.WriteLine(strError);
#endif
                return false;
            }
            else
            {
                byte[] bytData = null;
                bytData = Encoding.Default.GetBytes(msg);
                COPYDATASTRUCT cdsBuffer;
                cdsBuffer.dwData = (IntPtr)100;
                cdsBuffer.cbData = bytData.Length;
                cdsBuffer.lpData = Marshal.AllocHGlobal(bytData.Length);
                Marshal.Copy(bytData, 0, cdsBuffer.lpData, bytData.Length);
                // 使用系统定义的消息wmcopydata来发送消息。 
                int iReturn = SendMessage(iHWnd, WM_COPYDATA, 0, ref cdsBuffer);
                if (iReturn < 0)
                {
#if DEBUG
                    string strError = string.Format("SendMessageToTargetWindow: 没有发现{0}窗体!", wndName);
                    MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Debug.WriteLine(strError);
#endif
                    return false;
                }
                return true;
            }
        }


        /// <summary>  
        /// 向目标窗口发送消息
        /// </summary>  
        /// <param name="wndName">查找目标窗体名称</param>  
        /// <param name="wParam">整型数据</param>  
        /// <param name="lParam">整型数据</param>  
        /// <returns>数据发送成或者失败</returns>  
        public static bool SendMessageToTargetWindow(string wndName, int wParam, int lParam)
        {
            int iHWnd = FindWindow(null, wndName);
            if (iHWnd == 0)
            {
#if DEBUG
                string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", wndName);
                MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Debug.WriteLine(strError);
#endif
                return false;
            }
            else
            {
                //使用定义的消息wmdatatransfer来发送消息。(测试传int数据正常接收,传string数据接收有问题)
                int iReturn = SendMessage(iHWnd, WM_DATA_TRANSFER, wParam, lParam);
                if (iReturn < 0)
                {
#if DEBUG
                    string strError = string.Format("SendMessageToTargetWindow: Send message to the target window [{0}] failed!", wndName);
                    MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Debug.WriteLine(strError);
#endif
                    return false;
                }
                return true;
            }
        }
    }
}


然后创建一个通用重写部分功能的窗体,放一些窗体通用操作(在接收端NetFramework2._0Demo项目创建)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace NetFramework2._0Demo
{
    public partial class OverrideForm : Form
    {
        public OverrideForm()
        {
            InitializeComponent();
        }

        public OverrideForm(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        #region 解决窗体加载时控件闪烁
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000;
                return cp;
            }
        }
        #endregion

        #region 程序与程序之间相互通讯(接收端)
        /// <summary>  
        ///系统定义的消息
        /// </summary>  
        private const int WM_COPYDATA = 0x004A;


        /// <summary>  
        /// 自定义的消息
        /// </summary>  
        private const int WM_DATA_TRANSFER = 0x0437;


        /// <summary>  
        /// 传输的COPYDATASTRUCT结构体
        /// </summary>  
        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            public IntPtr lpData;
        }

        /// <summary>  
        ///覆盖DefWndProc函数,以便通过它接收消息。 
        /// </summary>  
        /// <param name="m">message</param>  
        protected override void DefWndProc(ref System.Windows.Forms.Message m)
        {
            switch (m.Msg)
            {
                // 这里,我们使用wmcopydata消息来接收COPYDATASTRUCT
                case WM_COPYDATA:
                    COPYDATASTRUCT cds = new COPYDATASTRUCT();
                    cds = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
                    byte[] bytData = new byte[cds.cbData];
                    Marshal.Copy(cds.lpData, bytData, 0, bytData.Length);
                    this.ProcessIncomingData(bytData);
                    break;
                // 在这里,我们使用我们定义的消息wmdatatransfer来接收 
                // 普通数据,例如整数。
                case WM_DATA_TRANSFER:
                    int iWParam = (int)m.WParam;
                    //string sLParam = m.LParam.ToString();
                    int sLParam = ((int)m.LParam);
                    ProcessIncomingData(iWParam, sLParam);
                    break;
                default:
                    base.DefWndProc(ref m);
                    break;
            }
        }

        /// <summary>  
        /// 处理传入的数据 
        /// </summary>  
        /// <param name="data">输入数据</param>  
        private void ProcessIncomingData(byte[] bytesData)
        {
            try
            {
                string str = Encoding.Default.GetString(bytesData);//接受的值
                Console.WriteLine(str);
                #region 根据接受值做操作

                #endregion
            }
            catch (Exception)
            {
            }
            //Console.WriteLine(str);
            //lstReceivedMsg.Items.Add(strRevMsg);
        }


        /// <summary>  
        /// 处理传入的数据  
        /// </summary>  
        /// <param name="iWParam">一个整数</param>  
        /// <param name="sLParam">一个整数</param>  
        private void ProcessIncomingData(int iWParam, int sLParam)
        {
            Console.WriteLine(iWParam + "," + sLParam);
            #region 根据接受值做操作

            #endregion
        }
        #endregion

    }
}

最后在NetFramework2._0Demo项目主窗体继承通用窗体

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;

namespace NetFramework2._0Demo
{
    public partial class NetFramework : OverrideForm
    {
        public NetFramework()
        {
            InitializeComponent();
        }
    }
}

通讯效果:

NetFramework4._0Demo程序发送消息
在这里插入图片描述
NetFramework2._0Demo程序接收消息
在这里插入图片描述
看到原文章有人留言能不能互相通讯,文章中已经实现由A程序发送到B程序接收,我们按照步骤实现B程序发送到A程序接收,互相通讯就实现了(注意窗体名别搞混了)

使用中单独传字符串无法满足需求,所以弄了个List对象传输,顺便完善这篇文章。
原理:把List转成byte[]再调用SendMessageToTargetWindow进行发送。

在这里插入图片描述

		/// <summary>  
        /// 向目标窗口发送消息
        /// </summary>  
        /// <param name="wndName">查找目标窗体名称</param>  
        /// <param name="msg">要发送的对象字节流</param>  
        /// <returns>返回的数据是否成功或则失败</returns>
        public static bool SendMessageToTargetWindow(string wndName, byte[] bytData)
        {
            int iHWnd = FindWindow(null, wndName);
            if (iHWnd == 0)
            {
                return false;
            }
            else
            {
                COPYDATASTRUCT cdsBuffer;
                cdsBuffer.dwData = (IntPtr)100;
                cdsBuffer.cbData = bytData.Length;
                cdsBuffer.lpData = Marshal.AllocHGlobal(bytData.Length);
                Marshal.Copy(bytData, 0, cdsBuffer.lpData, bytData.Length);
                //使用系统定义的消息wmcopydata来发送消息。 (使用WM_DATA_TRANSFER发送,接受时会报错)
                int iReturn = SendMessage(iHWnd, WM_COPYDATA, 0, ref cdsBuffer);
                if (iReturn < 0)
                {
                    return false;
                }
                return true;
            }
        }

		//对象序列化
        public static byte[] ObjectToBytes(object obj)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj); return ms.GetBuffer();
            }
        }
        //反序列化对象
        public static object BytesToObject(byte[] Bytes)
        {
            using (MemoryStream ms = new MemoryStream(Bytes))
            {
                IFormatter formatter = new BinaryFormatter(); return formatter.Deserialize(ms);
            }
        }

接收程序只要把获取到的byte[]流反序列化成指定对象即可。
在这里插入图片描述
按这个思路我试着传了一个自定义的对象Test,在接收反序列化时报了一个未找到Test项目集的错误,盲猜是如果两个程序共用的对象应该可以传输,上面我用的int[]就验证了这点。
待序列化的自定义类前加[Serializable]不加序列化会报错,大家可以试试。
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值