做项目的时候遇到了这个问题:

检测到:CallbackOnCollectedDelegate

对“xx.HookProc::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。
 

callbackOnCollectedDelegate MDA

.NET Framework 4

如果将一个委托作为函数指针从托管代码封送到非托管代码,并且在对该委托进行垃圾回收后对该函数指针发出了一个回调,则将激活 callbackOnCollectedDelegate 托管调试助手 (MDA)。

症状

尝试通过从托管委托获取的函数指针调入托管代码时发生访问冲突。 这些故障虽然不是公共语言运行时 (CLR) bug,但是会显示为公共语言运行时 bug,因为 CLR 代码中发生了访问冲突。

此故障的具体情况并非千篇一律:有时对函数指针发出的调用可以成功,有时却会失败。 仅在负载过大或按随机次数进行尝试时会发生此故障。

原因

从其创建函数指针并将创建的函数指针公开给非托管代码的委托已被垃圾回收。 当非托管组件尝试对该函数指针发出调用时,会产生访问冲突。

该故障是随机出现的,因为它的出现取决于垃圾回收发生的时间。 如果某个委托符合回收条件,则会在回调之后进行垃圾回收,并且调用会成功。 在其他一些情况下,垃圾回收发生在回调之前,回调会引发访问冲突,并且程序会停止。

该故障发生的可能性取决于从封送委托到对函数指针发出回调之间的时间以及垃圾回收的频率。 如果从封送委托到接着发生的回调之间的时间很短,则发生该故障会的机会就很少。 通常情况下,如果接收函数指针的非托管方法没有保存该函数指针以备以后使用,而是立即对函数指针发出回调以便在返回之前完成其操作,就很少发生这种故障。 同样道理,系统负载过大时会发生更多垃圾回收,进而使得垃圾回收更有可能在回调之前发生。

解决方法

一旦将委托作为非托管函数指针封送出去,垃圾回收器就无法跟踪其生存期。 这样,在该非托管函数指针的生存内,您的代码必须保持一个指向该委托的引用。 但是在此之前,您首先必须确定回收了哪个委托。 激活 MDA 之后,MDA 会提供该委托的类型名称。 请使用此名称在您的代码中搜索将该委托外传给非托管代码的平台调用或 COM 签名。 通过这些调用站点之一将有问题的委托传递出去。 您还可以启用 gcUnmanagedToManaged MDA 以强制在每次向运行时发出回调之前都进行垃圾回收。 这样可以确保在回调之前总是进行垃圾回,从而可以消除由垃圾回收引起的不确定性。 一旦您得知回收了哪个委托,请更改您的代码,以便在封送的非托管函数指针的生存期内在托管端保持对该委托的引用。

看了一会,也不是很清楚,大致知道它是因为委托在回调之前已经被回收了,看了网上一片资料,了解到,解决此问题的方法就是扩大委托的作用域,向非托管函数传递委托的引用。参考资料:http://blog.chinaunix.net/uid-22695386-id-3040624.html
具体到代码中的解决方式就是:
Win32Lib.cs
 using System;
 using System.Collections.Generic;
 using System.Text;
 using System.Runtime.InteropServices;

 namespace testNotifyIcon
 {
     #region 委托

     internal delegate int HookProc(int code, int wParam, IntPtr lParam);//声明委托

     #endregion

     //略去若干行代码

     /// <summary>
     /// Win32函数库(仅摘录用到的函数)
     /// </summary>
     internal static class Win32Lib
     {
         #region 字段
         public static HookProc hookproc;//这里是重点

         public const string ATOM_FLAG = "HookSysKey";
         public const string SHELL_FALG = "Winlogon";
         ;    //注入代码所占的双字数
         );    //字节数
         ;         //注入代码线程函数偏移量
         public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
         public const UInt32 TOKEN_QUERY = 0x0008;
         public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
         public const string SE_DEBUG_NAME = "SeDebugPrivilege";
         ;

         #endregion

         #region 外部函数

         #region user32.dll

         [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
         public static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr pInstance, int threadId);

         [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
         public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);

         [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
         public static extern int CallNextHookEx(IntPtr pHookHandle, int nCode, int wParam, IntPtr lParam);

         [DllImport("user32.dll")]
         public static extern bool BlockInput(bool fBlockIt);

         #endregion

         //此处略图N行代码

         #endregion
     }
 }

InputHook.cs

 //略去N行代码
 IntPtr pInstance = Win32Lib.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
 Win32Lib.hookproc = new HookProc(LowLevelKeyboardProc);//此为重点
 //安装钩子
 m_lHookID = Win32Lib.SetWindowsHookEx(
   (int)HookType.WH_KEYBOARD_LL,
   Win32Lib.hookproc,//此为重点
   pInstance,
   );
 //略去N行代码

重点就是这样

 internal delegate int HookProc(int code, int wParam, IntPtr lParam);
 public class test
 {
     private static HookProc hookproc;
     hookproc =  new HookProc(xxx);
     SetWindowsHookEx(,hookproc ,     Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[]), );
 }

