Chinaunix首页 | 论坛 | 博客
  • 博客访问: 49235
  • 博文数量: 21
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 190
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-24 15:25
文章分类

全部博文(21)

文章存档

2013年(21)

我的朋友

分类: C#/.net

2013-08-13 10:30:57

WPF – Host external app example : hosting a notepad

Topic: WPF – Host external app example : hosting a notepad

标题: WPF – 托管外部进程实例: 托管记事本

从SO上的一个关于托管external的win32程序。 其中的一个hack方法是用windowsFormsHost和SetParent 方法托管一个notepad进程的MainWindowHandle。


From the StackOverflow discussion on the hosting of some external win32 control in wpf. One of the hack that you can use is with the WindowsFormsHost trick and SetParent hack to host the MainWindowHandle from the Notepad process.


托管window的xaml代码如下:

 

        xmlns=""

        xmlns:x=""

        Title="MainWindow" Height="350" Width="525"

        xmlns:host=""

        >

   

   

   

       

       

            x:Name="windowsFormsHost1"

            >

 

       

   

 

托管window的code behind代码如下:

 

And the code behind is

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using System.Runtime.InteropServices;

using System.Diagnostics;

 

namespace HostingNotepad

{

    ///

    /// Interaction logic for MainWindow.xaml

    ///

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

            _panel = new System.Windows.Forms.Panel();

            windowsFormsHost1.Child = _panel;

        }

 

        private System.Windows.Forms.Panel _panel;

    private Process _process;

 

    [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")]

    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

 

    private const int SWP_NOZORDER = 0x0004;

    private const int SWP_NOACTIVATE = 0x0010;

    private const int GWL_STYLE = -16;

    private const int WS_CAPTION = 0x00C00000;

    private const int WS_THICKFRAME = 0x00040000;

 

    private void button1_Click(object sender, RoutedEventArgs e)

    {

        button1.Visibility = Visibility.Hidden;

        ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");

        psi.Arguments = @"C:\Temp\output.txt";

 

        _process = Process.Start(psi);

        _process.WaitForInputIdle();

        SetParent(_process.MainWindowHandle, _panel.Handle);

 

        // remove control box

        int style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);

        style = style & ~WS_CAPTION & ~WS_THICKFRAME;

        SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);

 

        // resize embedded application & refresh

        ResizeEmbeddedApp();

    }

 

    protected override void OnClosing(System.ComponentModel.CancelEventArgs e)

    {

        base.OnClosing(e);

        if (_process != null)

        {

            _process.Refresh();

            _process.Close();

        }

    }

 

    private void ResizeEmbeddedApp()

    {

        if (_process == null)

            return;

 

        SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)_panel.ClientSize.Width, (int)_panel.ClientSize.Height, SWP_NOZORDER | SWP_NOACTIVATE);

    }

 

    protected override Size MeasureOverride(Size availableSize)

    {

        Size size = base.MeasureOverride(availableSize);

        ResizeEmbeddedApp();

        return size;

    }

    }

}

 

 

另一个方法是用Hwndhost,在本例子中,我用到了System.Windows.Forms.Panel,如果你希望和纯粹的WPF工作,你可以使用Border作为HwndHost的父容器,但是,本例有启动的问题。

And there is yet another implementation which leverage the HwndHost, while I adapted it a little bit to have System.Windows.Forms.Panel, while if you are working with pure WPF, you can just use a Border as the Parent of the HwndHost.  However, there seems to be problem starting up the application.

 

首先是这个NotepadHwndHost的代码

