using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms.Integration; using System.Windows.Interop; namespace ClientHelper { public static class ExtentionMethods { #region 调用外部exe程序 /// <summary> /// 在一个WPF控件Boder里显示一个exe程序,程序铺满窗口,但程序有标题栏,可以拖动 /// </summary> /// <param name="border">border对象</param> /// <param name="exePath">exe程序路径</param> /// <param name="processName">exe进程名称</param> public static void ShowExeInBorder_Movable(this System.Windows.Controls.Border border, string exePath, string processName) { ExeHost e = new ExeHost(exePath, processName); border.Child = e; } /// <summary> /// 在一个WPF控件Boder里显示一个exe程序,程序铺满窗口,不可拖动 /// </summary> /// <param name="border">border对象</param> /// <param name="exePath">exe程序路径</param> /// <param name="processName">exe进程名称</param> /// <param name="exeTitleBarHeight">exe程序标题栏高度</param> /// <param name="exeWidth">exe程序显示宽度</param> /// <param name="exeHeight">exe程序显示高度(包括标题栏高度)</param> public static void ShowExeInBorder_NoTitleBar(this System.Windows.Controls.Border border, string exePath, string processName, int exeTitleBarHeight, int exeWidth, int exeHeight) { border.Height = exeHeight - exeTitleBarHeight; border.Width = exeWidth; border.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; border.VerticalAlignment = System.Windows.VerticalAlignment.Center; WindowsFormsHost host = new WindowsFormsHost() { Width = border.Width, Height = border.Height }; ExeHostUserControl uc = new ExeHostUserControl(); InvalidataExeProcess(uc, exeHeight, exeWidth, exePath, processName); host.Child = uc; border.Loaded += new System.Windows.RoutedEventHandler((s, e) => { IntPtr notepadHandle = uc.EXEIntprt = uc._process.MainWindowHandle; //强制使用样式,给exe程序设置父窗体 int style = GetWindowLong(notepadHandle, GWL_STYLE); style = style & ~((int)WS_CAPTION) & ~((int)WS_THICKFRAME); // Removes Caption bar and the sizing border style |= ((int)WS_CHILD); // Must be a child window to be hosted SetWindowLong(notepadHandle, GWL_STYLE, style); SetParent(notepadHandle, uc.Handle); uc.Invalidate(); //移动exe程序的位置。 MoveWindow(uc.EXEIntprt, 0, exeTitleBarHeight * (-1), exeWidth, exeHeight, true); }); border.Child = host; border.InvalidateVisual(); } private static void InvalidataExeProcess(ExeHostUserControl uc, int exeHeight, int exeWidth, string exePath, string processName) { Process[] ps = Process.GetProcessesByName(processName); if (ps.Length > 0) { var p = ps[0]; p.Kill(); } ProcessStartInfo psi = new ProcessStartInfo(exePath); psi.WindowStyle = ProcessWindowStyle.Minimized; uc._process = Process.Start(psi); uc._process.WaitForInputIdle(); uc.Size = new System.Drawing.Size(exeWidth, exeHeight); // The main window handle may be unavailable for a while, just wait for it while (uc._process.MainWindowHandle == IntPtr.Zero) { Thread.Yield(); } IntPtr notepadHandle = uc.EXEIntprt = uc._process.MainWindowHandle; int style = GetWindowLong(notepadHandle, GWL_STYLE); style = style & ~((int)WS_CAPTION) & ~((int)WS_THICKFRAME); // Removes Caption bar and the sizing border style |= ((int)WS_CHILD); // Must be a child window to be hosted SetWindowLong(notepadHandle, GWL_STYLE, style); SetParent(notepadHandle, uc.Handle); uc.Invalidate(); } [DllImport("user32.dll")] static extern bool MoveWindow(IntPtr Handle, int x, int y, int w, int h, bool repaint); #region win32 [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32")] private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent); [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)] internal static extern bool DestroyWindow(IntPtr hwnd); private const int WS_CAPTION = 0x00C00000; private const int WS_THICKFRAME = 0x00040000; private const int GWL_STYLE = -16; private const int WS_CHILD = 0x40000000; #endregion #endregion } class ExeHost : HwndHost { public ExeHost(string exePath, string processName) { this._processName = processName; this._path = exePath; } private Process _process; protected override HandleRef BuildWindowCore(HandleRef hwndParent) { Process[] ps = Process.GetProcessesByName(_processName); if (ps.Length > 0) { var p = ps[0]; p.Kill(); } ProcessStartInfo psi = new ProcessStartInfo(_path); psi.WindowStyle = ProcessWindowStyle.Minimized; _process = Process.Start(psi); _process.WaitForInputIdle(); // The main window handle may be unavailable for a while, just wait for it while (_process.MainWindowHandle == IntPtr.Zero) { Thread.Yield(); } IntPtr notepadHandle = _process.MainWindowHandle; int style = GetWindowLong(notepadHandle, GWL_STYLE); style = style & ~((int)WS_CAPTION) & ~((int)WS_THICKFRAME); // Removes Caption bar and the sizing border style |= ((int)WS_CHILD); // Must be a child window to be hosted SetWindowLong(notepadHandle, GWL_STYLE, style); SetParent(notepadHandle, hwndParent.Handle); this.InvalidateVisual(); HandleRef hwnd = new HandleRef(this, notepadHandle); return hwnd; } protected override void DestroyWindowCore(HandleRef hwnd) { DestroyWindow(hwnd.Handle); } private const int GWL_STYLE = -16; private const int WS_CAPTION = 0x00C00000; private const int WS_THICKFRAME = 0x00040000; private const int WS_CHILD = 0x40000000; private string _path; private string _processName; [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32")] private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent); [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)] internal static extern bool DestroyWindow(IntPtr hwnd); } }