代码之家  ›  专栏  ›  技术社区  ›  Mikhail Poda

WPF线程:“无法使用已与其基础RCW分离的COM对象。”

  •  0
  • Mikhail Poda  · 技术社区  · 14 年前

    我遇到以下错误:

    "COM object that has been separated from its underlying RCW cannot be used."
    

    我确信问题是因为COM对象不是在创建它的线程上被调用-sta。我试图实现IDisposable,但它对我没有作用。

    有几个职位处理类似问题,但仍然无法解决我的问题:

    Is it safe to call an RCW from a finalizer? Release Excel Object In My Destructor

    是否有人可以发布一个示例/解释如何从另一个线程正确访问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;
            }
        }    
    }
    
    4 回复  |  直到 14 年前
        1
  •  4
  •   Hans Passant    14 年前

    问题是程序的启动线程。它创建COM对象,启动线程,然后 出口 . 作为清理主线程的一部分,.NET调用couninitialize(),这是COM对象的结尾。得到这个错误是预期的结果。

    让主启动线程这样退出是没有意义的。现在就让它完成你自己的工作,问题解决了。

        2
  •  2
  •   Adam Houldsworth    14 年前

    通常这是因为基础COM对象已从其包装中释放-当您通过marshal.release手动释放它或释放托管包装时,就会发生这种情况。在错误的线程上使用它只会导致对COM对象的任何调用实际发生在创建它的线程上-我以前被它刺痛过,它具有执行的线程关联性。

    您似乎没有处理包装器,但我不确定动态变量会有什么影响。

    您是否尝试将线程单元状态更改为MTA?

        3
  •  1
  •   jdehaan    14 年前

    抱歉,可能没有直接回答你的问题。这只是用不同方式处理它的建议。希望它有帮助。

    对于COM与Excel的互操作,有很多陷阱——我认为这与COM没有直接关系,而是与Excel COM的实现方式有关。

    我在COM与Excel(以及MSProject)的互操作方面遇到了很多困难。对于Excel,唯一好的解决方案是一个专用线程,用于处理从创建到终止的整个Excel通信。ExcelAPI中存在一些设计缺陷。有些方法调用不是无状态的,这意味着两个线程将很难让这些东西工作。将所有通信委托给一个线程并自己处理与其他线程的通信会更安全。

    除此之外,用于通信的线程还必须具有en/US文化( LCID issues )这通常会导致另一条消息:

    旧格式或无效的类型库

    但可能对你有用。

        4
  •  1
  •   Jeremiah Morrill    14 年前

    尝试使DispatcherObject的Mycom类继承。启动另一个线程后,请执行_mycom.dispatcher.run()。当您想与COM对象对话时,只需执行mycom.dispatcher.begininvoke/invoke。