Я ломал голову над этим в течение нескольких дней, и мне может понадобиться помощь! Я могу обнаружить крючок CBT, используя SetWindowsHookEx, когда он подключен к идентификатору потока моего приложения WPF, но я не могу заставить его подключиться к идентификатору потока другого окна процесса, когда это окно становится приложением переднего плана .
Изображение 1: показывает, что я МОГУ получить хук CBT для обнаружения максимизации окна по идентификатору потока основного приложения
Изображение 2: показывает, что я НЕ МОГУ получить хук CBT при прослушивании идентификатора потока другого приложения, и это приведет к сбою приложения! а>
Я хочу избежать отправки ThreadId=0 и создания полного глобального хука, потому что я знаю, что хочу слушать только приложение переднего плана, а не все приложения на рабочем столе. Я хочу иметь возможность прослушивать несколько оконных событий до того, как они произойдут (WH_CBT делает это, насколько я понимаю) для любого окна, которое в настоящее время имеет фокус переднего плана.
Опять же, следующий код работает, когда текущее приложение WPF становится приложением переднего плана, но происходит сбой, когда окно другого приложения становится передним планом (например, Блокнот, Internet Explorer, File Explorer, Chrome и т. д.).
Полный код: (ссылка на zip-файл github) а>
Вот несколько фрагментов кода, чтобы показать, что я сделал:
DLL, определяющая обратный вызов (inject.dll):
inject.h: Snippettypedef void(__stdcall* MYFUNCPTR)(int code, WPARAM wparam, LPARAM lparam);
extern "C" __declspec(dllexport) void Init(MYFUNCPTR funcPtr);
extern "C" __declspec(dllexport) LRESULT CALLBACK CbtProcCallback(int code, WPARAM wparam, LPARAM lparam);
WPARAM wparam, LPARAM lparam);
MYFUNCPTR _handler = 0;
inject.cpp: Snippet
void Init(MYFUNCPTR funcPtr)
{
_handler = funcPtr;
}
LRESULT CALLBACK CbtProcCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code >= 0)
{
// Only send the code if you are about to MAXIMIZE
if (code == HCBT_MINMAX)
{
if (lparam == SW_MAXIMIZE)
{
_handler(0, wparam, lparam);
}
}
}
return CallNextHookEx(NULL, code, wparam, lparam);
}
DLL, устанавливающая хук CBT (dllwrapper.dll):
dllwrapper.cpp: Snippet // Load library in which we'll be hooking our functions.
HMODULE dll = LoadLibrary(L"inject.dll");
if (dll == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-LoadLibrary failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("LoadLibrary passed!");
// Get the address of the function inside the DLL.
MYPROC iaddr = (MYPROC)GetProcAddress(dll, "Init");
if (iaddr == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-GetProcAddress for Init failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("GetProcAddress for Init passed!");
iaddr(OnInjectionCallback);
// Get the address of the function inside the DLL.
HOOKPROC cbtProcAddress = (HOOKPROC)GetProcAddress(dll, "CbtProcCallback");
if (cbtProcAddress == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-GetProcAddress for CbtProcCallback failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("GetProcAddress for CbtProcCallback passed!");
// Hook the function
cbtProcHook = SetWindowsHookEx(WH_CBT, cbtProcAddress, dll, _threadId);
if (cbtProcHook == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-SetWindowsHookEx cbtProcAddress failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("SetWindowsHookEx for cbtProcAddress passed!");
Snippet exporting to C#
typedef void(__stdcall* CodeCallback)(int code, WPARAM wparam, LPARAM lparam);
typedef void(__stdcall* MessageCallback)(const char* message);
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
#endif
__declspec(dllexport) bool StartHooks(unsigned int threadId, MessageCallback messageCallback, CodeCallback codeCallback);
__declspec(dllexport) void StopHooks();
#ifdef __cplusplus
}
#endif
NativeMethods.cs: Snippet of C# dll imports to the WPF app
public delegate void MessageCallback(string message);
public delegate void CodeCallback(int code, IntPtr wParam, IntPtr lParam);
[DllImport("dllwrapper.dll")]
public extern static bool StartHooks(uint threadId, MessageCallback messageHandler, CodeCallback codeHandler);
[DllImport("dllwrapper.dll")]
public extern static void StopHooks();
Из сообщений в окне приложения WPF я вижу, что хук проходит и не возвращает никаких ошибок Win32, но он просто не выполняет обратный вызов, когда фокус находится в другом окне (даже при использовании отладчика).
Любая помощь будет принята с благодарностью!
Среда разработки:
- Виндовс 10 1909
- VS2019 16.7.4
- С# .NET Framework 4.7.2, С++