我们正在Windows客户端平台(通常为WinXP)上运行小众行业计划,该计划在640x480窗口中运行回AS / 400服务器。为了减少我希望在程序的标题栏发生变化时要注意的错误。然后我需要捕获键盘条目以进行验证。然后我会确保每个条目都有效,因为古老的程序没有验证。然后,我可以弹出窗口,然后警告最终用户是否发生错误,并减少/消除异常报告。
我的问题是如何捕获我需要的应用程序标题栏change ='string'的事件? API调用?旨在在VB中执行此操作,除非另一个更明显更清洁。
答案 0 :(得分:1)
我假设您不拥有目标应用程序的代码。在这种情况下,没有简单的“当标题改变时给我回电话”事件。然后,您有两个选项可以执行您需要的操作,我将在下面概述。
让你的应用程序获得目标应用程序的主窗口(这应该很容易)并且每100毫秒左右轮询一次它的标题。当您检测到更改时,请采取相应措施。
使用例如Hook进入目标应用程序全球CBT hook。代码在其进程subclass their main window中运行后,会导致所有窗口消息首先通过您的代码。当您的代码看到WM_SETTEXT
消息进入主窗口时,您可以使用IPC选择主动通知您的“其他”应用程序。如果您只需要喊“嘿!”对于您的其他应用程序,请使用auto-reset event(这将是最简单的)。当然,所有这些都非常重视非托管代码。
如果简单的解决方案不够好而且困难的解决方案太多,你可以尝试使用像White这样的自动化库(我从来没有使用它,所以我不能说更多)。
答案 1 :(得分:1)
WinEvents应该在这里运作良好。这些是在发生某些UI更改时被触发的轻量级事件 - 例如,对象的名称发生变化 - 其中包括标题栏文本更改。这种类型的钩子的一个好处是,您可以将其设置为将通知发送回您自己的进程,因此您不需要处理挂钩或IPC。 (它也适用于32位和64位进程。)
这在普通的C / C ++中最容易做到;但如果添加适当的[DllImport],可以在.Net(VB,C#)中完成。
#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;
}
需要注意的事项:你可能会得到假阳性;如果名称快速变化,当您获得第一个事件时,名称可能是第二个值,因此您可能会看到第二个值的两个事件。但是,如果您只是将其用作检查指定值的触发器,则这些都不是问题。