0

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.

Community
  • 1
  • 1
fziska
  • 43
  • 6
  • Hmm, no, this is not your choice and what you've been trying to do cannot work. You are at the mercy of the C++ app that uses your COM server, it is the one that creates the thread. If it doesn't want to support STA then you have a problem. It is a problem anyway when you want to use WPF, pretty important that its Application.Run() method is in charge. These are unpleasant system integration details that are not easily ignored. Start by talking to a programmer that works on the C++ app to see what is possible. – Hans Passant Dec 10 '15 at 23:28
  • @Hans What's the reason for not just creating a second thread with the right apartment and handling that yourself? – Voo Dec 11 '15 at 06:36
  • @Voo I tried that already but that doesn't work because I need to have WPF component accesible within the C++ GUI Thread. When I create my own STA Thread, thats not possible. – fziska Dec 11 '15 at 13:20
  • In that case there really isn't anything you can do - you can't change the threading model of a thread after the fact and you don't seem to be able to use a different thread. – Voo Dec 11 '15 at 13:51
  • But do I understand @Noseratio correct that it shouldn't matter what threading model the client is using because " If marshaled to another thread via COM, they always get marshaled to themselves, regardless of whether the creator thread was STA or not, and regardless of their ThreadingModel registry value." Also the API states clearly that the COM objects should be apartment state so I assume the client is in apartment state too. – fziska Dec 11 '15 at 14:17
  • @Voo tried the extra STA Thread again and got it actually working now. What I missed previously was: System.Windows.Threading.Dispatcher.Run(); at the end of the Thread and using: _player.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { })); – fziska Dec 11 '15 at 22:31

0 Answers0