在Word加载项公开的对象上调用方法会抛出RemotingException

时间:2011-05-11 12:57:02

标签: c# .net word-automation

我正在C#中编写(共享)Word加载项,并希望通过COMAddIn类的Object属性公开对象来与之通信。

因为我希望我的代码在UI线程上执行,所以我从StandardOleMarshalObject类派生了我的加载项和公开对象。这应该照顾herehere所述的编组。

但是通过这样做,当我针对.NET 2.0或.NET 4.0进行编译时,我得到了不同的行为。在针对.NET 4.0进行编译时,我的公开对象的类型为__ComObject,并且可以将其自身强制转换为我公开可见的已定义接口。这反过来让我可以调用对象上的方法并完美地工作。

在针对.NET 2.0进行编译时,公开的对象的类型为__TransparentProxy。这也可以转换为我的界面,但是当我尝试调用一个方法时,它会抛出一个带有消息的System.Runtime.Remoting.RemotingException:

  

此远程处理代理没有通道接收器,这意味着服务器没有正在侦听的已注册服务器通道,或者此应用程序没有合适的客户端通道与服务器通信。

当我不从StandardOleMarshalObject继承它似乎工作但我的代码将在任意RPC线程上执行,这不是我正在寻找的。

我搜索了互联网,但无法找到解决方案或原因,因为这不适用于.NET 2.0。我确实发现了一些类似的问题,但它们似乎都解决了Excel问题。

目前我还没有转向.NET 4.0,所以我真的希望.NET 2.0可以解决这个问题。

有没有人能解决这个问题,或者至少有一个解释?

这是我的测试代码:

[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");
   }
}

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
   }
}

1 个答案:

答案 0 :(得分:1)

所以我找到了一个可接受的问题的解决方法,并且与.NET2.0完美配合。我发现它并不像它本来那样优雅,但它确实有效。我正在使用一个隐藏的“代理”窗口,它允许我将来自一个进程外客户端的调用封送到Word的UI线程。我不打算通过COM公开很多方法,因此额外的代码行不会成为问题。我在下面添加了重要的代码片段。

    /// <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;
      }
    }

在Office 7上测试Office 2007.希望这有助于其他人。

我仍然想知道为什么它在.NET4.0而不是.NET2.0中运行。所以,如果有人对此有答案,我们仍然感激不尽。