WinEvents здесь должно хорошо работать. Это легкие события, которые запускаются при определенных изменениях пользовательского интерфейса, например, при изменении имен объектов, включая изменения текста в Titlebar. Одним из преимуществ этого типа перехвата является то, что вы можете настроить его для доставки уведомлений обратно в ваш собственный процесс, поэтому вам не нужно заниматься перехватом или IPC. (Он также работает как с 32-битными, так и с 64-битными процессами.)
Это проще всего сделать на простом C / C ++; но может быть сделано в .Net (VB, C #), если вы добавите соответствующие [DllImport].
#include <windows.h>
#include <stdio.h>
#define WM_NAMECHANGED WM_APP
HWND g_hwndTarget; // window we're listening to
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime
)
{
// Check this is the window we want. Titlebar name changes result in these
// two values (obtained by looking at some titlebar changes with the
// Accessible Event Watcher tool in the Windows SDK)
if(hwnd == g_hwndTarget && idObject == OBJID_WINDOW && idChild == CHILDID_SELF)
{
// Do minimal work here, just hand off event to mainline.
// If you do anything here that has a message loop - eg display a dialog or
// messagebox, you can get reentrancy.
PostThreadMessage(GetCurrentThreadId(), WM_NAMECHANGED, 0, 0);
}
return;
}
void ReportName(HWND hwnd)
{
WCHAR szName[128];
GetWindowText(hwnd, szName, ARRAYSIZE(szName));
wprintf(L"hwnd 0x%08lx has title: %s\n", HandleToLong(hwnd), szName);
}
int main()
{
wprintf(L"Place mouse pointer over window titlebar to report name changes for and hit return...\n");
getchar();
POINT pt;
GetCursorPos(&pt);
g_hwndTarget = WindowFromPoint(pt);
ReportName(g_hwndTarget);
// Note: this doesn't work for console windows, which are managed by CSRSS.EXE. Simplest (though not efficient) workaround for those
// is to use threadId=0 and filter by hwnd in the callback.
DWORD threadId = GetWindowThreadProcessId(g_hwndTarget, NULL);
// This says: call the callback when any UI elements in the specified thread change
// name. _OUTOFCONTEXT means deliver the notifications in this process, don't hook.
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, NULL, WinEventProc, 0, threadId, WINEVENT_OUTOFCONTEXT);
// TODO: add error checking as appropriate.
wprintf(L"Waiting...\n");
// Thread needs to have a message loop for SetWinEventHook to work for out-of-context messages.
UINT count = 10;
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message == WM_NAMECHANGED)
{
ReportName(g_hwndTarget);
if(--count == 0)
{
break;
}
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWinEvent(hook);
return 0;
}
На что нужно обратить внимание: вы можете получить ложные срабатывания; и если имя быстро меняется, к тому времени, когда вы получите первое событие, имя может иметь второе значение, поэтому вы можете увидеть два события для второго значения. Однако ни один из них не должен вызывать проблем, если вы просто используете его в качестве триггера для проверки указанного значения.