c# 通过 SendMessage 实现跨进程数据通信

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication9
{
    public partial class Form1 : Form
    {
        const string hwndMapName = "MyMediaPlayerServiceHwnd";
        const string messageResultMapName = "MyMediaPlayerServiceResult";
        const int resultBufferSize = 1 * 1024 * 1024;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 创建或打开只读的内存映射文件
            MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateOrOpen(hwndMapName, sizeof(int));
            MemoryMappedViewAccessor accessor = memoryMappedFile.CreateViewAccessor();
            int sharedInt = this.Handle.ToInt32(); // 要写入的int值
            accessor.Write(0, ref sharedInt);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            new Form2().ShowDialog();
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct COPYDATASTRUCT
        {
            public IntPtr dwData; // 用于指定消息类型
            public int cbData; // 用于指定lpData指向的缓冲区的字节数
            public IntPtr lpData; // 用于指向要发送数据的指针
        }

        private const uint WM_COPYDATA = 0x004A;

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_COPYDATA)
            {
                var resultCode = 1;
                COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
                if (cds.cbData > 0 && cds.lpData != IntPtr.Zero)
                {
                    byte[] data = new byte[cds.cbData];
                    Marshal.Copy(cds.lpData, data, 0, cds.cbData);
                    string receivedString = System.Text.Encoding.Unicode.GetString(data);
                    using (MemoryMappedFile resultMappedFile = MemoryMappedFile.OpenExisting(messageResultMapName, MemoryMappedFileRights.ReadWrite))
                    {
                        // 从内存映射文件中读取int值
                        using (MemoryMappedViewAccessor resultAccessor = resultMappedFile.CreateViewAccessor())
                        {
                            var message = "Hi Sender!";
                            var result = Encoding.UTF8.GetBytes(message);
                            if (result.Length > resultBufferSize)
                                resultCode = 0;
                            else
                                resultAccessor.WriteArray(0, result, 0, result.Length);
                        }
                    }
                }

                m.Result = new IntPtr(resultCode);
                return;
            }

            base.WndProc(ref m);
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO.MemoryMappedFiles;

namespace WindowsFormsApplication9
{
    public partial class Form2 : Form
    {
        const string hwndMapName = "MyMediaPlayerServiceHwnd";
        const string messageResultMapName = "MyMediaPlayerServiceResult";
        const int resultBufferSize = 1 * 1024 * 1024;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, ref COPYDATASTRUCT cds);

        private const uint WM_COPYDATA = 0x004A;

        [StructLayout(LayoutKind.Sequential)]
        private struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            public IntPtr lpData;
        }

        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            textBox1.Text = SendMessage("Hi, Reciever!");
        }

        private string SendMessage(string message)
        {
            // 打开只读的内存映射文件,以读取目标窗口句柄
            using (MemoryMappedFile hwndMappedFile = MemoryMappedFile.OpenExisting(hwndMapName, MemoryMappedFileRights.ReadWrite))
            {
                // 从内存映射文件中读取int值
                using (MemoryMappedViewAccessor hwndAccessor = hwndMappedFile.CreateViewAccessor())
                {
                    int sharedInt;
                    hwndAccessor.Read(0, out sharedInt);

                    var hwnd = new IntPtr(sharedInt);

                    #region 向目标窗口发送消息

                    // 将字符串转换为字节数组
                    byte[] messageBytes = System.Text.Encoding.Unicode.GetBytes(message);

                    // 分配内存并将字节数组复制到内存中
                    IntPtr messagePtr = Marshal.AllocCoTaskMem(messageBytes.Length);
                    Marshal.Copy(messageBytes, 0, messagePtr, messageBytes.Length);

                    try
                    {
                        // 构造 COPYDATASTRUCT 结构体,将字符串指针和长度传递给接收方
                        COPYDATASTRUCT cds = new COPYDATASTRUCT();
                        cds.dwData = IntPtr.Zero;
                        cds.cbData = messageBytes.Length;
                        cds.lpData = messagePtr;

                        using (MemoryMappedFile resultMappedFile = MemoryMappedFile.CreateOrOpen(messageResultMapName, resultBufferSize, MemoryMappedFileAccess.ReadWrite))
                        {
                            // 使用 SendMessage 发送自定义消息
                            var result = SendMessage(hwnd, WM_COPYDATA, IntPtr.Zero, ref cds);
                            if (result.ToInt32() != 1)
                                return null;

                            // 创建一个内存映射视图
                            using (MemoryMappedViewAccessor accessor = resultMappedFile.CreateViewAccessor(0, resultBufferSize, MemoryMappedFileAccess.ReadWrite))
                            {
                                // 创建一个字节数组来接收读取的数据
                                byte[] byteArray = new byte[resultBufferSize];

                                // 从内存映射文件中读取字节数组
                                accessor.ReadArray(0, byteArray, 0, resultBufferSize);

                                // 将字节数组转换为字符串
                                string data = Encoding.UTF8.GetString(byteArray);
                                
                                // 去除末尾的 \0 字符
                                data = data.TrimEnd('\0');

                                return data;
                            }
                        }
                    }
                    finally
                    {
                        // 释放内存
                        Marshal.FreeCoTaskMem(messagePtr);
                    }

                    #endregion
                }
            }
        }
    }
}

 注意:不同权限的进程之间发消息是有限制的

posted on 2024-05-26 18:47  空明流光  阅读(106)  评论(0编辑  收藏  举报

导航