使用 C# 插件挂在 COM 应用程序中
Posted
技术标签:
【中文标题】使用 C# 插件挂在 COM 应用程序中【英文标题】:Hang in COM application with C# plugin 【发布时间】:2012-02-17 11:47:43 【问题描述】:我遇到了一个问题,我们的应用程序挂在客户的机器上,我已经使用了好几天都没有解决。从我们所看到的情况来看,这个问题是随机出现的,尽管情况可能并非如此。客户还报告说,当应用程序挂起时,CPU 正在达到峰值。
问题是我不知道应用程序在哪里失败(挂起)。我们还有几个用 C# 编写的插件作为主要 COM 应用程序的插件。
我已经设法让客户在出现问题的机器上使用 ProcExp 进行 MiniDump。但是,我对 WinDBG 或 MiniDumps 也不是很熟悉。我已经运行了!analyze -v
和!analyze -v -hang
,它们会产生一些输出,包括下面的堆栈。据我所知,应用程序似乎正在转换到我们的 C# 插件 (CLR) 之一,然后又回到 COM,它应该是返回到插件可用的主应用程序的接口。但是然后呢?可以从这个堆栈中说更多吗?
如果重要的话,主应用程序是用 VB6 编写的。
0012da70 7e3693e9 7e3693a8 0012daf0 00000000 ntdll!KiFastSystemCallRet
0012da9c 7e37a43b 0012daf0 00000000 0000000f user32!NtUserPeekMessage+0xc
0012dac8 7348e6fd 0012daf0 00000000 0000000f user32!PeekMessageA+0xeb
0012db1c 77532a9c 00d03774 00000000 00000000 msvbvm60!CMsgFilter::MessagePending+0x21f
0012db60 77532a48 00000102 0012dbec 00000001 ole32!CCliModalLoop::HandlePendingMessage+0x40
0012dba8 7751eda6 80010116 80010115 00000000 ole32!CCliModalLoop::HandleWakeForMsg+0x46
0012dbbc 77547297 0012ddf0 00000001 0012dbe8 ole32!CCliModalLoop::BlockFn+0x8b
0012dc30 0ae8a2fd 00000002 00000001 00000001 ole32!CoWaitForMultipleHandles+0xcf
0012dc50 0ae8a264 00000000 00000001 00000001 mscorwks!NT5WaitRoutine+0x51
0012dcbc 0ae8a1c8 00000001 0012ddf0 00000000 mscorwks!MsgWaitHelper+0xa5
0012dcdc 0af3ccd0 00000001 0012ddf0 00000000 mscorwks!Thread::DoAppropriateAptStateWait+0x28
0012dd60 0af3cd65 00000001 0012ddf0 00000000 mscorwks!Thread::DoAppropriateWaitWorker+0x13c
0012ddb0 0ae8c026 00000001 0012ddf0 00000000 mscorwks!Thread::DoAppropriateWait+0x40
0012de00 0ae90f4c 00000001 05ae5c80 0012de60 mscorwks!Thread::JoinEx+0x86
0012de10 0b00ea40 00000001 00000001 5bdf0a2d mscorwks!Thread::Join+0x14
0012de60 0af0b9a7 00000001 0012deb0 0af0ba10 mscorwks!RCWCleanupList::CleanupWrappersInCurrentCtxThread+0x15a
0012de6c 0af0ba10 001df674 0012df10 5bdf0afd mscorwks!RCW::Initialize+0x78
0012deb0 0af0b6a7 001df674 0012df10 5bdf0b6d mscorwks!RCW::CreateRCW+0x84
0012df20 0af0b7b5 00000000 0012df5c 5bdf0b21 mscorwks!COMInterfaceMarshaler::CreateObjectRef+0x45
0012df6c 0ae892a8 5bdf3065 0012e6c8 0012e6c8 mscorwks!COMInterfaceMarshaler::FindOrCreateObjectRef+0xac
0012e428 0ae89444 001df658 11a11014 00000001 mscorwks!GetObjectRefFromComIP+0x1ec
0012e448 0ae894ab 05b3b0a8 001df658 0e896204 mscorwks!UnmarshalObjectFromInterface+0x19
0012e464 0af164d1 0012e6c8 0012e6ac 0af164c1 mscorwks!InterfaceMarshalerBase::ConvertSpaceNativeToCLR+0x30
0012e470 0af164c1 0012e748 0012e738 5bdf32e1 mscorwks!DefaultMarshalOverrides<InterfaceMarshalerBase>::ReturnCLRFromNativeRetval+0xb
0012e6ac 0aeb4bff 11741a76 0012e734 0012e74c mscorwks!RunML+0x9ac
0012e780 11740172 05ae5c80 0012e7d4 501b6046 mscorwks!CLRToCOMWorker+0x25f
...
... Stack begins down here in our main COM application.
编辑 1: 在阅读了一些其他论坛帖子后,我得到了一些想法。在我看来,挂起是在将数据类型从 .NET 编组到 COM 之后引入的。现在我读到了another problem,这似乎源于传递给 COM 方法的局部变量被垃圾收集的事实,因此 VB6 运行时在处理释放的内存时遇到了问题。另一个帖子不完全是这个问题,但它让我思考。
在调用 COM 的 .NET 代码中,我们有这种类型的代码
void SomeNETMethod(MyObject obj, bool doIt)
string someString = obj.SomeString;
this.myComComponent.DoItInCOM(ref someString, ref doIt); // This is where it hangs.
ref bool
以及直接从方法到方法传递的参数有什么关系吗?如您所见,我在这里的黑暗中跌跌撞撞...
【问题讨论】:
VB6 和线程是水和火。当 VB6 主线程停止泵送消息循环时,看起来像死锁。您需要 VB6 调试器来了解它在做什么。 @HansPassant 即使我们的 C# 插件不是多线程的,也会出现这些问题吗?我可以看到在这里发挥作用的唯一“其他”线程是 GC 线程,但我认为这不是问题。 我认为它可能会有所帮助:[BUG: AV Running VB-Built Component in Multi-Threaded Environment](support.microsoft.com/kb/186273) 祝你好运。 谢谢,但是我们没有多线程环境。正如我所提到的,我们有 GC 线程,因为我们的插件是 .NET,但我不想计算它。 在被调用的 VB6 代码中是否有 DoEvents?正如@HansPassant 所指出的,VB6 主线程可能与 C# 线程并不真正兼容(特别是如果它具有任何 WinForms 或 WPF 交互),并且在互操作代码中在幕后完成了一系列魔术以将线程捆绑在一起。我过去发现,从 DotNet 调用的 VB6 应用程序调用的任何 DoEvents 最终都会导致某种挂起/硬崩溃。 【参考方案1】:查看您的“DoItInCOM”方法,因为内核转储表明正在显示模式对话框(可能是由于 COM 方法调用中的错误。)
.NET 参数被正确编组到 COM 端。如果您使用一些非标准 C# 类型,您可能会遇到序列化问题,但这里不是这种情况。
如果您在 VB 代码中放置“On Error Goto”处理程序,您可能会抑制会在 UI 线程上生成消息的错误。如果错误是较低级别的(VB 运行时抛出它),您将需要通过直接修复 COM 组件来解决该问题。另请查看 Windows 事件查看器以获取 VB 运行时原始消息以获取更多信息。
【讨论】:
以上是关于使用 C# 插件挂在 COM 应用程序中的主要内容,如果未能解决你的问题,请参考以下文章
与 Sql 服务器的连接挂在 con.Open() [重复]