win32 setParent()を使用して非WPFアプリ内のWPFアプリをホストする
質問
WPFアプリケーションがあります。これは、別の-WPFでホストされているように見せたいと考えています。実生活では、この非WPFアプリはInternet Explorer内のActiveXですが、問題を説明するために、単純なWindowsフォームアプリを使用しています。
Windows API関数SetParentを使用していますが、すでに数十個のスレッドがあります。しかし、私の正確な問題に書かれたものを見つけることができません: WPFアプリの右下にある小さな領域は、非WPFアプリのウィンドウ内でペイントされていません.
WPFウィンドウを単独で実行しています:
親としてのWinformアプリのウィンドウを備えたWPFウィンドウ:
WWPFアプリをWinformsアプリまたはPlain 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のこの使用は必ずしも推奨されるプラクティスではないことを知っていますが、この方法でそれを行う方法を知る必要があるので、私をさせてください:)
解決
私はかなりうまく機能する回避策を見つけました: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);
}
サイズチェンジのイベントハンドラーでは、私は子供を親から連れ出し、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);
}
MoveWindowがSetParentの後に機能しない理由は説明していませんが、それは私の問題を解決しますので、何かがより良いものが現れない限り、これを答えとしてマークします。
他のヒント
おそらく、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)
フォーム / usercontrolをパネルで使用しました。次に、パネルを新しい親として使用し、SetWindowposを使用してパネルの新しい位置とサイズをChild Windowに設定しました。
注:MSは、SetWindowlong(またはSetWindowLongPtr)を使用して新しいスタイルをアクティブにした後、SetWindowposを使用することをお勧めします。