【问题标题】:Hosting external exe in WPF在 WPF 中托管外部 exe
【发布时间】:2013-12-04 21:31:39
【问题描述】:

您好,我正在尝试在 WPF 应用程序中托管一个 exe(记事本)。 请在此处找到代码:

public partial class MainWindow : Window
{
    private Process _process;
    private System.Windows.Forms.Panel _panel;

    [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;
    const string patran = "patran";
    public MainWindow()
    {
        InitializeComponent();
        _process = Process.Start("notepad.exe");

        _panel = new System.Windows.Forms.Panel();
        wfHost.Child = _panel;
        var patranPanelHandle = _panel.Handle;
        SetParent(_process.MainWindowHandle, patranPanelHandle);

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

    private void ResizeEmbeddedApp()
    {
        if (_process == null)
            return;
        SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)_panel.Width, (int)_panel.Height, SWP_NOZORDER | SWP_NOACTIVATE);
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        Size size = base.MeasureOverride(availableSize);
        ResizeEmbeddedApp();
        return size;
    }
}

相同的代码在 Winforms 上运行得非常好,所以我使用了 WinformsHost,然后添加了一个 winforms 面板,如上所述。但结果并不如预期。记事本出现在 WPF 应用程序之外,父子程序无法正常工作

this 也没有答案

【问题讨论】:

    标签: wpf winforms wpf-4.0 windowsformshost


    【解决方案1】:

    我认为,您调用SetParent 太快了。一旦父窗口和子窗口都准备好,您需要执行SetParent。所以,你可以做的是等到父窗口是Loaded,然后启动子进程。但是,在调用 SetParent 之前,请在子进程上调用 WaitForInputIdle

    下面是我尝试过的示例代码,它可以工作:

    public partial class MainWindow : Window
    {
        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;
        const string patran = "patran";
        public MainWindow()
        {
            InitializeComponent();
    
            Loaded += (s, e) => LaunchChildProcess();
        }
    
        private void LaunchChildProcess()
        {
            _process = Process.Start("notepad.exe");
            _process.WaitForInputIdle();
    
            var helper = new WindowInteropHelper(this);
    
            SetParent(_process.MainWindowHandle, helper.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();
        }
    
        private void ResizeEmbeddedApp()
        {
            if (_process == null)
                return;
            SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)ActualWidth, (int)ActualHeight, SWP_NOZORDER | SWP_NOACTIVATE);
        }
    
        protected override Size MeasureOverride(Size availableSize)
        {
            Size size = base.MeasureOverride(availableSize);
            ResizeEmbeddedApp();
            return size;
        }
    

    有关 WaitForInputIdle 的更多信息,请参阅此MSDN 页面。

    更新

    附加结果图片:

    【讨论】:

      猜你喜欢
      • 2015-02-28
      • 2011-06-29
      • 2010-09-09
      • 1970-01-01
      • 1970-01-01
      • 2017-04-15
      • 1970-01-01
      • 2016-10-08
      • 1970-01-01
      相关资源
      最近更新 更多