none
Deriving AddIn from StandardOleMarshalObject throws RemotingException RRS feed

  • Question

  • Hi All,

    I'm trying to create a COM AddIn for Word in C# 2.0. I need to call methods on it from an external application so I exposed an object through the COMAddIn.Object property. This partially works. I want my code to be run on the UI thread so i followed the advice described here and here by inheriting from StandardOleMarshalObject for the Addin itself and also for the exposed object. However when i do this i wil receive a RemotingException telling me:

     

    This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server.

     

    This is some minimal code that should give a impression of what i'm doing:

    [ComVisible(true)][Guid("...")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IService
    {
     void Hello();
    }
    
    [ComVisible(true)][Guid("...")]
    [ClassInterface(ClassInterfaceType.None)]
    public class MyService : StandardOleMarshalObject, IService
    {
     public void Hello()
     {
     MessageBox.Show("Hello");
     }
    }
    
    [ComVisible(true)][Guid("...")][ProgId("MyAddIn")
    [ClassInterface(ClassInterfaceType.None)]
    public class MyAddIn : StandardOleMarshalObject, IDTExtensibility2
    {
     public void OnConnection(object application, ext_ConnectMode connectMode, 
     object addInInst, ref Array custom)
     {
     _service = new MyService();
     ((COMAddIn)addInInst).Object = _service;
     }
    
     //Rest of the IDTExtensibility2 implementation
    }
    
    public class Test
    {
     public static void Main(string[] args)
     {
     Application app = new Application();
     app.Visible = true;
    
     COMAddIn addIn = app.COMAddIns.Item("MyAddin");
     IService service = addIn.Object as IService;
     if (service != null)
     service.Hello(); // <-- RemotingException happening here
     }
    }
    

    The "weird" thing is that this code works fine when i'm compiling against C# 4.0. I suspect it has something to do with the new dynamic stuff that 4.0 supports. The difference I discovered through the debugger is that the service variable derives from __ComObject in C# 4.0 and __TransparentProxy in C# 2.0. When not deriving from StandardOleMarshalObject it also derives from __ComObject in C# 2.0.

    The problem is that i can't switch to C# 4.0 at this moment and I do need my code to be executed on the Word UI Thread for performance reasons.

    I posted a similar question on stackoverflow some time ago be did not get any answers. Here is the link for who's interested. link  

    What is the reason for this behavior?




    • Moved by Cindy Meister MVPModerator Tuesday, May 31, 2011 6:34 PM not using VSTO technology (From:Visual Studio Tools for Office)
    Tuesday, May 31, 2011 12:49 PM

Answers

  • So I found a workaround for my problem that is acceptable and works perfectly with .NET2.0. I don't find it as elegant as it could have been, but it works. I'm using a little hidden "proxy" window that lets me marshal calls made from an out-of-proc client to the UI thread of Word. I'm not planning to have many methods exposed through COM so the extra lines of code won't be a problem. I've added the important pieces of code below.

    /// <summary>
    /// HiddenForm can be used to marshal calls to the UI thread but is not visible
    /// </summary>
    public class HiddenForm : Form
    {
      public HiddenForm()
      {
       //Making a dummy call to the Handle property will force the native 
       //window handle to be created which is the minimum requirement for 
       //InvokeRequired to work.
       IntPtr hWnd = Handle;
      }
    }
    
    /// <summary>
    /// AddInService will be exposed through the Object property of the AddIn but does NOT derive 
    /// from StandardOleMarshalObject but instead uses a <see cref="HiddenForm"/> to marshal calls
    /// from an arbitrary RPC thread to the UI thread.
    /// </summary>
    public class AddInService : IAddInService
    {
      private readonly Form _invokeForm;
    
      public AddInService()
      {
       //create an instance of the HiddenForm which allows to marshal COM
       //calls to the UI thread.
       _invokeForm = new HiddenForm();
      }
    
      public void HelloOutOfProc()
      {
       if(_invokeForm.InvokeRequired)
       {
         _invokeForm.Invoke(
          new Action<object>(o => HelloOutOfProc()), new object()); //not really elegant yet but Action<> was the only "out of the box" solution that I could find
       }
       else
       {
         MessageBox.Show("HelloOutOfProc on thread id " + Thread.CurrentThread.ManagedThreadId);
       }
      }
    }
    
    /// <summary>
    /// AddIn Class which DOES derive from StandardOleMarshalObject so it's executed on the UI thread
    /// </summary>
    public class Connect : StandardOleMarshalObject, IDTExtensibility2
    {
      private IAddInService _service;
    
      public void OnConnection(object application, ext_ConnectMode connectMode,
                   object addInInst, ref Array custom)
      {
       //create service object that will be exposed to out-of-proc processes
       _service = new AddInService();
    
       //expose AddInService through the COMAddIn.Object property
       ((COMAddIn)addInInst).Object = _service;
      }
    }
    
    
    

    Tested on Window 7, Office 2007. Hope this helps others.

    I do still like to know WHY it's working in .NET4.0 and not .NET2.0. So if anyone has a answer to this, it is still appreciated.

    • Proposed as answer by Bruce Song Tuesday, June 21, 2011 1:45 PM
    • Marked as answer by Bruce Song Thursday, July 7, 2011 11:31 AM
    Tuesday, June 7, 2011 11:54 AM

All replies

  • <sub>Onetime kick because I'm still hoping someone has a answer for me.</sub>
    Monday, June 6, 2011 10:18 AM
  • Dear Mc_Bob,

    It will be nice if you can upload your demo project to the skydrive and share it with me: 

    http://www.skydrive.com

    I will do research with the problem.

    Regards,


    Be happy.
    Monday, June 6, 2011 11:53 AM
  • Mike_HelpYou, thanks in advance for taking the time to have a look.

    Hope this helps: http://cid-b711382c7d9a72da.office.live.com/self.aspx/.Public/MyWordAddIn.zip

    Created using VS2010 tested on Word 2007 Compiled against .NET 2.0

    Monday, June 6, 2011 8:29 PM
  • So I found a workaround for my problem that is acceptable and works perfectly with .NET2.0. I don't find it as elegant as it could have been, but it works. I'm using a little hidden "proxy" window that lets me marshal calls made from an out-of-proc client to the UI thread of Word. I'm not planning to have many methods exposed through COM so the extra lines of code won't be a problem. I've added the important pieces of code below.

    /// <summary>
    /// HiddenForm can be used to marshal calls to the UI thread but is not visible
    /// </summary>
    public class HiddenForm : Form
    {
      public HiddenForm()
      {
       //Making a dummy call to the Handle property will force the native 
       //window handle to be created which is the minimum requirement for 
       //InvokeRequired to work.
       IntPtr hWnd = Handle;
      }
    }
    
    /// <summary>
    /// AddInService will be exposed through the Object property of the AddIn but does NOT derive 
    /// from StandardOleMarshalObject but instead uses a <see cref="HiddenForm"/> to marshal calls
    /// from an arbitrary RPC thread to the UI thread.
    /// </summary>
    public class AddInService : IAddInService
    {
      private readonly Form _invokeForm;
    
      public AddInService()
      {
       //create an instance of the HiddenForm which allows to marshal COM
       //calls to the UI thread.
       _invokeForm = new HiddenForm();
      }
    
      public void HelloOutOfProc()
      {
       if(_invokeForm.InvokeRequired)
       {
         _invokeForm.Invoke(
          new Action<object>(o => HelloOutOfProc()), new object()); //not really elegant yet but Action<> was the only "out of the box" solution that I could find
       }
       else
       {
         MessageBox.Show("HelloOutOfProc on thread id " + Thread.CurrentThread.ManagedThreadId);
       }
      }
    }
    
    /// <summary>
    /// AddIn Class which DOES derive from StandardOleMarshalObject so it's executed on the UI thread
    /// </summary>
    public class Connect : StandardOleMarshalObject, IDTExtensibility2
    {
      private IAddInService _service;
    
      public void OnConnection(object application, ext_ConnectMode connectMode,
                   object addInInst, ref Array custom)
      {
       //create service object that will be exposed to out-of-proc processes
       _service = new AddInService();
    
       //expose AddInService through the COMAddIn.Object property
       ((COMAddIn)addInInst).Object = _service;
      }
    }
    
    
    

    Tested on Window 7, Office 2007. Hope this helps others.

    I do still like to know WHY it's working in .NET4.0 and not .NET2.0. So if anyone has a answer to this, it is still appreciated.

    • Proposed as answer by Bruce Song Tuesday, June 21, 2011 1:45 PM
    • Marked as answer by Bruce Song Thursday, July 7, 2011 11:31 AM
    Tuesday, June 7, 2011 11:54 AM