窗户挂钩的奇怪行为
Strange behaviour of windows hooks
当操作系统(windows XP 32位)中的任何窗口被激活时,我正在寻找在.NET窗口应用程序中收到通知的可能性。在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
方法来中断过滤器函数链。这会对我的问题起作用吗?请提供帮助。
显然挂钩在outlook的情况下不起作用-其他微软产品(word,power point…)呢??
但是,为什么要勾搭?即使outlook被激活,这个小类也能工作
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsMonitor
{
public class ActiveWindowChangedEventArgs : EventArgs
{
public IntPtr CurrentActiveWindow { get; private set; }
public IntPtr LastActiveWindow { get; private set; }
public ActiveWindowChangedEventArgs(IntPtr lastActiveWindow, IntPtr currentActiveWindow)
{
this.LastActiveWindow = lastActiveWindow;
this.CurrentActiveWindow = currentActiveWindow;
}
}
public delegate void ActiveWindowChangedEventHandler(object sender, ActiveWindowChangedEventArgs e);
public class ActiveWindowMonitor
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
private Timer monitorTimer;
public IntPtr ActiveWindow { get; private set; }
public event ActiveWindowChangedEventHandler ActiveWindowChanged;
public ActiveWindowMonitor()
{
this.monitorTimer = new Timer();
this.monitorTimer.Tick += new EventHandler(monitorTimer_Tick);
this.monitorTimer.Interval = 10;
this.monitorTimer.Start();
}
private void monitorTimer_Tick(object sender, EventArgs e)
{
CheckActiveWindow();
}
private void CheckActiveWindow()
{
IntPtr currentActiveWindow = GetForegroundWindow();
if (this.ActiveWindow != currentActiveWindow)
{
IntPtr lastActiveWindow = this.ActiveWindow;
this.ActiveWindow = currentActiveWindow;
OnActiveWindowChanged(lastActiveWindow, this.ActiveWindow);
}
}
protected virtual void OnActiveWindowChanged(IntPtr lastActiveWindow, IntPtr currentActiveWindow)
{
ActiveWindowChangedEventHandler temp = ActiveWindowChanged;
if (temp != null)
{
temp.Invoke(this, new ActiveWindowChangedEventArgs(lastActiveWindow, currentActiveWindow));
}
}
}
}
使用
public void InitActiveWindowMonitor()
{
WindowsMonitor.ActiveWindowMonitor monitor = new WindowsMonitor.ActiveWindowMonitor();
monitor.ActiveWindowChanged += new WindowsMonitor.ActiveWindowChangedEventHandler(monitor_ActiveWindowChanged);
}
private void monitor_ActiveWindowChanged(object sender, WindowsMonitor.ActiveWindowChangedEventArgs e)
{
//ouh a window got activated
}
- 如何在窗户上使用和配置叮当声?
- 从 c++ 运行 MsiExec.exe?窗户
- 管道到窗户上的ffmpeg
- 如何为我的窗户腾出顶部空间?
- 在窗户中编译CUDA的意义
- 窗户的C BLE中央开发
- 在离开模式下唤醒窗户
- 窗户上的cmake,加载静态库
- QMediaPlayer在窗户上使用西里尔的错误解析URL
- 在窗户上与libssh挣扎
- 在窗户上建造数学
- 如何修复窗户上的 cmake find_package "Could NOT find SDL2"?
- 窗户上的PCL 1.8.1 CMAKE问题
- 窗户不打开
- 我对窗户中的纤维有一些疑问
- Box2D-我应该多久在窗户循环中使用台阶
- 窗户排列的顺序
- 使用C 构建器在窗户上拍摄屏幕截图的线程安全
- CEF 3无边界的窗户
- 交叉编译壁炉靶向窗户