C# WPF线程:“无法使用已与其基础RCW分离的COM对象。”
我遇到以下错误:C# WPF线程:“无法使用已与其基础RCW分离的COM对象。”,c#,wpf,multithreading,com,interop,C#,Wpf,Multithreading,Com,Interop,我遇到以下错误: "COM object that has been separated from its underlying RCW cannot be used." 我确信问题是因为COM对象不是在创建它的线程上被调用的-STA。我试图实现IDisposable,但它对我不起作用 有几个帖子处理类似的问题,但仍然不能解决我的问题: 是否有人可以发布一个示例/解释如何从另一个线程正确访问COM对象 下面是显示问题的最少代码: using System; using System.Thr
"COM object that has been separated from its underlying RCW cannot be used."
我确信问题是因为COM对象不是在创建它的线程上被调用的-STA。我试图实现IDisposable,但它对我不起作用
有几个帖子处理类似的问题,但仍然不能解决我的问题:
是否有人可以发布一个示例/解释如何从另一个线程正确访问COM对象
下面是显示问题的最少代码:
using System;
using System.Threading;
namespace Test.ComInterop
{
public class Program
{
MyCom _myCom;
[STAThread]
static void Main( string[] args )
{
new Program();
}
public Program()
{
_myCom = new MyCom();
// this method call works
string version = _myCom.ComMethod();
StartThread();
}
private void StartThread()
{
Thread t = new Thread( UIRun );
t.SetApartmentState( ApartmentState.STA );
t.Start();
}
void UIRun()
{
TestUI window = new TestUI();
window.Show();
// this method call fails
window.Title = _myCom.ComMethod();
window.Closed += ( sender2, e2 )
=> window.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
}
}
class MyCom
{
private dynamic _com;
public MyCom()
{
_com = Activator.CreateInstance(
Type.GetTypeFromProgID( "Excel.Application" ) );
}
public string ComMethod()
{
return (string) _com.Version;
}
}
}
通常这是因为底层COM对象已从其包装器中释放-当您通过Marshal.release手动释放它或释放托管包装器时,会发生这种情况。在错误的线程上使用它只会导致对COM对象的任何调用实际上都发生在创建它的线程上——我在过去被它刺痛了,它对执行具有线程亲和力 您似乎没有处理包装器,但我不确定动态变量会有什么影响
您是否尝试将线程单元状态更改为MTA?问题在于程序的启动线程。它创建COM对象,启动一个线程,然后退出。作为主线程清理的一部分,.NET调用ConInitialize,这就是COM对象的结束。获得该错误是预期的结果 让主启动线程那样退出是没有意义的。现在让它完成你自己的线程所做的工作,问题就解决了。很抱歉没有直接回答你的问题。这仅仅是一个以不同方式处理它的建议。希望能有帮助 COM与Excel的互操作有很多缺陷——我认为与COM没有直接关系,但与Excel COM的实现方式有关 我在使用Excel和MsProject进行COM互操作时遇到了很多困难。对于Excel,唯一好的解决方案是一个专用线程,用于处理从创建到终止的整个Excel通信。Excel API中存在一些设计缺陷。有些方法调用不是无状态的,这意味着两个线程将很难让这些东西正常工作。将所有通信委托给一个线程并自己处理与其他线程的通信会更安全 除此之外,您用于通信的线程还必须具有en/US文化。这通常会导致另一条消息: 旧格式或无效的类型库
但是知道这一点可能对您很有用。尝试让您的MyCom类为DispatcherObject继承。启动另一个线程后,执行_myCom.Dispatcher.Run。当您想与COM对象对话时,只需执行_myCom.Dispatcher.BeginInvoke/Invoke即可。由于UI的原因,我必须使用STA。我应该怎么做才能防止COM被处理?啊,Hans发现它实际上被处理了,因为你的应用程序中的执行流程。我怀疑底层对象正在被释放,但没有立即在代码中发现。非常感谢!我在不理解的情况下复制粘贴的UI线程相关内容。我不需要开始一个新的线程。谢谢,这似乎是一个有趣的方法。你能推荐一个更深入解释的链接吗?我没有链接,但我在处理运行在不同于UI STA线程的STA COM对象时使用了这种方法。Dispatcher基本上是它自己的消息循环IIRC,它甚至处理Win32消息和.NET委托。基本上你只需要运行两个调度员,这样你就可以轻松地在两个公寓之间进行调度。