[INFO] オートメーションにおける事前バインディングおよび実行時バインディングの使用

文書翻訳 文書翻訳
文書番号: 245115 - 対象製品
すべて展開する | すべて折りたたむ

目次

概要

オートメーション サーバーへのバインド方法は、パフォーマンス、柔軟性、保守性など、プログラムの多くの点に影響を及ぼす可能性があります。

この資料では、オートメーション クライアントで使用できるバインディングの種類について説明し、それぞれの方法について比較検討します。

詳細

オートメーションとは、マイクロソフトの COM (Component Object Model) を使用して、あるソフトウェア コンポーネントが別のソフトウェア コンポーネントとの通信や制御を行う処理です。オートメーションは、Visual Basic や Visual Basic for Applications (VBA) などの言語で使用される大部分のコンポーネント間通信の基盤であり、大半のプログラムで標準的に使用されるようになっています。

過去には、IDispatch インターフェイスをサポートするオブジェクトをオートメーション オブジェクトと呼んでいました。IDispatch インターフェイスを使用することで、クライアントは、通信するオブジェクトが設計時には確定していなくても、実行時にメソッドやプロパティを呼び出すことができます。これは、実行時バインディングと呼ばれます。しかし、現在、"オートメーション オブジェクト" という用語は、事実上、IDispatch をサポートしない (実行時バインディングできない) ものも含め、すべての COM オブジェクトに適用できます。この資料では、自動化するオブジェクトで両方のバインディング方法がサポートされていることを前提としています。

バインディングについて

バインディングとは、プログラマが記述した関数呼び出しと、その関数を実装している実際の (内部または外部) コードを対応付ける処理です。バインディングはアプリケーションのコンパイル時に実行され、コードを実行する前に、コード内で呼び出されるすべての関数がバインドされている必要があります。

わかりやすくするために、本の出版に置き換えて "バインディング" について説明します。コードを、1 冊の本に書かれたテキストと考えてみます。その本のある段落に「詳細については第 12 章の x ページを参照してください」などのように記述していた場合、本が完成するまでページ番号はわからないため、段落のテキストを意図したとおりに構成するには、本の全ページを 1 つにまとめて製本 (バインド) し、正しいページ番号を段落に挿入する必要があります。本の他の部分を参照するには、本が "バインド" されるのを待つ必要があります。

ソフトウェアのバインディングも同様です。コードを "読み取る" ためには、コードを構成している要素をまとめる必要があります。バインディングは、関数名を、関数が呼び出されたときにコードが "ジャンプ" する先のメモリのアドレス (具体的にはメモリ オフセット) に置き換える作業です。COM オブジェクトの場合、このアドレスは、オブジェクトで保持されているポインタのテーブル (v-table) 内のメモリ オフセットです。COM 関数をバインドすると、関数は v-table 経由でバインドされます。

COM オブジェクトの構造は単純です。コード内にオブジェクトへの参照がある場合、v-table の先頭への間接的なポインタが保持されています。v-table はメモリ アドレスの配列で、配列の各エントリは、そのオブジェクトで呼び出すことができるさまざまな関数です。COM オブジェクトで 3 番目の関数を呼び出すには、テーブルで 3 つ下のエントリにジャンプして、そこで指定されているメモリの場所にジャンプします。この処理により、その関数のコードが実行され、コードの実行が完了すると、次のコード行を実行できる状態に戻ります。

+-[コード]-----------+  +.......................[COM オブジェクト].……..+
|                   |  : +-------------+                                :
|Set obj = Nothing -|--->| obj ポインタ  |                                :
|                   |  : +-|-----------+                                :
+-------------------+  :   |   +-----------------+                      :
                       :   +-->| v-table ポインタ  |                      :
                       :       +--|--------------+                      :
                       :          |                                     :
                       :          |  +----------------------------+     :
                       :(3 つ目の) |  | 関数 1 アドレス ポインタ        |     :
                       :(オフセット)|  +----------------------------+     :
                       :          |  | 関数 2 アドレス ポインタ        |     :
                       :          |  +----------------------------+     :
                       :          +->| 関数 3 アドレス ポインタ        |     :
                       :             +----------------------------+     :
                       +................................................+

				
上記の例は、COM オブジェクトを解放した場合にどのような状況が発生するかを示しています。すべての COM オブジェクトは IUnknown を継承しているため、テーブル内の最初の 3 つのエントリは IUnknown のメソッドです。オブジェクトを解放する必要がある場合、コードでは、v-table 内の 3 番目の関数 (IUnknown::Release) を呼び出します。

さいわいにも、この操作は Visual Basic で自動的に行われます。Visual Basic のプログラマは、v-table を直接処理する必要はありません。ただし、すべての COM オブジェクトのバインドはこのような構造になっており、バインディングについて理解するには、この構造を知っておくことが重要です。

事前バインディング

