gpt4 book ai didi

c# - 检测到 globalKeyboardHook 中的 CallbackOnCollectedDelegate

转载 作者:可可西里 更新时间:2023-11-01 08:16:15 28 4
gpt4 key购买 nike

我正在使用全局键盘 Hook 类。此类允许检查是否在任何地方按下了键盘键。一段时间后我遇到了一个错误:

        **CallbackOnCollectedDelegate was detected**

A callback was made on a garbage collected delegate of type 'Browser!Utilities.globalKeyboardHook+keyboardHookProc::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.

这是 globalkeyboardHook 类:

        public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);

public struct keyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}

const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;

public List<Keys> HookedKeys = new List<Keys>();

IntPtr hhook = IntPtr.Zero;

public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;

public globalKeyboardHook()
{
hook();
}

~globalKeyboardHook()
{
unhook();
}

public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}

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

public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kea);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}

[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);


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

[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);

[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
#endregion

有什么解决办法吗?该程序运行良好,但一段时间后程序卡住,我收到此错误。

最佳答案

hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);

这是你的问题。您依靠 C# 语法糖让它自动为 hookProc 创建一个委托(delegate)对象。实际代码生成如下所示:

keyboardHookProc $temp = new keyboardHookProc(hookProc);
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, $temp, hInstance, 0);

只有一个对委托(delegate)对象的引用,$temp。但它是局部变量,一旦您的 hook() 方法停止执行并返回,它就会消失。垃圾收集器无力查看 Windows 也有对它的“引用”,它无法探测非托管代码的引用。因此下次垃圾收集器运行时,委托(delegate)对象将被销毁。当 Windows 进行 Hook 回调时,那是一个爆炸。内置的 MDA 会检测问题并在程序因 AccessViolation 崩溃之前生成有用的诊断信息。

您将需要创建一个对存活时间足够长的委托(delegate)对象的附加引用。例如,您可以使用 GCHandle。或者更简单,只需自己存储一个引用,这样垃圾收集器就可以始终看到该引用。向您的类(class)添加一个字段。将其设为静态是确保无法收集对象的可靠方法:

    private static keyboardHookProc callbackDelegate;

public void hook()
{
if (callbackDelegate != null) throw new InvalidOperationException("Can't hook more than once");
IntPtr hInstance = LoadLibrary("User32");
callbackDelegate = new keyboardHookProc(hookProc);
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, callbackDelegate, hInstance, 0);
if (hhook == IntPtr.Zero) throw new Win32Exception();
}

public void unhook()
{
if (callbackDelegate == null) return;
bool ok = UnhookWindowsHookEx(hhook);
if (!ok) throw new Win32Exception();
callbackDelegate = null;
}

无需调用 FreeLibrary,user32.dll 始终加载直到您的程序终止。

关于c# - 检测到 globalKeyboardHook 中的 CallbackOnCollectedDelegate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9957544/

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