【问题标题】:Unable to cast COM object of type exception无法转换类型异常的 COM 对象
【发布时间】:2010-11-17 00:51:35
【问题描述】:

我有以下代码:

public void Test(IMyInterface iInterface)
{
  iInterface.CallMethod ( );
}

效果很好。但是,如果我更改要线程化的代码:

private IMyInterface myInterface;
public void Test(IMyInterface iInterface)
{
  myInterface = iInterface;
  new Thread ( new ThreadStart ( CallInterfaceMethod) ).Start ( );
}

public void CallInterfaceMethod ( )
{
  myInterface.CallMethod ( )
}

当我使用线程时,我收到异常:

无法将“System.__ComObject”类型的 COM 对象转换为接口类型“IMyInterface”。 此操作失败,因为 IID 为“{GUID}”的接口的 COM 组件上的 QueryInterface 调用因以下错误而失败:不支持此类接口

但是接口应该支持就好了吧?有人对这里发生的事情有任何想法吗?

【问题讨论】:

标签: c# com interface


【解决方案1】:

好吧,首先,您正在对对象进行跨线程调用而不锁定它,这会自动导致一些问题。您的代码应该看起来更像:

private IMyInterface myInterface;
private static readonly object _myObjectLock = new object();

public void Test(IMyInterface iInterface)
{
     myInterface = iInterface;
     new Thread ( new ThreadStart ( CallInterfaceMethod) ).Start ( );
}

public void CallInterfaceMethod ( )
{
     lock(_myObjectLock)
     {
        myInterface.CallMethod ( );
     }
}

据我了解,您列出的错误有时可能会在无法访问资源时发生,而像这样的跨线程操作很可能会发生这种情况。不过不要引用我的话,我不是 COM 专家。

说实话,我不认为我会以这种方式调用此方法,这样做的风险太大。您是否考虑过使用ParameterizedThreadStart 并通过这种方式传递对象?您仍然需要安全地锁定对象以进行跨线程操作,但这会更安全。

此外,请检查以确保您的“myInterface”类仍然可以调用“CallMethod()”方法。接口没有实现,设置“myInterface = iInterface”时可能会遇到问题。

【讨论】:

  • 谢谢你的回答,但使用 ParameterizedThreadStart 也不起作用(有或没有锁)。我也检查过,myInterface 设置后仍然可以“CallMethod”(myInterface = iInterface)。
  • 此答案中有两处错误信息:1. 跨线程对象访问不会总是自动导致问题。例如,只读访问不需要锁定。 2.关于最后一段,你不能将接口作为对象传递,所以即使你将非空对象分配给接口(静态)类型的变量,并且代码编译,那么所有可以调用这些方法。将静态类型(接口)视为另一种实现类型的某种外观。
【解决方案2】:

这个讨厌的、讨厌的异常是由一个称为 COM 编组的概念引起的。问题的本质在于,为了从任何线程消费 COM 对象,线程必须有权访问描述 COM 对象的类型信息。

在您描述的场景中,它在第二个线程上失败的原因是因为第二个线程没有接口的类型信息。

您可以尝试将以下内容添加到您的代码中:

[ComImport]
[Guid("23EB4AF8-BE9C-4b49-B3A4-24F4FF657B27")]
public interface IMyInterface
{
    void CallMethod();
}

基本上,上面的声明指示 .NET 框架 COM 加载器使用传统技术从注册表加载类型信息,并找到关联的类型库并从那里开始。

您还应该将 COM 对象的创建限制为单个线程(以防止线程编组)以帮助解决此问题。

总而言之,此错误与类型信息和线程编组有关。确保每个想要访问 COM 对象的线程都有相关信息,以便从源线程中解组对象。

PS:这个问题在 .NET 4.0 中使用一种称为“类型等效”的技术来解决

【讨论】:

  • 感谢您的回复。您的解释很有意义,并且在 MSDN 上查找 ComImport 声明似乎也很有意义。干杯。
  • 我很高兴:) 我以前遇到过这个问题,尝试解决它是一场噩梦,直到​​灯泡熄灭,我最终从创建它的线程中消耗了 COM 对象.
  • [+1] 非常感谢大家!对我来说,错误是缺少 [STAThread]。这个问答让我看完threading问题才找到的。
  • ComImport 和 Guid 就是它!我一直在努力处理相同的强制转换异常(与线程无关),以使我的包装器单元可测试并隔离 COM 组件。谢谢!
【解决方案3】:

我得到了一个建议,它帮助了我!

在主线程 (Program.cs) 中找到 [STAThread] 行并将其更改为 [MTAThread]。

【讨论】:

  • 它就像一个魅力。你能解释一下变化吗?
【解决方案4】:

我一直在开发一个通过 COM 接口使用 7-zip 的 C# 应用程序。我遇到了一个有趣的事情,我能够在一个实例中从工作线程中提取档案,但在另一个实例中却没有,得到了同样的异常。

我发现,只要您在使用它的线程中初始化有问题的 COM 对象,就不会引发异常。我的解决方案是处理使用 COM 接口的对象,并在线程之间传递它们时重新初始化它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-10
    • 1970-01-01
    • 1970-01-01
    • 2019-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-02
    相关资源
    最近更新 更多