お世話になります。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;
}
ソースコードを追加で加えました。フックの開始と終了の関数を別で作っていないのは、横着しました。