2009-08-05 44 views
18

的COM对象,我有以下代码:无法投类型的异常

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 () 
} 

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

无法转换类型的COM对象“系统.__ ComObject”到接口类型“IMyInterface的” 。 此操作失败,因为IID为{{GUID}的接口的COM组件上的QueryInterface调用失败,原因如下错误:没有此类接口支持

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

+0

http://blogs.msdn.com/b/oldnewthing/archive/2004/12/13/281910.aspx – EricLaw 2015-10-20 18:20:08

回答

20

这个令人讨厌的,令人讨厌的异常出现,因为一个称为COM编组的概念。问题的实质在于,为了从任何线程中使用COM对象,线程必须有权访问描述COM对象的类型信息。

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

你可以尝试加入以下代码:

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

基本上宣告上述指示.NET框架COM加载使用传统技术从注册表加载类型信息,并找到相关的类型库,并去从那里。

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

总之,这个错误围绕着类型信息和线程编组。确保每个想要访问COM对象的线程都具有相关信息,以便从源线程解组对象。

PS:这个问题在.NET 4中解决。0使用称为“类型对等”的技术

+0

感谢您的回复。您的探索是有道理的,并且在MSDN上查找ComImport的删减似乎也是有道理的。干杯。 – Kyle 2009-08-11 12:21:27

+0

这是我的荣幸:)我之前遇到过这个问题,这是一个噩梦,试图解决,直到灯泡熄灭,并最终从创建它的线程中消耗COM对象。 – 2009-08-11 12:58:58

+1

[+1]非常感谢你们!对我来说,错误是[STAThread]丢失。这个问题和答案让我在阅读线程问题后找到它。 – Marc 2010-08-19 07:26:19

-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”时,你可能会遇到问题。

+0

比你的答案,但使用ParameterizedThreadStart无效(有或没有锁)。 另外我也检查过,myInterface在设置好后仍然可以“调用方法”(myInterface = iInterface)。 – Kyle 2009-08-06 14:30:49

+0

在这个答案中有两点错误信息:** 1。**跨线程对象访问不会总是自动导致问题。例如,对于只读访问,锁定不是必需的。 ** 2。**关于最后一段,您不能将对象作为对象传递,所以即使您将一个非null对象指定给具有接口(静态)类型的变量,并且代码也会编译,那么所有这些方法都可以叫做。将静态类型(接口)视为另一种实现类型的某种外观。 – stakx 2012-07-13 09:19:09

3

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

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

+0

它像一个魅力工作。请你解释一下这个变化吗? – 2016-12-21 12:21:07

0

我一直在开发一个C#应用程序,它通过COM接口使用7-zip。我遇到了这样一个有趣的事情,我可以在一个实例中从工作线程中提取归档文件,但不是另一个,得到相同的异常。

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

相关问题