title: How to make make a .NET COM object apartment-threaded?
body: <p>.NET objects are free-threaded by default. 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 <code>ThreadingModel</code> registry value. I suspect, they aggregate the <a href="http://support.microsoft.com/kb/256217/en-us">Free Threaded Marshaler</a> (more details about COM threading could be found <a href="http://support2.microsoft.com/?kbid=150777">here</a>).</p>
  
  <p>I want to make my .NET COM object use the standard COM marshaller proxy when marshaled to another thread. The problem:</p>
  
  <pre><code>using System;
  using System.Runtime.InteropServices;
  using System.Threading;
  using System.Threading.Tasks;
  using System.Windows.Threading;
  
  namespace ConsoleApplication
  {
      class Program
      {
          static void Main(string[] args)
          {
              var apt1 = new WpfApartment();
              var apt2 = new WpfApartment();
  
              apt1.Invoke(() =&gt;
              {
                  var comObj = new ComObject();
                  comObj.Test();
  
                  IntPtr pStm;
                  NativeMethods.CoMarshalInterThreadInterfaceInStream(NativeMethods.IID_IUnknown, comObj, out pStm);
  
                  apt2.Invoke(() =&gt;
                  {
                      object unk;
                      NativeMethods.CoGetInterfaceAndReleaseStream(pStm, NativeMethods.IID_IUnknown, out unk);
  
                      Console.WriteLine(new { equal = Object.ReferenceEquals(comObj, unk) });
  
                      var marshaledComObj = (IComObject)unk;
                      marshaledComObj.Test();
                  });
              });
  
              Console.ReadLine();
          }
      }
  
      // ComObject
      [ComVisible(true)]
      [Guid("00020400-0000-0000-C000-000000000046")] // IID_IDispatch
      [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
      public interface IComObject
      {
          void Test();
      }
  
      [ComVisible(true)]
      [ClassInterface(ClassInterfaceType.None)]
      [ComDefaultInterface(typeof(IComObject))]
      public class ComObject : IComObject
      {
          // IComObject methods
          public void Test()
          {
              Console.WriteLine(new { Environment.CurrentManagedThreadId });
          }
      }
  
  
      // WpfApartment - a WPF Dispatcher Thread 
      internal class WpfApartment : IDisposable
      {
          Thread _thread; // the STA thread
          public System.Threading.Tasks.TaskScheduler TaskScheduler { get; private set; }
  
          public WpfApartment()
          {
              var tcs = new TaskCompletionSource&lt;System.Threading.Tasks.TaskScheduler&gt;();
  
              // start the STA thread with WPF Dispatcher
              _thread = new Thread(_ =&gt;
              {
                  NativeMethods.OleInitialize(IntPtr.Zero);
                  try
                  {
                      // post a callback to get the TaskScheduler
                      Dispatcher.CurrentDispatcher.InvokeAsync(
                          () =&gt; tcs.SetResult(System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext()),
                          DispatcherPriority.ApplicationIdle);
  
                      // run the WPF Dispatcher message loop
                      Dispatcher.Run();
                  }
                  finally
                  {
                      NativeMethods.OleUninitialize();
                  }
              });
  
              _thread.SetApartmentState(ApartmentState.STA);
              _thread.IsBackground = true;
              _thread.Start();
              this.TaskScheduler = tcs.Task.Result;
          }
  
          // shutdown the STA thread
          public void Dispose()
          {
              if (_thread != null &amp;&amp; _thread.IsAlive)
              {
                  InvokeAsync(() =&gt; System.Windows.Threading.Dispatcher.ExitAllFrames());
                  _thread.Join();
                  _thread = null;
              }
          }
  
          // Task.Factory.StartNew wrappers
          public Task InvokeAsync(Action action)
          {
              return Task.Factory.StartNew(action,
                  CancellationToken.None, TaskCreationOptions.None, this.TaskScheduler);
          }
  
          public void Invoke(Action action)
          {
              InvokeAsync(action).Wait();
          }
      }
  
      public static class NativeMethods
      {
          public static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
          public static readonly Guid IID_IDispatch = new Guid("00020400-0000-0000-C000-000000000046");
  
          [DllImport("ole32.dll", PreserveSig = false)]
          public static extern void CoMarshalInterThreadInterfaceInStream(
              [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
              [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
              out IntPtr ppStm);
  
          [DllImport("ole32.dll", PreserveSig = false)]
          public static extern void CoGetInterfaceAndReleaseStream(
              IntPtr pStm,
              [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
              [MarshalAs(UnmanagedType.IUnknown)] out object ppv);
  
          [DllImport("ole32.dll", PreserveSig = false)]
          public static extern void OleInitialize(IntPtr pvReserved);
  
          [DllImport("ole32.dll", PreserveSig = true)]
          public static extern void OleUninitialize();
      }
  }
  </code></pre>
  
  <p>Output:</p>
  
  <pre>
  { CurrentManagedThreadId = 11 }
  { equal = True }
  { CurrentManagedThreadId = 12 }
  </pre>
  
  <p>Note I use <code>CoMarshalInterThreadInterfaceInStream</code>/<code>CoGetInterfaceAndReleaseStream</code> to marshal <code>ComObject</code> from one STA thread to another. <strong>I want both <code>Test()</code> calls to be invoked on the same original thread, e.g. <code>11</code></strong>, as it would have been the case with a typical STA COM object implemented in C++.</p>
  
  <p>One possible solution is to disable <code>IMarshal</code> interface on the .NET COM object:</p>
  
  <pre><code>[ComVisible(true)]
  [ClassInterface(ClassInterfaceType.None)]
  [ComDefaultInterface(typeof(IComObject))]
  public class ComObject : IComObject, ICustomQueryInterface
  {
      // IComObject methods
      public void Test()
      {
          Console.WriteLine(new { Environment.CurrentManagedThreadId });
      }
  
      public static readonly Guid IID_IMarshal = new Guid("00000003-0000-0000-C000-000000000046");
  
      public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr ppv)
      {
          ppv = IntPtr.Zero;
          if (iid == IID_IMarshal)
          {
              return CustomQueryInterfaceResult.Failed;
          }
          return CustomQueryInterfaceResult.NotHandled;
      }
  }
  </code></pre>
  
  <p>Output (as desired):</p>
  
  <pre>
  { CurrentManagedThreadId = 11 }
  { equal = False }
  { CurrentManagedThreadId = 11 }
  </pre>
  
  <p>This works, but it feels like an implementation-specific hack. Is there a more decent way to get this done, like some special interop attribute I might have overlooked? Note that in real life <code>ComObject</code> is used (and gets marshaled) by a legacy unmanaged application.</p>