CLR 4.0 Beta1新功能:Stub Method Redirection

print spooler服务总是停止的解决方法 print spooler服务总是停止的解决方法。。。。。。。。 立即下载

.NET Framework v4.0和VisualStudio 2010 Beta1已经出来有阵子了,估计有些喜欢尝鲜的朋友已经下载试用了。这一次发布包含了大量的新功能。我们上海CLR开发团队会编写一系列的文章介绍Interop的相关新功能。我来给大家简单介绍一下Stub Method Redirection功能。这个功能是CLR上海开发团队设计、开发并测试的新功能之一,这一次我们上海CLR小组共开发了下面几个功能

1. Managed TlbImp (Rewrite)

2. Stub Method Redirection

3. IL Stub ETW Diagnostics

4. Custom QueryInterface

而在CodePlex上面:

1. 发布了TlbImp的最新版本,包括基于规则的Customization(具体可以参考:这一篇)

2. 即将发布IL Stub Diagnostics Tool,可以方便大家直接观看IL Stub,内部使用IL Stub ETW Diagnostics新功能实现

除此之外,还有一些功能是由美国团队开发的:

1. NO PIA

2. IL Stub Everywhere

3. Limit Pumping

4. PreferComThanRemoting

除了NOPIA在我之前的文章已经介绍过之外,其他功能我们会陆续写文章介绍。这次我们先介绍Stub Method Redirection。在介绍这个功能之前,有必要先介绍一下相关的背景知识:

什么是IL Stub

大家都知道,在进行Interop调用的时候,CLR会对参数进行转换(也就是所谓的Marshalling),然后再调用到目标函数。这样一个参数转换和Marshalling实际上是一小段Stub(桩代码)来负责的,比如在调用MessageBox的时候,MessageBox_IL_STUB就是负责Marshalling和参数调用的Stub:

clip_image002

