28

質問

私の質問は: C# は遅延バインディング IDispatch をネイティブにサポートしていますか?


顧客がインストールしたバージョンと互換性を保ちながら、Office を自動化しようとしているふりをします。

.NET の世界では、Office 2000 をインストールして開発した場合、すべての開発者とすべての顧客は、現在から最後まで Office 2000 を使用する必要があります。

.NET 以前の世界では、COMを使用して Office アプリケーションと通信していました。

例えば:

1) バージョンに依存しない ProgID を使用する

"Excel.Application"

これは次のように解決されます。

clsid = {00024500-0000-0000-C000-000000000046}

次に、COM を使用して、これらのクラスの 1 つをオブジェクトにインスタンス化するように要求します。

IUnknown unk;
CoCreateInstance(
    clsid, 
    null,
    CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
    IUnknown, 
    out unk);

そして今、私たちは競争に出かけています - アプリケーション内から Excel を使用できるようになりました。もちろん、本当にオブジェクトを使用したい場合は、何らかの方法でメソッドを呼び出す必要があります。

私たちの言語に翻訳されたさまざまなインターフェース宣言を手に入れることができました。このテクニックは優れています。

  • 早期バインディング
  • コードインサイト
  • コンパイル型の構文チェック

いくつかのコード例は次のとおりです。

Application xl = (IExcelApplication)unk;
ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
Worksheet worksheet = workbook.ActiveSheet;

しかし、インターフェイスを使用することには欠点があります。言語に変換されたさまざまなインターフェイス宣言を把握する必要があります。そして、すべてのパラメーターを指定する必要があるメソッドベースの呼び出しの使用に行き詰まっています。

ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
xl.Worksheets.Add(before, after, count, type, lcid);

これには、現実の世界で、喜んであきらめるほどの欠点があることが証明されています。

  • 早期バインディング
  • コードインサイト
  • コンパイル時の構文チェック

代わりにIDispatchレイト バインディングを使用します。

Variant xl = (IDispatch)unk;
Variant newWorksheet = xl.Worksheets.Add();

Excel の自動化は VB スクリプト用に設計されているため、多くのパラメーターを省略することができます。パラメーターなしではオーバーロードがない場合でも省略できます。

注: Excel の例と、IDispatch を使用する理由を混同しないでください。すべての COM オブジェクトが Excel であるとは限りません。一部の COM オブジェクトは、IDispatch 以外ではサポートされていません。

4

6 に答える 6

26

比較的、遅延バインディング IDispatch バインディングを C# で使用できます。

http://support.microsoft.com/kb/302902

Excel を使用したサンプルを次に示します。この方法では、Microsoft の肥大化した PIA に不必要な依存関係を追加する必要はありません。

//Create XL
Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));

//Get the workbooks collection.
//   books = xl.Workbooks;
Object books = xl.GetType().InvokeMember( "Workbooks", 
      BindingFlags.GetProperty, null, xl, null);

//Add a new workbook.
//   book = books.Add();
Objet book = books.GetType().InvokeMember( "Add", 
      BindingFlags.InvokeMethod, null, books, null );

//Get the worksheets collection.
//   sheets = book.Worksheets;
Object sheets = book.GetType().InvokeMember( "Worksheets",
      BindingFlags.GetProperty, null, book, null );

Object[] parameters;

//Get the first worksheet.
//   sheet = sheets.Item[1]
parameters = new Object[1];
parameters[0] = 1;
Object sheet = sheets.GetType().InvokeMember( "Item", 
      BindingFlags.GetProperty, null, sheets, parameters );

//Get a range object that contains cell A1.
//   range = sheet.Range["A1];
parameters = new Object[2];
parameters[0] = "A1";
parameters[1] = Missing.Value;
Object range = sheet.GetType().InvokeMember( "Range",
      BindingFlags.GetProperty, null, sheet, parameters );

