C#将外部窗口嵌入到WPF控件当中

来源:互联网 发布:淘宝保证金别骗怎么办 编辑:程序博客网 时间:2024/05/16 19:49

C#讲外部窗口嵌入到WPF控件当中

本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦:

  • 可能会用到的API函数
    public class Win32API    {        #region Win32 API        [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,             CharSet = CharSet.Unicode, ExactSpelling = true,             CallingConvention = CallingConvention.StdCall)]        public static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);        [DllImport("user32.dll", SetLastError = true)]        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);        [DllImport("user32.dll", SetLastError = true)]        public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);        [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]        public static extern long GetWindowLong(IntPtr hwnd, int nIndex);        public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)        {            if (IntPtr.Size == 4)            {                return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);            }            return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);        }        [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]        public static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]        public static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong);        [DllImport("user32.dll", SetLastError = true)]        public static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);        [DllImport("user32.dll", SetLastError = true)]        public static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);        [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]        public static extern bool PostMessage(IntPtr hwnd, uint Msg, uint wParam, uint lParam);        /// <summary>        /// 获取系统错误信息描述        /// </summary>        /// <param name="errCode">系统错误码</param>        /// <returns></returns>        public static string GetLastError()        {            var errCode = Marshal.GetLastWin32Error();            IntPtr tempptr = IntPtr.Zero;            string msg = null;            FormatMessage(0x1300, ref tempptr, errCode, 0, ref msg, 255, ref tempptr);            return msg;        }        /// <summary>        /// 获取系统错误信息描述        /// </summary>        /// <param name="errCode">系统错误码</param>        /// <returns></returns>        public static string GetLastErrorString(int errCode)        {            IntPtr tempptr = IntPtr.Zero;            string msg = null;            FormatMessage(0x1300, ref tempptr, errCode, 0, ref msg, 255, ref tempptr);            return msg;        }        [System.Runtime.InteropServices.DllImport("Kernel32.dll")]        public extern static int FormatMessage(int flag, ref IntPtr source, int msgid, int langid, ref string buf, int size, ref IntPtr args);        [DllImport("user32.dll", SetLastError = true)]        public static extern IntPtr GetParent(IntPtr hwnd);        [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);        public const int SWP_NOOWNERZORDER = 0x200;        public const int SWP_NOREDRAW = 0x8;        public const int SWP_NOZORDER = 0x4;        public const int SWP_SHOWWINDOW = 0x0040;        public const int WS_EX_MDICHILD = 0x40;        public const int SWP_NOACTIVATE = 0x10;        public const int SWP_ASYNCWINDOWPOS = 0x4000;        public const int SWP_NOMOVE = 0x2;        public const int SWP_NOSIZE = 0x1;        public const int WM_CLOSE = 0x10;        public const int SW_HIDE = 0; //{隐藏, 并且任务栏也没有最小化图标}        public const int SW_SHOWNORMAL = 1; //{用最近的大小和位置显示, 激活}        public const int SW_NORMAL = 1; //{同 SW_SHOWNORMAL}        public const int SW_SHOWMINIMIZED = 2; //{最小化, 激活}        public const int SW_SHOWMAXIMIZED = 3; //{最大化, 激活}        public const int SW_MAXIMIZE = 3; //{同 SW_SHOWMAXIMIZED}        public const int SW_SHOWNOACTIVATE = 4; //{用最近的大小和位置显示, 不激活}        public const int SW_SHOW = 5; //{同 SW_SHOWNORMAL}        public const int SW_MINIMIZE = 6; //{最小化, 不激活}        public const int SW_SHOWMINNOACTIVE = 7; //{同 SW_MINIMIZE}        public const int SW_SHOWNA = 8; //{同 SW_SHOWNOACTIVATE}        public const int SW_RESTORE = 9; //{同 SW_SHOWNORMAL}        public const int SW_SHOWDEFAULT = 10; //{同 SW_SHOWNORMAL}        public const int SW_MAX = 10; //{同 SW_SHOWNORMAL}        //const int PROCESS_ALL_ACCESS = 0x1F0FFF;        //const int PROCESS_VM_READ = 0x0010;        //const int PROCESS_VM_WRITE = 0x0020;             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 int              WS_CHILD = 0x40000000,              WS_VISIBLE = 0x10000000,              LBS_NOTIFY = 0x00000001,              HOST_ID = 0x00000002,              LISTBOX_ID = 0x00000001,              WS_VSCROLL = 0x00200000,              WS_BORDER = 0x00800000;        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;        #endregion Win32 API    }
  • 给该窗口添加一个容器
    public partial class PluginContainer : ContentControl    {        public PluginContainer(string appFileName,IntPtr hostHandle)        {            InitializeComponent();            _appFilename = appFileName;            _hostWinHandle = hostHandle;        }        private void OpenExternProcess(int width,int height)        {            try{                ProcessStartInfo info = new ProcessStartInfo(_appFilename) ;                info.UseShellExecute = true;                //info.WindowStyle = ProcessWindowStyle.Minimized;                info.WindowStyle = ProcessWindowStyle.Hidden;                AppProcess = System.Diagnostics.Process.Start(info);                // Wait for process to be created and enter idle condition                AppProcess.WaitForInputIdle();                while (AppProcess.MainWindowHandle == IntPtr.Zero){                    Thread.Sleep(5);                }                                }            catch (Exception ex){                throw ex;                         }        }        public bool EmbedProcess(int width, int height)        {            OpenExternProcess(width, height);            try {                var pluginWinHandle = AppProcess.MainWindowHandle;//Get the handle of main window.                embedResult = Win32API.SetParent(pluginWinHandle, _hostWinHandle);//set parent window                Win32API.SetWindowLong(new HandleRef(this, pluginWinHandle), Win32API.GWL_STYLE, Win32API.WS_VISIBLE);//Set window style to "None".                var moveResult = Win32API.MoveWindow(pluginWinHandle, 0, 0, width, height, true);//Move window to fixed position(up-left is (0,0), and low-right is (width, height)).                //embed failed, and tries again                if (!moveResult || embedResult==0){                    AppProcess.Kill();                    if (MAXCOUNT-->0){                        EmbedProcess(width, height);                    }                                    }                else{                    Win32API.ShowWindow(pluginWinHandle, (short)Win32API.SW_MAXIMIZE);                }                  }            catch (Exception ex)            {                var errorString = Win32API.GetLastError();                MessageBox.Show(errorString+ex.Message);            }            return (embedResult != 0);        }        #region        public int embedResult = 0;        public Process AppProcess { get; set; }        private  IntPtr _hostWinHandle { get; set; }        private string _appFilename = "";        private  int MAXCOUNT=10;        #endregion    }
  • 正式使用
//把句柄传进去,这个mainBorder是在MainWindow中一个Border控件的名字,下面这个获取句柄这个只能在MainWindow.xaml.cs文件中才能获取,我也不知道为什么。在其他的某个xaml.cs中却获取不到这个句柄,这个窗口句柄被当做外部窗口的父窗口了(API中的 SetParent函数来实现的)var hostWinHandle = ((HwndSource)PresentationSource.FromVisual(mainBorder)).Handle;var plugin = new PluginContainer(fileName, hostWinHandle);mainBorder.Content = plugin;plugin.EmbedProcess((int)mainBorder.Width,(int)mainBorder.Height);``
  • *此外
    获取窗口句柄还可以用API函数FindWindow来实现
IntPtr handle = FindWindow(null,"Window_Name");
0 0