当然了,这里的Stub的内容只是一个简单的抽象,实际的内容会比这个复杂一些。在实际情况下,CLR在第一次执行MessageBox的时候,会动态生成MessageBox对应的IL STUB,使用内部的类似于ReflectionEmit的机制直接输出IL代码的Byte Code,然后交给JIT来编译之,比如MessageBox对应的IL Stub是这样子的:

  1: .maxstack 6 
  2: .locals (native int,int32,native int,int32,native int,native int,int32,native int,int32,int32,int32,int32)
  3: // Initialize {
  4:          /*( 0)*/ call            native int [mscorlib] System.StubHelpers.StubHelpers::GetStubContext() 
  5:          /*( 1)*/ call            void [mscorlib] System.StubHelpers.StubHelpers::DemandPermission(native int) 
  6: // } Initialize 
  7: // Marshal {
  8:          /*( 0)*/ ldc.i4.0         
  9:          /*( 1)*/ stloc.0          
 10: IL_000c: /*( 0)*/ nop             // argument {  
 11:          /*( 0)*/ ldarg.0          
 12:          /*( 1)*/ stloc.1          
 13:          /*( 0)*/ ldc.i4.1         
 14:          /*( 1)*/ stloc.0          
 15:          /*( 0)*/ nop             // } argument 
 16:          /*( 0)*/ nop             // argument {  
 17:          /*( 0)*/ ldc.i4.0         
 18:          /*( 1)*/ stloc.s         0x4 
 19:          /*( 0)*/ ldarg.1          
 20:          /*( 1)*/ brfalse         IL_0037 
 21:          /*( 0)*/ ldarg.1          
 22:          /*( 1)*/ call            instance int32 [mscorlib] System.String::get_Length() 
 23:          /*( 1)*/ ldc.i4.2         
 24:          /*( 2)*/ add              
 25:          /*( 1)*/ stloc.3          
 26:          /*( 0)*/ ldc.i4          0x105 
 27:          /*( 1)*/ ldloc.3          
 28:          /*( 2)*/ clt              
 29:          /*( 1)*/ brtrue          IL_0037 
 30:          /*( 0)*/ ldloc.3          
 31:          /*( 1)*/ localloc         
 32:          /*( 1)*/ stloc.s         0x4 
 33: IL_0037: /*( 0)*/ ldc.i4.1         
 34:          /*( 1)*/ ldarg.1          
 35:          /*( 2)*/ ldloc.s         0x4 
 36:          /*( 3)*/ call            native int [mscorlib] System.StubHelpers.CSTRMarshaler::ConvertToNative(int32,string,native int) 
 37:          /*( 1)*/ stloc.2          
 38:          /*( 0)*/ ldc.i4.2         
 39:          /*( 1)*/ stloc.0          
 40:          /*( 0)*/ nop             // } argument 
 41:          /*( 0)*/ nop             // argument {  
 42:          /*( 0)*/ ldc.i4.0         
 43:          /*( 1)*/ stloc.s         0x7 
 44:          /*( 0)*/ ldarg.2          
 45:          /*( 1)*/ brfalse         IL_006c 
 46:          /*( 0)*/ ldarg.2          
 47:          /*( 1)*/ call            instance int32 [mscorlib] System.String::get_Length() 
 48:          /*( 1)*/ ldc.i4.2         
 49:          /*( 2)*/ add              
 50:          /*( 1)*/ stloc.s         0x6 
 51:          /*( 0)*/ ldc.i4          0x105 
 52:          /*( 1)*/ ldloc.s         0x6 
 53:          /*( 2)*/ clt              
 54:          /*( 1)*/ brtrue          IL_006c 
 55:          /*( 0)*/ ldloc.s         0x6 
 56:          /*( 1)*/ localloc         
 57:          /*( 1)*/ stloc.s         0x7 
 58: IL_006c: /*( 0)*/ ldc.i4.1         
 59:          /*( 1)*/ ldarg.2          
 60:          /*( 2)*/ ldloc.s         0x7 
 61:          /*( 3)*/ call            native int [mscorlib] System.StubHelpers.CSTRMarshaler::ConvertToNative(int32,string,native int) 
 62:          /*( 1)*/ stloc.s         0x5 
 63:          /*( 0)*/ ldc.i4.3         
 64:          /*( 1)*/ stloc.0          
 65:          /*( 0)*/ nop             // } argument 
 66:          /*( 0)*/ nop             // argument {  
 67:          /*( 0)*/ ldarg.3          
 68:          /*( 1)*/ stloc.s         0x8 
 69:          /*( 0)*/ ldc.i4.4         
 70:          /*( 1)*/ stloc.0          
 71:          /*( 0)*/ nop             // } argument 
 72:          /*( 0)*/ nop             // return {  
 73:          /*( 0)*/ nop             // } return 
 74: // } Marshal 
 75: // CallMethod {
 76:          /*( 0)*/ ldloc.1          
 77:          /*( 1)*/ ldloc.2          
 78:          /*( 2)*/ ldloc.s         0x5 
 79:          /*( 3)*/ ldloc.s         0x8 
 80:          /*( 4)*/ call            native int [mscorlib] System.StubHelpers.StubHelpers::GetStubContext() 
 81:          /*( 5)*/ ldc.i4.s        0x30 
 82:          /*( 6)*/ add              
 83:          /*( 5)*/ ldind.i          
 84:          /*( 5)*/ ldind.i          
 85:          /*( 5)*/ calli           unmanaged stdcall int32(int32,native int,native int,int32) 
 86: // } CallMethod 
 87: // UnmarshalReturn {
 88:          /*( 1)*/ nop             // return {  
 89:          /*( 1)*/ stloc.s         0xa 
 90:          /*( 0)*/ ldc.i4.5         
 91:          /*( 1)*/ stloc.0          
 92:          /*( 0)*/ ldloc.s         0xa 
 93:          /*( 1)*/ stloc.s         0x9 
 94:          /*( 0)*/ ldloc.s         0x9 
 95:          /*( 1)*/ nop             // } return 
 96:          /*( 1)*/ stloc.s         0xb 
 97: // } UnmarshalReturn 
 98: // Unmarshal {
 99:          /*( 0)*/ nop             // argument {  