First is the NotepadHwndHost,

 

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Diagnostics;

    using System.Runtime.InteropServices;

    using System.Windows.Interop;

    using HostingExternalApp.Natives;

    using System.Threading;

 

    ///

    /// TODO: Update summary.

    ///

    public class NotepadHwndHost : HwndHost

    {

        private System.Windows.Forms.Panel _panel;

 

        private Process _process;

 

 

        #region Construction and Initialization

        public NotepadHwndHost(System.Windows.Forms.Panel panel)

        {

            _panel = panel;

        }

        #endregion

 

        #region HwndHost overrides

 

        protected override HandleRef BuildWindowCore(HandleRef hwndParent)

        {

            ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");

 

            _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();

            }

 

            //HWND hwnd = new HWND(_process.MainWindowHandle);

 

            IntPtr hwnd = _process.MainWindowHandle;

 

            int style = NativeMethods.GetWindowLong(hwnd, /*GWL.Style*/ (int) WindowLongFlags.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

 

            style = style & ~((int)Constants.WS_CAPTION) & ~((int)Constants.WS_THICKFRAME); // Removes Caption bar and the sizing border

            style |= ((int)Constants.WS_CHILD);

            NativeMethods.SetWindowLong(hwnd, /* GWL.Style */((int) WindowLongFlags.GWL_STYLE), style);

 

 

            //NativeMethods.SetParent(_process.MainWindowHandle, _panel.Handle);

            NativeMethods.SetParent(_process.MainWindowHandle, hwndParent);

           

            ResizeEmbeddedApp();

 

 

            //return hwnd;

            return new HandleRef(this, hwnd);

        }

 

        #region Hosting handler

        public void ResizeEmbeddedApp()

        {

            if (_process == null)

                return;

 

            NativeMethods.SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)_panel.ClientSize.Width, (int)_panel.ClientSize.Height, SWP_NOZORDER | SWP_NOACTIVATE);

        }

 

        #endregion

 

        protected override void DestroyWindowCore(HandleRef hwnd)

        {

            _process.CloseMainWindow();

 

            _process.WaitForExit(5000);

 

            if (_process.HasExited == false)

            {

                _process.Kill();

            }

 

            _process.Close();

            _process.Dispose();

            _process = null;

            // we don't use the DwayneNeed library

            //hwnd.Dispose();

            //hwnd = null;

 

        }

 

        #endregion

 

 

        #region Constants

 

        private const int SWP_NOZORDER = 0x0004;

        private const int SWP_NOACTIVATE = 0x0010;

        private const int GWL_STYLE = -16;

        private const int WS_CAPTION = 0x00C00000;

        private const int WS_THICKFRAME = 0x00040000;

 

        #endregion

 

    }

 

下面是MainWindow的xaml代码和c# 代码。

And the MainWindow.xaml’s xaml code and code-behind are separately

        xmlns=""

        xmlns:x=""

        Title="MainWindow" Height="350" Width="525">

   

       

            x:Name="hostElement"

            >

           

       

   

 

And

 

    public partial class MainWindow : Window

    {

 

        private System.Windows.Forms.Panel _panel;

        private NotepadHwndHost _notepadHwndhost;

 

        public MainWindow()

        {

            InitializeComponent();

 

            _panel = new System.Windows.Forms.Panel();

            hostElement.Chlid = _panel;

            _notepadHwndhost = new NotepadHwndHost(_panel);

        }

 

        protected override Size MeasureOverride(Size availableSize)

        {

            Size size = base.MeasureOverride(availableSize);

            _notepadHwndhost.ResizeEmbeddedApp();

            return size;

        }

    }


代码中用到的NativeMehods和常量如下:

