執筆者: 大野 元久

動作確認環境: Visual Studio 2008、Visual Studio 2010

更新日: 2010 年 12 月 3 日

Windows フォームで使われるコントロールの大半は、Windows 自身が提供している機能であり、それぞれがウィンドウ ハンドルを持ちます。コントロールを拡張する場合は、このウィンドウ ハンドルを使って Windows メッセージを処理する必要があります。これに対し、WPF ではコントロールの描画や管理は (DirectX を使って) WPF が行い、ウィンドウだけがウィンドウ ハンドルを持ちます。コントロールを拡張する場合も、ウィンドウ ハンドルが必要になることはありません。

しかし、Windows API を直接呼び出す場合など、ウィンドウ ハンドルが必要なこともあります。ここではウィンドウ ハンドルを使うプログラミングを解説します。

C#
using System.Windows.Interopusing System.Runtime.InteropServices; 
   …… 
public partial class MainWindow : Window 
{ 
   …… 
   private void Window_Loaded(object sender, RoutedEventArgs e) 
   { 
       HwndSource source = HwndSource.FromVisual(thisas HwndSource; 
       IntPtr handle = source.Handle; 
       source.CompositionTarget.BackgroundColor = Color.FromArgb(0000); 
 
       MARGINS margins = new MARGINS 
           { cxLeftWidth = -1, cxRightWidth = 0, cyTopHeight = 0, cyBottomHeight = 0 }; 
       DwmExtendFrameIntoClientArea(handle, margins); 
   } 
 
   [StructLayout(LayoutKind.Sequential)] 
   public class MARGINS 
   { 
       public int cxLeftWidth; 
       public int cxRightWidth; 
       public int cyTopHeight; 
       public int cyBottomHeight; 
   } 
 
   [DllImport("dwmapi.dll", PreserveSig = false)] 
   public static extern void DwmExtendFrameIntoClientArea( 
       IntPtr hWnd, MARGINS pMargins); 
} 
 
 
XAML
スクリプトの編集|{#scriptcode_dlg.remove_script}
<Window x:Class="WpfWindowHandleApplication.MainWindow" 
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       Title="MainWindow" Height="350" Width="525" 
       Loaded="Window_Loaded" Background="Transparent"> 
   <Grid> 
 
   </Grid> 
</Window>
 

 

実行結果


ポイント

ここでは、Windows Vista や Windows 7 の Aero Glass を使って WPF アプリケーションの背景を半透明化しています。WPF はウィンドウのクライアント領域を描画しますが、Aero Glass は WPF の機能ではなく、タイトル バーや枠の描画は Windows 自身に任されています。ここでは、四辺の枠の太さのうち左側を最大値にすることで、ウィンドウ全体を枠として半透明で描画します。このとき、WPF のウィンドウの背景 (Background プロパティ) は Transparent (透明) に設定しておかなければなりません。

※Aero Glass が有効でない環境では試すことができません。

ウィンドウ ハンドルのような WPF 以外と連携するための機能は、System.Windows.Interop 名前空間で定義されています。HwndSource は、WPF コンテンツを格納する Win32 のウィンドウを実装します。このオブジェクトの Handle プロパティがウィンドウ ハンドルです。ここでは、Aero Glass を使って枠をクライアント領域に延長する API、DwmExtendFrameIntoClientArea に、このウィンドウ ハンドルを渡しています。

WPF で、デスクトップのドット密度 (DPI) を取得したい場合にもウィンドウ ハンドルが使えます。あらかじめ、Windows フォームで使われる System.Drawing アセンブリを参照として追加しておき、次のようにプログラムします。

C#
private void button1_Click(object sender, RoutedEventArgs e) 
{ 
   HwndSource source = HwndSource.FromVisual(this) as HwndSource; 
   System.Drawing.Graphics desktop = System.Drawing.Graphics.FromHwnd(source.Handle); 
   MessageBox.Show(string.Format("DpiX: {0}, DpiY: {1}", desktop.DpiX, desktop.DpiY)); 
} 
 
 

なお、ウィンドウ ハンドルに送られるメッセージを処理したい場合は、HwndSource オブジェクトの AddHook メソッドを使って、メッセージを横取りできるようにします (解除する場合は、RemoveHook メソッドを使います)。次に簡単な例を示します。

C#
protected override void OnSourceInitialized(EventArgs e) 
{ 
   HwndSource source = HwndSource.FromVisual(thisas HwndSource; 
   source.AddHook(WndHookProc); 
 
   base.OnSourceInitialized(e); 
} 
 
private IntPtr WndHookProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
{ 
   // メッセージ処理 
   return IntPtr.Zero; 
} 
 
 

WPF は、Windows 自身とのやりとりを WPF 自身の中に隠ぺいすることで、ウィンドウ ハンドルやメッセージを考えずにプログラミングできます。特に必要がなければ、できるだけウィンドウ ハンドルを使わないようにプログラミングすることが望ましいでしょう。 


Code Recipe Code Recipe

ページのトップへ