C#问题记录-CallbackOnCollectedDelegate的更多相关文章

  1. 记一次debug记录:Uncaught SyntaxError: Unexpected token ILLEGAL

    在使用FIS3搭建项目的时候,遇到了一些问题,这里记录下. 这里是发布搭建代码: // 代码发布时 fis.media('qa') .match('*.{js,css,png}', { useHash ...

  2. nginx配置反向代理或跳转出现400问题处理记录

    午休完上班后,同事说测试站点访问接口出现400 Bad Request  Request Header Or Cookie Too Large提示,心想还好是测试服务器出现问题,影响不大,不过也赶紧上 ...

  3. Kali对wifi的破解记录

    好记性不如烂笔头,记录一下. 我是在淘宝买的拓实N87,Kali可以识别,还行. 操作系统:Kali 开始吧. 查看一下网卡的接口.命令如下 airmon-ng 可以看出接口名称是wlan0mon. ...

  4. 2015 西雅图微软总部MVP峰会记录

    2015 西雅图微软总部MVP峰会记录 今年决定参加微软MVP全球峰会,在出发之前本人就已经写这篇博客,希望将本次会议原汁原味奉献给大家 因为这次是本人第一次写会议记录,写得不好的地方希望各位园友见谅 ...

  5. 分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)

    分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间) 很多时候我们都需要计算数据库中各个表的数据量和每行记录所占用空间 这里共享一个脚本 CREATE TABLE #tab ...

  6. 我是如何在SQLServer中处理每天四亿三千万记录的

    首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...

  7. 前端学HTTP之日志记录

    前面的话 几乎所有的服务器和代理都会记录下它们所处理的HTTP事务摘要.这么做出于一系列的原因:跟踪使用情况.安全性.计费.错误检测等等.本文将谥介绍日志记录 记录内容 大多数情况下,日志的记录出于两 ...

  8. ASP.NET Core应用中如何记录和查看日志

    日志记录不仅对于我们开发的应用,还是对于ASP.NET Core框架功能都是一项非常重要的功能特性.我们知道ASP.NET Core使用的是一个极具扩展性的日志系统,该系统由Logger.Logger ...

  9. python+uwsgi导致redis无法长链接引起性能下降问题记录

    今天在部署python代码到预生产环境时,web站老是出现redis链接未初始化,无法连接到服务的提示,比对了一下开发环境与测试环境代码,完全一致,然后就是查看各种日志,排查了半天也没有查明是什么原因 ...

随机推荐

  1. 理解setTimeout和setInterval

    setTimeout和setInterval,这两个js函数都是用来定时执行.setTimeout执行一次,setInterval执行多次. 问题出现在今天,使用setInterval是,设置执行速度 ...

  2. enter键触发事件的清除

    使用iframe弹窗时 父级页面 初始化的时候 给enter键绑定了事件 在子页面中 按下enter键会触发 而报错,此时在本页面的初始化的时候 将enter键绑定的方法取消 即可: $(docume ...

  3. 通过jQuery实现AJAX

    通过jQuery实现AJAX > 使用get和getJSON都会有缓存问题,并且使用get方法不能传送较多的数据. 问题: 在IE浏览器中,get请求使用ajax存在缓存问题,会使用上一次请求的 ...

  4. CTS/APIO2019游记

    退役后游记... 这次是真·游记了 ghj1222自从省选翻车后心情一直不错 5.12 (CTS 报到) 没去thupc(话说都不知道thupc这时候举行),于是就这天从衡水出发了 翻来覆去睡不着觉, ...

  5. Python中list的复制及深拷贝与浅拷贝探究

    在Python中,经常要对一个list进行复制.对于复制,自然的就有深拷贝与浅拷贝问题.深拷贝与浅拷贝的区别在于,当从原本的list复制出新的list之后,修改其中的任意一个是否会对另一个造成影响,即 ...

  6. idea长用快捷键

    1CA(ctrl+alt) 1.1(记忆mlv) ctrl alt m 代码封装成方法 ctrl alt L格式化代码 ctrl alt v补全返回值 (eclipse: alt shift l) 1 ...

  7. git教程2-git基础

    clone 使用IDE,直接在vcs里,从git checkout,方便. commit commit是提交到本地git仓库,本质是做一次存储快照. 可以多次commit之后,再次push到git服务 ...

  8. Python之PIP安装

    Python有两个著名的包管理工具easy_install.py和pip.Python2.7的安装包中自带了easy_install.py,而pip需要手动安装.而在Python3.5之后都是默认安装 ...

  9. js中大数据量form表单卡顿问题解决

    转载大神: http://www.mamicode.com/info-detail-1773696.html

  10. FTP服务器windows配置

    1.配置IIS Web的FTP站点 1.1 打开iis管理器(方法很多,这里我们用命令) Win+r中输入:inetmgr 1.2 新建FTP站点 1.2.1 新建FTP服务器根目录文件夹 1.2.2 ...