进程间通讯-发送消息

一、发送方

User32.dll中提供了发送消息的系统API。

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(
            IntPtr hWnd, //目标窗体句柄
            int Msg, //WM_COPYDATA
            int wParam, //自定义数值
            ref CopyDataStruct lParam//传递消息的结构体
            );

 调用此函数可以实现进程间的通讯,但是这种方式的实现需要有一定条件的。分析函数参数可以发现,第一个参数需要传递目标窗体句柄,所以消息接收方必须是一个窗体,这样才可以有一个能被获取到的句柄。

下面进行参数分析。

(1)IntPtr hwnd  目标窗体句柄,即接收方的窗体句柄

句柄:整个Windows编程的基础。一个句柄是指使用的一个唯一的整数值,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类中的不同的实例诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。应用程序能够通过句柄访问相应的对象的信息,但是句柄不是指针,程序不能利用句柄来直接阅读文件中的信息。如果句柄不在I/O文件中,它是毫无用处的。 句柄是Windows用来标志应用程序中建立的或是使用的唯一整数,Windows大量使用了句柄来标识对象。

User32.dll中提供了查找窗体并获取句柄的系统API。

        /// <summary>
        /// Find Window by Name
        /// </summary>
        /// <param name="lpClassName">指向一个以null结尾的字符串,指定了窗口类(一个WNDCLASS结构)的名字。如果lpszClassName为NULL,则所有的类名都匹配。</param>
        /// <param name="lpWindowName">指向一个以null结尾的字符串,指定了窗口的名字(窗口的标题)。如果lpWindowName为NULL,所有的窗口名都匹配。</param>
        /// <returns></returns>
        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

 具体用法如下

 (2)WM_COPYDATA

消息传递时区别传递消息的类型,不同的消息类型会有不同的处理方式,常见的类型如下

        #region 定义常量消息值
        public const int WM_GETTEXT = 0x0D;
        public const int WM_SETTEXT = 0x0C;
        public const int WM_SIZEING = 0x0214;
        public const int WM_COPYDATA = 0x004A;
        public const int WM_LBUTTONDBLCLK = 0x0203;
        #endregion

 这里我们只需将WM_COPYDATA传递给形参即可。

(3)wParam自定义数值:相同的参数类型下可以根据此数值做进一步区分。

我们定义了两种消息类型,命令Command和消息Message,在发送消息时将对应消息类型传递到形参中,接收端可根据此参数的不同做处理(可见第二部分):

        #region 自定义消息
        public const int WM_MESSAGE = 0x0001;
        public const int WM_COMMAND = 0x0002;
        #endregion

(4)CopyDataStruct lParam 传递消息的结构体

此结构体的定义如下

        [StructLayout(LayoutKind.Sequential)]
        public struct CopyDataStruct
        {
            public IntPtr dwData;//用户定义的数据
            public int cbData;//字符串长度
            [MarshalAs(UnmanagedType.LPTStr)]
            public string lpData;//字符串
        }

 在封装消息时,需要将消息组装到结构体中,然后将对应参数传递到函数形参中。

        public static int SendMessage(string message, int wmtype, IntPtr hWnd)
        {
            CopyDataStruct data;
            data.dwData = (IntPtr)wmtype;
            data.lpData = message;
            data.cbData = Encoding.UTF8.GetBytes(message).Length + 1;
            return SendMessage(hWnd, WM_COPYDATA, 0, ref data);
        }

 

二、接收方

由一可知,此时接收方是一个窗体,这里我们只讨论WPF窗体。winform更加简单,直接重写重写winform的消息处理方法WndProc即可。

而对WPF,没有这个消息处理方法,因此要利用HwndSource来接收并处理消息。

 实现如下

        /// <summary>
        /// 重写资源初始化函数,增加HwndSource消息处理
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
            if (hwndSource != null)
            {
                hwndSource.AddHook(new HwndSourceHook(WndProc));
            }
        }

        /// <summary>
        /// 消息处理函数
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="msg"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <param name="handled"></param>
        /// <returns></returns>
        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_COPYDATA)
            {
                CopyDataStruct cds = (CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(CopyDataStruct));//从发送方接收到的数据结构
                string param = cds.lpData;//获取发送方传过来的消息
                switch ((int)cds.dwData)
                {
                    case WM_COMMAND:
                        receive.Text = receive.Text + "\n" + "command:" + param; break;
                    case WM_MESSAGE:
                        receive.Text = receive.Text + "\n" + "message:" + param; break;
                }
            }
            return hwnd;
        }
posted on 2021-07-21 16:41  freden  阅读(279)  评论(0编辑  收藏  举报