WPF應用程式嵌入第三方exe
阿新 • • 發佈:2019-01-25
思路是,
第一步:在自己的應用程式中準備顯示第三方控制元件的容器,Border,Grid什麼的都可以,下面是觸發程式碼
第二步:編寫啟動第三方exe的類,主要是獲取第三方窗體的控制代碼,這裡需要一些WindowAPI,然後啟動流程就是先把第三方控制元件啟動,然後嵌入到自己的應用程式中。這樣就有一個問題,先第三方exe起來,過會再嵌入。解決思路是程式初始化的時候做這些事情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); }
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