愚者の経験

「また今度」はほとんどこない

VBAでサブクラス化に挑戦 1

サブクラス化とは「Windowからの情報(メッセージ)を先取りして処理しよう」というもので
「OSの仕組みとか詳しくない人は安易にサブクラス化しない」と説明に但し書きがあるものです。

私は詳しくない人ですが「VBAでスクロールを検知したい」という願望から
色々なページを参考に調べてみました。

参考URL:http://homepage1.nifty.com/rucio/main/tyukyu/tyukyu9.htm
失敗するとかなりやばいです。私はPCを強制終了するはめになりました…
運がよければタスクマネージャーを起動してMSACCESS.EXEのプロセス終了で持ち直せます。
どうもCPUの使用率が100%になっているっぽいです。
実験したコードは以下になります。(やってみたい人以外は実行しないでください。)
標準モジュールに以下を記述。

Option Explicit

Private Declare Function SetWindowLong Lib “user32” _
                Alias “SetWindowLongA” ( _
                ByVal Hwnd As Long, _
                ByVal nIndex As Long, _
                ByVal dwNewLong As Long) As Long

Private Declare Function CallWindowProc Lib “user32” _
                Alias “CallWindowProcA” ( _
                ByVal lpPrevWndFunc As Long, _
                ByVal Hwnd As Long, _
                ByVal Msg As Long, _
                ByVal wParam As Long, _
                ByVal lParam As Long) As Long

Private Const GWL_WNDPROC = -4
Private Const WM_VSCROLL = &H115
Dim lpprocs As New Collection

‘コールバック関数
Public Function WindowProc(ByVal Hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    Dim DefaultProc As Long

    If uMsg = WM_VSCROLL Then
        Debug.Print “縦スクロールしました。”
    End If

    DefaultProc = lpprocs(CStr(Hwnd))
    WindowProc = CallWindowProc(DefaultProc, Hwnd, uMsg, wParam, lParam)

End Function

Public Sub BeginSubClass(Target As Form)

    Dim DefaultProc As Long

    ‘サブクラス化
    DefaultProc = SetWindowLong(Target.Hwnd, GWL_WNDPROC, AddressOf WindowProc)

    lpprocs.Add  DefaultProc, CStr(Target.Hwnd)

End Sub

Public Sub EndSubClass(Target As Form)

    Dim Ret As Long
    Dim DefaultProc As Long

    DefaultProc = lpprocs(CStr(Target.Hwnd))
    Ret = SetWindowLong(Target.Hwnd, GWL_WNDPROC, DefaultProc)
    lpprocs.Remove CStr(Target.Hwnd)

End Sub

あとはフォームの「読み込み時」にBeginSubClassし、「読み込み解除時」にEndSubClassします。

大体の流れは
1.SetWindowLongでフォームにウィンドウプロシージャの設定を行う。
2.対象のフォームにメッセージが入ってくると標準モジュールのWindowProcが動作するので
  引数で動作を判定し個別に処理。
3.フォームを閉じる前にかならずウィンドウプロシージャを元に戻す。

でいいはずなんですが…どうもうまくいきません。
確かに動いていますが、しばらくするとOSごとフリーズしたような感じになります。
みなさん気をつけましょう(笑)

追記:サブフォームに対して行うとちゃんと動作しました。メインフォームだとフリーズします。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。