6

据我了解,当从MTA线程使用标记为使用STA的 COM 组件时,应该将调用编组到 STA 线程并从该专用线程执行。对于 Windows 客户端应用程序,这意味着它将在 UI 线程上执行(如果标记为 STA),并且从 COM 组件到我的回调将由发送到隐藏窗口的 Windows 消息处理并在Windows 消息循环。

但是,如果我在 IIS 中托管的 WCF 服务中使用 STA COM 组件会发生什么?工作进程是否会在 STA 线程上有 Windows 消息循环?我可以使用自己的消息循环启动自己的 STA 线程吗?

4

2 回答 2

5

COM 运行时负责对 STA 内的 COM 对象上的方法调用的分派:您是对的,这基于用于分派 Windows 消息的相同操作系统机制,但您不必担心会发生这种情况 - COM 在后台为您执行此操作。

需要担心的是您的 COM 对象将驻留在哪个 STA。如果您使用 WCF 服务中的 COM 互操作实例化单元线程 COM 对象,则需要小心。

如果执行此操作的线程不是 STA 线程,则所有进程内 COM 对象都将存在于IIS 工作进程的默认主机 STA中。您不希望发生这种情况:所有服务操作的所有 COM 对象都将在同一个 STA 中结束。线索就在名称中——所有对象只有一个线程——并且对其方法的所有调用都将被序列化,等待单元中唯一的线程执行它们。您的服务将无法扩展以处理多个并发客户端。

您需要确保为服务特定 WCF 请求而实例化的 COM 对象位于它们自己的 STA 中,与为其他请求创建的对象分开。大致有两种方法可以做到这一点:

  • 启动您自己的 Thread,在启动之前指定ApartmentState.STAin ,在其上为特定请求实例化 COM 对象。SetApartmentState()这是 Scott Seely 在Kev 答案中的链接中详述的方法:他确保在新的 STA 初始化线程上调用每个服务操作调用。沿着这些思路,一个更难但更可扩展的解决方案是实现一个可重用的 STA 初始化线程池。
  • 在 COM+ 应用程序中托管您的 COM 对象,以便它们存在于单独的 DllHost 进程中,其中 COM+(通过其抽象称为)可以负责将不同请求的对象放入不同的 STA Activity

当您提到回调时,我不确定您的确切含义。也许您的意思是在托管代码中实现的某些 COM 接口上的 COM 方法调用,通过作为 COM 对象方法之一的参数传递给 COM 对象的引用:如果是这样,这应该可以工作。但也许你的意思是别的,在这种情况下,也许你可以修改问题来澄清。

于 2011-03-10T13:28:19.983 回答
3

我发现您需要在 WCF 服务中的 STA 线程上发送消息,或者您错过了来自 COM 对象的回调。

以下代码有效,但它需要您通过 Dispatcher 调用 COM 对象。

ComWrapper comWrapper;
Thread localThread;
Dispatcher localThreadDispatcher;

public Constructor()
{
   localThread = new Thread(ThreadProc)
   {
       Name = "test"
   };
   localThread.SetApartmentState(ApartmentState.STA);

   AutoResetEvent init = new AutoResetEvent(false);

   localThread.Start(init);

   init.WaitOne();
}

private void ThreadProc(object o)
{
    localThreadDispatcher = Dispatcher.CurrentDispatcher;
    ((AutoResetEvent)o).Set();

    comWrapper = new ComWrapper()

    Dispatcher.Run();

    localThreadFinished.Set();
 }

然后按如下方式拨打电话。

public void UsefulComOperation()
{
    localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}
于 2011-05-17T09:56:56.290 回答