zoukankan      html  css  js  c++  java
  • 关于C#中实现两个应用程序消息通讯的问题

    最近项目中需要在两个应用程序之间通讯,这里的两个程序是在一台机器上,看了csdn上的一篇文章《如何在C#用WM_COPYDATA消息来实现两个进程之间传递数据》,原理是讲清楚了,但使起来很不爽,决定自己封装一下,满足项目需要就行。

    注意这里发送消息的函数:

    public static void SendMessage(string destProcessName, int msgID, string strMsg);

    只能发送一个msgID和一个strMsg, 接收方只接收了strMsg,我的项目中已经够用了,你如果需要读msgID,还需要改一下。客户端代码请参考csdn上的原文自己写吧。

    进程之间通讯的几种方法: 

    在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事件中处理这条消息。由于中文编码是两个字节, 所以传递中文时候字节长度要搞清楚。

    接收方

    protected override void DefWndProc(ref  System.Windows.Forms.Message m)
    {
        switch (m.Msg)
        {
        case WinMessageUtil.WM_COPYDATA:
            string str = WinMessageUtil.ReceiveMessage(ref m);
            break;
        default:
            break;
        }
        base.DefWndProc(ref  m);
    }

    操作为

    using System;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    namespace Speeding.Util
    {
        //WM_COPYDATA消息所要求的数据结构
        public struct CopyDataStruct
        {
            public IntPtr dwData;
            public int cbData;
    
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }
    
        /// <summary>
        /// 本类封装了一些进程间通讯的细节
        /// </summary>
        public class WinMessageUtil
        {
            public const int WM_COPYDATA = 0x004A;
    
            //通过窗口的标题来查找窗口的句柄
            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            private static extern int FindWindow(string lpClassName, string lpWindowName);
    
            //在DLL库中的发送消息函数
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            private static extern int SendMessage
                (
                int hWnd,                        // 目标窗口的句柄  
                int Msg,                        // 在这里是WM_COPYDATA
                int wParam,                    // 第一个消息参数
                ref  CopyDataStruct lParam        // 第二个消息参数
                );
    
            /// <summary>
            /// 发送消息,只能传递一个自定义的消息ID和消息字符串,想传一个结构,但没成功
            /// </summary>
            /// <param name="destProcessName">目标进程名称,如果有多个,则给每个都发送</param>
            /// <param name="msgID">自定义数据,可以通过这个来决定如何解析下面的strMsg</param>
            /// <param name="strMsg">传递的消息,是一个字符串</param>
            public static void SendMessage(string destProcessName, int msgID, string strMsg)
            {
                if (strMsg == null)
                    return;
    
                //按进程名称查找,同名称的进程可能有许多,所以返回的是一个数组
                Process[] foundProcess = Process.GetProcessesByName(destProcessName);
                foreach (Process p in foundProcess)
                {
                    int toWindowHandler = p.MainWindowHandle.ToInt32();
                    if (toWindowHandler != 0)
                    {
                        CopyDataStruct cds;
                        cds.dwData = (IntPtr) msgID;   //这里可以传入一些自定义的数据,但只能是4字节整数      
                        cds.lpData = strMsg;            //消息字符串
                        cds.cbData = System.Text.Encoding.Default.GetBytes(strMsg).Length + 1;  //注意,这里的长度是按字节来算的
    
                        //发送方的窗口的句柄, 由于本系统中的接收方不关心是该消息是从哪个窗口发出的,所以就直接填0了
                        int fromWindowHandler = 0;
                        SendMessage(toWindowHandler, WM_COPYDATA, fromWindowHandler, ref  cds);
                    }
                }
            }
    
            /// <summary>
            /// 接收消息,得到消息字符串
            /// </summary>
            /// <param name="m">System.Windows.Forms.Message m</param>
            /// <returns>接收到的消息字符串</returns>
            public static string ReceiveMessage(ref  System.Windows.Forms.Message m)
            {
                CopyDataStruct cds = (CopyDataStruct) m.GetLParam(typeof(CopyDataStruct));
                return cds.lpData;
            }
        }
    }
  • 相关阅读:
    【翻译】Longest Palindromic Substring 最长回文子串
    java三大框架学习总结(1)
    select XXX into 和 Insert into XXX select
    在WinForm编程中犯的一些错误
    自定义类型数组排序的两种实现方式
    C# 释放非托管资源
    在已创建的DataTable对象中添加在首列一列
    WinForm编程时窗体设计器中ComboBox控件大小的设置
    php处理序列化jQuery serializeArray数据
    谈谈对程序员的培养
  • 原文地址:https://www.cnblogs.com/DoNetCShap/p/2564460.html
Copyright © 2011-2022 走看看