9

別の非 WPF アプリケーション内でホストされているように見せたい WPF アプリケーションがあります。実際には、この非 WPF アプリは Internet Explorer 内の ActiveX ですが、問題を説明するために単純な Windows フォーム アプリを使用します。

私は Windows API 関数 SetParent を使用します。これには既に数十のスレッドがあります。ただし、正確な問題について書かれたものは見つかりません。WPF アプリの右側と下部にある小さな領域が、非 WPF アプリのウィンドウ内に描画されません

単独で実行される 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

パネルで Form / UserControl を使用しました。次に、Panel を新しい親として使用し、SetWindowPos を使用してパネルの新しい位置とサイズを子ウィンドウに設定しました。

注: MS では、SetWindowLong (または SetWindowLongPtr) を使用して新しいスタイルを有効にした後、SetWindowPos を使用することをお勧めします。

于 2011-01-26T13:25:05.820 に答える