C# 无法转换类型异常的 COM 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1233468/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unable to cast COM object of type exception
提问by Kyle
I have the following code:
我有以下代码:
public void Test(IMyInterface iInterface)
{
iInterface.CallMethod ( );
}
Which works fine. However, if I change the code to be threaded:
哪个工作正常。但是,如果我更改要线程化的代码:
private IMyInterface myInterface;
public void Test(IMyInterface iInterface)
{
myInterface = iInterface;
new Thread ( new ThreadStart ( CallInterfaceMethod) ).Start ( );
}
public void CallInterfaceMethod ( )
{
myInterface.CallMethod ( )
}
When i use the thread I receive the exception:
当我使用线程时,我收到异常:
Unable to cast COM object of type 'System.__ComObject' to interface type 'IMyInterface'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{GUID}' failed due to the follow error: No such interface supported
无法将“System.__ComObject”类型的 COM 对象转换为接口类型“IMyInterface”。此操作失败,因为 IID 为“{GUID}”的接口的 COM 组件上的 QueryInterface 调用因以下错误而失败:不支持此类接口
But the interface should be supported just fine? Anyone have any thoughts on what is going on here?
但是接口应该支持就好了?有人对这里发生的事情有任何想法吗?
采纳答案by Mike J
This nasty, nasty exception arises because of a concept known as COM marshalling. The essence of the problem lies in the fact that in order to consume COM objects from any thread, the thread must have access to the type information that describes the COM object.
这个讨厌的、讨厌的异常是由一个称为 COM 编组的概念引起的。问题的本质在于,为了从任何线程使用 COM 对象,该线程必须能够访问描述 COM 对象的类型信息。
In your scenario described, the reason it fails on the second thread is because the second thread does not have type information for the interface.
在您描述的场景中,它在第二个线程上失败的原因是因为第二个线程没有接口的类型信息。
You could try adding the following to your code:
您可以尝试将以下内容添加到您的代码中:
[ComImport]
[Guid("23EB4AF8-BE9C-4b49-B3A4-24F4FF657B27")]
public interface IMyInterface
{
void CallMethod();
}
Basically the declaration above instructs the .NET framework COM loader to load type information using traditional techniques from the registry and locate the associated type library and go from there.
基本上,上面的声明指示 .NET 框架 COM 加载器使用传统技术从注册表加载类型信息,并定位关联的类型库并从那里开始。
You should also restrict the creation of the COM object to a single thread (to prevent thread marshalling) to help solve this issue.
您还应该将 COM 对象的创建限制为单个线程(以防止线程编组)以帮助解决此问题。
To summarize, this error revolves around type information and thread marshalling. Make sure that each thread that wants to access the COM object has the relevant information to unmarshal the object from the source thread.
总而言之,此错误与类型信息和线程编组有关。确保想要访问 COM 对象的每个线程都具有相关信息以从源线程解组对象。
PS: This problem is solved in .NET 4.0 using a technique called "Type Equivalence"
PS:这个问题在 .NET 4.0 中使用一种叫做“Type Equivalence”的技术解决了
回答by Zensar
Well, for one, you are making a cross-thread call to an object without locking it, this automatically will cause some issues. Your code should look more like:
嗯,一方面,您正在对一个对象进行跨线程调用而不锁定它,这会自动导致一些问题。您的代码应该看起来更像:
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 ( );
}
}
From what I understand, the error you listed can sometimes occur when the resource cannot be accessed, which, with a cross-thread operation like this, would most likely happen. Don't quote me on it though, I'm no COM expert.
据我了解,您列出的错误有时会在无法访问资源时发生,而使用这样的跨线程操作,很可能会发生这种情况。不要引用我的话,我不是 COM 专家。
Truthfully, I don't think I would approach calling this method in this fashion, way too many risks in doing so. Have you considered using a ParameterizedThreadStartand passing the object through that way? You'd still need to safely lock your objects for the cross-thread operations, but it would be safer.
说实话,我不认为我会以这种方式调用这个方法,这样做的风险太大了。您是否考虑过使用ParameterizedThreadStart并通过这种方式传递对象?您仍然需要安全地锁定跨线程操作的对象,但这样会更安全。
Furthermore, check to make sure that your "myInterface" class can still call the "CallMethod()" method. Interfaces have no implementation, you may be running into problems when you set "myInterface = iInterface".
此外,检查以确保您的“myInterface”类仍然可以调用“CallMethod()”方法。接口没有实现,当您设置“myInterface = iInterface”时可能会遇到问题。
回答by gbaor
I got an advice and it helped me!
我得到了一个建议,它帮助了我!
Find in the main thread (Program.cs) the line [STAThread] and change it to [MTAThread].
在主线程 (Program.cs) 中找到 [STAThread] 行并将其更改为 [MTAThread]。
回答by Mator
I've been developing a C# application which uses 7-zip through COM interfaces. I ran into this funny thing where I was able to extract archives from a worker thread in one instance, but not another, getting this same exception.
我一直在开发一个 C# 应用程序,它通过 COM 接口使用 7-zip。我遇到了一个有趣的事情,我能够在一个实例中从一个工作线程中提取档案,但在另一个实例中却没有,得到同样的异常。
I found that, so long as you initialize the offending COM object in the thread where it is used no exception is thrown. My solution was to dispose the objects which utilized COM interfaces and re-initialize them when passing them between threads.
我发现,只要您在使用它的线程中初始化有问题的 COM 对象,就不会引发异常。我的解决方案是处理使用 COM 接口的对象,并在线程之间传递它们时重新初始化它们。