//Write "Hello, World!" in cell A1.
//   range.Value = "Hello, World!";
parameters = new Object[1];
parameters[0] = "Hello, World!";
objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty, 
      null, range, parameters );

//Return control of Excel to the user.
//   xl.Visible = true;
//   xl.UserControl = true;
parameters = new Object[1];
parameters[0] = true;
xl.GetType().InvokeMember( "Visible", BindingFlags.SetProperty,
      null, xl, Parameters );
xl.GetType().InvokeMember( "UserControl", BindingFlags.SetProperty,
      null, xl, Parameters );
于 2009-01-28T20:47:42.240 に答える
9

探している遅延バインディングを取得するには、C#4.0がリリースされるのを待つ必要があります。相互運用機能が必要なときはいつでも、VB.Netモードに切り替えて、C#にはないように見えるCOM機能を利用できるようにします。

私が使用する簡単なメソッドは、IDispatchの動作を行うVB.Netでクラスを作成し、ラッパーのメソッドとして使用するメソッドを公開して、C#コードから自由に呼び出すことができます。最も洗練されたソリューションではありませんが、過去数か月の間に1つか2つのジャムから抜け出しました。

于 2008-12-31T15:43:30.300 に答える
5

C# 4 のdynamicキーワードは、IDispatch と遅延バインディングをサポートします。詳細については、 Sam Ng のダイナミック シリーズをご覧ください。

ああ、C# 4 は現在 CTP としてのみ利用可能です。それを使用するには、Visual Studio vNext を待つか、(Windows Server 2008 Virtual PC で実行される) ベータ版を使用する必要があります。

于 2008-12-31T15:36:37.257 に答える
3

他の人が言ったように-c#4の「動的」キーワードロックを使用しています。これは簡単な例です。「InvokeMethod」を使用するよりもはるかに簡潔です。

dynamic xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
dynamic books = xl.Workbooks;
dynamic book = books.Add();

Console.WriteLine(books.Count);     //Writes 1

foreach (dynamic b in books)        
{
Console.WriteLine(b.Name);      //Writes "Book1"
}
于 2011-11-09T18:33:44.960 に答える
2

時間をかけてオブジェクトに必要なメソッドとプロパティを含むインターフェイスを記述し、いくつかの属性を追加すると、C#2.0 / 3.0でより優れたコードを使用できるようになります(メモリから書き込むため、詳細がわからない場合があります)。正しいですが、私はそれが私のために働いたことを誓います...)

    using System.Runtime.Interopservices;

    [Guid("00024500-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    interface IExcel
    {
      // sample property
      string Name{get;}
      // more properties
    }

    // and somewhere else
    void main()
    {
      Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
      IExcel excel = (IExcel)xl;
      string name = xl.name
    }

前述のように、コードはそのままでは機能しません。msdnで何を探すべきかについてのヒントです。

于 2009-10-31T20:31:59.227 に答える
1

やあ、私は現在、この問題を解決するために 2 つの codeplex プロジェクトを持っています。

最初のものは、既知のオブジェクト モデルへの LateBindingApi.Excel http://excel.codeplex.com マッピングされた latebind 呼び出し呼び出しです。これは、次のプロジェクトのテスト プロジェクトでした。

2 つ目は CodeGenerator http://latebindingapi.codeplex.com で、このツールは COM タイプ ライブラリから C# プロジェクトを作成します。生成されたプロジェクトには、COM サーバーにアクセスする latebind を持つマッパー オブジェクトが含まれます。ハイライトは、ツールが異なるバージョンの COM タイプ ライブラリを 1 つのプロジェクト (Excel 9、10、11 など) に変換し、すべてのエンティティを自己定義の SupportByLibrary 属性でマークしたことです。このツールを使用して、バージョン 9、10、11、12、14 のすべてのオフィス アプリを分析し、ac# ソリューションを生成しました。これは、メイン ページにサンプル コードを含むテスト済みベータ版として利用できます。

于 2011-04-28T12:35:53.840 に答える