上記の例は、事前バインディング (v-table バインディング) と呼ばれるものです。すべての COM オブジェクトでは、COM オブジェクトの IUnknown インターフェイスが呼び出されると、必ずこの形式のバインディングが実行されます。しかし、オブジェクトのその他の関数、たとえば Refresh メソッドや Parent プロパティは、通常オブジェクトごとに異なるカスタム関数です。v-table 内のその関数の位置があらかじめわかっていない場合、その関数の呼び出しに必要な関数のアドレスはどのように探すのでしょうか。

当然ながら、この答えは、オブジェクトの v-table の構成が事前にわかっているかどうかによって異なります。事前にわかっている場合は、IUnknown メソッドの場合と同様に、オブジェクトのカスタム メソッドに対して事前バインディング処理を実行できます。これが、通常 "事前バインディング" と呼ばれている処理です。

オブジェクトで事前バインディングを使用するには、そのオブジェクトの v-table の構成を把握している必要があります。Visual Basic でこの処理を行うには、オブジェクト、オブジェクトのインターフェイス (v-table)、およびオブジェクトで呼び出し可能なすべての関数が記述されているタイプ ライブラリへの参照を追加します。この操作を実行すると、オブジェクトを特定の型として宣言し、v-table を使用してそのオブジェクトを設定および使用できます。たとえば、事前バインディングを使用して Microsoft Excel を自動化する場合、[プロジェクト] メニューの [参照設定] をクリックし、[参照設定] ダイアログ ボックスで、[Microsoft Excel 8.0 Object Library] への参照を追加し、"Excel.Application" 型として変数を宣言します。それ以降、作成したオブジェクト変数に対して行われるすべての呼び出しは、事前バインディングされます。
' Set reference to 'Microsoft Excel 8.0 Object Library' in
' the Project|References dialog (or Tools|References for VB4 or VBA).

' Declare the object as an early-bound object
  Dim oExcel As Excel.Application

  Set oExcel = CreateObject("Excel.Application")

' The Visible property is called via the v-table
  oExcel.Visible = True
				
ほとんどの場合、この方法でうまくいきます。しかし、使用するオブジェクトを設計時に特定できない場合はどうでしょうか。たとえば、複数のバージョンの Excel、ときには "未知の" オブジェクトとの通信が必要になる場合があります。

実行時バインディング

COM には IDispatch が含まれています。IDispatch が実装されているオブジェクトのインターフェイスは、オブジェクトでサポートされているインターフェイスが IDispatch のみの場合はディスパッチ インターフェイス、また、オブジェクトに事前バインディングできるカスタム インターフェイスも含まれている場合はデュアル インターフェイスと呼ばれます。IDispatch にバインドするクライアントで呼び出される具体的なプロパティやメソッドは、実行時に決定され、IDispatch のメソッドを使用して場所が特定されるため、IDispatch にバインドするクライアントは、"実行時バインディング" されます。前述のように本の出版にたとえると、実行時バインディングでは、本文中に参照先のページ番号ではなく、参照先のページ番号を特定するための目次の場所が脚注の形で示されています。そのため、実際に本を読むときに、目次を見て参照先のページ番号を特定する必要があります。

インターフェイスの動作は、2 つの関数 (GetIDsOfNames および Invoke) で制御されます。1 つ目の GetIDsOfNames 関数は、関数を表す ID (dispid) に関数名 (文字列) をマップします。呼び出す関数の ID がわかったら、Invoke 関数を使用してその関数を呼び出すことができます。このようなメソッドの呼び出し方を "実行時バインディング" と呼びます。

Visual Basic では、オブジェクトの宣言方法によってバインディング方法が決定します。オブジェクト変数を "Object" として宣言すると、実際には Visual Basic で IDispatch を使用するように指定したことになり、その結果、実行時バインディングが行われます。
' No reference to a type library is needed to use late binding.
' As long as the object supports IDispatch, the method can 
' be dynamically located and invoked at run-time.

' Declare the object as a late-bound object
  Dim oExcel As Object

  Set oExcel = CreateObject("Excel.Application")

' The Visible property is called via IDispatch
  oExcel.Visible = True
				
このように、コードの残りの部分は同じです。(コードの記述に関して) 事前バインディングと実行時バインディングで異なるのは、変数の宣言のみです。

"実行時バインディング" の対象は、呼び出される関数であり、関数の呼び出し方法ではないということが重要です。上記のバインディングに関する一般的な説明からわかるように、IDispatch 自体は "事前バインディング" されます。つまり、Visual Basic では、COM 呼び出しを行う場合と同様、v-table エントリ (IDispatch::Invoke) を使用して Visible プロパティを設定するための呼び出しを行います。COM オブジェクト自体には、適切な関数の呼び出しを転送して、Excel を表示する役目があります。この間接参照により、Visual Basic クライアントで実際に実行される関数が確定していなくても、そのクライアントをコンパイル (つまり、有効な関数のアドレスにバインド) することができます。

dispid バインディング

