简单的C ++ .Net控制台应用程序在64位Win7中崩溃

时间:2013-09-19 19:55:17

标签: c++ windows com

我的公司使用第三方DLL连接到某些硬件(我在这里将其重命名为hwLib)。我想很久以前就是在VB6中写的。 DLL附带一个安装程序来注册自己,等等。

我们有一个使用它的C#应用​​程序,它在XP和Win7,32或64位上运行得很好。但我写了一个简单的C ++控制台应用程序,在XP / 32位上运行良好,但在Win7 / 64位上崩溃。控制台应用程序看起来像这样,

#include "stdafx.h"
using namespace System;

int main(array<System::String ^> ^args)
{
    using namespace hwLib;
    ChwLib^ myLib = gcnew ChwLib();
    String^ str = myLib->GetDllVersion();
    Console::WriteLine(L"Hello hwLib");
    Console::WriteLine(str);
    Console::ReadLine();  //to keep window open til you hit the "any" key
    return 0;
}
  

未处理的异常:System.InvalidCastException:无法转换COM   对象类型&#39; hwLib.ChwLibClass&#39;接口问题&#39; hwLib._ChwLib&#39;。

     

此操作失败,因为QueryInterface调用COM   与IID接口的组件   &#39; {E0560D1E-9A54-4EBF-83E8-D7BD2C936512}&#39;由于以下原因而失败   错误:

     

不支持此类接口(来自HRE SULT的异常:   0x80004002(E_NOINTERFACE))。在   System.StubHelpers.StubHelpers.GetCOMIPFromRCW(Object objSrc,IntPtr   pCPCMD,布尔&amp; pfNeedsRelease)at   hwLib.ChwLibClass.GetDllVersion()在main(String [] args)at   mainCRTStartupStrArray(String [] arguments)

C#程序,这是一个更大更复杂的程序,否则我会在这里发布,在同一系统上运行没有问题。

COM在我的时间之前 - 我在10年或15年前参加了一门课程,但我不记得了 - 有关如何开始调试的建议吗?谢谢!!

1 个答案:

答案 0 :(得分:4)

COM为COM组件提供线程安全保证,声明自己不支持线程。用VB6编写的任何组件都可以做到这一点。由名为ThreadingModel的注册表中的条目指示。

您的测试程序没有为这样的组件提供安全的家,您的控制台模式应用程序创建了一个多线程公寓,简称MTA。哪个承诺提供线程安全。 COM然后创建自己的STA线程来运行组件的代码。对组件的每次调用都将从主线程封送到该辅助线程。

但是在你的情况下它会遇到问题,你的组件没有注册所需的代理/存根。 COM需要弄清楚如何复制方法参数的额外代码。借助Reflection而不是COM,可以轻松实现.NET。代理/存根由HKCR \ Interface注册表项中的条目选择,VB6组件始终使用与类型库一起使用的标准编组器。 E_NOINTERFACE错误代码用于IMarshal接口,这是COM找不到的方法,而不是VB6实现的。

在获得正确注册之后,创可贴就是让你的控制台模式应用程序创建一个STA线程而不是MTA线程。这很容易做到,只需要一个属性:

[STAThread]
int main(array<System::String ^> ^args)
// etc..

COM现在不再创建帮助程序线程,并且调用不必编组。这实际上不够,STA线程还必须泵送消息循环。 Application :: Run()可能在您较大的C#程序中使用。消息循环提供了编组调用的方法,非常类似于Control.BeginInvoke()和Dispatcher.BeginInvoke()。你可能会因为你实际上没有从另一个线程调用组件而逃脱它。但是许多COM组件依赖于消息循环来做自己的事情。当您看到死锁或组件未引发事件时,您会发现自己遇到了问题。例如,VB6代码可以使用Timer,如果没有该消息循环,它将不会打勾。