2

在 C# 中创建进程外 COM 服务器时,如 Microsoft 的 All-In-One 代码示例中所述:CSExeCOMServer,似乎很难控制在服务器中(由客户端)创建的对象的线程模型。

由于它使用 WPF 对象,正在创建的对象需要在 STA 中,并且它的工厂正在注册,如ExeCOMServer.cs的第 95 行所示并粘贴在下面...

private void PreMessageLoop()
{
    //
    // Register the COM class factories.
    // 

    Guid clsidSimpleObj = new Guid(SimpleObject.ClassId);

    // Register the SimpleObject class object
    int hResult = COMNative.CoRegisterClassObject(
        ref clsidSimpleObj,                 // CLSID to be registered
        new SimpleObjectClassFactory(),     // Class factory
        CLSCTX.LOCAL_SERVER,                // Context to run
        REGCLS.MULTIPLEUSE | REGCLS.SUSPENDED,
        out _cookieSimpleObj);
    if (hResult != 0)
    {
        throw new ApplicationException(
        "CoRegisterClassObject failed w/err 0x" + hResult.ToString("X"));
    }

但是,总是在 MTA 中的新线程中调用 CreateInstance 函数。本地服务器的主线程被标记(并验证)为 STA 线程似乎并不重要。

所发现的所有材料都表明,所创建对象的单元应与工厂注册所在线程的单元相匹配。事实上,这似乎是使用 ATL COM 服务器(与托管 C++ 混合创建对象)时的情况,但这种方法似乎是将一个新线程注入到初始化参数的工作流中,特别是 COM 线程模型, 似乎不可变。

有没有人在不求助于主要用非托管代码编写的 COM 服务器的情况下解决了这个问题。

4

1 回答 1

2

我们最近在设置 WinForm 应用程序来托管一些 64 位互操作对象时遇到了非常相似的情况。UI 线程在启动时进入 STA(使用 STAThread 属性)。不久之后,我们发现所有构造函数都在 UI 线程 (STA) 中运行,但所有其他方法都在 .Net 创建的工作线程 (MTA) 中运行。

问题并不是真正的 MTA,但我们确实有访问 UI 的方法,而且它们总是在困扰我们的工作线程中运行。虽然我们不知道如何强制 .Net 编组对 UI 线程 (STA) 的调用,但我们确实想出了一些非常肮脏的技巧,涉及 ContextBoundObject 和方法拦截。我不会详细介绍,但您可以查看 System.Runtime.Remoting.Messaging 和 System.Runtime.Remoting.Contexts 命名空间。这个想法是欺骗 CCW 将透明代理视为互操作对象,我们拦截对代理的每个调用,将消息传递给 UI 线程,然后将消息反向转换为方法调用。肮脏的?是的。表现?很坏。但它有效。

如果您想查看方法拦截代码,可以给我发电子邮件。

于 2011-01-18T13:54:03.947 回答