一部のオートメーション クライアントでは、dispid バインディングという複合形式の実行時バインディングが使用されます (最も顕著なのが、MFC および Visual Basic 3.0 ですが、ActiveX コントロールに関しては Visual Basic 5.0 および 6.0 にも当てはまります)。設計時に COM オブジェクトがわかっている場合は、呼び出される関数の dispid をキャッシュして、IDispatch::Invoke に直接渡すことができます。この場合、実行時に GetIDsOfNames 関数を呼び出す必要はありません。これにより、関数ごとに 2 つの COM 呼び出しを行う必要はなく、1 つの COM だけを呼び出せばよいので、パフォーマンスが大幅に向上します。

dispid バインディングは、Visual Basic 5.0 または 6.0 で通常使用されるバインディング方法ではありません。このバインディングは、タイプ ライブラリで参照されていて、カスタム インターフェイスを含んでいないオブジェクト (つまり、ディスパッチ インターフェイスのみを持つオブジェクト)、および ActiveX コントロールの集合に対して使用されます。ただし、一般的に、Visual Basic では、通常 dispid バインディングが使用される場所で事前バインディングが使用されます。

使用するバインディングの形式

どちらのバインディングを使用するかは、主にプロジェクトの設計によって決まります。マイクロソフトでは、ほとんどの場合において、事前バインディングを使用することをお勧めします。ただし、実行時バインディングを選択した方がよい場合もあります。

望ましいバインディング方法は、事前バインディングです。事前バインディングでは、呼び出される関数のアドレスにアプリケーションが直接バインドし、実行時に参照のための余分なオーバーヘッドが発生しないため、このバインディングのパフォーマンスが最も優れています。全体的な実行速度で比較しても、事前バインディングの実行速度は、実行時バインディングの少なくとも 2 倍です。

また、事前バインディングは、タイプ セーフです。コンポーネントのタイプ ライブラリへの参照を設定しておけば、Visual Basic の IntelliSense 機能が各関数を正しくコーディングする手助けをします。さらに、Visual Basic では、パラメータまたは戻り値のデータ型が適切でない場合に警告が表示されるため、コーディングおよびデバッグにかかる時間を大幅に短縮できます。

実行時バインディングは、設計時にはオブジェクトの具体的なインターフェイスが確定しない場合に役立ちます。アプリケーションで複数の未知のサーバーとの通信を試行する場合、または (たとえば、Visual Basic 6.0 の CallByName を使用して) 名前で関数を呼び出す必要がある場合、実行時バインディングを使用する必要があります。また、コンポーネントの複数のバージョンでインターフェイスに不用意な変更や調整が行われている場合に、バージョン間の互換性の問題を回避するためにも、実行時バインディングが役立ちます。

このように実行時バインディングが役立つ場合もありますが、可能な場合はさまざまな面で優れている事前バインディングを使用することをお勧めします。

複数のバージョン間での互換性の維持

使用するコンポーネントをセットアップ パッケージで再配布せず、実行時の通信相手のコンポーネントのバージョンが確定していない場合は、そのコンポーネントのすべてのバージョンと互換性のあるインターフェイスに対して事前バインディングを行うか、または (場合によっては) 特定のバージョンに存在するメソッドの呼び出しに実行時バインディングを使用して、そのメソッドがクライアント システムにインストールされているバージョンのコンポーネントに存在しない場合は正常にエラー終了するようにするなど、特別な注意を払う必要があります。

Microsoft Office アプリケーションは、このような COM サーバーの好例です。通常、Office アプリケーションでは、バージョンごとにインターフェイスを拡張して、新機能の追加や、以前の問題の修正がされています。Office アプリケーションを自動化する必要がある場合、クライアントのシステムにインストールされている可能性のある最も古いバージョンの製品に対して事前バインディングを行うことをお勧めします。たとえば、Excel 95、Excel 97、Excel 2000、および Excel 2002 を自動化する必要がある場合、他の 3 つのすべてのバージョンとの互換性を維持するためには、Excel 95 のタイプ ライブラリ (XL5en32.olb) を使用する必要があります。

また、Office アプリケーションから、多数のデュアル インターフェイスを持つオブジェクト モデルでは一部のプラットフォーム上でマーシャリングの制限を受ける可能性があることがわかります。すべてのプラットフォーム上でコードを最適に機能させるには、IDispatch を使用します。 Office アプリケーションを対象とした場合の互換性の維持についての関連情報を参照するには、以下の「サポート技術情報」 (Microsoft Knowledge Base) をクリックしてください。
247579 [INFO] Office アプリケーションの自動化には可能な限り DISPID バインディングを使用する

関連情報

COM、v-table、およびオートメーションの使用の詳細については、以下の書籍およびオンライン コンテンツを参照してください。
『Inside COM』 (Dale Rogerson 著、アスキー出版局発行、ISBN: 1-57231-349-8)

『Advanced Visual Basic 6』 (Matt Curland 著、DevelopMentor シリーズ、ISBN: 0201707128)

プロパティ

文書番号: 245115 - 最終更新日: 2006年2月10日 - リビジョン: 6.0
この資料は以下の製品について記述したものです。
  • Microsoft Office Standard Edition 2003
  • Microsoft Office XP Developer Edition
  • Microsoft Office 2000 Developer
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
キーワード:?
kbautomation kbinfo KB245115
"Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。"

フィードバック

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com