C# .Net COM对象需要是STA线程
我正在为第三方系统实现一个.NET COM服务器,它是COM客户端(C++)。我提供了一个IDL,用于使用tlbimp生成.dll。在API中,它还建议实现双和单元接口。在这个COM服务器中,我必须实例化一个WPF组件,该组件当前失败,因为它必须从STA线程调用。我已经在谷歌上做了很多关于如何强制我的COM服务器成为线程模型公寓的研究。我更改了注册表项,但没有帮助,然后我发现了以下关于stackoverflow的文章: 我按照说明实现了ICustomQueryInterface,但失败了;这是我的IDL:C# .Net COM对象需要是STA线程,c#,.net,wpf,multithreading,com,C#,.net,Wpf,Multithreading,Com,我正在为第三方系统实现一个.NET COM服务器,它是COM客户端(C++)。我提供了一个IDL,用于使用tlbimp生成.dll。在API中,它还建议实现双和单元接口。在这个COM服务器中,我必须实例化一个WPF组件,该组件当前失败,因为它必须从STA线程调用。我已经在谷歌上做了很多关于如何强制我的COM服务器成为线程模型公寓的研究。我更改了注册表项,但没有帮助,然后我发现了以下关于stackoverflow的文章: 我按照说明实现了ICustomQueryInterface,但失败了;这是我
[
object,
uuid(ABB09FED-F7BE-4654-88BC-5F4D2941111A),
dual,
nonextensible,
helpstring("IDVRServer Interface"),
pointer_default(unique)
]
interface IDVRServer : IDispatch{
[id(1), helpstring("Creates a DVR Unit Connection based on connection information
such as IP address, user name...")]
HRESULT CreateConnection(
[in] DVRConnectionInfo* pConnInfo, [out, retval] IDVRUnitConnection** ppConn);
};
这里是C#中的实现(包括ICustomQueryInterface):
Marshal.QueryInterface的结果始终为0x80004002 E_NOINTERFACE。我已经尝试了很多不同的东西,也来自StandardOleMarshalObject和ServicedComponent,但都没有成功。还有一个问题是,如果注册表真的算数,或者我可以忽略其中的ThreadingModel,我并没有从Noseratio的帖子中真正了解到这一点。提前感谢您对该主题的任何帮助
我使用的是VisualStudio 2012和.Net Framework 4。嗯,不,这不是你的选择,你一直试图做的事情无法奏效。你在使用你的COM服务器的C++应用程序的支配下,它是创建线程的那个。如果它不想支持STA,那么您就有问题了。不管怎样,当您想要使用WPF时,这是一个问题,它的Application.Run()方法负责这一点非常重要。这些都是令人不快的系统集成细节,不容易被忽略。首先,和一个在C++应用程序上工作的程序员谈谈,看看什么是可能的。@ HANS,为什么不用正确的公寓创建一个第二线程并处理自己的问题?@ Voo我已经尝试过了,但是这不起作用,因为我需要在C++ GUI线程中有WPF组件。当我创建自己的STA线程时,这是不可能的。在这种情况下,你真的没有什么可以做的-你不能在事后更改线程的线程模型,而且你似乎不能使用其他线程。但是我是否理解@Noseratio正确,客户端使用的线程模型不重要,因为“如果通过COM封送到另一个线程,则无论创建者线程是否为STA,也不管其ThreadingModel注册表值如何,它们都会被封送到自己的线程中。”此外,API明确指出COM对象应为单元状态,因此我假设客户端也处于单元状态。
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)
public class DVRServer : IDVRServer, ICustomQueryInterface
{
private IntPtr _dvrPointer;
public DVRServer() {
NativeMethods.CoGetStdMarshalEx(this, NativeMethods.SMEXF_SERVER, out _dvrPointer);
}
public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr ppv) {
if (iid == NativeMethods.IID_IMarshal_DVRServerDispatch)
{
res = 0;
res = Marshal.QueryInterface(_dvrPointer, ref NativeMethods.IID_IMarshal_DVRServerDispatch, out ppv);
string hex = res.ToString("X");
if (res != 0)
{
return CustomQueryInterfaceResult.Failed;
}
return CustomQueryInterfaceResult.Handled;
}
return CustomQueryInterfaceResult.Failed;
}
static class NativeMethods
{
public static Guid IID_IMarshal_DVRServerDispatch = new Guid("ABB09FED-F7BE-4654-88BC-5F4D2941111A");
public const UInt32 SMEXF_SERVER = 1;
[DllImport("ole32.dll", PreserveSig = true)]
public static extern void CoGetStdMarshalEx([MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, UInt32 smexflags, out IntPtr ppUnkInner);
}