100:          /*( 0)*/ nop             // } argument 
101:          /*( 0)*/ nop             // argument {  
102:          /*( 0)*/ nop             // } argument 
103:          /*( 0)*/ nop             // argument {  
104:          /*( 0)*/ nop             // } argument 
105:          /*( 0)*/ nop             // argument {  
106:          /*( 0)*/ nop             // } argument 
107:          /*( 0)*/ leave           IL_00b3 
108: IL_00b3: /*( 0)*/ ldloc.s         0xb 
109:          /*( 1)*/ ret              
110: // } Unmarshal 
111: // Cleanup {
112: IL_00b6: /*( 0)*/ ldloc.0          
113:          /*( 1)*/ ldc.i4.1         
114:          /*( 2)*/ ble             IL_00ca 
115:          /*( 0)*/ ldloc.s         0x4 
116:          /*( 1)*/ brtrue          IL_00ca 
117:          /*( 0)*/ ldloc.2          
118:          /*( 1)*/ call            void [mscorlib] System.StubHelpers.CSTRMarshaler::ClearNative(native int) 
119: IL_00ca: /*( 0)*/ ldloc.0          
120:          /*( 1)*/ ldc.i4.2         
121:          /*( 2)*/ ble             IL_00df 
122:          /*( 0)*/ ldloc.s         0x7 
123:          /*( 1)*/ brtrue          IL_00df 
124:          /*( 0)*/ ldloc.s         0x5 
125:          /*( 1)*/ call            void [mscorlib] System.StubHelpers.CSTRMarshaler::ClearNative(native int) 
126: IL_00df: /*( 0)*/ endfinally       
127: // } Cleanup 
128: .try IL_000c to IL_00b3 finally handler IL_00b6 to IL_00e0
129: 

可以看到IL代码非常多,这些都是CLR内部自动生成的。因为看到这些代码有助于开发者理解内部工作原理和找到错误(一般来说是开发者本身的问题,比如MarshalAs写错了),我们将发布一个工具可以让你看到IL Stub具体内容,底层是通过调用另外一个CLR V4 Interop的新功能:IL Stub ETW Diagnostics实现的,以后有机会我会写另外一篇文章介绍。至于IL代码本身的相关内容可以参考Experts IL Assembler和Common Language Infrastructure Annotated Standard.

总的来说,一般的IL Stub总要负责下面几件事情:

1. 安全检查

2. 参数转换,包括返回值

3. 调用目标函数,检查返回值,可能会抛出异常

4. 清理临时内存

其实还有一些其他细节问题如切换GC模式等,建立Frame等等,但是这些属于CLR内部细节问题,这里不再赘述。

IL Stub的问题

IL Stub目前为止都工作的很好。其实,CLR内部本来不是所有情况下都是用IL Stub,2.0以前还存在所谓的ML Stub (Marshalling Language),专门工作在x86下,IL则是工作在x64和IA-64上,后来美国团队将之整合,现在就只有IL Stub了。看起来现在的IL Stub就足够了,不过事实上我们认为ILStub仍然存在一些问题:

1. 无法调试

    a. 目前VS暂时不支持调试IL代码

    b. 即使可以调试,绝大多数开发者根本不熟悉IL代码

    c. IL代码是动态生成,增大了调试支持实现的难度

    d. 较难通过工具直接看到(我们即将发布新工具支持看到IL Stub)

2. 不够灵活

    a. IL Stub是CLR根据内置规则生成(也就是MarshalAs那一套),开发者无法加入新的规则

    b. 开发者无法使用自己的Stub来替换ILStub

3. 组件化和维护性:CLR有大量生成IL Stub的代码,这些代码非常复杂,规则繁多,大大增加了CLR的复杂度,而且本身是由C++写成,较难维护

我们的Vision

既然IL Stub本身有这么多问题,那么我们应该如何解决这些问题呢?在开发Stub Method Redirection新功能之前,我们Team内部有一些讨论,达成的共识如下:

1. CLR只支持最简单的calli调用本地代码

2. IL Stub由编译时刻工具生成:ILStubGen.exe

   a. 工具内置数据转换规则

   b. 用户可通过插件自定义

3. 生成的IL Stub通过calli调用本地代码

4. Interop类型和Stub直接嵌入在目标程序中:NO PIA是朝这个方向的正确一步

5. CLR运行时刻加载IL Stub:Stub Method Redirection支持该功能

可以看到,按照如上的方法,CLR可以完全从生成IL stub的任务中解放出来,IL Stub的生成也从动态(运行时)转为静态(编译时),并且可以用C#编写,解决了调试、性能、组件化,维护性的众多问题。为了实现这个美好的Vision,有很多工作要做,而且这些工作显然没法在一个Release之内完成,因此我们采取的方法是迭代渐进式的。也就是说,每个Release都会添加一些功能,和这个Vision更加接近。这个Release,我们做的就是NO PIA,以及Stub Method redirection(的一部分)。

Stub Method Redirection

