我在MSVC2013中使用混合调试遇到了一个严重的问题。在从本地C++ DLL调用COM方法后,调试器不再在断点处停止。
代码结构
上图展示了代码的整体结构。
我有一个单一的解决方案,大约有十个C#项目,约50个本地C++项目和一个用于管理和本地世界之间桥梁的C++/CLI项目。启动项目是一个C# WPF项目(GUI应用程序
),它内部调用C++ / cli项目(Bridge
),后者又调用各种本地C++ Dlls(Various libraries
)。或者,我可以创建一个C++控制台应用程序(服务控制台应用程序
)作为仅用于测试目的的启动项目。
我实现了一个库来导入一些来自Autodesk Inventor文档文件的信息。使用Inventor Apprentice COM服务器(图片中的Inventor Apprentice
)来实现,该服务器随Inventor View 2015一起免费下载。首先,将导入功能在独立的本地C++控制台应用程序中实现,一切都正常工作。然后将其适配为可在整个基础设施中使用的本地C++ DLL(Import library
),并开始了调试之旅。
症状
"调试已损坏"。在调用Import library
中的以下COM方法后,在调试版本中:
auto pComponentDefinitions = pDocument->GetComponentDefinitions();
C++代码中的断点不再触发。即使我在另一个DLL的代码中设置了断点,它也不会触发。断点仍然呈现为红色实心圆圈,因此与PDB问题无关。
应用程序本身继续执行,并且一段时间后,我可以在GUI中看到数据导入的正确结果,这意味着Import library
已经正确执行。之后,我可以使用Break All按钮暂停GUI应用程序
,此时主线程被卡在Inventor的一个dll(rse.dll)中,但这显然不可能是真的,因为该线程已经完成了导入并返回了正确的结果。
在输出窗口中,我可以看到以下消息,出现在存在问题的COM方法调用期间(在学徒中,访问冲突似乎是正常的):
First-chance exception at 0x000007FEDD451F0C (rse.dll) in GUIApplication.exe: 0xC0000005: Access violation writing location 0x000007FFFDE3AFCC.
The Common Language Runtime cannot stop at this exception. Common causes include: incorrect COM interop marshalling and memory corruption. To investigate further use native-only debugging.
First-chance exception at 0x000007FEDD455F6C (rse.dll) in GUIApplication.exe: 0xC0000005: Access violation writing location 0x000007FFFDE3EE6C.
我曾试图在编译时将断点嵌入代码中,通过在有问题的导入代码之前和之后插入__debugbreak()。如果调试尚未中断,则会触发第一个断点,但不会触发第二个断点。然而,调试器明显注意到了它,因为它会将以下消息写入“输出”窗口:
The process hit a breakpoint the Common Language Runtime cannot continue from.
This may be caused by an embedded breakpoint in the native runtime or a breakpoint set in a can't-stop region.
To investigate further, use native-only debugging.
针对此诊断信息,Google没有任何结果。这似乎是MSVC认为它正在调试托管代码,而实际上是本机代码。
"调用崩溃".在发布构建的情况下,以混合调试模式运行应用程序会导致在问题COM调用期间rse.dll内部崩溃。
可重现性
我使用MSVC 2013更新4。项目以x64模式构建。使用Net Framework v4.0。使用来自Inventor 2015的Inventor Apprentice。 实验证明:
- 没有调试器附加时一切正常。
- 仅使用本机调试(通过Service console app或在本机模式下附加到已运行的进程后),一切都正常(包括调试)。
- 在混合(即本机+托管)调试模式下,无论是通过调试启动“GUI应用程序”还是附加调试器到工作进程,都会复制该问题。
- 在调试和发布模式下都存在问题,但表现不同。在调试版本中出现了疯狂的调试问题("调试中断"),但在发布版本中只是在某个地方崩溃("崩溃里面")。
可以在此处查看运行的完整列表。
主要问题
有人看到过类似的行为吗?这种行为的原因可能是什么?是否有方法来解决它?