【发布时间】:2012-08-20 08:42:32
【问题描述】:
我一直在寻找在操作系统(Windows XP 32 位)中激活任何窗口时在 .NET Windows 应用程序中收到通知的可能性。在 CodeProject 上,我找到了使用全局系统挂钩的解决方案。
http://www.codeproject.com/Articles/18638/Using-Window-Messages-to-Implement-Global-System-H.
以下是此过程的简短摘要:
在非托管程序集(用 C++ 编写)中,实现了一个安装 WH_CBT 挂钩的方法。
bool InitializeCbtHook(int threadID, HWND destination)
{
if (g_appInstance == NULL)
{
return false;
}
if (GetProp(GetDesktopWindow(), " HOOK_HWND_CBT") != NULL)
{
SendNotifyMessage((HWND)GetProp(GetDesktopWindow(), "HOOK_HWND_CBT"),
RegisterWindowMessage("HOOK_CBT_REPLACED"), 0, 0);
}
SetProp(GetDesktopWindow(), " HOOK_HWND_CBT", destination);
hookCbt = SetWindowsHookEx(WH_CBT, (HOOKPROC)CbtHookCallback, g_appInstance, threadID);
return hookCbt != NULL;
}
在回调方法(过滤函数)中,根据钩子类型窗口消息被发送到目标窗口。
static LRESULT CALLBACK CbtHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code >= 0)
{
UINT msg = 0;
if (code == HCBT_ACTIVATE)
msg = RegisterWindowMessage("HOOK_HCBT_ACTIVATE");
else if (code == HCBT_CREATEWND)
msg = RegisterWindowMessage("HOOK_HCBT_CREATEWND");
else if (code == HCBT_DESTROYWND)
msg = RegisterWindowMessage("HOOK_HCBT_DESTROYWND");
else if (code == HCBT_MINMAX)
msg = RegisterWindowMessage("HOOK_HCBT_MINMAX");
else if (code == HCBT_MOVESIZE)
msg = RegisterWindowMessage("HOOK_HCBT_MOVESIZE");
else if (code == HCBT_SETFOCUS)
msg = RegisterWindowMessage("HOOK_HCBT_SETFOCUS");
else if (code == HCBT_SYSCOMMAND)
msg = RegisterWindowMessage("HOOK_HCBT_SYSCOMMAND");
HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), HOOK_HWND_CBT");
if (msg != 0)
SendNotifyMessage(dstWnd, msg, wparam, lparam);
}
return CallNextHookEx(hookCbt, code, wparam, lparam);
}
要在 .NET Windows 应用程序中使用此程序集,必须导入以下方法:
[DllImport("GlobalCbtHook.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool InitializeCbtHook (int threadID, IntPtr DestWindow);
[DllImport("GlobalCbtHook.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void UninitializeCbtHook(int hookType);
调用InitializeCbtHook后,从GlobalCbtHook.dll收到的消息可以在:
protected override void WndProc(ref Message msg)
消息必须通过调用在程序集和应用程序中注册
RegisterWindowMessage.
[DllImport("user32.dll")]
private static extern int RegisterWindowMessage(string lpString);
此实现工作正常。但在大多数情况下,当我激活 Microsoft Office Outlook
在我最小化 Outlook 或激活其他窗口后,我的 .NET 应用程序会收到激活事件。起初我认为我的 .NET 包装器是问题的原因。但是在我使用上述链接的来源之后,我可以识别出相同的行为。
我实际的解决方法是使用WH_SHELL 钩子。我知道WH_CBT 和WH_SHELL 钩子之间的一个区别是,当使用WH_CBT 钩子时,可以通过不调用CallNextHookEx 方法来中断过滤器函数链。这会在我的问题中发挥作用吗?
请提供帮助。
【问题讨论】:
-
为什么不直接使用
System.Windows.UIAutomation命名空间?这是专门为你想做的事情而写的! -
感谢您的回复,但根据我的信息,您只能在WPF-Applications中使用
System.Windows.UIAutomation命名空间。 -
奇怪,因为我在控制台应用程序中使用过它!
-
所以我会尝试一下并通知您结果。谢谢!