所谓Stub Method,也就是用户编写的编译时刻决定的Stub,可以用任意语言编写,CLR在运行时刻不会动态生成IL Stub,而是会使用用户自定义的Stub,而实现这个的秘诀就是:

ManagedToNativeComInteropStubMethodAttribute

这个Attribute有两个参数:

1. Type:Stub Method所位于的类

2. Name:Stub Method的名称。虽然我们也想实现所谓的methodof功能(类似typeof),但是让C#在4.0中替我们加上这个功能不是太现实,因此我们就先使用名字来查找,速度稍慢,但是因为相关查找只用进行一次,而且可以通过NGEN来避免查找(NGEN来负责查找然后把查找结果直接写入本地代码中),因此速度上不存在问题。

一旦在接口(非接口不可以)的某个方法上面添加上这个Attribute,CLR就知道根据这个Attribute来找Stub,而非自己生成。

用户可以通过这个功能做下面的事情:

1. 编写自己的Stub

    a. 加以优化(比如内存池之类的)

    b. 提供自定义的类型转换

2. 编写第三方工具自己生成Stub(不过一般来讲这个会是由CLR和.NET Framework提供)

任何编写的Stub Method必须满足下面这些要求:

1. 必须是静态

2. 第一个参数是接口类型

3. 其他参数和对应接口方法完全一致

4. 必须和对应接口位于同一个Assembly,这既是简化,也符合我们的Vision

5. 必须满足访问性要求:从接口的方法必须可以访问到Stub,这个和逻辑上的调用顺序是一致的

6. 不可以是generic

一旦不满足要求,CLR在执行方法的时候会抛出异常,比如:

clip_image004

这个信息是我和PM MM讨论数次之后决定的,目的是让其尽量清晰。

对于一个Stub Method来讲,通常的格式是这样子的:

  1: class FooStubClass
  2: {
  3: 	internal static void ForwardFooStub(IFoo thisObject, string arg) 
  4: 	{
  5: 		try{
  6: 			// Step 1: 	托管参数转换到非托管参数(In)
  7: 			// Step 2: 	获得调用目标函数的地址
  8: 		 	// Step 3:	通过Delegate调用目标函数
  9: 			// Step 4:	非托管参数转换到托管参数(Out) 
 10: 			// Step 5:	转换返回值
 11: 		}
 12: 		finally
 13: 		{
 14: 			// Step 6:	清理工作
 15: 		}
 16: 	}
 17: }
 18: 

下面分别解释一下:

1. 托管参数转换到非托管参数(In):一般这里调用Marshal的对应函数来进行转换,比如Marshal.StringToBSTR

2. 获得调用目标函数的地址:这个稍微复杂一点,注意因为是COM,所以需要通过虚函数表来获得:

  1:                 //
  2:                 // Get interface pointer
  3:                 //
  4:                 IntPtr pIntf = Marshal.GetComInterfaceForObject(_this, typeof(IFoo));
  5: 
  6:                 //
  7:                 // Get target
  8:                 //
  9:                 IntPtr pTarget = IntPtr.Zero;
 10: 
 11:                 unsafe
 12:                 {
 13:                     void** pVtbl = *(void***)pIntf;
 14:                     pTarget = new IntPtr(*(pVtbl + 7)); // IUnknown => 3, IDispatch => 4
 15:                 }
 16: 

比如上面的代码就获得了_this的IFoo指针,然后获取了虚函数表第八项(跳过IUnknown3个函数,IDispatch 4个函数)作为函数指针

3. 通过Delegate调用目标函数:这一步骤需要首先调用Marshal.GetDelegateForFunctionPointer获得函数指针对应的Delegate,注意Delegate的参数必须得是对应非托管的类型,比如MessageBox对应的delgate是(IntPtr, IntPtr, IntPtr, int),然后再调用delegate,传入参数

4. 非托管参数转换到托管参数(Out):转换的时候既要包括IN也要包括OUT,比如[in, out]char []这种情况,必须两种方向都要照顾到,IN在调用之前转换,而OUT则是在调用之后转换

5. 转换返回值:这个没太多好说的,和OUT比较类似

6. 清理工作:转换不要忘记清理中间生成的临时数据,比如string转换到char *需要调用Marshal.StringToCoTaskMemAnsi转换,之后调用Marshal.FreeCoTaskMem释放,释放则是在Cleanup中作

