9

我有一个 WPF 应用程序,我希望它看起来像是托管在另一个 - 非 WPF - 应用程序中。在现实生活中,这个非 WPF 应用程序是 Internet Explorer 中的 ActiveX,但为了说明问题,我使用了一个简单的 Windows 窗体应用程序。

我使用 Windows API 函数 SetParent,它已经有几十个线程。但是,我找不到任何关于我的确切问题的内容:WPF 应用程序右侧和底部的一个小区域未绘制在非 WPF 应用程序的 window 内

自行运行的 WPF 窗口:
替代文字

以 WinForm 应用程序的窗口为父窗口的 WPF 窗口:
替代文字

如果将 WPF 应用程序与 WinForms 应用程序或普通 Win32 应用程序(如记事本)交换,我不会遇到此问题。

WinForm 代码如下所示:

private void Form1_Load(object sender, EventArgs e)
    {
        // Start process
        var psi = new ProcessStartInfo("c:\\wpfapp\\wpfapp\\bin\\Debug\\wpfapp.exe");
        psi.WindowStyle = ProcessWindowStyle.Normal;
        _process = Process.Start(psi);

        // Sleep until new process is ready
        Thread.Sleep(1000);

        // Set new process's parent to this window
        SetParent(_process.MainWindowHandle, this.Handle);

        // Remove WS_POPUP and add WS_CHILD window style to child window
        const int GWL_STYLE = -16;
        const long WS_POPUP = 0x80000000;
        const long WS_CHILD = 0x40000000;
        long style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
        style = (style & ~(WS_POPUP)) | WS_CHILD;
        SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);

        // Move and resize child window to fit into parent's
        MoveWindow(_process.MainWindowHandle, 0, 0, this.Width, this.Height, true);
    }

注意:我知道 SetParent 的这种使用不一定是推荐的做法,但我想并且需要了解如何这样做,所以请让我 :)

4

3 回答 3

6

我找到了一个很好的解决方法:在 SetParent 之前调用 MoveWindow:

private void Form1_Load(object sender, EventArgs e)
{
     // Start process            
     var psi = new ProcessStartInfo("C:\\WpfApp\\WpfApp.exe");
     psi.WindowStyle = ProcessWindowStyle.Normal;
     _process = Process.Start(psi);

     // Sleep until new process is ready
     Thread.Sleep(3000);

     // Move and resize child window to fit into parent's
     Rectangle rect;
     GetClientRect(this.Handle, out rect);
     MoveWindow(_process.MainWindowHandle, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, true);

     // Set new process's parent to this window
     SetParent(_process.MainWindowHandle, this.Handle);

     // Remove WS_POPUP and add WS_CHILD window style to child window
     long style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
     style = (style & ~(WS_POPUP) & ~(WS_CAPTION)) & ~(WS_THICKFRAME) | WS_CHILD;
     SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);
}           

在 SizeChanged 事件处理程序中,我将子项从父项中取出,调用 MoveWindow 并将其移回父项。为了减少闪烁,我在执行这些操作时隐藏了窗口:

private void Form1_SizeChanged(object sender, EventArgs e)
{
     ShowWindow(_process.MainWindowHandle, SW_HIDE);

     var ptr = new IntPtr();
     SetParent(_process.MainWindowHandle, ptr);

     Rectangle rect;
     GetClientRect(this.Handle, out rect);

     MoveWindow(_process.MainWindowHandle, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, true);            
     SetParent(_process.MainWindowHandle, this.Handle);
     ShowWindow(_process.MainWindowHandle, SW_SHOW);
}

它没有解释为什么在 SetParent 之后 MoveWindow 不起作用,但它解决了我的问题,所以我会将其标记为答案,除非出现更好的情况。

于 2010-11-10T12:59:10.150 回答
3

您可能应该调整 WPF 窗口的大小,使其适合新父窗口的客户区:

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

// Move and resize child window to fit into parent's client area.
RECT rc = new RECT();
GetClientRect(this.Handle, out rc);
MoveWindow(_process.MainWindowHandle, 0, 0, rc.Right - rc.Left,
    rc.Bottom - rc.Top, true)
于 2010-11-09T16:44:02.803 回答
0

我使用了带面板的表单/用户控件。然后我将 Panel 用作新的父窗口,并使用 SetWindowPos 将面板的新位置和大小设置为子窗口。

注意:MS 建议在使用 SetWindowLong(或 SetWindowLongPtr)激活新样式后使用 SetWindowPos。

于 2011-01-26T13:25:05.820 回答