如何将暴露给COM-Interop的.NET对象标记为单线程?

7

当在C++中定义一个COM可见的类时,我可以在头文件中定义支持的线程模型(threading(single) 行):

[
    coclass,
    default(IComInterface),
    threading(single),
    vi_progid("Example.ComClass"),
    progid("Example.ComClass.1"),
    version(1.0),
    uuid("72861DF5-4C77-43ec-A4DC-ED04396F0CCD")
]

在.NET中是否有类似的设置线程模型的方法(例如属性)?我目前将我的COM类定义为:

[Guid("67155A91-2948-43f5-B07F-5C55CDD240E5")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IComInterface
{
    ...
}


[Guid("DC5E6955-BB29-44c8-9FC0-6AADEEB2AFFB")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Example.ComClass")]
public class ComClass : IComInterface
{
    ...
}

--编辑:

标记答案下的评论非常重要。看起来,唯一告诉RegAsm设置不同ThreadingModel的方法是编写一个使用[ComRegisterFunction]属性标记的自定义注册方法。

1个回答

6

这真的很晦涩,我从未在MIDL中看到过“线程化”属性,MSDN Library authors也没有。

COM coclass会在注册表中使用HKCR\CLSID\{guid}\InProcServer32键发布其线程需求。 ThreadingModel值声明所需的公寓。 如果缺少或设置为“Apartment”,则宣布它不是线程安全的,并需要来自STA线程的帮助。 CoCreateInstance()在创建对象时使用此值。 如果必要,它将启动STA线程并创建代理(如果当前线程不是STA),以确保始终以线程安全的方式使用它。

一个[ComVisible]的.NET类将被注册为"Both",表示它可以在MTA线程上使用。这很乐观,但遵循.NET哲学,即一切都是线程不安全的,但是可以通过在正确位置放置lock关键字来使其安全。这个承诺通常不经常测试,有风险。覆盖ThreadingModel值(或省略它)需要编写代码来自行注册coclass,并加上[ComRegisterFunction]属性。RegistrationServices.RegisterTypeForComClients()对于将基本密钥放置到正确位置非常有用。

2
我认为OP并不是在谈论MIDL属性。http://msdn.microsoft.com/de-de/library/zfbxt3zs.aspx - Henrik
我刚刚检查了注册表,ThreadingModel 的当前值为“Both”,这不是我要找的值。除了使用标有 [ComRegisterFunction] 标记的方法手动注册 COM 类之外,还有其他设置 ThreadingModel 的方法吗? - Xperimental
我在MSDN(位于“COM客户端和Windows Server 2003”下:http://msdn.microsoft.com/en-us/library/eaw10et3(VS.80).aspx)中找到了额外的信息,告诉我RegAsm注册的.NET COM服务器的默认线程模型实际上是“Both”。那么,除了编写自己的注册方法之外,还有没有其他方法告诉RegAsm使用另一个线程模型? - Xperimental
1
不,你需要编写一个[ComRegisterFunction]。 - Hans Passant
1
这是一个ComRegisterFunction的示例,用于设置线程模型:https://dev59.com/I1bTa4cB1Zd3GeqP-WUM#5727733 - Rory

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接