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);
}
}