gpt4 book ai didi

c# - 多次按 Tab 键后不再调用线程 Hook 程序。为什么?

转载 作者:行者123 更新时间:2023-11-30 12:12:48 25 4
gpt4 key购买 nike

我安装了一个线程特定的窗口钩子(Hook)来监视发送到 WndProc 的消息。一开始它起作用了。但是,在我按 Tab 键大约 19 次以围绕表单移动焦点后,我的 Hook 回调不再被调用。无论我是快速还是缓慢地按下 Tab,都会发生这种情况。谁能解释一下到底发生了什么?

下面是我写的代码。我在 Windows 7 64 位上对其进行了测试。

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);
}
}
}

最佳答案

在测试你的程序时我遇到了以下错误

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.

我认为问题是隐式创建以传递给 SetWindowsHookEx 以进行回调的委托(delegate)正在被垃圾收集。通过为委托(delegate)显式创建一个变量并将其保留在范围内,我认为这将使您的问题消失,当我将 InstallHook 修改为以下内容时,我无法再重新创建错误。

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.");
}
}

关于c# - 多次按 Tab 键后不再调用线程 Hook 程序。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12878729/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com