【问题标题】:Simple C++ .Net console app crashing in 64 bit Win7简单的 C++ .Net 控制台应用程序在 64 位 Win7 中崩溃
【发布时间】:2013-09-20 04:19:11
【问题描述】:

我的公司使用第 3 方 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 'hwLib.ChwLibClass' 类型的对象与类型 'hwLib._ChwLib' 的接口。

此操作失败,因为 COM 上的 QueryInterface 调用 带有 IID 的接口组件 “{E0560D1E-9A54-4EBF-83E8-D7BD2C936512}”由于以下原因而失败 错误:

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

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

COM 早于我的时代 - 我可能在 10 或 15 年前参加过它的课程,但我不记得了 - 关于如何开始调试它有什么建议吗?谢谢!!

【问题讨论】:

标签: c++ windows com


【解决方案1】:

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

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

但在您的情况下,它会碰壁,您的组件没有注册所需的代理/存根。 COM 需要弄清楚如何复制方法的参数的额外代码。由于反射,在 .NET 中很容易,而不是在 COM 中。代理/存根由 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,如果没有消息循环,它就不会滴答作响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多