Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.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集合更改时的pinvoke异步委托?_C#_Pinvoke_User32 - Fatal编程技术网

C# 桌面windows集合更改时的pinvoke异步委托?

C# 桌面windows集合更改时的pinvoke异步委托?,c#,pinvoke,user32,C#,Pinvoke,User32,我有一个C程序,可以轮询EnumDesktopWindows集合的更改。如果用户关闭或打开窗口,轮询例程会检测到这一点,并将可用窗口的更新列表发送给另一个.Net windows窗体项目。但是,我不喜欢轮询方法。我希望对EnumDesktopWindows的任何更改都会触发一个事件,以便异步响应更改 我能想出的最好办法就是你在下面看到的。我尝试了Scott C.的建议,从控制台窗口执行,但没有成功 当前,当Windows窗体加载这是一个Windows窗体应用程序时,您在下面看到的内容捕获Crea

我有一个C程序,可以轮询EnumDesktopWindows集合的更改。如果用户关闭或打开窗口,轮询例程会检测到这一点,并将可用窗口的更新列表发送给另一个.Net windows窗体项目。但是,我不喜欢轮询方法。我希望对EnumDesktopWindows的任何更改都会触发一个事件,以便异步响应更改

我能想出的最好办法就是你在下面看到的。我尝试了Scott C.的建议,从控制台窗口执行,但没有成功

当前,当Windows窗体加载这是一个Windows窗体应用程序时,您在下面看到的内容捕获CreateWnd=3。但是,它不会全局捕获:它只捕获当前运行的可执行文件中的窗口事件。如果有人有鹰眼,并且能够发现如何在全球范围内捕获此代码,我将给出答案

尝试一下;首先创建一个Windows窗体应用程序项目,并将以下代码添加到Form1.cs中。您需要向名为lstLog的窗体中添加一个列表框才能正确编译

using System;
using System.Windows.Forms;

namespace Utilities
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var gwh = new GlobalWindowHook();
            gwh.WindowCreated += onWindowCreated;
        }

        private void onWindowCreated()
        {
            lstLog.Items.Add("window creation event detected.");
        }
    }
}
在同一项目中创建名为GlobalWindowHook.cs的类文件,并复制粘贴以下内容:

using System;
using System.Runtime.InteropServices;

namespace Utilities
{
    internal class GlobalWindowHook
    {
        private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        public enum HookType
        {
            WH_JOURNALRECORD = 0,
            WH_JOURNALPLAYBACK = 1,
            WH_KEYBOARD = 2,
            WH_GETMESSAGE = 3,
            WH_CALLWNDPROC = 4,
            WH_CBT = 5,
            WH_SYSMSGFILTER = 6,
            WH_MOUSE = 7,
            WH_HARDWARE = 8,
            WH_DEBUG = 9,
            WH_SHELL = 10,
            WH_FOREGROUNDIDLE = 11,
            WH_CALLWNDPROCRET = 12,
            WH_KEYBOARD_LL = 13,
            WH_MOUSE_LL = 14
        }

        public enum HCBT
        {
            MoveSize = 0,
            MinMax = 1,
            QueueSync = 2,
            CreateWnd = 3,
            DestroyWnd = 4,
            Activate = 5,
            ClickSkipped = 6,
            KeySkipped = 7,
            SysCommand = 8,
            SetFocus = 9
        }

        private IntPtr hhook = IntPtr.Zero;

        public GlobalWindowHook()
        {
            hook();
        }


        ~GlobalWindowHook()
        {
            unhook();
        }


        public void hook()
        {
            IntPtr hInstance = LoadLibrary("User32");

            hhook = SetWindowsHookEx(HookType.WH_CBT, hookProc, hInstance, 0);
        }

        public void unhook()
        {
            UnhookWindowsHookEx(hhook);
        }

        public IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code != (int) HCBT.CreateWnd && code != (int) HCBT.DestroyWnd)
                return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);

            //Do whatever with the created or destroyed window.

            return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
        }


        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(HookType code, HookProc func, IntPtr hInstance, int threadId);

        [DllImport("user32.dll")]
        private static extern bool UnhookWindowsHookEx(IntPtr hInstance);

        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern IntPtr LoadLibrary(string fileName);
    }
}

执行上述步骤后,执行windows窗体项目。您应该看到它检测到一个正在创建的窗口,即您刚刚执行的窗口。

如果您希望推送通知而不是拉送通知,这并不太困难。您需要做的是P/Invoke并注册WH_CBT事件。一旦你们收到这些信息,你们就可以用代码来监听信息。它将在创建或销毁新窗口时通知您

使用在中定义的类型


我想您可以使用带有WH_CBT钩子类型的SetWindowsHookx来完成这项工作。我刚刚修改了我的问题,并用我迄今为止最好的尝试进行了更新。谢谢Scott。我仍在寻找答案。@Hans-所以不要使用SetWindowsHookEx?我要试一试。我是这方面的新手。@sapbucket您的问题是hModule需要指向包含_callbackDelegate函数的程序集。user32.dll不包含您的函数,这就是它不工作的原因。尝试在测试控制台应用程序中执行此操作,然后再尝试在单元测试中运行它。此外,您的单元测试程序将在事件触发之前退出并关闭。Hans Passat解释说,hModule不在低级库中使用,传入任何有效的内容都可以。这就是我坚持使用LoadLibrary的原因。汉斯错了吗?不管怎样,我都不会成功。这只适用于低级钩子。CBT钩子并不是低级的,模块句柄是非常重要的。@Hans-我发现一个线程表明我试图做的事情不受.Net支持;我相信你的意见——这条线正确吗?没错,是的。不能将C代码注入另一个进程。好了,Scott的代码只会告诉你你自己的应用程序中的windows被创建和关闭的情况。这不是程序员通常想要的,尤其不是在控制台模式的应用程序中:这就是我发布替代方案的原因。需要消息循环,因此避免使用控制台模式应用程序。
class HookingClass
{
    private delegate IntPtr CBTProc(HCBT nCode, IntPtr wParam, IntPtr lParam);

    private readonly CBTProc _callbackDelegate;

    public HookingClass()
    {
         _callbackDelegate = CallbackFunction;
    }

    private IntPtr _hook;

    private void CreateHook()
    {
        using (Process process = Process.GetCurrentProcess())
        using (ProcessModule module = process.MainModule)
        {
            IntPtr hModule = GetModuleHandle(module.ModuleName);

            _hook = SetWindowsHookEx(HookType.WH_CBT, _callbackDelegate, hModule, 0);
            if(_hook == IntPtr.Zero)
                throw new Win32Exception(); //The default constructor automatically calls Marshal.GetLastError()
        }

    }

    private void Unhook()
    {
        var success = UnhookWindowsHookEx(_hook);
        if(!success)
            throw new Win32Exception();
    }

     private IntPtr CallbackFunction(HCBT code, IntPtr wParam, IntPtr lParam)
     {
         if (code != HCBT.CreateWnd && code != HCBT.DestroyWnd) 
         {         
             return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
         }

         //Do whatever with the created or destroyed window.

         return CallNextHookEx(IntPtr.Zero, (int)code, wParam, lParam);
     }
}