WH_CBT フックを使用して、アプリの起動を検知する [C++Builder]

自アプリ以外のアプリが起動したことを検知する方法です。

WH_CBT フックをグルーバルフック指定で起動すると、自アプリ以外のアプリのウィンドウ作成やフォーカス取得時のイベントを処理できるようになります。これらのイベントを利用してアプリの起動を検知できるようにします。

説明を飛ばしてコードを見る方はこちら → コード

他のアプリの起動を検知したい

自分以外のアプリが起動したことを検知できるようにします。  

起動中のアプリ一覧を表示するようなアプリは、後から起動したアプリでも一覧に追加されるようにしたいものです。一定間隔で起動しているアプリ一覧を取得して画面を再描画する方法もありますが、必要の無いときにも動作することにもなりますし、タイミングによっては画面が更新されていません。起動したことを検知して、更新ボタンなどを押さなくても一覧を更新できるようにした方が便利です。

このページでは、起動したアプリを検知する方法を記載します。

検知のしかた

自分以外の他アプリの起動を検知するには WH_CBT フックを使用します。WH_CBT フックをグローバルック指定で開始すると、各アプリのウィンドウ作成やフォーカス取得の発生を知ることが出来ます。

必要なファイル

フック用の DLL を作成する

WH_CBT フックを実装するには、自アプリである実行可能ファイル(exe) の他に、フック用の DLL を作る必要があります。32bit と 64bit アプリの両方の起動を検出したい場合には、それぞれ用意する必要があります。

このページでは、自アプリである実行可能ファイル を MyApp.exe、フック用の DLL を CbtHook.dll として記載します。

なぜフック用の DLL が必要か

フック用の DLL が各アプリにアタッチするためです。ライブラリである DLL が各アプリにアタッチすることで、アタッチしたアプリのイベントを処理することが出来ます。

グローバルフックを開始するとフック用の DLL は各アプリにアタッチします。アタッチした状態でイベントが発生すると、フック開始時に登録したコールバック関数(例では _CbtHook()) が呼ばれ、アタッチ先で発生したウィンドウ生成やフォーカス取得などを処理することが出来ます。

動作の流れ

フックを使用したときの大まかな動作の流れです。

自アプリ起動時にフックを開始する

まず自分のアプリが起動したときに WH_CBT フックをグローバルフック指定で開始します。

フック用の DLL、CbtHook.dll をロードし、DLL 側に実装したフック開始関数を呼び、フック開始関数の中で SetWindowsHookEx() を WH_CBT フックをグローバルフックで開始します。フックを開始すると、起動中の全てのアプリに CbtHook.dll がアタッチしてイベントを受け取れる状態になります。

起動していたアプリでイベントが発生すると自アプリに通知される

各アプリでフォーカス取得などのイベントが発生すると、フック開始時に登録したコールバック関数(例では _CbtHook()) が呼ばれます。フォーカス取得のイベントを受け取ったら PostMessage() で自分のアプリにイベントの発生を通知するようにします。

新しく起動したアプリからもイベントが自アプリに通知される

アプリが起動したことも検知できます。

下図は notepad.exe を後から起動したときの例です。後から起動した notepade.exe にも CbtHook.dll はアタッチされて WH_CBT のイベントを受け取れるようになります。_CbtHook() がウィンドウ作成やフォーカス取得のイベントで呼ばれるので、PostMessage() で自分のアプリ宛に通知することでアプリが起動したことを知るが出来ます。

どのフックコードを「アプリ起動」と判定するか

掲載しているコードでは「HCBT_ACTIVATE か HCBT_SETFOCUS をアプリ起動と判定する」としています。

なぜこのような判定にしたのか実際のログを見て考えてみます。次のログが実際にメモ帳を起動したときのログです。

