none
CreateWindow関数で作った他プロセスに文字列を送りたい(フックやEnumChildWindowsについて) RRS feed

  • 質問

  • お世話になります。Win32APIを使っています。
    タイトルの通り、CreateWindowで作った他プロセス(他の人が作ったアプリ)に文字列を送りたいです。それで、他プロセスのエディタのハンドルが必要なので自分なりにいろいろ調べた結果、EnumChildWindows内でGetWindowTextとGetWindowClassで得たウィンドウ名とクラス名をそれぞれspy++で調べた値に照らし合わせてハンドルを特定する方針にしました。ここで、GetWindowTextとGetWindowClassは自プロセスにしか使えないとのことで(すみません、使えました)、過去の質問から見つけた「dllで他プロセスをフックして、その中でEnumChildWindowsを使うことでプロセスの境界を超える」という方法を採用しました。しかしこのdllでいくつかの問題が出たので、今回質問させていただきました。

    VisualStudioはMicrosoft Visual Studio Community 2019 Version 16.11.10を使っています。
    dll呼び出し元のexeとdll,libは同ディレクトリ内にあり、その他設定もしているのでdllの呼び出し自体はできています。それで問題というのが、

    1.SetWindowHookEx関数の第四引数にCreateWindowの返り値のPROCESS_INFORMATION構造体から得たdwThreadId(プライマリスレッドID)を入れると「パラメータが間違っています」とエラーが出てしまい、フックできません。NULLでのフックは一応できます。

    2.(SetWindowHookEx関数の第四引数をNULLした場合)SendMessageやSendInputでWM_KEYDOWNを送ってもフックされません。
    SendMessageなど自体をフックする必要があるのでしょうか。
    dll内のヘッダファイル
    #include "pch.h"
    #include <windows.h>
    
    HHOOK hhk;
    HWND TophWnd, ResulthWnd, MainhWnd;
    WCHAR KiriWindowText[2048];
    WCHAR KiriWindowClass[2048];
    //freeをDLLMainのDLL_PROCESS_DETACHに置くとエラーが出てmallocを使えなかったためWCHAR
    HINSTANCE inst;
    
    INPUT input[] = {
    
         { INPUT_KEYBOARD, VK_UP, MapVirtualKey(VK_UP,NULL),NULL,NULL,0 },
    
         { INPUT_KEYBOARD,  VK_UP, MapVirtualKey(VK_UP,NULL), KEYEVENTF_KEYUP, NULL, 0}
    
    };
    
    extern "C" LRESULT  CALLBACK KeyProc(int nCode, WPARAM wParam, LPARAM lParam);
    extern "C" BOOL  CALLBACK EnumChildProc(HWND KirihWnd, LPARAM lp);
    extern "C" HWND __declspec(dllexport) GetKiriWindowHandle( //目的ウインドウのハンドルを取得する関数
        HWND hWnd, //呼び出し側のプログラムのハンドル
        HWND TopWindowHandle, //目的ウインドウの属するトップレベルウインドウのハンドル
        DWORD ThreadHandle,  //CreateWindowの返り値のPROCESS_INFORMATION構造体から得たdwThreadId(プライマリスレッドID)
        LPCWSTR strWindowText,  //目的ウインドウのウインドウタイトル
        LPCWSTR strWindowClass);  //同じくクラス名
    
    //ソースファイル
    #include "pch.h"
    #include "Get_Kiri_WindowHandle.h" //ヘッダファイル
    
    //変数bufやMessageBoxはデバッグ用
    
    extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            inst = hModule;
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    
    extern "C" LRESULT CALLBACK KeyProc(int nCode, WPARAM wParam, LPARAM lParam) {
        if (nCode < 0)
            return CallNextHookEx(hhk, nCode, wParam, lParam);
        if (lParam & 0x80000000) {  //キーが押されたとき
            EnumChildWindows(TophWnd, EnumChildProc, 0);
            MessageBox(MainhWnd, KiriWindowClass, NULL, MB_OK);
        }
    
        return CallNextHookEx(hhk, nCode, wParam, lParam);
    }
    
    extern "C" BOOL CALLBACK EnumChildProc(HWND KirihWnd, LPARAM lp) {
        WCHAR strWindowText[2048];
        WCHAR strWindowClass[2048];
    
        GetWindowText(KirihWnd, strWindowText, 2048);
        GetClassName(KirihWnd, strWindowClass, 2048);
    
        if (KiriWindowText == TEXT("") && KiriWindowClass == strWindowClass) {
            ResulthWnd = KirihWnd;
            return false;
        }
        if (KiriWindowText == strWindowText && KiriWindowClass == strWindowClass) {
            ResulthWnd = KirihWnd;
            return false;
        }
    
        return true;
    }
    
    extern "C" HWND __declspec(dllexport) GetKiriWindowHandle(HWND hWnd, HWND TopWindowHandle, DWORD ThreadHandle, LPCWSTR strWindowText, LPCWSTR strWindowClass) {
        TophWnd = TopWindowHandle;
        MainhWnd = hWnd;
        if (strWindowText == NULL)  //ウィンドウタイトルなしの場合
            wsprintf(KiriWindowText, TEXT("%s"), TEXT(""));
        else wsprintf(KiriWindowText, TEXT("%s"), strWindowText);
        wsprintf(KiriWindowClass, TEXT("%s"), strWindowClass);
    
        hhk = SetWindowsHookEx(WH_KEYBOARD, KeyProc, inst, NULL);
        WCHAR buf[1000];
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), NULL, buf, 4096, NULL);
        if (hhk == NULL)
            MessageBox(MainhWnd, buf, TEXT("Error"), MB_OK);
    
        SendInput(2,input,sizeof(input)); //SendMessageでフックできなかったのでダメ元
        Sleep(100);
        if (!ResulthWnd)
            MessageBox(MainhWnd, TEXT("ハンドルの取得に失敗しました"), TEXT("Error"), MB_OK);
        UnhookWindowsHookEx(hhk);
        return ResulthWnd;
    }

    ソースコードを追加で加えました。フックの開始と終了の関数を別で作っていないのは、横着しました。



    • 編集済み dfcklp 2022年2月26日 6:27
    2022年2月26日 4:33

