質問


質問

私の質問: 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 Script用に設計されているため、多くのパラメータは、パラメータなしでオーバーロードが発生していなくても省略できます。

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

役に立ちましたか?

解決

C#で遅延バインディングのIDispatchバインディングを使用できます。

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

他のヒント

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

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

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

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

インターフェースを書くのに時間をかけるなら、おそらく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で何を調べるべきかのヒントです。

他の人が言ったように-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"
}

おいおい、 現在、この問題を解決するための2つのcodeplexプロジェクトがあります。

最初のものはLateBindingApi.Excel http://excel.codeplex.com です。 よく知られたオブジェクトモデルへのマップされた遅延バインド呼び出し。 これは、次のプロジェクトのテストプロジェクトでした。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top