2024/10/21(Mon) 21:55:40.788 HCBT_CREATEWND    hWnd=0x0012110e class=OleMainThreadWndClass text=OLEChannelWnd
2024/10/21(Mon) 21:55:40.788 HCBT_CREATEWND    hWnd=0x000b10e6 class=OleMainThreadWndClass text=OLEChannelWnd
2024/10/21(Mon) 21:55:40.806 HCBT_CREATEWND    hWnd=0x000a0d56 class=OleMainThreadWndClass text=OLEChannelWnd
2024/10/21(Mon) 21:55:40.831 HCBT_CREATEWND    hWnd=0x000d1124 class=OleMainThreadWndClass
2024/10/21(Mon) 21:55:40.867 HCBT_CREATEWND    hWnd=0x0005115c class=Windows.UI.Core.CoreWindow
2024/10/21(Mon) 21:55:40.873 HCBT_CREATEWND    hWnd=0x00061156 class=SystemUserAdapterWindowClass
2024/10/21(Mon) 21:55:40.893 HCBT_CREATEWND    hWnd=0x00251136 class=IME text=Default IME
2024/10/21(Mon) 21:55:40.904 HCBT_CREATEWND    hWnd=0x0007117c class=OleMainThreadWndClass text=OLEChannelWnd
2024/10/21(Mon) 21:55:40.915 HCBT_CREATEWND    hWnd=0x001f1120 class=XCPTimerClass text=XCP
2024/10/21(Mon) 21:55:40.927 HCBT_CREATEWND    hWnd=0x002e1122 class=XAMLMessageWindowClass
2024/10/21(Mon) 21:55:40.937 HCBT_CREATEWND    hWnd=0x000e0338 class=Notepad text=メモ帳
2024/10/21(Mon) 21:55:40.964 HCBT_CREATEWND    hWnd=0x001010fa class=Windows.UI.Composition.DesktopWindowContentBridge text=DesktopWindowXamlSource
2024/10/21(Mon) 21:55:40.991 HCBT_CREATEWND    hWnd=0x00051158 class=Windows.UI.Input.InputSite.WindowClass
2024/10/21(Mon) 21:55:41.013 HCBT_ACTIVATE     hWnd=0x000e0338 class=Notepad text=メモ帳
2024/10/21(Mon) 21:55:41.025 HCBT_SETFOCUS     hWnd=0x000e0338 class=Notepad text=メモ帳
2024/10/21(Mon) 21:55:41.034 HCBT_CREATEWND    hWnd=0x00051152 class=
2024/10/21(Mon) 21:55:41.049 HCBT_DESTROYWND   hWnd=0x00051152 class=
2024/10/21(Mon) 21:55:41.060 HCBT_CREATEWND    hWnd=0x00061152 class=CicMarshalWndClass text=CicMarshalWnd
2024/10/21(Mon) 21:55:41.079 HCBT_CREATEWND    hWnd=0x001c113e class=MSCTFIME UI text=MSCTFIME UI
2024/10/21(Mon) 21:55:41.091 HCBT_CREATEWND    hWnd=0x00071130 class=Windows.UI.Composition.DesktopWindowContentBridge text=DesktopWindowXamlSource
2024/10/21(Mon) 21:55:41.122 HCBT_CREATEWND    hWnd=0x0005113a class=Windows.UI.Input.InputSite.WindowClass
2024/10/21(Mon) 21:55:41.136 HCBT_CREATEWND    hWnd=0x0008112a class=Windows.UI.Composition.DesktopWindowContentBridge text=DesktopWindowXamlSource
2024/10/21(Mon) 21:55:41.152 HCBT_CREATEWND    hWnd=0x002a0cae class=Windows.UI.Input.InputSite.WindowClass
2024/10/21(Mon) 21:55:41.169 HCBT_CREATEWND    hWnd=0x00301128 class=Windows.UI.Composition.DesktopWindowContentBridge text=DesktopWindowXamlSource
2024/10/21(Mon) 21:55:41.185 HCBT_CREATEWND    hWnd=0x000e111e class=Windows.UI.Input.InputSite.WindowClass
2024/10/21(Mon) 21:55:41.185 HCBT_CREATEWND    hWnd=0x00081126 class=Windows.UI.Composition.DesktopWindowContentBridge text=DesktopWindowXamlSource
2024/10/21(Mon) 21:55:41.206 HCBT_CREATEWND    hWnd=0x00171052 class=Windows.UI.Input.InputSite.WindowClass
2024/10/21(Mon) 21:55:41.226 HCBT_CREATEWND    hWnd=0x000208d0 class=NotepadTextBox
2024/10/21(Mon) 21:55:41.243 HCBT_CREATEWND    hWnd=0x000208c8 class=IME text=Default IME
2024/10/21(Mon) 21:55:41.264 HCBT_CREATEWND    hWnd=0x00050d86 class=RichEditD2DPT
2024/10/21(Mon) 21:55:41.285 HCBT_CREATEWND    hWnd=0x000b033a class=OleMainThreadWndClass text=OLEChannelWnd
2024/10/21(Mon) 21:55:41.300 HCBT_CREATEWND    hWnd=0x00020a8e class=
2024/10/21(Mon) 21:55:41.327 HCBT_DESTROYWND   hWnd=0x00020a8e class=
2024/10/21(Mon) 21:55:41.342 HCBT_CREATEWND    hWnd=0x00030a8e class=CicMarshalWndClass text=CicMarshalWnd
2024/10/21(Mon) 21:55:41.359 HCBT_CREATEWND    hWnd=0x00161100 class=base_window_class
2024/10/21(Mon) 21:55:41.359 HCBT_SETFOCUS     hWnd=0x00050d86 class=RichEditD2DPT
2024/10/21(Mon) 21:55:41.382 HCBT_CREATEWND    hWnd=0x000510d2 class=MSCTFIME UI text=MSCTFIME UI
2024/10/21(Mon) 21:55:41.402 HCBT_CREATEWND    hWnd=0x00031146 class=SystemUserAdapterWindowClass

