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

检测到: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. Luogu 4556 雨天的尾巴

    主席树+线段树合并. 首先我们想一想如果只有一个结点的话,我们弄一个权值线段树就可以随便维护了. 那么我们可以运用差分的思想,把一个询问拆成四个操作,对于一个询问$(x, y, v)$,我们在$x$的 ...

  2. c++中placement new

    c++中的placement new是::operator new的重载版本,用于在已经分配好的内存上创建对象.这样就可以在用户空间对内存进行操作,减少了对象生成的成本,控制对象的地址从而减少内存碎片 ...

  3. Lucene.net 搜索引擎的中文资料

    以下是我找到的网上一些关于Lucene.net 搜索引擎的介绍资料 https://code.i-harness.com/zh-CN/tagged/lucene?page=5 http://jingp ...

  4. C#识别图中二维码

    1.在NuGet中添加 ZXing.Net 2.实例代码 /// <summary> /// 识别图中二维码 /// </summary> /// <param name ...

  5. EIP权限工作流平台总结-2前端框架

      1.预览地址:www.eipflow.com (1) 权限工作流:www.demo.eipflow.com/Account/Login (2) 基础权限版:www.auth.eipflow.com ...

  6. go培训课程都学什么?xorm框架学习系列(二):xorm结构体映射规则和表操作

    上节内容我们学习了基本的xorm框架的知识和基础配置的相关信息.本节课内容我们继续学习相关的知识和相关操作. 名称映射规则 名称映射规则主要负责结构体名称到表名和结构体field到表字段的名称映射. ...

  7. 暴风魔镜SDK:MojingSDK For Unity V1.3.5112 (R).zip

    去年买了个暴风魔镜4,如今一直放在家里吃灰,这些天对Unity3D开发VR兴趣正浓,刚好公司项目不忙,花了几天玩玩暴风魔镜SDK,因为网上的资料不算多,暴风提供的文档也不太适合像我这样的Unity小白 ...

  8. Spring AOP 自定义注解实现统一日志管理

    一.AOP的基本概念: AOP,面向切面编程,常用于日志,事务,权限等业务处理.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容(Spring核心之一),是函数式编程 ...

  9. .gitkeep--git提交空目录的解决方法

    前言 git和 svn不同,仅仅跟踪文件的变动,不跟踪目录.所以,一个空目录,如果里面没有文件,即便 git add 这个目录,另外在别处 check out 的时候,是没有这个空目录的. 只跟踪文件 ...

  10. AngularJs页面跳转

    同一页面之间的跳转: $state.go('station.booking'); 打开新页面的跳转方式: var url = $state.href("knowledge.questiond ...