最后是一个完整的例子:

  1: Using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.Runtime.InteropServices;
  6: using System.Runtime.CompilerServices;
  7: 
  8: namespace StubMethodDemo
  9: {
 10:     [ComImport]
 11:     [Guid("0741BD5F-549A-46FD-A857-0E3B23620399")]
 12:     interface IFoo
 13:     {
 14:         [MethodImplAttribute(MethodImplOptions.InternalCall)]
 15:         [ManagedToNativeComInteropStubAttribute(typeof(FooStubClass), "IFoo_Hello_Stub")]
 16:         void Hello(string name);
 17:     }
 18: 
 19:     [ComImport]
 20:     [Guid("68389CF3-212B-449D-83CB-0DD4572FEF03")]
 21:     class Foo : IFoo
 22:     {
 23:         [MethodImplAttribute(MethodImplOptions.InternalCall)]
 24:         public extern void Hello(string name);
 25:     }
 26: 
 27:     class FooStubClass
 28:     {
 29:         public delegate int IFoo_Hello_Delegate(IntPtr _this, IntPtr a);
 30: 
 31:         public void IFoo_Hello_Stub(IFoo _this, string name)
 32:         {
 33:             IntPtr nativeArg_name = IntPtr.Zero;
 34: 
 35:             try
 36:             {
 37:                 // 
 38:                 // Marshal CLR => Native
 39:                 //
 40:                 nativeArg_name = Marshal.StringToBSTR(name);
 41: 
 42:                 //
 43:                 // Get interface pointer
 44:                 //
 45:                 IntPtr pIntf = Marshal.GetComInterfaceForObject(_this, typeof(IFoo));
 46: 
 47:                 //
 48:                 // Get target
 49:                 //
 50:                 IntPtr pTarget = IntPtr.Zero;
 51: 
 52:                 unsafe
 53:                 {
 54:                     void** pVtbl = *(void***)pIntf;
 55:                     pTarget = new IntPtr(*(pVtbl + 7)); // IUnknown => 3, IDispatch => 4
 56:                 }
 57: 
 58:                 //
 59:                 // Make the call
 60:                 //
 61:                 Delegate dele = Marshal.GetDelegateForFunctionPointer(pTarget, typeof(IFoo_Hello_Delegate));
 62:                 IFoo_Hello_Delegate targetDelegate = (IFoo_Hello_Delegate)dele;
 63:                 int hr = targetDelegate(pIntf, nativeArg_name);
 64:                 if (hr < 0)
 65:                     Marshal.ThrowExceptionForHR(hr);
 66: 
 67:                 //
 68:                 // Marshal Native => CLR
 69:                 //
 70: 
 71:                 //
 72:                 // Marshal return
 73:                 //
 74:             }
 75:             finally
 76:             {
 77:                 //
 78:                 // Cleanup
 79:                 //
 80:                 if (nativeArg_name != IntPtr.Zero)
 81:                     Marshal.FreeBSTR(nativeArg_name);
 82:                 nativeArg_name = IntPtr.Zero;
 83:             }
 84:         }
 85:     }
 86: 
 87:     class Program
 88:     {
 89:         static void Main(string[] args)
 90:         {
 91:             Foo myFoo = new Foo();
 92:             myFoo.Hello("Foo!");
 93:         }
 94:     }
 95: }
 96: 

 

作者:张羿

转载请注明出处

电路方案分析(十二)USB Type-C PD 移动电源参考设计方案 TPD8S300为USB Type-C连接器的CC1,CC2,SBU1和SBU2引脚集成了四个通道的20v短到vbus和过压保护。TPD8S300集成了八个IEC61000-4-2ESD保护通道,用于USB Type-C连接器的CC1、CC2、SBU1、SBU2、DP_T (顶侧D-) 、DM_T (顶侧D-) 、DP_B (底侧D-) 引脚。当电源组是接收器并为其自身的电池充电时,该芯片会对电池充电,而在电源模式期间,该芯片充当DC-DC转换器以生成VBUS。 阅读详情

相关推荐

保姆级教程:用rosbag录制和回放你的第一个ROS机器人数据(附C++/Python代码)

本文提供了一份详细的ROS机器人数据录制与回放教程,涵盖从命令行操作到C++/Python编程实现的全流程。通过rosbag工具,开发者可以高效记录和回放机器人运行时的传感器数据和控制指令,适用于故障复现、算法调试等多种场景。教程还包含高级技巧如时间同步和大文件处理,帮助用户快速掌握ROS数据管理核心技能。

