WPF
tips

WPFアプリケーションでウィンドウプロシージャをフックする

More than 3 years have passed since last update.

WPFアプリケーションでウィンドウプロシージャをフックしたい場合、HwndSource.FromHwndメソッドを呼び出して、HwndSourceオブジェクトを取得し、そのオブジェクトに対してHwndSource.AddHookメソッドを呼び出すことで行います。

MSDN : HwndSource クラス (System.Windows.Interop)

以下のコードは、WPFでは通常取得できない、ALT+F4キーの押下を検知して無効化するサンプルです。
当たり前ですがフックをWindowの生成が終わった後でないとエラーになります。サンプルでは、MainWindowクラスのLoadedイベント内でフックを実行しています。

WindowHookSample.xaml
<Window x:Class="WindowHookSample.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">
    <Grid>
        <Button Name="CloseButton" Content="Close" VerticalAlignment="Center" HorizontalAlignment="Center" Width="100" Height="40" />
    </Grid>
</Window>

WindowHookSample.xaml.cs
using System;
using System.Windows;
using System.Windows.Interop;

namespace WindowHookSample
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private static readonly int WM_SYSKEYDOWN = 0x0104;
        private static readonly int VK_F4 = 0x73;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            Loaded += (o, e) =>
            {
                var source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
                source.AddHook(new HwndSourceHook(WndProc));
            };

            CloseButton.Click += (o, e) => { Close(); };
        }

        /// <summary>
        /// ウィンドウプロシージャ
        /// </summary>
        /// <param name="hwnd">IntPtr : ウィンドウハンドル</param>
        /// <param name="msg">int : メッセージ</param>
        /// <param name="wParam">IntPtr : パラメータ</param>
        /// <param name="lParam">IntPtr : パラメータ</param>
        /// <param name="handled">ref book : ハンドルフラグ</param>
        /// <returns>IntPtr</returns>
        private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            // ALT+F4キーを無効化する
            if ((msg == WM_SYSKEYDOWN) && (wParam.ToInt32() == VK_F4))
                handled = true;
            return IntPtr.Zero;
        }
    }
}