控制 .NET 进程外服务器提供的 COM 对象的线程模型

发布于 2024-09-27 11:29:36 字数 1348 浏览 1 评论 0原文

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

正在创建的对象需要位于 STA 中,因为它使用 WPF 对象,并且它的工厂正在注册,如 ExeCOMServer.cs 并粘贴在下面...

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"));
    }

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

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

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

When creating an out-of-process COM server in C# as documented in Microsoft's All-In-One code sample: CSExeCOMServer, it seems difficult to control the threading model of objects that are created in the server (by a client).

The object being created needs to be in an STA due to the fact that it uses WPF objects, and it's factory is being registered as demonstrated on line 95 of ExeCOMServer.cs and pasted below...

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"));
    }

However, the CreateInstance function is Always called in a new thread which is in an MTA. It doesn't seem to matter that the main thread of the local server is marked (and verified) as an STA thread.

All material on the matter that has been found intimates that the apartment of the created objects should match the apartment of the thread in which the factory was registered. In fact, this seems to be the case when using an ATL COM server (mixed with Managed C++ to create the objects), but this method appears to be injecting a new thread in to the work flow who's intialization parameters, particularly the COM threading model, do not appear to be changeable.

Has anyone solved this issue without resorting to a COM server written largely in unmanaged code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

御弟哥哥 2024-10-04 11:29:37

最近,在设置 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 线程,然后将消息反向转换为方法调用。肮脏的?是的。表现?非常糟糕。但它确实有效。

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

We have very similar situation recently when setting up a WinForm application to host some objects for 64bit interop. The UI thread enters the STA on startup (with the STAThread attribute). It wasn't long before we discovered all the constructors are run in the UI thread (STA) but all other methods are run in a worker thread (MTA) that .Net creates.

It wasn't really the MTA that's the problem, but we do have methods that accesses the UI and the fact that they are always run in a worker thread that's bugging us. Although we couldn't figure out how to force .Net to marshal the calls to the UI thread (STA), we did come up with some very dirty trick involving ContextBoundObject and method interception. I won't go into the details, but you can take a look at System.Runtime.Remoting.Messaging and System.Runtime.Remoting.Contexts namespaces. The idea is to trick the CCW into thinking a transparent proxy as the interop object, and we intercept every invocation to the proxy, pass the message to UI thread, then back-translate the message into method call. Dirty? Yes. Performance? Very bad. But it WORKS.

If you would like to see the method interception code you can drop me an email.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文