1. 程式人生 > >WPF應用程式嵌入第三方exe

WPF應用程式嵌入第三方exe

思路是,

第一步:在自己的應用程式中準備顯示第三方控制元件的容器,Border,Grid什麼的都可以,下面是觸發程式碼

 private void button_Click(object sender, RoutedEventArgs e)
        {
            //載入.exe檔案
            String path = @"D:\NMS\MR\Bin\VusionDTI\MR_Diffusion.exe"; //VusionDTI  ImAgenGine_MRDP
            EmbeddedApp ea = new EmbeddedApp(WndHost, 100, 100, path, "IMAgenGINE_MRDP");
            WndHost.Child = ea;
//            System.Threading.Thread.Sleep(10000);
        }
第二步:編寫啟動第三方exe的類,主要是獲取第三方窗體的控制代碼,這裡需要一些WindowAPI,然後啟動流程就是先把第三方控制元件啟動,然後嵌入到自己的應用程式中。這樣就有一個問題,先第三方exe起來,過會再嵌入。解決思路是程式初始化的時候做這些事情
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;

namespace EmbedVusion
{
    class EmbeddedApp :  HwndHost, IKeyboardInputSink
    {
        [DllImport("user32.dll")]
        private static extern int SetParent(IntPtr hWndChild, IntPtr hWndParent);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern uint SetWindowLong(IntPtr hwnd, int nIndex, uint newLong);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern uint GetWindowLong(IntPtr hwnd, int nIndex);
        [DllImport("user32.dll")]
        private static extern int EnumWindows(CallBackPtr callPtr, ref WindowInfo WndInfoRef);
        [DllImport("User32.dll")]
        static extern int GetWindowText(IntPtr handle, StringBuilder text, int MaxLen);
        [DllImport("user32.dll")]
        public static extern int GetWindowRect(IntPtr hwnd, ref RECT rc);
        [DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern int SendMessage(IntPtr hwnd, uint wMsg, int wParam, int lParam); //對外部軟體視窗傳送一些訊息(如 視窗最大化、最小化等)
        internal const int
            GWL_WNDPROC = (-4),
            GWL_HINSTANCE = (-6),
            GWL_HWNDPARENT = (-8),
            GWL_STYLE = (-16),
            GWL_EXSTYLE = (-20),
            GWL_USERDATA = (-21),
            GWL_ID = (-12);
        internal const uint
              WS_CHILD = 0x40000000,
              WS_VISIBLE = 0x10000000,
              LBS_NOTIFY = 0x00000001,
              HOST_ID = 0x00000002,
              LISTBOX_ID = 0x00000001,
              WS_VSCROLL = 0x00200000,
              WS_BORDER = 0x00800000,
              WS_POPUP = 0x80000000;
        private const int HWND_TOP = 0x0;
        private const int WM_COMMAND = 0x0112;
        private const int WM_QT_PAINT = 0xC2DC;
        private const int WM_PAINT = 0x000F;
        private const int WM_SIZE = 0x0005;
        private const int SWP_FRAMECHANGED = 0x0020;
        private const int WM_SYSCOMMAND = 0x0112;
        private const int SC_CLOSE = 0xF060;
        private const int SC_MINIMIZE = 0xF020;
        private const int SC_MAXIMIZE = 0xF030;
        private const uint WM_LBUTTONDOWN = 0x0201;
        private const uint WM_LBUTTONUP = 0x0202;
        private const int BM_CLICK = 0xF5;

        private Border WndHoster;
        private double screenW, screenH;
        private System.Diagnostics.Process appProc;
        private uint oldStyle;
        public IntPtr hwndHost;
        private String appPath;
        public EmbeddedApp(Border b, double sW, double sH, String p, String f)
        {
            WndHoster = b;
            screenH = sH;
            screenW = sW;
            appPath = p;
            WinInfo = new WindowInfo();
            WinInfo.winTitle = f;
        }
        protected override HandleRef BuildWindowCore(HandleRef hwndParent)
        {
            hwndHost = FindTheWindow();
            //if (hwndHost == null)   
            //{   
            appProc = new System.Diagnostics.Process();
            appProc.StartInfo.FileName = appPath;
            appProc.Start();
            Thread.Sleep(5000);
            hwndHost = FindTheWindow();
            SendMessage(hwndHost, WM_SYSCOMMAND, SC_MINIMIZE, 0);
            //}   
            // 嵌入在HwnHost中的視窗必須要 設定為WS_CHILD風格    
            oldStyle = GetWindowLong(hwndHost, GWL_STYLE);
            uint newStyle = oldStyle;
            //WS_CHILD和WS_POPUP不能同時存在。有些Win32視窗,比如QQ的視窗,有WS_POPUP屬性,這樣嵌入的時候會導致程式錯誤   
            newStyle |= WS_CHILD;
            newStyle &= ~WS_POPUP;
            newStyle &= ~WS_BORDER;
            SetWindowLong(hwndHost, GWL_STYLE, newStyle);
            //將視窗居中,實際上是將視窗的容器居中   
            RePosWindow(WndHoster, WndHoster.Width, WndHoster.Height);

            //將netterm的父視窗設定為HwndHost    
            SetParent(hwndHost, hwndParent.Handle);
            return new HandleRef(this, hwndHost);
        }
        protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)
        {
            SetWindowLong(hwndHost, GWL_STYLE, oldStyle);
            SetParent(hwndHost, (IntPtr)0);
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct WindowInfo
        {
            public String winTitle;
            public RECT r;
            public IntPtr hwnd;
        }
        public delegate bool CallBackPtr(IntPtr hwnd, ref WindowInfo WndInfoRef);
        private static CallBackPtr callBackPtr;
        private WindowInfo WinInfo;
        public static bool CallBackProc(IntPtr hwnd, ref WindowInfo WndInfoRef)
        {
            StringBuilder str = new StringBuilder(512);
            GetWindowText(hwnd, str, str.Capacity);
            Console.WriteLine(str.ToString());
            if (str.ToString().IndexOf(WndInfoRef.winTitle, 0) >= 0)
            {
                WndInfoRef.hwnd = hwnd;
                GetWindowRect(hwnd, ref (WndInfoRef.r));
            }

            return true;
        }
        public IntPtr FindTheWindow()
        {
            callBackPtr = new CallBackPtr(CallBackProc);
            EnumWindows(callBackPtr, ref WinInfo);
            return WinInfo.hwnd;
        }
        public void RePosWindow(Border b, double screenW, double screenH)
        {
            double width = WinInfo.r.right - WinInfo.r.left;
            double height = WinInfo.r.bottom - WinInfo.r.top;

            double left = (screenW - width) / 2;
            double right = (screenW - width) / 2;
            double top = (screenH - height) / 2;
            double bottom = (screenH - height) / 2;

            //b.Margin = new Thickness(left, top, right, bottom);
        }
    }
}

我實現的一個demo