我有以下代码:
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调用由于以下错误而失败:不支持此类接口
但界面应该得到支持就好了吗?有人对这里发生的事情有任何想法吗?
答案 0 :(得分:21)
由于称为COM编组的概念,这种令人讨厌的令人讨厌的异常产生了。问题的实质在于,为了从任何线程使用COM对象,线程必须能够访问描述COM对象的类型信息。
在您描述的场景中,它在第二个线程上失败的原因是因为第二个线程没有该接口的类型信息。
您可以尝试在代码中添加以下内容:
[ComImport]
[Guid("23EB4AF8-BE9C-4b49-B3A4-24F4FF657B27")]
public interface IMyInterface
{
void CallMethod();
}
基本上上面的声明指示.NET框架COM加载器使用注册表中的传统技术加载类型信息,并找到相关的类型库并从那里开始。
您还应该将COM对象的创建限制为单个线程(以防止线程编组)以帮助解决此问题。
总而言之,此错误围绕类型信息和线程编组。确保每个想要访问COM对象的线程都具有从源线程解组对象的相关信息。
PS:使用名为“Type Equivalence”的技术在.NET 4.0中解决了这个问题
答案 1 :(得分:4)
我得到了一个建议并帮助了我!
在主线程(Program.cs)中查找[STAThread]行并将其更改为[MTAThread]。
答案 2 :(得分:0)
我一直在开发一个C#应用程序,它通过COM接口使用7-zip。我遇到了这个有趣的事情,我能够在一个实例中从工作线程中提取存档,而不是另一个,从而获得同样的例外。
我发现,只要在使用它的线程中初始化有问题的COM对象,就不会抛出异常。我的解决方案是处理使用COM接口的对象,并在线程之间传递它们时重新初始化它们。
答案 3 :(得分:-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”时可能会遇到问题。