weixin_29313239的博客 283

Wikipedia上面关于Method stub的说明

对大家在写程序中经常看到的“Method Stub”的解释[译文]

[ 自由 ][ 专业 ][ 执着 ] 1755

代码实现ROS2bag录制数据和回放数据(C++)

ROS2的ROS2bag功能可以将指定Topic中的数据以.db3的格式(不同于ROS)保存到本地文件中。读取文件数据可以实现数据回放。

m0_57124501的博客 3256

解决:0x80070057 ValueClassMarshaler.ConvertToNative

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34044273的博客 666

FOC实战笔记:RC吸收电路的设计考量与参数调优

本文深入探讨了FOC驱动器中RC吸收电路的设计与调优。针对MOS管开关过程中的电压尖峰问题,详细阐述了RC电路的钳位与能量吸收原理,并提供了从参数计算、实验调试到布局布线的完整实战指南,旨在帮助工程师有效提升系统可靠性与稳定性。

weixin_29219539的博客 273

EGO-Planner文章解读(一)——论文原理和算法实现

详细解读egoplanner论文和代码

fegxg的博客 3984

Java单元测试之Mockito

本人的理解:就是在实际调用代码前,我就规定它返回什么。// 您可以模拟具体的类,而不仅仅是接口s LinkedList mockedList = mock(LinkedList . class);// 或者使用Mockito 4.10.0+更简单 // LinkedList mockedList = mock();// 存根(stubbing)在实际执行之前出现 when(mockedList . get(0)) . thenReturn("first");

midnight_DJ的博客 2168

Linux系列:SecurtCRT中的密码如何找回

【代码】Linux系列:SecurtCRT中的密码如何找回。

NIO4444 1084

Java单元测试实践-08.Stub、Replace、Suppress静态方法

Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Stub、Replace、Suppress静态方法 以下主要说明,如何使用PowerMockito对静态方法进行Stub、Replace,以及对静态方法所在的类进行Suppress。 1.1. 对静态方法进行Stub 使用PowerMockito.stub()方法支持对静态方法进行Stub。 当间接调用被Stub方法时,

adrninistrat0r的博客 3979

飞书接入OpenClaw:从零到一的保姆级图文教程

本文主要介绍了飞书接入OpenClaw:从零到一的保姆级图文教程,希望能对学习使用OpenClaw 的同学们有所帮助。 文章目录 1. 背景 2. 解决方案 2.1 步骤一:安装插件 2.2 步骤二:创建机器人应用 2.3 步骤三:测试 3. 注意事项

weixin_43178406的博客 13万+

Python爬虫实战:使用Scrapy+Playwright高效爬取全球专利数据库

本文将详细介绍如何使用Python最新技术栈(Scrapy+Playwright)构建一个高效的专利数据库爬虫系统。我们将从爬虫基础知识讲起,逐步深入到反爬应对策略、分布式爬虫架构以及数据存储方案,最终实现一个完整的专利数据采集系统。专利数据是技术创新领域的重要信息资源,包含技术描述、权利要求、申请人信息等宝贵数据。中国国家知识产权局(CNIPA)美国专利商标局(USPTO)欧洲专利局(EPO)世界知识产权组织(WIPO)

2201_76125261的博客 1382

C#调用C++函数传入回调函数出现空引用问题

文章目录一、先看测试代码二、查看传入的函数地址1.直接传入函数2.传入委托3.小结二、测试空引用BUG1.直接传入函数2.直接传入委托总结 # 前言 C#调用C++函数时,如果C++函数需要传入回调函数,当C#调用时,如果直接传入函数作为参数的话,那么Release版本运行时就会出现**System.NullReferenceException: 未将对象引用设置到对象的实例。**这个异常问题。(Debug测试了一个晚上没出现不清楚为啥)这是由于直接传入函数作为参数的话,C#会自动构建一个委托传给C++,

anjisi的博客 1753

【AUTOSAR-DCM】-3.1-将CDD导入CFG并查看$22服务配置变化(UDS诊断DID带一个Data)

