0

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

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

但是通过这样做,当我针对 .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
   }
}
4

1 回答 1

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

在 Window 7、Office 2007 上测试。希望这对其他人有所帮助。

我仍然想知道为什么它在 .NET4.0 而不是 .NET2.0 中工作。因此,如果有人对此有答案,仍然不胜感激。

于 2011-06-12T10:55:28.763 回答