Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# windows钩子的奇怪行为_C#_C++_Winapi_Dll_Hook - Fatal编程技术网

C# windows钩子的奇怪行为

C# windows钩子的奇怪行为,c#,c++,winapi,dll,hook,C#,C++,Winapi,Dll,Hook,我一直在寻找在操作系统(windows XP 32位)中激活任何窗口时,在.NET windows应用程序中收到通知的可能性。在CodeProject上,我通过使用全局系统钩子找到了一个解决方案 以下是该程序的简短摘要: 在非托管程序集中(用C++编写)实现了一个方法,该方法安装WH_CBThook bool InitializeCbtHook(int threadID, HWND destination) { if (g_appInstance == NULL) {

我一直在寻找在操作系统(windows XP 32位)中激活任何窗口时,在.NET windows应用程序中收到通知的可能性。在CodeProject上,我通过使用全局系统钩子找到了一个解决方案

以下是该程序的简短摘要:

在非托管程序集中(用C++编写)实现了一个方法,该方法安装
WH_CBT
hook

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
hook。我知道
WH_CBT
WH_SHELL
hook之间的一个区别是,当使用
WH_CBT
hook时,可以通过不调用
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));
            }
        }
    }
}
用法


显然,这种挂钩在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));
            }
        }
    }
}
用法


为什么不直接使用
System.Windows.UIAutomation
名称空间呢?这是专为你想做的事写的!感谢您的回复,但根据我的信息,您只能在WPF-Applications.Strange中使用
System.Windows.UIAutomation
命名空间,因为我从控制台应用程序中使用过它!所以我会尝试一下,并告诉你结果。谢谢为什么不直接使用
System.Windows.UIAutomation
名称空间呢?这是专为你想做的事写的!感谢您的回复,但根据我的信息,您只能在WPF-Applications.Strange中使用
System.Windows.UIAutomation
命名空间,因为我从控制台应用程序中使用过它!所以我会尝试一下,并告诉你结果。谢谢嗨,谢谢你的回复。我试用了你的
WindowsMonitor
课程,效果很好。但是我不理解activeWindowChanged方法的
实现。你在一个单独的线程中引发一个事件。这个线安全吗?那么性能呢。我认为在循环中检测活动窗口非常耗时。很高兴听到你的消息:)是的,只要你在主线程上初始化监视器,它应该是线程安全的。。。但是,我没有测试它。性能问题?嗯,我想不会-因为GetActiveWindow()方法并不慢,它不是一个“循环”,而是一个定时事件(计时器),每10毫秒触发一次(当然你可以增加间隔,但你会松开快速窗口开关…)。我自己在一些应用程序中运行了这段代码,但我还没有发现任何性能问题。您好,谢谢您的回复。我试用了你的
WindowsMonitor
课程,效果很好。但是我不理解activeWindowChanged方法的
实现。你在一个单独的线程中引发一个事件。这个线安全吗?那么性能呢。我认为在循环中检测活动窗口非常耗时。很高兴听到你的消息:)是的,只要你在主线程上初始化监视器,它应该是线程安全的。。。但是,我没有测试它。性能问题?嗯,我想不会-因为GetActiveWindow()方法并不慢,它不是一个“循环”,而是一个定时事件(计时器),每10毫秒触发一次(当然你可以增加间隔,但你会松开快速窗口开关…)。我自己在一些应用程序中运行这段代码,但还没有发现任何性能问题。