HCBT_CREATEWND が連続し、その後に HCBT_ACTIVATE/SETFOCUS が発生しています。続いてメインウィンドウに含まれる入力領域 RichEdit などを生成する HCBT_CREATEWND が連続し、HCBT_SETFOCUS が発生しています。最後に IME 生成の HCBT_CREATEWND で起動が完了します。

HCBT_CREATEWND が連続して HCBT_ACTIVE/SETFOCUS が来るという同じ流れが 2セット発生していますので、「HCBT_ACTIVATE か HCBT_SETFOCUS をアプリ起動と判定する」で十分です。また、最後の RichEdit まで待つ必要もなく、先に発生している HCBT_ACTIVE/SETFOCUS で判定すれば良いので、掲載しているコードは 「HCBT_ACTIVE か HCBT_SETFOCUS のどちらかが発生したらアプリが起動した」と判定することにします。

フックコードの説明は公式 CBTProc コールバック関数 (Windows) – Win32 apps | Microsoft Learn を参照ください。

コード

ファイル構成

自アプリである実行可能ファイルとフック用の DLL を作ります。それぞれ、自アプリは MyApp.exe、フック用の DLL は CbtHook.dll という名前としています。

MyApp.exe

自アプリです。自アプリの起動時にフックを開始し、他のアプリが起動したときの通知を受けられるようにします。

FormMain.h

FormMain.h に、フックに関する変数と関数を追加します。11行目のインクルードと private 内が追加部分です。

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>

#include "cbt_hook.h" // CbtHook.dll 使うためのインクルードファイル

class TForm1 : public TForm
{
private:	// ユーザー宣言
  // CbtHook.dll のモジュールのハンドル。LodLibrary() したときの返値。
  HINSTANCE m_hHookInst = NULL;

  // CbtHook.dll から PostMessage される ウィンドウメッセージの ID。
  Cardinal m_hookMessageId = NULL;

  // CbtHook.dll の関数
  GetHookMessage_t m_GetHookMessage;
  StartHook_t m_StartHookCBT;
  StopHook_t m_StopHookCBT;

  // CbtHook.dll の操作関数。
  void _StartCbtHook(); // ロードして WH_CBT フックを開始する
  void _StopCbtHook();  // 開放して WH_CBT フックを終了する

