首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C# STAThread COMException

C# STAThread COMException
EN

Stack Overflow用户
提问于 2013-04-19 17:00:48
回答 1查看 1.4K关注 0票数 7

我有一个外部组件(C++),我想从我的C#代码中调用它。

代码如下所示:

代码语言:javascript
复制
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace dgTEST
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            ExtComponentCaller extCompCaller = new ExtComponentCaller();
            result = extCompCaller.Call(input);

            Thread t = new Thread(new ThreadStart(() =>
            {
                try
                {
                    result = extCompCaller.Call(input);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }));

            t.SetApartmentState(ApartmentState.STA);
            t.Start();
            t.Join();
        }
    }
}

所以问题是,在第一次调用时,它工作正常,外部组件调用,我得到了返回的结果。

但是当我尝试在另一个线程中调用它时,我得到了一个异常: System.InvalidCastException: Unable to cast COM object of 'System.__ComObject‘...。我确信这个异常被抛出了,是因为STAThread。因为如果我从Main函数中删除STAThread属性,在第一次调用外部组件时也会发生同样的情况,它工作得很好。

如何从其他线程调用此外部组件以消除此异常?

更新

另一件疯狂的事情现在发生了。当我用F5从Visual Studio启动程序时,问题也出现在第一个调用中,但是当我直接执行二进制.exe文件时,它工作了(从另一个线程它不是:( )。如果我将构建从调试切换到发布,并使用F5从Visual Studio启动它,则第一个调用将再次工作。

为什么会发生这种情况?

感谢您的提前帮助!

致以最好的问候,佐利

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-04-19 21:39:52

线程化从来不是一个小细节。如果代码没有明确的文档来支持线程,那么99%的可能性是它不支持它。

很明显,这个组件不支持线程。创建另一个STA线程不是神奇的解决方案,它仍然是一个不同的线程。InvalidCastException告诉您,它还缺少从工作线程编组调用所需的代理/存根支持,例如您正在尝试创建的线程。对不是线程安全的代码进行线程安全调用时需要。尽管您确实破坏了STAThread的约定,但它必须产生一个消息循环。它是消息循环,允许从工作线程调用不是线程安全的组件。您将从Application.Run()获得一个消息循环。

这就是责任所在。它不是线程安全的,句号。即使修复了主线程,或者要求供应商或作者为您提供代理/存根,您仍然没有完成您计划要做的事情,它实际上不会在您创建的工作线程上运行。所以它必须看起来像这样:

代码语言:javascript
复制
    static void Main(string[] args)
    {
        Thread t = new Thread(new ThreadStart(() =>
        {
             ExtComponentCaller extCompCaller = new ExtComponentCaller();
             result = extCompCaller.Call(input);
        }));

        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        t.Join();
    }

它在您进行调用的同一线程上创建对象,因此它是线程安全的。仍然有一个问题,这个工作线程不会产生消息循环,COM组件往往依赖于此。您将从死锁或不运行的事件中了解这是否是一个问题。如果当你从主线程调用它时,它已经在你的测试程序中正常工作了,那么你可能不需要泵送。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16100941

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档