C#线程异常

C#线程异常,c#,.net,com,sta,C#,.net,Com,Sta,我有一个外部组件(C++),我想从我的C#代码中调用它 代码如下所示: using System.Text; using System.Threading; using System.Threading.Tasks; namespace dgTEST { class Program { [STAThread] static void Main(string[] args) { ExtComponentCal

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

代码如下所示:

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();
        }
    }
}
    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();
    }
所以问题是,在第一次调用时,它运行良好,外部组件调用,我得到了结果

但当我尝试在另一个线程中调用它时,我遇到了一个异常: System.InvalidCastException:无法强制转换类型为“System.\u ComObject”的COM对象。 我敢肯定,这个例外被抛出了,因为这个线程。因为如果我从主函数中删除[StatThread]属性,那么外部组件的第一次调用也会发生同样的情况,这很好

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

更新-------------

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

为什么会这样

提前谢谢你的帮助

致以最良好的祝愿,
Zoli

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

显然,这个组件不支持线程。创建另一个STA线程并不是一个神奇的解决方案,它仍然是一个不同的线程。InvalidCastException告诉您,它还缺少代理/存根支持,这是封送来自工作线程的调用所必需的,就像您正在尝试创建的线程一样。这是执行任务所必需的对非线程安全代码的ad-safe调用。尽管您确实违反了[StatThread]的约定,但它必须泵送消息循环。正是消息循环允许从工作线程调用非线程安全的组件。您从Application.Run()获得消息循环

这就是责任所在。它不是线程安全的。即使修复主线程或要求供应商或作者向您提供代理/存根,您仍然没有完成您计划要做的事情,它实际上不会在您创建的工作线程上运行。因此,它必须如下所示:

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();
        }
    }
}
    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组件往往依赖于此。您将从死锁或未运行的事件中找出这是否是问题。如果它在测试程序中已经正常工作,则am当您从主线程调用它时,您可能可以不使用泵送。

当您在标记为STA的线程中执行整个工作(创建COM实例和运行方法)时会发生什么情况?可能此COM对象在注册表中标记为STA,并且在不同的COM单元中无法正常工作(从MTA到STA或从STA到MTA)可能是由于编码方式的错误。我得到了相同的异常:(.但是主功能是STA,线程是在那里创建的。线程也设置为STA,所以我不明白。这可能是由于组件中的错误。当所有事情都在一个STA线程中完成时,它应该可以工作。你是说主线程是一个“单线程单元”您正在该线程上创建一个COM对象,然后启动另一个线程(现在是多线程的)并尝试访问该COM对象(同样是在单线程单元中创建的)来自多个线程。实际上不受支持。是的,我尝试在其他线程中创建所有内容,但在这种情况下,主函数不应该是[StatThread],否则我会遇到相同的异常。感谢您的评论!非常好的描述,感谢您的帮助!:)现在它正在我的测试程序中工作。我将把它放到真实的环境中,希望一切都会好起来:)。