  // ウィンドウメッセージを受信する関数
  void __fastcall WndProc(Messages::TMessage &msg); // override TForm::WndProc
  void _WndProcHook(Messages::TMessage &msg); // call by WndProc()

public:		// ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

FormMain.cpp

FormMain.cpp に追加する処理です。イベントを受け取って実行したい処理は _WndProcHook() に追加してください。

void __fastcall TForm1::FormShow(TObject *Sender)
{
    // WH_CBT フックを開始する
    _StartCbtHook();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
    // WH_CBT フックを終了する
    _StopCbtHook();
}
//---------------------------------------------------------------------------

void TForm1::_StartCbtHook()
{
    // CbtHook.dll のフルパスを作る。
    UnicodeString exePath = ExtractFilePath(Application->ExeName);
    UnicodeString hookDllPath = exePath + L"CbtHook.dll";

    // CbtHook.dll をロードする。
    m_hHookInst = LoadLibrary(hookDllPath.c_str());
    if (m_hHookInst == NULL) {
        // 失敗した (fileを削除しているなど)
        return;
    }

    // CbtHook.dll に実装している関数をロードする。
    m_GetHookMessage = (GetHookMessage_t)GetProcAddress(m_hHookInst, "GetHookMessage");
    m_StartHookCBT = (StartHook_t)GetProcAddress(m_hHookInst, "StartHookCBT");
    m_StopHookCBT = (StopHook_t)GetProcAddress(m_hHookInst, "StopHookCBT");
    if (m_GetHookMessage == NULL || m_StartHookCBT == NULL || m_StopHookCBT == NULL) {
        // load出来たが関数を取得出来ない
        FreeLibrary(m_hHookInst);
        m_hHookInst = NULL;
        return;
    }

    // CbtHook.dll から PostMessage される ウィンドウメッセージの ID を取得する。
    // 登録するメッセージ識別子は CbtHook.dll から GetHookMessage() で得た値を使う。
    UnicodeString HookMessage = m_GetHookMessage();
    m_hookMessageId = RegisterWindowMessage(HookMessage.c_str());
    if (m_hookMessageId == 0) {
        FreeLibrary(m_hHookInst);
        m_hHookInst = NULL;
        return;
    }

    // WH_CBT フックを開始する。 (CbtHook.dll に指示する)
    m_StartHookCBT(Handle);
}
//---------------------------------------------------------------------------

void TForm1::_StopCbtHook()
{
    if (m_hHookInst == NULL) return;

    // WH_CBT フックを終了する。 (CbtHook.dll に指示する)
    m_StopHookCBT();

    // CbtHook.dll を開放する。
    FreeLibrary(m_hHookInst);
	m_hHookInst = NULL;
    m_hookMessageId = NULL;
}
//---------------------------------------------------------------------------

//=============================================================================
//  Application側でメッセージ通知を受取る
//  ここではフォームのWndProcメソッドを使用
//=============================================================================
void __fastcall TForm1::WndProc(Messages::TMessage &msg)
{
    if (msg.Msg == m_hookMessageId) {
		// CbtHook.dll からの通知を受信した。
        _WndProcHook(msg);
    }

    // デフォルトの WndProc() を実行する。
    TForm::WndProc(msg);
}
//---------------------------------------------------------------------------

void TForm1::_WndProcHook(Messages::TMessage &msg)
{
    if (m_hookMessageId == NULL) return;

    UINT msgId = m_hookMessageId;
    WPARAM wParam = msg.WParam;
    int nCode = (int)msg.LParam;

    switch (nCode) {
        // wParam = hWnd イベント
        case HCBT_CREATEWND:
        case HCBT_DESTROYWND:
            break;
        case HCBT_ACTIVATE:
        case HCBT_SETFOCUS:
            // ここにイベントを受信したときの処理を書く
            break;
        case HCBT_MOVESIZE:
        case HCBT_MINMAX:
        case HCBT_SYSCOMMAND:
        case HCBT_CLICKSKIPPED:
        case HCBT_KEYSKIPPED:
        case HCBT_QS:
        default:
            break;
    }  // switch (cd->dwData)
    return;
}

CbtHook.dll

フック用 DLL です。WH_CBT フックをグローバルフック指定で開始します。コールバック関数として 登録した _CbtProc() でフックイベントを受け取って、自アプリに PostMessage() で通知します。

cbt_hook.h

CbtHook.dll の関数を呼ぶためのインクルードファイルです。FormMain.h で #include します。

#ifndef CBT_HOOK_H
#define CBT_HOOK_H

// CbtHook.dll の型宣言
typedef char * __stdcall (*GetHookMessage_t)(void);
typedef bool __stdcall (*StartHook_t)(HWND);
typedef void __stdcall (*StopHook_t)(void);

#endif // CBT_HOOK_H

CbtHookUnit.h

CbtHook.dll 本体のヘッダーファイルです。

#ifndef HOOKUNIT_H
#define HOOKUNIT_H

#include <windows.h>

#include "cbt_hook.h" // CbtHook.dll を使うためのインクルードファイル
#ifdef _HOOK_CPP
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif

extern "C" DECLSPEC const char *__stdcall GetHookMessage();
extern "C" DECLSPEC bool __stdcall StartHookCBT(HWND);
extern "C" DECLSPEC void __stdcall StopHookCBT();

// 共有メモリの内容の構造体
struct THookInfo {
    HWND hWndHookOwner;  // 通知を受け取るアプリのウィンドウハンドル
    UINT msgId;                 // 通知時のメッセージID
};

#endif /* HOOKUNIT_H */

CbtHookUnit.cpp

CbtHook.dll の本体です。g_HookMessage と g_MapFileName はシステム全体で一意となる文字列にする必要があります。9行目と10行目の両方を自分のアプリに合わせた値に変更してください。

//---------------------------------------------------------------------------
#include <windows.h>
#include "cbt_hook.h" // CbtHook.dll を使うためのインクルードファイル
#define _HOOK_CPP
#include "CbtHookUnit.h"

// グローバル変数 ............................................................
// 識別子 - システム全体で一意となる文字列にすること。
const char *g_HookMessage = "MyApp_CbtHookMsg";  // 自アプリ宛メッセージ識別子
const char *g_MapFileName = "MyApp_CbtHookMapFile";  // 共有マップファイル名

// フックの開始/終了を制御する自exeにアタッチした CbtHook.dll のみ知っている情報。
HHOOK g_HookHandleCBT = NULL;  // SetWindowsHookEx() で得たハンドル。

// DLL_PROCESS_ATTACH した各々のexeで異なる値が入る変数。
// g_hookDataには、フックが挿入される全アプリで共有したいデータを入れる。
// フックで取得した情報の通知先の自アプリのウィンドウハンドルなど。
HINSTANCE g_hinstDLL = NULL;
HANDLE g_hMapFile = NULL;
THookInfo *g_tHookInfo = NULL;

// 内部関数プロトタイプ宣言 ..................................................
bool _DllProcessAttach(HINSTANCE, LPVOID);
void _DllProcessDetach(LPVOID);
bool _MapHookData();
void _UnmapHookData();
LRESULT CALLBACK _CbtProc(int, WPARAM, LPARAM);
void _HandleHookEvent(int, WPARAM, LPARAM);
bool _IsEventOccuredOwnWnd(HWND, HWND);

#pragma argsused
//=============================================================================
// DllMain()
//=============================================================================
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved)
{
    switch (fwdreason) {
        case DLL_PROCESS_ATTACH:  // ロードされるときの処理
            if (_DllProcessAttach(hinstDLL, lpvReserved) == false) return FALSE;
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:  // アンロードされるときの処理
            _DllProcessDetach(lpvReserved);
            break;
    }
    return TRUE;
}

