在具有ui/非ui线程差异的WPF中使用PInvoke

本文关键字:ui WPF PInvoke 线程 | 更新日期: 2023-09-27 17:57:52

我从WPF应用程序中的c#代码访问一个c++dll库。从ui线程访问dll时没有问题。但是我需要UI在运行c++dll的代码时做出响应。所以我尝试从另一个线程访问它。但是,当我第一次尝试在非ui线程中调用同一个函数(从ui线程调用)时,函数会返回,但返回值表示函数中存在内部错误。但是,当我从非ui线程运行代码一次或两次时,它成功地返回了一个无错误值。我没有dll的源代码,所以我不确定里面发生了什么。

c++功能

UINT32 myfunc1()

在C#中

[DllImport("mydll.dll")]
public static extern uint myfunc1();

如何在ui线程中获取代码

uint errorCode = myfunc1(); // returns 0 means no error occured

如何在非ui线程中获取代码

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, args) => { args.Result = myfunc1(); };
// 1st call args.Result is 10 means internal error ocurred
// 2nd call args.Result is sometimes 0 and sometimes 10
// 3rd or later calls args.Result is 0 means no error occured
worker.RunWorkerCompleted += doSth();
worker.RunWorkerAsync();

在具有ui/非ui线程差异的WPF中使用PInvoke

它"可能"与线程上使用的Apartment模型有关。

您的UI线程将使用STA(单线程公寓)模型。。。它依赖于消息循环进行同步/序列化访问。

您的BackgroundWorker将使用MTA(多线程公寓)模型。

DLL库中可能有一些代码依赖于在UI/STA线程中运行来进行正确的同步,例如一些COM调用。它有时有效,有时无效的原因可能是由于种族条件。。。由于缺乏同步。

可以指定线程是STA线程。。。。但不在BackgroundWorker线程上,因为它们是由ThreadPool创建和管理的,并且总是设置为使用MTA单元模型、重复使用等…并且线程在启动之前必须设置其单元状态。。。之后它就不能改变了。

因此,创建一个新的Thread,将其单元设置为STA,并发送一个消息循环。

  • 如何将后台工作线程设置为"单线程单元"?

  • 如何在C#的后台工作程序中使用web浏览器对象

  • http://bytes.com/topic/c-sharp/answers/823166-can-backgroundworker-single-threaded-apartment