如何调试C#托管/非托管编组异常?

时间:2011-07-04 15:55:45

标签: c# debugging com interop marshalling

我正在C#上编写DirectShow过滤器,我不想使用任何第三方库。此任务几乎100%基于正确的COM接口原型,如IGraphBuilder,IBaseFilter,IPin等。如果接口原型不正确,则会抛出托管/本地边界的各种异常。问题是确定错误原型接口方法的位置。

目前我有: DirectShow.dll中出现类型'System.NullReferenceException'的异常(这是我的托管dll的名称),并且在托管/本地边界之前未处理

调用堆栈:

  

ntdll.dll!NtWaitForSingleObject()+ 0xa bytes
      KernelBase.dll!WaitForSingleObjectEx()+ 0x9c bytes
      clr.dll!CLREvent :: WaitEx()+ 0x20f bytes
      clr.dll!CLREvent :: WaitEx()+ 0x1b8 bytes
      clr.dll!CLREvent :: WaitEx()+ 0x73 bytes
      clr.dll!Thread :: WaitSuspendEventsHelper()+ 0xcf bytes       clr.dll!Thread :: WaitSuspendEvents()+ 0x10 bytes
      clr.dll!string“d:\ iso_whid \ amd64fre \ base \ ntos \ r \ n”...()+ 0x35688d字节
      clr.dll!Thread :: RareDisablePreemptiveGC()+ 0x118 bytes
      clr.dll!GCHolderEEInterface< 0,0,0> ::〜GCHolderEEInterface< 0,0,0>()+ 0x19 bytes       clr.dll!Debugger :: SendCatchHandlerFound()+ 0x150 bytes
      clr.dll!string“d:\ iso_whid \ amd64fre \ base \ ntos \ r”...()+ 0x3b9340 bytes
      clr.dll!NotifyOfCHFFilterWrapper()+ 0x77字节
      clr.dll!string“d:\ iso_whid \ amd64fre \ base \ ntos \ r \ n”...()+ 0x336941字节
      msvcr100_clr0400.dll!__ C_specific_handler()+ 0x97字节
      ntdll.dll!RtlpExecuteHandlerForException()+ 0xd bytes       ntdll.dll!RtlDispatchException()+ 0x38f字节       ntdll.dll!KiUserExceptionDispatch()+ 0x2e bytes
      KernelBase.dll!RaiseException()+ 0x3d bytes
      clr.dll!NakedThrowHelper2()+ 0xc bytes
      clr.dll!NakedThrowHelper_RspAligned()+ 0x3d bytes       clr.dll!NakedThrowHelper_FixRsp()+ 0x5 bytes
      000007ff00179486()
      clr.dll!COMToCLRDispatchHelper()+ 0x4e bytes
      clr.dll!SecurityDeclarative :: CheckLinkDemandAgainstAppDomain() - 0x40e bytes
      clr.dll!COMToCLRWorkerBody()+ 0xd6 bytes
      clr.dll!COMToCLRWorkerDebuggerWrapper()+ 0x22字节
      clr.dll!COMToCLRWorker()+ 0x201字节       clr.dll!GenericComCallStub()+ 0x57字节
      [原产于管理过渡]
      quartz.dll!CEnumConnectedPins :: CEnumConnectedPins()+ 0x4a bytes
      quartz.dll!CFilterGraph :: FindUpstreamInterface()+ 0x150字节       quartz.dll!CFilterGraph :: FindUpstreamInterface()+ 0xc1 bytes
      quartz.dll!CFilterGraph :: FindUpstreamInterface()+ 0x171字节       quartz.dll!CFilterGraph :: FindUpstreamInterface()+ 0xc1 bytes
      quartz.dll!CFilterGraph :: FindUpstreamInterface()+ 0x171字节       quartz.dll!CFilterGraph :: FindUpstreamInterface()+ 0xc1 bytes
      quartz.dll!CWaveSlave :: UpdateSlaveMode()+ 0xa7 bytes
      quartz.dll!CWaveOutInputPin :: RemovePreroll()+ 0x95 bytes
      quartz.dll!CWaveOutInputPin :: Receive()+ 0x12f bytes
      msmpeg2adec.dll!CBaseOutputPin :: Deliver()+ 0x22字节       msmpeg2adec.dll!CIVIAudioFilter :: DeliverOutSample()+ 0x3da bytes
      msmpeg2adec.dll!CIVIAudioCodec :: DecodeDDPlus()+ 0x556 bytes
      msmpeg2adec.dll!CIVIAudioCodec :: DecodeAll()+ 0x121 bytes
      msmpeg2adec.dll!CIVIAudioFilter :: Process()+ 0xda7 bytes
      msmpeg2adec.dll!CIVIAudioFilter :: Receive()+ 0x16d bytes
      msmpeg2adec.dll!CTransformInputPin :: Receive()+ 0x4c字节       msmpeg2adec.dll!CIVIAudioInPin :: Receive()+ 0x3f字节       quartz.dll!CBaseOutputPin :: Deliver()+ 0x22 bytes
      quartz.dll!CBaseMSRWorker :: TryDeliverSample()+ 0x14f bytes
      quartz.dll!CBaseMSRWorker :: PushLoop()+ 0x1da bytes
      quartz.dll!CBaseMSRWorker :: ThreadProc()+ 0x90 bytes
      quartz.dll!CAMThread :: InitialThreadProc()+ 0x1c字节       kernel32.dll!BaseThreadInitThunk()+ 0xd bytes       ntdll.dll!RtlUserThreadStart()+ 0x21 bytes

换句话说,管道是:

  1. 名为CEnumConnectedPins()的本机代码函数
  2. 原生到托管转换 - >如果抛出异常,则步骤3中的xxx仅为编组人员所知,但我们处于不知名的地方。
  3. 名为xxx的托管代码方法。
  4. 所以这不会让我在任何地方,我不知道如何调试。

1 个答案:

答案 0 :(得分:3)

非常难以调试,失败发生在你没写的代码中。慢一点来诊断这个。编写一个本机测试程序,获取要测试的接口指针,并按v表顺序逐个验证方法。坏的会弹出来。

请注意C#不支持多重继承。从非IUnknown或IDispatch的另一个接口继承的任何COM接口都要求您重复基接口中方法的声明。忘记这样做会导致调用错误的方法。或者由于v表太短而不存在。 NullReference或AccessViolation是一个常见的结果。