在C#中停止对非托管代码的垃圾回收 [英] stop garbage collection on unmanaged code in C#

查看:123
本文介绍了在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屋!

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