在C#中停止对非托管代码的垃圾回收 [英] stop garbage collection on unmanaged code in C#
问题描述
我有这个按键钩子脚本,当我在运行它的过程中持续几秒钟出错时,就会发现它.错误:调用垃圾收集的委托'childMonitor!Utilities.globalKeyboardHook + keyboardHookProc :: Invoke'.
I have this key hook script and when I keep getting an error a few seconds into running it. ERROR: call on garbage collected delegate 'childMonitor!Utilities.globalKeyboardHook+keyboardHookProc::Invoke'.
我听说我需要使用处置模式,我在这里尝试过使用该模式,但我99%的确定我失败了.在我的主程序中,我有一个按钮事件,该事件在完成后会调用hook(),并另一个调用unhook().
I heard I need to use dispose pattern and I tried that here but I am 99% sure I failed at it. In my main program I have a button event that calls hook() and another to unhook() when its done.
使用系统;
使用System.Collections.Generic;
使用System.Text;
使用System.Runtime.InteropServices;
使用System.Windows.Forms;
使用System.IO;
命名空间实用程序
{
///< summary>
///管理全局低级键盘挂钩的类
///</summary>
class globalKeyboardHook:IDisposable
{
私人布尔_disposed;
#region常数,结构和委托定义
///< summary>
///定义钩子的回调类型
///</summary>
公共委托int keyboardHookProc(int代码,int wParam,ref keyboardHookStruct lParam);
公共结构keyboardHookStruct
{
public int vkCode;
public int scanCode;
公共int标志;
公共时间;
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;
#endregion
#region实例变量
///< summary>
///要注意的键的集合
///</summary>
公共列表<键> HookedKeys = new List< Keys>();
///< summary>
///处理钩子,需要用它来解钩并调用下一个钩子
///</summary>
IntPtr hhook = IntPtr.Zero;
#endregion
#region活动
///< summary>
///按下钩子键之一时发生
///</summary>
公共事件KeyEventHandler KeyDown;
///< summary>
///在释放其中一个挂钩的键时发生
///</summary>
公共事件KeyEventHandler KeyUp;
#endregion
#region构造函数和析构函数
///< summary>
///初始化< see cref ="globalKeyboardHook"/>的新实例.类并安装键盘挂钩.
///</summary>
公共globalKeyboardHook()
{
hook();
_disposed = false;
}
公共无效Dispose()
{
Dispose(true);
//如果有子类,请使用SupressFinalize
//会实现终结器.
GC.SuppressFinalize(this);
}
受保护的虚拟void Dispose(布尔处置)
{
//如果您需要线程安全,请在这些线程周围使用锁
//操作以及使用该资源的方法.
如果(!_disposed)
{
如果(处置)
{
unhook();
}
//表示实例已被处置.
_disposed = true;
}
}
///< summary>
///在
之前释放非托管资源并执行其他清理操作
///<请参阅cref =" globalKeyboardHook"/>被垃圾回收回收并卸载键盘钩.
///</summary>
〜globalKeyboardHook()
{
Dispose();
}
#endregion
#region公共方法
///< summary>
///安装全局钩子
///</summary>
公共无效挂钩()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL,新keyboardHookProc(hookProc),hInstance,0);
}
///< summary>
///卸载全局钩子
///</summary>
公共无效unhook()
{
UnhookWindowsHookEx(hhook);
}
///< summary>
///键盘钩子的回调
///</summary>
///< param name =代码">挂钩代码,如果不是> = 0,则该函数不应执行任何操作</param>
///< param name =" wParam">事件类型</param>
///< param name ="lParam">按键事件信息</param>
///< returns></returns>
public int hookProc(int code,int wParam,ref keyboardHookStruct lParam)
{
如果(代码> = 0)
{
键key =(Keys)lParam.vkCode;
如果(HookedKeys.Contains(key))
{
KeyEventArgs kea = new KeyEventArgs(key);
if(((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)&&(KeyDown!= null))
{
b KeyDown(this,kea);
}
否则((wParam == WM_KEYUP || wParam == WM_SYSKEYUP)&&(KeyUp!= null))
{
b KeyUp(this,kea);
}
如果(kea.Handled)
b返回1;
}
}
返回CallNextHookEx(hhook,代码,wParam,ref lParam);
}
#endregion
#region DLL导入
///< summary>
///设置Windows钩子,执行所需的事件,hInstance或threadId之一必须为非空
///</summary>
///< param name =" idHook">您要挂钩的事件的ID</param>
///< param name ="callback">回调.</param>
///< param name ="hInstance">您要将事件附加到的句柄,可以为null</param>
///< param name =" threadId">您要将事件附加到的线程可以为null</param>
///<返回>所需钩子的句柄</returns>
[DllImport("user32.dll")]
静态外部IntPtr SetWindowsHookEx(int idHook,keyboardHookProc回调,IntPtr hInstance,uint threadId);
///< summary>
///脱开窗户的钩子.
///</summary>
///< param name ="hInstance">从SetWindowsHookEx</param>
返回的挂钩句柄
///< returns>如果成功则为True,否则为false</returns>
[DllImport("user32.dll")]
静态外部布尔UnhookWindowsHookEx(IntPtr hInstance);
///< summary>
///调用下一个钩子.
///</summary>
///< param name =" idHook">钩子ID</param>
///< param name ="nCode">挂钩代码</param>
///< param name =" wParam"> wparam.</param>
///< param name ="lParam"> lparam.</param>
///< returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook,int nCode,int wParam,ref keyboardHookStruct lParam);
///< summary>
///加载库.
///</summary>
///< param name =" lpFileName">库的名称</param>
///< returns>库的句柄</returns>
[DllImport("kernel32.dll")]
静态外部IntPtr LoadLibrary(string lpFileName);
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.IO;
namespace Utilities
{
/// <summary>
/// A class that manages a global low level keyboard hook
/// </summary>
class globalKeyboardHook : IDisposable
{
private bool _disposed;
#region Constant, Structure and Delegate Definitions
/// <summary>
/// defines the callback type for the hook
/// </summary>
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;
#endregion
#region Instance Variables
/// <summary>
/// The collections of keys to watch for
/// </summary>
public List<Keys> HookedKeys = new List<Keys>();
/// <summary>
/// Handle to the hook, need this to unhook and call the next hook
/// </summary>
IntPtr hhook = IntPtr.Zero;
#endregion
#region Events
/// <summary>
/// Occurs when one of the hooked keys is pressed
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// Occurs when one of the hooked keys is released
/// </summary>
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
/// </summary>
public globalKeyboardHook()
{
hook();
_disposed = false;
}
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// If you need thread safety, use a lock around these
// operations, as well as in your methods that use the resource.
if (!_disposed)
{
if (disposing)
{
unhook();
}
// Indicate that the instance has been disposed.
_disposed = true;
}
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
/// </summary>
~globalKeyboardHook()
{
Dispose();
}
#endregion
#region Public Methods
/// <summary>
/// Installs the global hook
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, new keyboardHookProc(hookProc), hInstance, 0);
}
/// <summary>
/// Uninstalls the global hook
/// </summary>
public void unhook()
{
UnhookWindowsHookEx(hhook);
}
/// <summary>
/// The callback for the keyboard hook
/// </summary>
/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
/// <param name="wParam">The event type</param>
/// <param name="lParam">The keyhook event information</param>
/// <returns></returns>
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);
}
#endregion
#region DLL imports
/// <summary>
/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
/// </summary>
/// <param name="idHook">The id of the event you want to hook</param>
/// <param name="callback">The callback.</param>
/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
/// <param name="threadId">The thread you want to attach the event to, can be null</param>
/// <returns>a handle to the desired hook</returns>
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
/// <summary>
/// Unhooks the windows hook.
/// </summary>
/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
/// <returns>True if successful, false otherwise</returns>
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
/// <summary>
/// Calls the next hook.
/// </summary>
/// <param name="idHook">The hook id</param>
/// <param name="nCode">The hook code</param>
/// <param name="wParam">The wparam.</param>
/// <param name="lParam">The lparam.</param>
/// <returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
#endregion
}
}
推荐答案
使用
这篇关于在C#中停止对非托管代码的垃圾回收的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!