SAK 図書館
VB テクニック編31 - サブクラスコントロール、フックプロシジャ、メッセージ処理
■SAK 関数利用規程 ・テクニック編で紹介する関数は、私こと Y.SAK の開発関数である。 ・著作権明示部分の改編は認めない。 ・個人、企業がこれらの関数を使用したり、一部を使用して新たなシステムや プログラムを開発することは自由です。 ・但し、これらの関数を一部でも使用しているソフトウェアをシェアウェア、 その他有償プロダクトとして配布・販売するには、私の許可が必要です。 (無償のフリーソフトウェアなら、自由に配布しても良い。) ・これらの関数を使用して発生した、いかなる形での損害も私こと Y.SAK は 賠償しません。 ■ウィンドウプロシジャのサブクラスコントロール ・C 言語では、通常ウィンドウプロシジャで、メッセージイベント処理を行う。 しかし、VB では、サブクラス、フックと言う手法を使わない限り、ウィン ドウプロシジャを直接コードするようなことは出来ない。 C 言語による WndProc は次のような感じである。 LRESULT CALLBACK _export WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // メッセージ処理 switch (message) { // ドラッグ and ドロップ case WM_DROPFILES: ... // ウィンドウ作成 case WM_CREATE: ... // サイズ固定 case WM_GETMINMAXINFO: ... // サイズ変更 case WM_SIZE: ... // ウィンドウ移動 case WM_MOVE: ... // アクティブ case WM_ACTIVATE: ... // パレット変更 case WM_PALETTECHANGED: ... // フォーカス case WM_SETFOCUS: ... // 再画像 case WM_PAINT: ... // タイマー case WM_TIMER: ... // メニュー選択 case WM_COMMAND: ... // コントロールメニュー選択 case WM_SYSCOMMAND: ... // アイコンオープン case WM_QUERYOPEN: ... // ウィンドウクローズ case WM_CLOSE: ... // ウィンドウ廃棄 case WM_DESTROY: ... } // デフォルトメッセージ処理 return(DefWindowProc(hWnd, message, wParam, lParam)); } ・VB で、ウィンドウメッセージ処理を記述するには、例えば、サブクラスで 割り込みます。 サブクラスの場合、デフォルトメッセージ処理は、DefWindowProc には なりません。CallWindowProc で、他にもサブクラスしているかもしれない プロシジャを呼び出します。 WndProc は、必ず、コードモジュール(.bas) に配置して下さい。 ・VB では、自分に対するサブクラス化やフックプロシジャのインストールは 出来るが、他プログラムに対しては、うまく動かないようです。 C 言語であれば、DLL レベルにすれば、まったく問題ありません。 VB でも DLL にすれば、できるかもしれません。 public OldWndProc as long public const GWL_WNDPROC = -4 public const WM_SIZE = 5 public const WM_MOVE = 3 public function WndProc(ByVal hwindow as long, ByVal message as long, ByVal wParam as long, ByVal lParam as long) as long '** メッセージ処理 select case message case WM_SIZE ... case WM_MOVE ... end select '** デフォルトメッセージ処理 WndProc = CallWindowProc(OldWndProc, hwindow, message, wParam, lParam) end function ・サブクラスコントロールの開始は次のようにします。 一般的にサブクラスコントロール開始は、Form_Load などで最初に一度だけ 行います。(VB の予約語 HWND は、フォームのウィンドウハンドルです。) '** サブクラスコントロール開始 OldWndProc = GetWindowLong(HWND, GWL_WNDPROC) SetWindowLong HWND, GWL_WNDPROC, AddressOf WndProc ・サブクラスコントロールの終了は次のようにします。 一般的にサブクラスコントロール終了は、Form_Unload などで最後に一度だ け行います。 '** サブクラスコントロール終了 SetWindowLong HWND, GWL_WNDPROC, OldWndProc ・サブクラスコントロール以外に Hook 関数を使用したメッセージフックでも メッセージ処理できるかもしれません。少しパラメタや使用関数は違います が、基本的な考え方は似ています。 Private Declare Function GetWindowLongA Lib "user32" (ByVal hwd As Long, ByVal nIndex As Long) As Long Private Declare Function GetWindowLongW Lib "user32" (ByVal hwd As Long, ByVal nIndex As Long) As Long Private Declare Function SetWindowLongA Lib "user32" (ByVal hwd As Long, ByVal nIndex As Long, ByVal dt As Long) As Long Private Declare Function SetWindowLongW Lib "user32" (ByVal hwd As Long, ByVal nIndex As Long, ByVal dt As Long) As Long Private Declare Function CallWindowProcA Lib "user32" (ByVal oldproc As Long, ByVal hwd As Long, ByVal msg as long, ByVal wParam as long, ByVal lParam as long) as long Private Declare Function CallWindowProcW Lib "user32" (ByVal oldproc As Long, ByVal hwd As Long, ByVal msg as long, ByVal wParam as long, ByVal lParam as long) as long '======================================================================= ' Windows API GetWindowLong() '======================================================================= Public Function GetWindowLong(hwd As Long, nIndex As Long) As Long If GetOS() = VER_PLATFORM_WIN32_NT Then GetWindowLong = GetWindowLongW(hwd, nIndex) Else GetWindowLong = GetWindowLongA(hwd, nIndex) End If End Function '======================================================================= ' Windows API SetWindowLong() '======================================================================= Public Function SetWindowLong(hwd As Long, nIndex As Long, dt As Long) As Long If GetOS() = VER_PLATFORM_WIN32_NT Then SetWindowLong = SetWindowLongW(hwd, nIndex, dt) Else SetWindowLong = SetWindowLongA(hwd, nIndex, dt) End If End Function '======================================================================= ' Windows API CallWindowProc() '======================================================================= Public Function CallWindowProc(oldproc As Long, hwd As Long, msg as long, wParam as long, lParam as long) as long If GetOS() = VER_PLATFORM_WIN32_NT Then CallWindowProc = CallWindowProcW(oldproc, hwd, msg, wParam, lParam) Else CallWindowProc = CallWindowProcA(oldproc, hwd, msg, wParam, lParam) End If End Function ■フックプロシジャ ・フックプロシジャをインストールすることで、メッセージ処理を行うことも 出来る。VB では、サブクラス同様にシステム全体にフックするような事は できない。(DLL にすれば可能かもしれない。) ・以下のサンプルは正常に動作しない。(^^; どこかにミスがあるか、VB ではフックが使えないかのどちらかである。 (以前にテストしたときは、動かせたと思うのだが...) また、動作テストができなかったので、HOOKLPARAM 構造体が逆順かもしれ ない。(しおしお) Type HOOKLPARAM lParam As Long wParam As Long uMsg As Long hWnd As Long End Type public hInstance as long public ThreadId as long public hHook as long public const GWL_HINSTANCE = -6 public const WH_CALLWNDPROC = 4 public const WM_SIZE = 5 public const WM_MOVE = 3 public function CallWndProc(ByVal ncode as long, ByVal wParam as long, lParam as HOOKLPARAM) as long '** メッセージ処理 if ncode >= 0 then select case lParam.hWnd case WM_SIZE ... case WM_MOVE ... end select end if '** デフォルトメッセージ処理 CallWndProc = CallNextHookEx(hHook, ncode, wParam, lParam) end function ・フックの開始は次のようにします。 一般的にフック開始は、Form_Load などで最初に一度だけ行います。 (VB の予約語 HWND は、フォームのウィンドウハンドルです。) '** フック開始 hInstance = GetWindowLong(HWND, GWL_HINSTANCE) ThreadId = GetCurrentThreadId() hHook = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf CallWndProc, hInstance, ThreadId) ・フックの終了は次のようにします。 一般的にフック終了は、Form_Unload などで最後に一度だけ行います。 '** フック終了 UnhookWindowsHookEx hHook ・以下は、関連 API である。 Private Declare Function SetWindowsHookExA Lib "user32" (ByVal idhook As Long, ByVal hookproc As Long, ByVal hinstance as long, ByVal htask as long) as long Private Declare Function SetWindowsHookExW Lib "user32" (ByVal idhook As Long, ByVal hookproc As Long, ByVal hinstance as long, ByVal htask as long) as long Private Declare Function UnhookWindowsHookExA Lib "user32" (ByVal hhook As Long) as long Private Declare Function UnhookWindowsHookExW Lib "user32" (ByVal hhook As Long) as long Private Declare Function CallNextHookExA Lib "user32" (ByVal hhook As Long, ByVal ncode As Long, ByVal wPrame As Long, lParam As HOOKLPARAM) as long Private Declare Function CallNextHookExW Lib "user32" (ByVal hhook As Long, ByVal ncode As Long, ByVal wPrame As Long, lParam As HOOKLPARAM) as long Public Declare Function GetCurrentThreadId Lib "kernel32" () as long '======================================================================= ' Windows API SetWindowsHookEx() '======================================================================= Public Function SetWindowsHookEx(idhook As Long, hookproc As Long, hinstance as long, htask as long) as long If GetOS() = VER_PLATFORM_WIN32_NT Then SetWindowsHookEx = SetWindowsHookExW(idhook, hookproc, hinstance, htask) Else SetWindowsHookEx = SetWindowsHookExA(idhook, hookproc, hinstance, htask) End If End Function '======================================================================= ' Windows API UnhookWindowsHookEx() '======================================================================= Public Function UnhookWindowsHookEx(hhook As Long) as long If GetOS() = VER_PLATFORM_WIN32_NT Then UnhookWindowsHookEx = UnhookWindowsHookExW(hhook) Else UnhookWindowsHookEx = UnhookWindowsHookExA(hhook) End If End Function '======================================================================= ' Windows API CallNextHookEx() '======================================================================= Public Function CallNextHookEx(hhook As Long, ncode As Long, wPrame As Long, lParam As HOOKLPARAM) as long If GetOS() = VER_PLATFORM_WIN32_NT Then CallNextHookEx = CallNextHookExW(hhook, ncode, wPrame, lParam) Else CallNextHookEx = CallNextHookExA(hhook, ncode, wPrame, lParam) End If End Function ■VB テクニック編資料
■VB 入門編資料
■VB 基礎編資料
■VB ビジュアル編資料