2006年01月22日
川俣晶の縁側ソフトウェア技術雑記total 12902 count

C++/CLIとSetWindowsHookEx APIを使ったキーボードフックの試行

Written By: 川俣 晶連絡先

 NyaRuRuさんが■[.NET]C++/CLIなら面倒は無い?で、私の書いた「余談」に意見を述べていただきました。

 そこで、実際にC++/CLIでキーボードフックのプログラムを書いてみました。

 昔のソースを引っ張り出して、ちょっと調べて出てきた断片的な情報をつなぎ合わせて書いたものなので、これで完全かどうかは分かりません。また、正しいかどうか、適切かどうかも分かりません。ま、とりあえず動くことは動いた……ということで (汗。

ソース一式 §

 とりあえず動いた状態のツリー丸ごと(一部削除)です。

 Debugディレクトリの実行ファイルを走らせると動きます。

Visual Studio 2005用サンプルソース

 正常に動作した場合、別ウィンドウのウィンドウアプリケーションにフォーカスを設定してTABキーを押すとBeepが鳴ります。

コンセプト §

 面倒なことは全て優秀なマーシャラーにお任せ、ということで難しいことは何も考えていません。

 基本的には、以下の2段構造です。

  • フックDLLを起動するC++/CLIのコンソールアプリケーション
  • C++/CLIで書いたmanagedなフックDLL本体 (C++/CLIのクラスライブラリのプロジェクト)

 自分で書いたコードは、基本的に全てmanagedコードとして動作します。unmanagedコードとの境界は、自動的に挿入されるC++/CLIのマーシャラーがすべて受け持ちます。

問題点 §

 実行を終了させてもフックDLLをどこかのプロレスが持ち続けて解放しない、という現象が起きるようです。DLLをどこでロード、アンロードするかはシステムに任せっきりなので、そのあたりをもうちょっと煮詰める必要があるでしょう。ただし、アーキテクチャ的に解決可能な問題なのか、それともできないのかは分かりません。

サンプルソースの主要部分 §

// hookdll.h

#pragma once

using namespace System;

namespace hookdll {

static HHOOK hhook;

extern "C" LRESULT CALLBACK KeyboardProc( int code, 

           WPARAM wParam, LPARAM lParam )

{

    //Console::WriteLine("here!");

    if( code < 0 ) return CallNextHookEx( hhook, code, wParam, lParam );

    if( wParam == VK_TAB ) {

        MessageBeep(0);

    }

    //return 0;

    return CallNextHookEx( hhook, code, wParam, lParam );

}

    public ref class Hooker

    {

    public:

        void static SetHook()

        {

           MessageBeep(0); // 音が出ることを確認するために、ここで1回鳴らしておく

           HINSTANCE hInstance;

           BOOL result = GetModuleHandleEx(

                         GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS

                         |GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,

                (LPCTSTR)KeyboardProc,

                (HMODULE*)&hInstance );

            Console::WriteLine("hInstance={0}",(int)hInstance);

            Console::WriteLine("result of GetModuleHandleEx={0}",result);

            hhook = SetWindowsHookEx( WH_KEYBOARD, 

                (HOOKPROC)KeyboardProc, hInstance/*hInst*/, NULL );

            Console::WriteLine("hhook={0}",(int)hhook);

        }

        void static ResetHook()

        {

            BOOL result = UnhookWindowsHookEx( hhook );

            Console::WriteLine("result of UnhookWindowsHookEx={0}",result);

        }

    };

}

感想 §

 半ば予想されたこととはいえ、あまりにもあっさりしたコードで実現したのはびっくり。

 しかも、10年以上前に書いたフックのソースをちょいちょいと手直ししただけなのに。

 しかし、休日出勤してるのに、こんなものを書いてる暇はないのだ! 仕事をしなさい→私。

(2006年1月25日追記)上記のコードには欠陥 §

 上記のコードには欠陥があることをNyaRuRuさんが明らかにしました。

 下記参照。

Facebook

トラックバック一覧

2006年01月24日[.NET]混合モード DLL の直接ロードFrom: NyaRuRuの日記

川俣さんに折角サンプルコードを作っていただいたので,ちょっとばかし実験. C++/CLIとSetWindowsHookEx APIを使ったキーボードフックの試行 実験用に川俣さんのサンプルコードを書換えさせていただきました.修正後のソースとバイナリはこちらにおいておきます. http://www.dwahan.net/nyaruru/hatena/cppclihooktest003.zip まず DLL にこんな感じで Export 関数を作成し,現在使用中の .NET Framework のバージョンを ... 続きを読む

キーワード【 川俣晶の縁側ソフトウェア技術雑記
【技術雑記】の次のコンテンツ
2006年
01月
25日
続・C++/CLIとSetWindowsHookEx APIを使ったキーボードフックの試行
3days 0 count
total 5121 count
【技術雑記】の前のコンテンツ
2006年
01月
04日
ソフト冒険記・ソースコードの重複を調べるSimian - Similarity Analyser
3days 0 count
total 5886 count

このコンテンツを書いた川俣 晶へメッセージを送る

[メッセージ送信フォームを利用する]

メッセージ送信フォームを利用することで、川俣 晶に対してメッセージを送ることができます。

この機能は、100%確実に川俣 晶へメッセージを伝達するものではなく、また、確実に川俣 晶よりの返事を得られるものではないことにご注意ください。

このコンテンツへトラックバックするためのURL

http://mag.autumn.org/tb.aspx/20060122170124
サイトの表紙【技術雑記】の表紙【技術雑記】のコンテンツ全リスト 【技術雑記】の入手全リスト 【技術雑記】のRSS1.0形式の情報このサイトの全キーワードリスト 印刷用ページ

管理者: 川俣 晶連絡先

Powered by MagSite2 Version 0.34 (Alpha-Test) Copyright (c) 2004-2018 Pie Dey.Co.,Ltd.