//---------------------------------------------------------------------------
// _DllProcessAttach()
//---------------------------------------------------------------------------
bool _DllProcessAttach(HINSTANCE hinstDLL, LPVOID lpvReserved)
{
    if (g_hinstDLL) return true;

    // Dll instanceの保存
    g_hinstDLL = hinstDLL;

    // メモリマップドファイルの作成
    if (_MapHookData() == false) {
        _UnmapHookData();
        return false;
    }

    return true;
}

//---------------------------------------------------------------------------
// _DllProcessDetach()
//---------------------------------------------------------------------------
void _DllProcessDetach(LPVOID lpvReserved)
{
    if (g_hinstDLL == NULL) return;

    // フックの停止
    StopHookCBT();

    //  メモリマップドファイルのクローズ
    _UnmapHookData();

    // 保存した Dll instance のクリア
    g_hinstDLL = NULL;
}

//=============================================================================
// GetHookMessage() - Application側でメッセージ通知を受取るために
// RegisterWindowMessage する関数
//=============================================================================
extern "C" __declspec(dllexport) const char *__stdcall GetHookMessage()
{
    return g_HookMessage;
}

//=============================================================================
// StartHookCBT() - WH_CBT フック関数の登録/解除
// 登録するフック関数は _CbtProc()
// PARAMETER
//   HWND hWnd :
//       フックイベント発生時に通知を受け取るウィンドウのハンドル
//=============================================================================
extern "C" __declspec(dllexport) bool __stdcall StartHookCBT(
    HWND hWnd)
{
    if (g_tHookInfo == NULL) return false;

    if (g_HookHandleCBT != NULL)
        // フックが解除されていない.
        return true;

    // フック情報構造体初期化とフック関数の登録
    g_tHookInfo->hWndHookOwner = hWnd;

    // アプリケーションへ通知するメッセージを登録
    g_tHookInfo->msgId = RegisterWindowMessage(g_HookMessage);
    if (g_tHookInfo->msgId == 0) {
        return false;
    }

    // WH_CBT フック開始 - _CbtProc() をフックチェーンにインストールする
    g_HookHandleCBT = SetWindowsHookEx(
        /* idHook    =*/WH_CBT,
        /* lpFn      =*/(HOOKPROC)_CbtProc,
        /* hmod      =*/g_hinstDLL,
        /* dwThreadId=*/0);
    if (g_HookHandleCBT == NULL) {
        // 失敗してるので失敗(false)を返す.
        return false;
    }

    // フック成功
    return true;
}

