Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF线程:“无法使用已与其基础RCW分离的COM对象。”_C#_Wpf_Multithreading_Com_Interop - Fatal编程技术网

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委托。基本上你只需要运行两个调度员,这样你就可以轻松地在两个公寓之间进行调度。