回答

  • GetWindowTextWのRemarksで説明されている通りです。

    • 自プロセスならWM_GETTEXTと同じ動きをする
    • 他プロセスならキャプションを取得する
    • キャプションが空なら空が得られる
    • 他プロセスのテキストが必要であれば直接WM_GETTEXTを呼ぶこと

    という関係です。キャプションが欲しければGetWindowTextのままでいいですし、テキストが欲しければWM_GETTEXTを呼べばいいです。

    • 回答としてマーク dfcklp 2022年2月26日 6:27
    2022年2月26日 5:55

すべての返信

  • GetWindowTextとGetWindowClassは自プロセスにしか使えないとのことで

    出典を明らかにしてください。どのように書かれていたのかわかりませんが、他プロセスにも使えますので、他プロセスに侵入する必要はありません。WM_SETTEXT等で文字列を送り込むことも可能です。

    …となるとそもそもフックが不要だったりしますか?

    2022年2月26日 5:05
  • 「自プロセスのみ」というのとは少し表現が違いましたが、ここに書かれてました。https://www.tokovalue.jp/function/GetWindowText.htm
    (ここも参考にしましたhttps://social.msdn.microsoft.com/Forums/ja-JP/7af1cc0b-b8d2-4f15-95b2-be72a4e5de82/findwindowex12289findwindow12364228332594312377124272258021512123982355?forum=vcgeneralja)
    他にも見たような気がするんですが、古い情報や間違ったものを見ていただけかもしれません。教えていただきありがとうございます。
    とりあえず、SETTEXTを使ってやってみたいと思います。

    あとすみません、書き忘れていたのですがこの後、同プロセスのボタンコントロールを押す処理をしたいです。その場合はハンドルを入手する必要があるでしょうか(ボタンは複数あります)
    • 編集済み dfcklp 2022年2月26日 5:33
    2022年2月26日 5:20
  • GetWindowTextWのRemarksで説明されている通りです。

    • 自プロセスならWM_GETTEXTと同じ動きをする
    • 他プロセスならキャプションを取得する
    • キャプションが空なら空が得られる
    • 他プロセスのテキストが必要であれば直接WM_GETTEXTを呼ぶこと

    という関係です。キャプションが欲しければGetWindowTextのままでいいですし、テキストが欲しければWM_GETTEXTを呼べばいいです。

    • 回答としてマーク dfcklp 2022年2月26日 6:27
    2022年2月26日 5:55
  • おっしゃる通りGetWindowTextやGetWindowClassが使え、はじめの問題もフックが必要なくなり解決したも同然なので、解答とさせていただきます。
    ただ、もしフックの問題も分かる方がいればご教授いただければと思います。
    2022年2月26日 6:27