The constants and NativeMethods used inside the program is as follow.


    // C# definition:

    //   WindowsLongFlags: (Enums)

    enum WindowLongFlags : int

    {

         GWL_EXSTYLE = -20,

         GWLP_HINSTANCE = -6,

         GWLP_HWNDPARENT = -8,

         GWL_ID = -12,

         GWL_STYLE = -16,

         GWL_USERDATA = -21,

         GWL_WNDPROC = -4,

         DWLP_USER = 0x8,

         DWLP_MSGRESULT = 0x0,

         DWLP_DLGPROC = 0x4

    }

 

    ///

    /// TODO: Update summary.

    ///

    public static class Constants

    {

 

        internal const int GWL_HWNDPARENT = (-8);

 

        internal const int GWL_ID = (-12);

        internal const int GWL_STYLE = (-16);

        internal const int GWL_EXSTYLE = (-20);

 

 

        // Window Styles

        internal const UInt32 WS_OVERLAPPED = 0;

        internal const UInt32 WS_POPUP = 0x80000000;

        internal const UInt32 WS_CHILD = 0x40000000;

        internal const UInt32 WS_MINIMIZE = 0x20000000;

        internal const UInt32 WS_VISIBLE = 0x10000000;

        internal const UInt32 WS_DISABLED = 0x8000000;

        internal const UInt32 WS_CLIPSIBLINGS = 0x4000000;

        internal const UInt32 WS_CLIPCHILDREN = 0x2000000;

        internal const UInt32 WS_MAXIMIZE = 0x1000000;

        internal const UInt32 WS_CAPTION = 0xC00000;      // WS_BORDER or WS_DLGFRAME 

        internal const UInt32 WS_BORDER = 0x800000;

        internal const UInt32 WS_DLGFRAME = 0x400000;

        internal const UInt32 WS_VSCROLL = 0x200000;

        internal const UInt32 WS_HSCROLL = 0x100000;

        internal const UInt32 WS_SYSMENU = 0x80000;

        internal const UInt32 WS_THICKFRAME = 0x40000;

        internal const UInt32 WS_GROUP = 0x20000;

        internal const UInt32 WS_TABSTOP = 0x10000;

        internal const UInt32 WS_MINIMIZEBOX = 0x20000;

        internal const UInt32 WS_MAXIMIZEBOX = 0x10000;

        internal const UInt32 WS_TILED = WS_OVERLAPPED;

        internal const UInt32 WS_ICONIC = WS_MINIMIZE;

        internal const UInt32 WS_SIZEBOX = WS_THICKFRAME;

 

        // Extended Window Styles

        internal const UInt32 WS_EX_DLGMODALFRAME = 0x0001;

        internal const UInt32 WS_EX_NOPARENTNOTIFY = 0x0004;

        internal const UInt32 WS_EX_TOPMOST = 0x0008;

        internal const UInt32 WS_EX_ACCEPTFILES = 0x0010;

        internal const UInt32 WS_EX_TRANSPARENT = 0x0020;

        internal const UInt32 WS_EX_MDICHILD = 0x0040;

        internal const UInt32 WS_EX_TOOLWINDOW = 0x0080;

        internal const UInt32 WS_EX_WINDOWEDGE = 0x0100;

        internal const UInt32 WS_EX_CLIENTEDGE = 0x0200;

        internal const UInt32 WS_EX_CONTEXTHELP = 0x0400;

        internal const UInt32 WS_EX_RIGHT = 0x1000;

        internal const UInt32 WS_EX_LEFT = 0x0000;

        internal const UInt32 WS_EX_RTLREADING = 0x2000;

        internal const UInt32 WS_EX_LTRREADING = 0x0000;

        internal const UInt32 WS_EX_LEFTSCROLLBAR = 0x4000;

        internal const UInt32 WS_EX_RIGHTSCROLLBAR = 0x0000;

        internal const UInt32 WS_EX_CONTROLPARENT = 0x10000;

        internal const UInt32 WS_EX_STATICEDGE = 0x20000;

        internal const UInt32 WS_EX_APPWINDOW = 0x40000;

        internal const UInt32 WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);

        internal const UInt32 WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);

        internal const UInt32 WS_EX_LAYERED = 0x00080000;

        internal const UInt32 WS_EX_NOINHERITLAYOUT = 0x00100000; // Disable inheritence of mirroring by children

        internal const UInt32 WS_EX_LAYOUTRTL = 0x00400000; // Right to left mirroring

        internal const UInt32 WS_EX_COMPOSITED = 0x02000000;

        internal const UInt32 WS_EX_NOACTIVATE = 0x08000000;

 

    }


And

    using System;

    using System.Runtime.InteropServices;

 

    ///

    /// TODO: Update summary.

    ///

    public static class NativeMethods

    {

 

        #region P/Invoke

 

        [DllImport("user32.dll", SetLastError = true)]

        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

 

        [DllImport("user32.dll")]

        public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

 

 

        [DllImport("user32")]

        public static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);

 

        [DllImport("user32")]

        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

 

        #endregion

    }


引用:

References:

阅读(1269) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~