我有一个外部组件(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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以问题是,在第一次调用它运行良好时,调用了外部组件,我得到了结果.
但是当我尝试在另一个线程中调用它时,我得到一个异常:System.InvalidCastException:无法转换类型为'System .__ ComObject'的COM对象.... 由于STAThread,我确定这个例外被抛出了.因为如果我从Main函数中删除[STAThread]属性,那么第一次调用外部组件时也会发生同样的情况,这很正常.
如何从其他线程调用此外部组件以摆脱此异常?
UPDATE -------------
现在发生了其他疯狂的事情 当我从Visual Studio使用F5启动程序时,问题也出现在第一次调用中,但是当我直接执行二进制.exe文件时,它正在工作(从另一个线程它不是:().如果我切换从Debug到Release的构建,从Visual Studio和F5开始,第一次调用再次工作.
为什么会这样?
感谢您提前帮助!
最诚挚的问候,佐利
线程从来都不是一个小细节。如果代码没有明确记录为支持线程,那么 99% 的可能性是它不支持它。
显然这个组件不支持线程。创建另一个 STA 线程并不是神奇的解决方案,它仍然是一个不同的线程。InvalidCastException 告诉您它还缺少编组来自工作线程(如您尝试创建的线程)的调用所需的代理/存根支持。对非线程安全的代码进行线程安全调用时需要。尽管您确实违反了 [STAThread] 的约定,但它必须泵送消息循环。消息循环允许从工作线程调用非线程安全的组件。您可以从 Application.Run() 获得一个消息循环。
这就是责任的止点。它不是线程安全的。即使修复您的主线程或要求供应商或作者向您提供代理/存根,您仍然没有完成您打算做的事情,它实际上不会在您创建的工作线程上运行。所以它必须看起来像这样:
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();
}
Run Code Online (Sandbox Code Playgroud)
它在您进行调用的同一线程上创建对象,因此它是线程安全的。仍然存在这个工作线程不泵送消息循环的问题,COM 组件往往依赖于此。您可以通过死锁或不运行的事件来确定这是否是一个问题。如果当您从主线程调用它时它已经在您的测试程序中正常工作,那么您可能可以不进行泵送。
| 归档时间: |
|
| 查看次数: |
1024 次 |
| 最近记录: |