案例背景:(共8页精讲) 在《【UDS诊断描述文件CDD】-3.2-编辑CDD给$22服务创建一个带一个Data的DID(dataIdentifier)数据标识符》中,适应使用CANdela Studio在CDD中创建一个带一个Data的DID(dataIdentifier)数据标识符,见图0-1。现在我们将该CDD文件导入到CFG(DaVinci Configurator),看看配置会发生哪些变化。 图0-1 目录 1 将诊断描述文件CDD导入CFG(DaVinci Configurator.

「汽车电子助手」的博客 1630

C#托管堆 遭破坏 问题溯源分析

一:背景 1. 讲故事年前遇到了好几例托管堆被损坏的案例,有些运气好一些,从被破坏的托管堆内存现场能观测出大概是什么问题,但更多的情况下是无法做出准确判断的,原因就在于生成的dump是第二现场,借用之前文章的一张图,大家可以理解一下。为了帮助更多受此问题困扰的朋友,这篇来整理一下如何 快狠准 的抓取第一现场。二:抓取第一现场 1. 思路分析要想抓到第一现场,只需要让破坏托管堆的那个线程在修改完之后...

zls365365的博客 214

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

CoreCLR 桩(Stub)的触发(2)

上一篇文章中描述了CLR中是如何通过precode来触发JIT的编译,这篇文章接着说JIT将IL代码编译机器码之后需要进行什么操作。这两篇文章说了CoreCLR中调用函数触发JIT编译以及编译之后的流程,通过这种方式来实现懒编译,即如果一个函数在程序里面不被调用,则不会被编译。若有错误请指正,有问题欢迎指出。

kidwr的博客 1073

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java单元测试实践-18.使用注解进行Stub、Replace、Suppress

Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. 使用@MockPolicy注解进行Stub、Replace、Suppress @MockPolicy注解的说明可参考 https://javadoc.io/doc/org.powermock/powermock-core/latest/org/powermock/core/classloader/annotations/

adrninistrat0r的博客 852

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C# OpencvSharp异常 FileNotFoundException

OpenCvSharp 是一个OpenCV的.Net wrapper,应用最新的OpenCV库开发,使用习惯比EmguCV更接近原始的OpenCV,有详细的使用样例供参考。该库采用LGPL发行,对商业应用友好。使用OpenCvSharp,可用C#,VB.NET等语言实现多种流行的图像处理(image processing)与计算机视觉(computer vision)算法。...

钢铁男儿 1018

CLR 4.0 安全模型

在公共语言运行时(CLR)过往的版本中,安全模型一直是最为复杂的模块之一,由于涉及Evidence,CAS策略等机制,难以被用户使用。在Silverlight中,CLR团队提出了三层安全级别,大大简化了安全模型,得到了很多积极的反馈。所以CLR4.0对之加以改进,希望能帮助用户开发出更为安全的应用程序。 三层安全级别及其运作机制 CLR4.0中的安全级别,从低到高排列如下: Trans

mountaintai二世的运动场 1566

// TODO Auto-generated method stub作用及设置

作用: // TODO Auto-generated method stub  是我们写类时,通过Java工具自动生成的提示, //表示是注释语句,可删,也可以不删,告诉看代码的人,这段代码自动生成。 设置中去除这段话: 在 菜单栏中 Window --> Preferences -->Java -->Code Style -->Code Templates--> Code --> Met

nicknailo博客 3万+

java中// TODO Auto-generated method stub意义及如何快速去掉?

1、Auto-generated method stub 的完整意思是 :生成方法存根,就是“自动生成方法(空函数)”。编程软件在你使用代码生成时,自动帮你加上的,告诉你这些段代码是开发工具生成的,就是一个提示,可以删除,2、automatic 自动的; generated 生成;method 方法;stub 存根;空函数;     TODO 就是说在这写你自己的新代码。3、生成方法存根:如果某个...

墓亦龍的博客 2万+

谈谈何谓Stub

Stub桩为什么叫桩,我不知道。似乎更多的是一种测试概念,test stub 来看看Martin的说明吧: Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test.

3693

Eclipse中取消生成TODO Auto-generated method stub

我们在实现接口定义的方法、Eclipse往往会自动加上一句:TODO Auto-generated method stub 每次手动删除很麻烦,我们可以设置一下,让强大的Eclipse在完成自动代码时,不生成这句代码。

阿呆的专栏 1万+
上一篇: MSDN中文网络广播预告:公共语言运行库(CLR)开发系列课程(6):.NET中间语言(IL)入门 (Level 200)
下一篇: MSDN Webcast预告:.NET 4.0中的新特性系列课程(3):.NET 4.0 Beta1 Interop 新特性介绍 (Level 200)
ATField
博客等级 码龄25年 673粉丝 119原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值