//=============================================================================
// StopHookCBT() - フックの解除
//=============================================================================
extern "C" __declspec(dllexport) void __stdcall StopHookCBT()
{
    if (g_HookHandleCBT == NULL) return;

    // フック解除 - _CbtProc() をフックチェーンから削除する
    BOOL ret = UnhookWindowsHookEx(g_HookHandleCBT);
    if (ret == 0) {
        return;
    }

    g_HookHandleCBT = NULL;
    return;
}

//-----------------------------------------------------------------------------
// _MapHookData() - メモリマップドファイルの作成
//-----------------------------------------------------------------------------
bool _MapHookData()
{
    if (g_hMapFile) return false;
    if (g_tHookInfo) return false;

    g_hMapFile = CreateFileMapping(
        /* hFile = */ (HANDLE)INVALID_HANDLE_VALUE,
        /* lpFileMappingAttributes = */ NULL,
        /* flProtect         = */ PAGE_READWRITE,
        /* dwMaximumSizeHigh = */ 0,
        /* dwMaximuSizeLow   = */ sizeof(THookInfo),
        /* lpName            = */ g_MapFileName);
    if (g_hMapFile == NULL) {
        return false;
    }

    g_tHookInfo = (THookInfo *)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS,
                                               0, 0, sizeof(THookInfo));
    if (g_tHookInfo == NULL) {
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------
// _UnmapHookData() - メモリマップドファイルの破棄
//-----------------------------------------------------------------------------
void _UnmapHookData()
{
    if (g_HookHandleCBT != NULL) return;

    if (g_tHookInfo) {
        if (UnmapViewOfFile(g_tHookInfo) == 0) {
            return;
        }
        g_tHookInfo = NULL;
    }

    if (g_hMapFile) {
        CloseHandle(g_hMapFile);
        g_hMapFile = NULL;
    }
}

//=============================================================================
// フックのコールバック関数
//=============================================================================
LRESULT CALLBACK _CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0) {
        // 0以上ならフックイベントを処理する
        _HandleHookEvent(nCode, wParam, lParam);
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

//-----------------------------------------------------------------------------
// _HandleHookEvent
//-----------------------------------------------------------------------------
void _HandleHookEvent(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (g_tHookInfo == NULL) return;  // 共有メモリが未作成なら処理しない

    // 共有データに入っている情報を変数に取り出す
    HWND hWndHookOwner = (g_tHookInfo) ? g_tHookInfo->hWndHookOwner : NULL;
    UINT msgId = (g_tHookInfo) ? g_tHookInfo->msgId : NULL;
    if (hWndHookOwner == NULL) return;
    if (msgId == NULL) return;

    // イベントを処理する
    switch (nCode) {
        case HCBT_CREATEWND:  // 3 ウィンドウが作成されようとしている
        case HCBT_DESTROYWND:  // 4 ウィンドウが破棄されようとしている
            break;
        case HCBT_ACTIVATE:    // 5 システムがウィンドウをアクティブ化しようとしている
        case HCBT_SETFOCUS:    // 9 ウィンドウがキーボードフォーカスを受け取ろうとしている
            // HCBT_CREATEWND ではなく、HCBT_ACTIVATE/SETFOCCUS をアプリ起動として
            // 使用する。連続発生する HCBT_CREATEWND ではウィンドウタイトル等の情報が
            // 取れるタイミングが分からないため。情報取得できる HCBT_ACTIVE/SETFOCUS
            // を起動の検知に使用する。
            // PostMessage()したメッセージは、TForm1::WndProc()で受信される。
            // FormMain.cpp も CbtHookUnit.cpp も g_HooMessage の同じ文字列で
            // RegisterWindowMessage() して msgId を得ているので、同じ値であれば
            // CbtHookUnit -> FormMain と投げられたメッセージであると識別できる。
            PostMessage(hWndHookOwner, msgId, (WPARAM)wParam, (LPARAM)nCode);            
            break;
        case HCBT_MOVESIZE:    // 0 ウィンドウが移動/サイズ変更されようとしている
        case HCBT_MINMAX:      // 1 最大化/最小化
        case HCBT_SYSCOMMAND:  // 8 システムコマンドが実行されようとしている
        case HCBT_CLICKSKIPPED:// 6 システムメッセージキューからマウスメッセージを削除した
        case HCBT_KEYSKIPPED:  // 7 システムメッセージ待ち行列からキーボードメッセージを除去した
        case HCBT_QS:          // 2 システムメッセージ待ち行列から WM_QUEUESYNC メッセージを取り出した
        default:
            break;
    }  // switch(nCode)
}

参考

コメント