0

私は win32 プログラミングの初心者であることを前置きします。

.dll を使用してグローバル キーボード フックを作成しています。キーボード フックの実際の設定と削除を処理するために、インストールとアンインストールの機能を追加しました。

#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
static HHOOK hk=NULL;
//static CMyFile *pLF;
#pragma data_seg()

HINSTANCE hins = NULL;

__declspec( dllexport ) LRESULT Install(){
    std::cout << "Installing" << std::endl;
    hk = SetWindowsHookEx(WH_KEYBOARD_LL,EventAnalysis::KeystrokeAnalysis::KeyboardCallback,hins,0);
    if(hk == NULL){
        std::cout << "Hook creation failed! - " << GetLastError() << std::endl;
    }
    return 0;
}


 __declspec(dllexport) BOOL CALLBACK UnInstall()
{
    std::cout << "UnInstalling" << std::endl;
    return UnhookWindowsHookEx(hk);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        hins = (HINSTANCE) hModule;
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

.dll ができたので、ライブラリをロードしてフックをインストールする単純な実行可能ファイルを作成しました。

int _tmain(int argc, _TCHAR* argv[])
{
    auto funHandle = LoadLibrary(L"C:\\Users\\tprodanov\\Documents\\visual studio 2010\\Projects\\HaveFun\\Release\\HaveFun.dll");
    if(funHandle == NULL){
        std::cout << "Library load failed! - " << GetLastError() << std::endl;
    }

    auto Install = (LRESULT(*)()) GetProcAddress(funHandle, "?Install@@YAJXZ");
    if(Install == NULL){
        std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
    }
    Install();

    MSG Msg;

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    auto Uninstall = (BOOL(*)()) GetProcAddress(funHandle, "?UnInstall@@YGHXZ");
    if(Uninstall == NULL){
        std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
    }
    Uninstall();
    return 0;
}

私が興味を持っているのは、私のプログラムの動作が現在の状態で期待どおりであることです (また、メッセージループの代わりに、ユーザーが [OK] をクリックするのを待つ MessageBox() をポップアウトした場合) ですが、そうではありませんstd::cin.get() または空の while ループを使用すると機能します。誰かがなぜこれが動作なのか説明できますか?

また、フォローアップの質問として、KeyboardCallback関数はコンソールに「キーが押されました」と出力するだけです。

LRESULT CALLBACK EventAnalysis::KeystrokeAnalysis::KeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam){
    std::cout << "Key pressed" << std::endl;
    return CallNextHookEx(NULL,nCode,wParam,lParam);
}

これは、コンソール ウィンドウにフォーカスしているときにキーを押したときにのみ出力されると予想していましたが、メモ帳に入力しても、.dll のインストール機能を呼び出した実行可能ファイルに「キーが押されました」というメッセージが表示されます。私が理解している限り、動的ライブラリはすべてのプロセスで個別にロードされるため、これはわかりません。したがって、すべてのプロセスには KeyboardCallback 関数の独自のコピーがあり、フォアグラウンド ウィンドウのコンソールに出力しようとします。

4

1 に答える 1

2

ドキュメントは、何が起こっているかを明確にします:

このフックは、それをインストールしたスレッドのコンテキストで呼び出されます。呼び出しは、フックをインストールしたスレッドにメッセージを送信することによって行われます。したがって、フックをインストールしたスレッドにはメッセージ ループが必要です。

フックは、 への呼び出しによってインストールされますInstall。したがって、その呼び出しを行う同じスレッドで、メッセージ ループを実行する必要があります。

なぜメッセージ ボックスを表示すると影響を受けるのかというと、メッセージ ボックスはモーダル メッセージ ループを実行することで動作します。そして、そのメッセージ ループがフック メッセージをディスパッチします。

フォローアップの質問については、ドキュメントに回答があります。

システムは、新しいキーボード入力イベントがスレッド入力キューにポストされるたびに、この関数を呼び出します。

スレッド入力キューに投稿されたと言う場合、それは任意のスレッド入力キューを意味します。

または、ドキュメントのコメントSetWindowsHookExで、さまざまなフック タイプとそのスコープのリストを参照してください。はWH_KEYBOARD_LLグローバルフックとしてリストされています。

また、これWH_KEYBOARD_LLは低レベルのフックであるため、DLL が別のプロセスに挿入されることはありません。実際、あなたのコードは非常に複雑です。ここでは、DLL はまったく必要ありません。SetWindowsHookEx同じ実行可能ファイルでコールバック関数を渡す実行可能ファイルからの呼び出しで、すべてを実行できます。

以下は、これらすべてを示す最小限のサンプル プログラムです。

#include <Windows.h>
#include <iostream>

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    std::cout << "Key pressed" << std::endl;
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main(int argc, char* argv[])
{
    std::cout << "Installing" << std::endl;
    HHOOK hk;
    hk = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
    MSG Msg;
    while (GetMessage(&Msg, NULL, 0, 0))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    std::cout << "UnInstalling" << std::endl;
    UnhookWindowsHookEx(hk);
    return 0;
}
于 2013-09-30T09:30:35.570 に答える