博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

C# 嵌入第三方EXE界面到panel中,并相互通讯

Posted on 2019-11-07 11:59  PHP-张工  阅读(3787)  评论(0编辑  收藏  举报

C#可以通过windows API,将第三方程序嵌入到panel中,并且可以隐藏程序边框。
问题:
焦点在内部程序时,主窗口失去焦点;

通讯解决方案

使用 User32.dll SendMessage 发送窗口级的 WM_COPYDATA 消息;使用 DefWndProc 处理消息;
来实现两个独立C#程序之间的通讯。

主程序代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace CallMain
{
    public partial class Form1 : Form
    {
        #region 外部DLL定义

        [DllImport("User32.dll", EntryPoint = "SetParent")]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", EntryPoint = "ShowWindow")]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);

        [DllImport("user32.dll")]
        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
        [DllImport("user32.dll")]
        public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        const int WS_THICKFRAME = 262144;
        const int WS_BORDER = 8388608;
        const int GWL_STYLE = -16;

        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref COPYDATASTRUCT IParam);

        public const int WM_COPYDATA = 0x004A;

        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }

        // 发送 windows 消息
        public void SendMsg(IntPtr hwnd, string str)
        {
            byte[] arr = Encoding.Default.GetBytes(str);
            int len = arr.Length;
            COPYDATASTRUCT cdata;
            cdata.dwData = (IntPtr)100;
            cdata.lpData = str;
            cdata.cbData = len + 1;
            SendMessage(hwnd, WM_COPYDATA, this.Handle, ref cdata);
        }

        public delegate void EventMsg(object sender, IntPtr wnd, string str);
        public event EventMsg OnMsg;

        // 进程间消息通讯
        protected override void DefWndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_COPYDATA:
                    COPYDATASTRUCT cdata = new COPYDATASTRUCT();
                    Type mytype = cdata.GetType();
                    cdata = (COPYDATASTRUCT)m.GetLParam(mytype);
                    OnMsg(this, m.WParam, cdata.lpData);
                    break;
                default:
                    base.DefWndProc(ref m);
                    break;
            }
        }

        #endregion

        public Form1()
        {
            InitializeComponent();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            this.OnMsg += Form1_OnMsg; ;
        }

        private void Form1_OnMsg(object sender, IntPtr wnd, string str)
        {
            // 接收消息处理
            SendMsg(wnd, "收到了子窗口消息:" + str);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Process proApp = new Process();
            proApp.StartInfo.FileName = Application.StartupPath + "\\CallTest.exe";
            proApp.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
            proApp.Start();
            proApp.WaitForInputIdle();

            while (proApp.MainWindowHandle == IntPtr.Zero)
            {
                Thread.Sleep(100);
                proApp.Refresh();
            }
            IntPtr wnd = proApp.MainWindowHandle;

            Int32 wndStyle = GetWindowLong(wnd, GWL_STYLE);
            wndStyle &= ~WS_BORDER;
            wndStyle &= ~WS_THICKFRAME;
            SetWindowLong(wnd, GWL_STYLE, wndStyle);

            SetParent(wnd, panel1.Handle);
            ShowWindow(wnd, (int)ProcessWindowStyle.Maximized);

            panel1.Tag = proApp;

            SendMsg(wnd, "hi");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // 给子窗口发消息
            Process proApp = (Process)panel1.Tag;
            SendMsg(proApp.MainWindowHandle, "hello 子窗口");
        }
    }
}

子程序通讯代码

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

namespace CallTest
{
    public partial class Form1 : Form
    {
        #region 消息通讯

        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref COPYDATASTRUCT IParam);

        const int WM_COPYDATA = 0x004A;

        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }

        private IntPtr MainWnd = IntPtr.Zero;

        public delegate void EventMsg(object sender, string str);
        public event EventMsg OnMsg;

        //发送消息
        private void SendMsg(string str)
        {
            if (MainWnd == IntPtr.Zero)
            {
                return;
            }

            byte[] arr = Encoding.Default.GetBytes(str);
            int len = arr.Length;
            COPYDATASTRUCT cdata;
            cdata.dwData = (IntPtr)100;
            cdata.lpData = str;
            cdata.cbData = len + 1;
            SendMessage(MainWnd, WM_COPYDATA, this.Handle, ref cdata);
        }

        protected override void DefWndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_COPYDATA:
                    COPYDATASTRUCT cdata = new COPYDATASTRUCT();
                    Type mytype = cdata.GetType();
                    cdata = (COPYDATASTRUCT)m.GetLParam(mytype);
                    MainWnd = m.WParam;

                    OnMsg(this, cdata.lpData);
                    break;
                default:
                    base.DefWndProc(ref m);
                    break;
            }
        }
        #endregion

        public Form1()
        {
            InitializeComponent();
        }

        private int index = 0;
        private void button1_Click(object sender, EventArgs e)
        {
            // 发送消息
            index++;
            SendMsg("收到啦!" + index);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.OnMsg += Form1_OnMsg;
        }

        private void Form1_OnMsg(object sender, string str)
        {
            // 接收消息
            if (str == "hi")
            {
                SendMsg("hi");
                return;
            }

            label1.Text = str;
            label2.Text = MainWnd.ToString("x");
        }
    }
}