I'm implementing a .NET COM Server for a 3rd party system which is the COM client (C++). I had a IDL provided which I used to generate the .dll with tlbimp. In the API its also recommended to implement the interfaces dual and Apartment. In this COM server I have to instantiate a WPF component, which currently fails because it has to be called from a STA Thread. I did a lot of googeling already on how to enforce my COM Server to be of Threading model Apartment. I changed the registry entry which didn't help and then I found following article on stackoverflow: How to make make a .NET COM object apartment-threaded?
I followed the instructions to implement ICustomQueryInterface but it fails; Here my IDL:
[
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);
};
Here the implementation in C# (including the ICustomQueryInterface):
[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);
}
The result of Marshal.QueryInterface is always 0x80004002 E_NOINTERFACE. I tried a lot of different things already, also deriving from StandardOleMarshalObject and ServicedComponent but nothing worked. One question is also if the registry does count at all or if I can just ignore the ThreadingModel in there, I didn't really get that from Noseratio's post. Thanks in advance for any help on that topic.
I use VisualStudio 2012 and .Net Framework 4.