使用WPF(需要STAThread)和不能与STAThread一起使用的API

时间:2009-06-23 07:39:07

标签: .net wpf multithreading

我正在编写一个WPF应用程序,该应用程序具有对具有简单要求的API的可选依赖性;它必须在没有STAThread属性的线程上初始化/使用。当然,WPF需要STA才能让一切变得简单。

在这种情况下,无论如何都需要WPF。仅当用户选择在应用程序中启用此功能时,才需要此第三方API。这意味着一旦调用其他API,WPF应用程序就已经在运行。

如果不使用[STAThread]装饰主方法,它是否自动成为MTA线程?在这种情况下,这是否意味着我可以创建一个新的MTA线程并使用其他API?

如果这样可行,那么我猜这个API中的任何事件都可以使用Dispatcher与WPF应用程序通信(用于引发需要在UI中显示的事件等)。但是,有一种简单的方法可以让我的WPF应用程序在MTA线程上“调用”功能来进行API调用吗?

在MTA中我猜每个线程应该能够使用状态,但我想我的STA线程(WPF应用程序)不能只是“进入”MTA线程并执行API调用?

这里有很多混淆的可能性,我会喜欢关于如何设计这样的东西的一些意见!

谢谢!

[编辑7月8日]

哦,我在上面有一些概念混淆了。线程模型当然是为PROCESS设置的,而不是为每个线程设置的,这个第三方API不能与STA进程一起使用。

目前,我从这个混乱中看到的唯一方法是编写与此API通信的服务,然后使用命名管道与此服务进行通信。这根本不是一件小事,一个丑陋丑陋的解决方法,但第三方API不在我的控制之下。这就是人生。 :|

3 个答案:

答案 0 :(得分:6)

外部API是GUI API吗?或者只是功能等?如果是后者,则可以生成第二个线程(可能使用生产者/消费者队列),即MTA:

    Thread thread = new Thread(DoSomeStuff);
    thread.SetApartmentState(ApartmentState.MTA);
    thread.Name = "3rd aprty API spooler";
    thread.Start();

答案 1 :(得分:3)

您需要启动一个新线程来调用需要MTA线程的代码。 你可以尝试类似下面的内容,以便在mta线程上轻松调用。这将在MTA线程执行时阻止主线程。这有多高将取决于您的API使用情况,因为每次调用它时都会启动一个新线程。

public delegate void MtaMethod();

public class MtaHelper
{

    public static void RunMta(MtaMethod method)
    {

        ManualResetEvent evnt = new ManualResetEvent(false);

        Thread thread = new Thread(delegate()
        {
            method();
            evnt.Set();
        });

        thread.SetApartmentState(ApartmentState.MTA);
        thread.Start();
        evnt.WaitOne();
    }

}

然后你应该能够将你的api称为

MtaHelper.RuntMta( () => OtherAPIMethod() );

答案 2 :(得分:2)

我在WPF中利用了DispatcherObject。

我创建了DispatcherObject的子类,然后使用MTA线程创建一个实例。这样,我可以使用mySubclass.Invoke(...)或mySubclass.BeginInvoke(...),执行代码将在我的MTA线程上发生。

你可以在这里看到一个例子:

http://wpfmediakit.codeplex.com/SourceControl/changeset/view/24019#283908

特别注意CreateDvdPlayer静态方法,并查看BaseClasses.cs中的基类