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

检测到: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. Git 客户端在 WebIDE 中的实现

    Coding WebIDE 是 Coding.net 自主研发的在线集成开发环境 (IDE).你可以通过 WebIDE 创建项目的工作空间, 进行在线开发, 调试等操作,有功能健全的 Terminal ...

  2. opengl 和 vs2010的安装配置

    1.先安装vs2010, 输个激活秘钥 2.Windows 7下OpenGL如何配置,配置glut:    http://jingyan.baidu.com/article/b0b63dbfd1c08 ...

  3. Good Bye 2014 B. New Year Permutation(floyd )

    题目链接 题意:给n个数,要求这n个数字小的尽量放到前面,求一个最小的. 给一个矩阵s[i][j]==1,表示位置 i 的数字可以和 位置 j 的数字交换. 分析: 刚开始用的是3个循环,每次都找一个 ...

  4. Sharepoint2013商务智能学习笔记之Secure Store Service服务配置(二)

    Secure Store Service 是运行在应用程序服务器上的授权服务,它提供一个存储用户凭据的数据库,Secure Store Service 在商务智能中的地位很重要,Sharepoint商 ...

  5. Dapper.Common基于Dapper的开源LINQ超轻量扩展

    Dapper.Common Dapper.Common是基于Dapper的LINQ实现,支持.net core,遵循Linq语法规则.链式调用.配置简单.上手快,支持Mysql,Sqlserver(目 ...

  6. kolla-ansible安装cinder

    LVM后端 环境拓扑 节点 IP 主机名 Controller/Network/Apollo 92.0.0.11 anode Compute/Storage 92.0.0.12 bnode multi ...

  7. C++的STL总结(1)

    没有很系统的学过算法,c++也只是学些基础,虽然经常会用一些STL里面的函数,但是并没有对STL模板库有一个清晰的了解,趁着寒假有时间就自己在网上百度浏览别人的总结的内容,自己汇集并总结了一下,希望对 ...

  8. angular1 表单验证demo

    这是一个angular1 验证表单的小栗子: 先看代码: <div ng-controller="myController"> <form name=" ...

  9. GVIM安装手记

    GVIM安装手记 1. 安装GIT及GVIM Downloa Git URL : https://gitforwindows.org/ Downloa GVim URL : https://www.v ...

  10. 不重新编译安装php模块的方法

    如果你有下面两种经历: 如果php通过源码安装(php7),如果后来需要开启某个自带模块(例如ldap,snmp等),通常需要重新编译. 另外一些安装php模块的经历,例如redis,swoole,y ...