Tech Racho エンジニアの「?」を「!」に。

WPFで枠を消すその2

WPFで枠を消す の続きです。

前回紹介した方法は、以下のような内容でした。

  • WindowStyle=None, AllowsTransparency=True にすると枠が消える
  • 移動できるように、WM_NCLBUTTONDOWN + HTCAPTION を送信する

しかし、この方法には欠点があります。
AllowsTransparencyを有効にしていると、WindowsFormsHostが表示されなくなってしまうのです。

http://msdn.microsoft.com/ja-jp/library/aa970911(VS.80).aspx

HwndHost クラスは、レイヤ表示をサポートしません。つまり、WindowsFormsHost 要素で Opacity プロパティを設定しても何の効果もなく、AllowsTransparency が true に設定されている他の WPF ウィンドウとのブレンド操作は行われません。

そこで、DirectX と連携する際などは、AllowsTransparency を False のままにしておく必要があります。

困ったときのWinAPI。直接ウィンドウスタイルを設定して、枠を消してしまいましょう。
Windows Forms Application 時代は、CreateParams で設定していたような内容ですね。

[DllImport("user32.dll")]
static extern long GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
static extern long SetWindowLong(IntPtr hWnd, int nIndex, long dwNewLong);

[DllImport("user32.dll")]
static extern UInt32 SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);

private void RemoveFrame()
{
	long WS_THICKFRAME = 0x00040000L;
	int GWL_STYLE = -16;
	int SWP_FRAMECHANGED = 0x0020;
	int SWP_NOSIZE = 0x1;
	int SWP_NOMOVE = 0x2;
	int SWP_NOZORDER = 0x4;

	IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
	SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) ^ WS_THICKFRAME);

	SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
}

やっていることは以下のような感じです。

  • GetWindowLongでWindowStyleを取得
  • SetWindowLongで、今までのスタイルからWS_THICKFRAME(ウィンドウ枠)を除いたものを設定
  • SetWindowPosで表示を更新

最後のSetWindowPostをやらないと、サイズ変更するまで描画が崩れてしまいます。

注意点としては、WS_THICKFRAME を外すと、WM_NCLBUTTONDOWN で HTBOTTOMRIGHT を送信しても、サイズ変更できなくなります。
諦めて、自分でサイズ変更処理を書くしかないみたいですね。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。