在Microsoft的All-In-One代码示例CSExeCOMServer中记录的C#中创建进程外COM服务器时,似乎很难控制在服务器中创建的对象的线程模型(由客户)。
正在创建的对象需要在STA中,因为它使用WPF对象,并且它的工厂正在注册,如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"));
}
但是,CreateInstance函数始终在MTA中的新线程中调用。将本地服务器的主线程标记(并验证)为STA线程似乎并不重要。
有关此事项的所有材料都暗示所创建对象的公寓应与工厂注册的线程的公寓相匹配。实际上,当使用ATL COM服务器(与Managed C ++混合创建对象)时似乎就是这种情况,但是这种方法似乎是在工作流中注入一个新线程,其初始化参数,特别是COM线程模型,似乎没有变化。
有没有人在没有使用主要使用非托管代码编写的COM服务器的情况下解决了这个问题。
答案 0 :(得分: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线程,然后将消息反向转换为方法调用。脏?是。性能?很坏。但它有效。
如果您想查看方法拦截代码,可以给我发电子邮件。