1. 程式人生 > 實用技巧 >完美實現Wpf巢狀外部exe

完美實現Wpf巢狀外部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.Controls;
using System.Windows.Interop;

namespace WpfDisplayExe
{
    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(); 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); appProc.Kill(); appProc.Close(); } [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); } } }

呼叫的話,需要是在windows工作管理員中檢視它的名字,上面的類你可以稍作修改。DestroyWindowCore是你視窗推出的時候。

public MainWindow()
        {
            InitializeComponent();
            //載入.exe檔案
            
           String path = @"D:\VLC\vlc.exe"; //VusionDTI  ImAgenGine_MRDP
            EmbeddedApp ea = new EmbeddedApp(asd, 100, 100, path, "VLC media player");
            asd.Child = ea;
        }