我正在使用 COM 互操作将托管插件创建到使用 VS2012/.NET 4.5/Win8.1 的非托管应用程序中。所有互操作的东西似乎都正常,但是当我关闭应用程序时,我得到一个 MDA 异常,告诉我在释放 RCW 在完成期间持有的 COM 对象时发生了 AV。
这是调用堆栈:
clr.dll!MdaReportAvOnComRelease::ReportHandledException() + 0x91 bytes
clr.dll!**SafeRelease_OnException**() + 0x55 bytes
clr.dll!SafeReleasePreemp() + 0x312d5f bytes
clr.dll!RCW::ReleaseAllInterfaces() + 0xf3 bytes
clr.dll!RCW::ReleaseAllInterfacesCallBack() + 0x4f bytes
clr.dll!RCW::Cleanup() + 0x24 bytes
clr.dll!RCWCleanupList::ReleaseRCWListRaw() + 0x16 bytes
clr.dll!RCWCleanupList::ReleaseRCWListInCorrectCtx() + 0x9c bytes
clr.dll!RCWCleanupList::CleanupAllWrappers() + 0x2cd1b6 bytes
clr.dll!RCWCache::ReleaseWrappersWorker() + 0x277 bytes
clr.dll!AppDomain::ReleaseRCWs() + 0x120cb2 bytes
clr.dll!ReleaseRCWsInCaches() + 0x3f bytes
clr.dll!InnerCoEEShutDownCOM() + 0x46 bytes
clr.dll!WKS::GCHeap::**FinalizerThreadStart**() + 0x229 bytes
clr.dll!Thread::intermediateThreadProc() + 0x76 bytes
kernel32.dll!BaseThreadInitThunk() + 0xd bytes
ntdll.dll!RtlUserThreadStart() + 0x1d bytes
我的猜测是应用程序已经销毁了它的 COM 对象,其中一些引用被传递给了托管插件 - 并且对 IUnknown::Release 的调用 RCW 使它变得繁荣起来。
我可以在输出窗口 (VS) 中清楚地看到该应用程序已经开始卸载其中的一些 dll。
'TestHost.exe': Unloaded 'C:\Windows\System32\msls31.dll'
'TestHost.exe': Unloaded 'C:\Windows\System32\usp10.dll'
'TestHost.exe': Unloaded 'C:\Windows\System32\riched20.dll'
'TestHost.exe': Unloaded 'C:\Windows\System32\version.dll'
First-chance exception at 0x00000001400cea84 in VST3PluginTestHost.exe: 0xC0000005: Access violation reading location 0xffffffffffffffff.
First-chance exception at 0x00000001400cea84 in VST3PluginTestHost.exe: 0xC0000005: Access violation reading location 0xffffffffffffffff.
Managed Debugging Assistant 'ReportAvOnComRelease' has detected a problem in 'C:\Program Files\Steinberg\VST3PluginTestHost\VST3PluginTestHost.exe'.
Additional Information: An exception was caught but handled while releasing a COM interface pointer through Marshal.Release or Marshal.ReleaseComObject or implicitly after the corresponding RuntimeCallableWrapper was garbage collected. This is the result of a user refcount error or other problem with a COM object's Release. Make sure refcounts are managed properly. The COM interface pointer's original vtable pointer was 0x406975a8. While these types of exceptions are caught by the CLR, they can still lead to corruption and data loss so if possible the issue causing the exception should be addressed
所以我虽然会管理我自己的生命周期并编写了一个调用 Marshal.ReleaseComObject 的 ComReference 类。这不能正常工作,在阅读后我不得不同意在引用自由传递的场景中调用 Marshal.ReleaseComObject 不是一个好主意。 Marshal.ReleaseComObject 被认为是危险的
所以问题是:有没有办法管理这种情况,以便在退出主机应用程序时不导致 AV?