Windowsキーの無効化

最近、息子(2歳)がパソコンのキーボードで遊ぶようになりました。で、一度シャットダウンされてしまったので、それ以降はロックするようにしていました。ですが、多少は触らせてあげたいなぁと思い、息子用のデスクトップを作成することにしました。
そこで問題となったのがWindowsキーです。Formを作ってFormBorderStyleをNoneにして、WindowStateをMaximizedにすればそれっぽい画面にはなりますが、Windowsキーを押すとスタートメニューが開いてシャットダウンされる危険性が高くなります(実際、以前もWindowsキー経由でシャットダウンされました)。そこで、Windowsキーを無効化する方法について調査しました。

結論としては、Windowsキーを無効化するには低水準フック(グローバルフック)を利用する必要がありました。以下がVB.NETの実装ソースです。

Imports System.Runtime.InteropServices

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        InitKeyboard()
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Me.WindowState = FormWindowState.Maximized
    End Sub

    'Declare the keybord hook constant.
    'For other hook types, obtain these values from Winuser.h in Microsoft SDK.
    Dim WH_KEYBOARD_LL As Integer = 13
    Shared hHook As Integer = 0

    'Keep the reference so that the delegate is not garbage collected.
    Private hookproc As CallBack

    Public Delegate Function CallBack( _
        ByVal nCode As Integer, _
        ByVal wParam As IntPtr, _
        ByVal lParam As IntPtr) As Integer

    'Import for the SetWindowsHookEx function.
    <DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
     Public Overloads Shared Function SetWindowsHookEx _
          (ByVal idHook As Integer, ByVal HookProc As CallBack, _
           ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
    End Function

    'Import for the GetModuleHandle function.
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
     Public Overloads Shared Function GetModuleHandle _
           (ByVal lpModuleName As String) As IntPtr
    End Function

    'Import for the CallNextHookEx function.
    <DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
     Public Overloads Shared Function CallNextHookEx _
          (ByVal idHook As Integer, ByVal nCode As Integer, _
           ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    End Function

    'Import for the UnhookWindowsHookEx function.
    <DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
         Public Overloads Shared Function UnhookWindowsHookEx _
              (ByVal idHook As Integer) As Boolean
    End Function

    'KeyboardHookStruct structure declaration.
    <StructLayout(LayoutKind.Sequential)> Public Structure KeyboardLLHookStruct
        Public vkCode As Integer
        Public scanCode As Integer
        Public flags As Integer
        Public time As Integer
        Public dwExtraInfo As Integer
    End Structure

    Private Sub InitKeyboard()
        hookproc = AddressOf KeybordHookProc
        hHook = SetWindowsHookEx(WH_KEYBOARD_LL, hookproc, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0)
        If hHook.Equals(0) Then
            MsgBox("SetWindowsHookEx Failed")
        End If
    End Sub

    Public Shared Function KeybordHookProc( _
        ByVal nCode As Integer, _
        ByVal wParam As IntPtr, _
        ByVal lParam As IntPtr) As Integer

        If (nCode < 0) Then
            Return CallNextHookEx(hHook, nCode, wParam, lParam)
        End If

        Dim hookStruct As New KeyboardLLHookStruct()
        hookStruct = CType(Marshal.PtrToStructure(lParam, hookStruct.GetType()), KeyboardLLHookStruct)

        Select Case hookStruct.vkCode
            Case Keys.LWin, Keys.RWin
                Return 1
        End Select

        Return CallNextHookEx(hHook, nCode, wParam, lParam)
    End Function

    Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        Dim ret As Boolean = UnhookWindowsHookEx(hHook)
        If ret.Equals(False) Then
            MsgBox("UnhookWindowsHookEx Failed")
        End If
    End Sub
End Class

以下のページ(※1)が非常に参考になりました。4月から育児休暇を取得していたので、ゼロから学ぶVisualBasic(※2)を片手にVB.NETについて勉強を始めたのですが、やっぱりWindowsを操作できるのって楽しいですね。仕事ではJavaしか扱っていなかったのですが、あまりに簡単にWindowsアプリを作れることにビックリしています。

※1 http://www.ailight.jp/BBS/Detail.aspx?Header_ID=1784
   http://vsug.jp/tabid/63/view/topic/forumid/45/postid/1344/Default.aspx#1388
※2 http://itpro.nikkeibp.co.jp/article/MAG/20081113/319258/