0

C#で(共有)Wordアドインを作成していて、COMAddInクラスのObjectプロパティを介してオブジェクトを公開することで通信したいと考えています。

コードをUIスレッドで実行したいので、StandardOleMarshalObjectクラスからアドインと公開オブジェクトを派生させます。これにより、ここここで説明されているようにマーシャリングが処理されます。

ただし、これを行うと、.NET2.0または.NET4.0に対してコンパイルしたときに異なる動作が発生します。.NET 4.0に対してコンパイルする場合、公開されたオブジェクトは__ComObject型であり、公開されている定義済みのインターフェイスにキャストできます。これにより、オブジェクトのメソッドを呼び出すことができ、完全に機能します。

.NET 2.0に対してコンパイルする場合、公開されるオブジェクトのタイプは__TransparentProxyです。これはインターフェイスにキャストすることもできますが、メソッドを呼び出そうとすると、次のメッセージとともにSystem.Runtime.Remoting.RemotingExceptionがスローされます。

このリモートプロキシにはチャネルシンクがありません。つまり、サーバーにリッスンしているサーバーチャネルが登録されていないか、このアプリケーションにサーバーと通信するための適切なクライアントチャネルがありません。

StandardOleMarshalObjectから継承しない場合は機能しているように見えますが、コードは任意のRPCスレッドで実行されますが、これは私が探しているものではありません。

インターネットを検索しましたが、.NET2.0でこれが機能しない解決策や理由を見つけることができませんでした。私はいくつかの同様の問題を見つけましたが、それらはすべてExcelに対処しているようです。

現時点では、私は.NET 4.0に切り替える立場にないので、これが.NET2.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;
      }
    }

Windows 7、Office2007でテスト済み。これが他の人に役立つことを願っています。

.NET2.0ではなく.NET4.0で動作する理由を知りたいのですが。ですから、誰かがこれに対する答えを持っているなら、それはまだありがたいです。

于 2011-06-12T10:55:28.763 に答える