pressing标签几次后挂线的过程不再被调用。为什么? [英] Thread hook procedure is no longer called after pressing Tab several times. Why?

查看:129
本文介绍了pressing标签几次后挂线的过程不再被调用。为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我安装了一个线程特定的Windows钩子监视发送到WndProc的消息。它的工作在第一。然而,当我pressed标签约19倍将焦点围绕一个形式,我的钩子回调nolonger调用。这事我$ P $无论快或慢pssed标签regaless。任何人都可以解释一下什么是真的呢?

下面是code我写的。我测试了它在Windows 7 64位。

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Windows.Forms的;
使用了System.Runtime.InteropServices;

命名空间HookTest
{
    静态类节目
    {
        私人const int的WH_CALLWNDPROC = 4;

        私人委托的IntPtr HOOKPROC(INT N code,IntPtr的wParam中,IntPtr的lParam的);

        私有类的MainForm:表
        {
            私人按钮按钮1;
            私人文本框textBox1的;

            公众的MainForm()
            {
                this.button1 =新System.Windows.Forms.Button();
                this.textBox1 =新System.Windows.Forms.TextBox();
                this.SuspendLayout();
                //
                //按钮1
                //
                this.button1.Location =新System.Drawing.Point(12,38);
                this.button1.Name =Button1的;
                this.button1.Size =新System.Drawing.Size(75,23);
                this.button1.TabIndex = 0;
                this.button1.Text =按钮1;
                this.button1.UseVisualStyleBackColor = TRUE;
                //
                // textBox1的
                //
                this.textBox1.Location =新System.Drawing.Point(12,12);
                this.textBox1.Name =textBox1的;
                this.textBox1.Size =新System.Drawing.Size(100,20);
                this.textBox1.TabIndex = 1;
                //
                //的MainForm
                //
                this.Controls.Add(this.textBox1);
                this.Controls.Add(this.button1);
                this.Name =MainForm的;
                this.Text =主表;
                this.ResumeLayout(假);
                this.PerformLayout();
            }
        }

        私有静态的IntPtr hWndProcHook = IntPtr.Zero;
        私有静态诠释messageCount = 0;

        [的DllImport(Kernel32.dll中,字符集= CharSet.Auto)
        公共静态外部的IntPtr的GetModuleHandle(字符串lpModuleName);

        [的DllImport(Kernel32.dll中,字符集= CharSet.Auto)
        公共静态外部UINT GetCurrentThreadId();

        [的DllImport(User32.dll中,字符集= CharSet.Auto)
        私人静态外部的IntPtr调用SetWindowsHookEx(INT idHook,
            HOOKPROC lpfn,IntPtr的HMOD,UINT dwThreadId);

        [的DllImport(User32.dll中,字符集= CharSet.Auto)
        [返回:的MarshalAs(UnmanagedType.Bool)
        私人静态外部布尔UnhookWindowsHookEx(IntPtr的HHK);

        [的DllImport(User32.dll中,字符集= CharSet.Auto)
        私人静态外部的IntPtr CallNextHookEx方法(IntPtr的HHK,INT N code,
            IntPtr的wParam中,IntPtr的lParam的);

        ///<总结>
        ///的主入口点的应用程序。
        ///< /总结>
        [STAThread]
        静态无效的主要()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(假);
            InstallHook();
            Application.Run(新的MainForm());
            UninstallHook();
        }

        私有静态无效InstallHook()
        {
            如果(Program.hWndProcHook == IntPtr.Zero)
            {
                Console.WriteLine(挂钩......);

                Program.hWndProcHook =调用SetWindowsHookEx(
                    WH_CALLWNDPROC,
                    WndProcHookCallback,
                    的GetModuleHandle(空)
                    GetCurrentThreadId());

                如果(Program.hWndProcHook!= IntPtr.Zero)
                    Console.WriteLine(上钩成功。);
                其他
                    Console.WriteLine(无法挂钩。);
            }
        }

        私有静态无效UninstallHook()
        {
            如果(Program.hWndProcHook!= IntPtr.Zero)
            {
                Console.WriteLine(脱钩......);

                如果(UnhookWindowsHookEx(Program.hWndProcHook))
                    Console.WriteLine(脱钩成功。);
                其他
                    Console.WriteLine(无法解开。);

                Program.hWndProcHook = IntPtr.Zero;
            }
        }

        私有静态的IntPtr WndProcHookCallback(INT N code,IntPtr的wParam中,IntPtr的lParam的)
        {
            Console.WriteLine(WndProcHookCallback {0},Program.messageCount ++);

            返回CallNextHookEx方法(Program.hWndProcHook,N code,的wParam,lParam的);
        }
    }
}
 

解决方案

在测试你的节目,我得到了以下错误

  

CallbackOnCollectedDelegate检测
  消息:回调作出   在类型的垃圾回收委托沙盒   表格!Sandbox_Form.Program + HOOKPROC ::调用。这可能会导致   应用程序崩溃,损坏和数据丢失。当传递代表   非托管code,它们必须保持活由托管的应用程序   直到它被保证它们不会被调用

我相信这个问题是隐含在创建要传递给 SetWindowsHookEx函数回调越来越垃圾回收的委托。通过明确地创造了代表一个变量,并保持它的范围,我认为它会让你的问题消失,当我修改 InstallHook 下面我再也无法重新创建该错误。

 私有静态HOOKPROC hookProcDelegate;

私有静态无效InstallHook()
{
    如果(Program.hWndProcHook == IntPtr.Zero)
    {
        Console.WriteLine(挂钩......);

        hookProcDelegate =新HOOKPROC(WndProcHookCallback);

        Program.hWndProcHook =调用SetWindowsHookEx(
            WH_CALLWNDPROC,
            hookProcDelegate,
            的GetModuleHandle(空)
            GetCurrentThreadId());

        如果(Program.hWndProcHook!= IntPtr.Zero)
            Console.WriteLine(上钩成功。);
        其他
            Console.WriteLine(无法挂钩。);
    }
}
 

I installed a thread-specific windows hook to monitor messages sent to WndProc. It worked at first. However, after I pressed Tab about 19 times to move focus around a form, my hook callback is nolonger called. This happened regaless of whether I pressed Tab quickly or slowly. Can anybody explain what is really going on?

Below is the code I wrote. I tested it on Windows 7 64 bit.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace HookTest
{
    static class Program
    {
        private const int WH_CALLWNDPROC = 4;

        private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        private class MainForm : Form
        {
            private Button button1;
            private TextBox textBox1;

            public MainForm()
            {
                this.button1 = new System.Windows.Forms.Button();
                this.textBox1 = new System.Windows.Forms.TextBox();
                this.SuspendLayout();
                // 
                // button1
                // 
                this.button1.Location = new System.Drawing.Point(12, 38);
                this.button1.Name = "button1";
                this.button1.Size = new System.Drawing.Size(75, 23);
                this.button1.TabIndex = 0;
                this.button1.Text = "Button 1";
                this.button1.UseVisualStyleBackColor = true;
                // 
                // textBox1
                // 
                this.textBox1.Location = new System.Drawing.Point(12, 12);
                this.textBox1.Name = "textBox1";
                this.textBox1.Size = new System.Drawing.Size(100, 20);
                this.textBox1.TabIndex = 1;
                // 
                // MainForm
                // 
                this.Controls.Add(this.textBox1);
                this.Controls.Add(this.button1);
                this.Name = "MainForm";
                this.Text = "Main Form";
                this.ResumeLayout(false);
                this.PerformLayout();
            }
        }

        private static IntPtr hWndProcHook = IntPtr.Zero;
        private static int messageCount = 0;

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern uint GetCurrentThreadId();

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            HookProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

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

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            InstallHook();
            Application.Run(new MainForm());
            UninstallHook();
        }

        private static void InstallHook()
        {
            if (Program.hWndProcHook == IntPtr.Zero)
            {
                Console.WriteLine("Hooking...");

                Program.hWndProcHook = SetWindowsHookEx(
                    WH_CALLWNDPROC,
                    WndProcHookCallback,
                    GetModuleHandle(null),
                    GetCurrentThreadId());

                if(Program.hWndProcHook != IntPtr.Zero)
                    Console.WriteLine("Hooked successfully.");
                else
                    Console.WriteLine("Failed to hook.");
            }
        }

        private static void UninstallHook()
        {
            if (Program.hWndProcHook != IntPtr.Zero)
            {
                Console.WriteLine("Unhooking...");

                if (UnhookWindowsHookEx(Program.hWndProcHook))
                    Console.WriteLine("Unhooked successfully.");
                else
                    Console.WriteLine("Failed to unhook.");

                Program.hWndProcHook = IntPtr.Zero;
            }
        }

        private static IntPtr WndProcHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            Console.WriteLine("WndProcHookCallback {0}", Program.messageCount++);

            return CallNextHookEx(Program.hWndProcHook, nCode, wParam, lParam);
        }
    }
}

解决方案

While testing your program I got the following error

CallbackOnCollectedDelegate was detected
Message: A callback was made on a garbage collected delegate of type 'Sandbox Form!Sandbox_Form.Program+HookProc::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

I believe the problem is the delegate that is implicitly created to be passed in to SetWindowsHookEx for the callback is getting garbage collected. By explicitly creating a variable for the delegate and keeping it in scope I think it will make your problem go away, when I modified InstallHook to the following I could no longer re-create the error.

private static HookProc hookProcDelegate;

private static void InstallHook()
{
    if (Program.hWndProcHook == IntPtr.Zero)
    {
        Console.WriteLine("Hooking...");

        hookProcDelegate = new HookProc(WndProcHookCallback);

        Program.hWndProcHook = SetWindowsHookEx(
            WH_CALLWNDPROC,
            hookProcDelegate,
            GetModuleHandle(null),
            GetCurrentThreadId());

        if (Program.hWndProcHook != IntPtr.Zero)
            Console.WriteLine("Hooked successfully.");
        else
            Console.WriteLine("Failed to hook.");
    }
}

这篇关于pressing标签几次后挂线的过程不再被调用。为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