統合型 Office ソリューションの開発
David Shank
Microsoft Corporation
May 4, 2000
この記事は MSDN Online Voices のコラム "Office Talk" からの再録です。
「Microsoft Office アプリケーションをプログラム的に統合する」という言葉を聞くと、"greater than the sum of its parts" (集団は部分の総和以上の力を出す) という古い格言を思い起こします。Office アプリケーションはそのどれもが単体でも優れたアプリケーションですが、個々の Office アプリケーションが持つさまざまな機能を 1 個のカスタム ソリューションに統合することで、その優れた性能と機能とをさらに高めることができます。
ある Office アプリケーションからほかの Office アプリケーションのオブジェクトを Visual Basic® for Applications (VBA)を使って操作することを、「オートメーション」と呼びます。Office アプリケーションから公開されているオブジェクト群は 1 組の部品の集まりとして扱うことができ、自分のソリューションに組み込むことができます。そうすることで、Office ソフトウェアの設計、開発、試験にかけられた労力を有効利用できるだけでなく、開発期間の短縮も図れます。
今月はオートメーションの概要について説明し、実用的な例を用いてその概念を分かりやすく解説します。また、読者が自分のカスタム ソリューションの中でオートメーションを使う際に参考となる情報源も紹介します。
オートメーションとは
オートメーションとは、開発者が VBA のコードを使ってソフトウェア オブジェクトを作成し制御できるようにするための、コンポーネント オブジェクト モデル(COM)テクノロジーです(従来は「OLE オートメーション」と呼ばれていました)。これらのオブジェクトは、適切なプログラミング インターフェイスをサポートしている、アプリケーション、ダイナミック リンク ライブラリ(DLL)、または ActiveX® コントロールから公開されます。オートメーションを理解するには、オブジェクトおよびオブジェクト モデルがどのようなものであり、それらが単体で、または協調してどのように動作するのかについて理解することが大切です。
COM のソフトウェア アーキテクチャによって、ソフトウェア開発者は個々のソフトウェア コンポーネントからアプリケーションやサービスを作成することが可能になります。COM コンポーネントはコンパイル済みの物理ファイルから構成され、これらのファイルには「クラス」が収められています。クラスとは、プログラミング可能なオブジェクトを定義するコード モジュールです。
Windows オペレーティング システムや Office アプリケーション スイートは、COM のソフトウェア アーキテクチャを使って開発された製品の例です。ソフトウェアが COM で開発されているというだけでそのソフトウェアを VBA を使ってプログラミングできるとは限りませんが、アプリケーションやサービスがオートメーションと呼ばれる COM テクノロジーをサポートしているのであれば、VBA を始めとするほかの多くのプログラミング言語からプログラミング可能なオブジェクトとして、それらのコンポーネントの機能へのインターフェイスを公開できます。オートメーションをサポートするためには、次の 2 つの方法のどちらかまたは両方を使い、アプリケーションやサービスが自身のカスタム インターフェイスを公開できるようにする必要があります。
IDispatch インターフェイスを提供する方法。この方法では、アプリケーションやサービスに対してカスタム インターフェイスに関する情報を問い合わせることができます。IDispatch インターフェイスをサポートするアプリケーションやサービスは、実行時バインディングと呼ばれる方法で自身のカスタム インターフェイスに関する情報を実行時に提供します。
設計時に、アプリケーションやサービスのインターフェイスを実装している仮想関数テーブル(vtable)内のメンバ関数に直接アクセスできるようにする方法。カスタム インターフェイスへの直接アクセスをサポートするアプリケーションやサービスは、事前バインディングをサポートします。
アプリケーションがこれらの方法のどちらか一方でもサポートしていれば、オートメーションをサポートしていると言えます。Office アプリケーション スイートは両方の方法をサポートしています。
オートメーションは、アプリケーションどうしやコンポーネントどうしでプログラム的に通信やフィードバックを行えるようにする「神経システム」と考えることができます。あるいは、Office アプリケーションその他のソフトウェア コンポーネントの機能をカスタム ソリューションに統合できるようにする「接着剤」と捉えることもできます。
基本的なことがら
Office アプリケーションから公開されているオブジェクトは、自動化しようとするアプリケーションを参照することによって操作します。この参照によって、ほかのアプリケーションから公開されているオブジェクトを認識できるようになります。ほかのアプリケーションを参照するには 2 つの方法があり、そのどちらを使うかによって「事前バインディング」または「実行時バインディング」のどちらになるかが決まります。
参照の設定
Office アプリケーションのタイプライブラリを使う場合は、必ず事前バインド参照を作成します。これにより、オブジェクト ブラウザや、ステートメントの自動完了をはじめとする Visual Basic 開発環境(VBE)の Intellisense 機能をコードの記述時に利用できるようになります。また、事前バインド参照には、公開されているオブジェクトのヘルプ トピックが公開される、実行時バインディング オブジェクトを使う場合よりも実行時のパフォーマンスが向上する、などの利点もあります。事前バインディングという名称は、C プログラマが仮想関数テーブル バインディング、または vtable バインディングと呼んでいたものです。事前バインディングを使うには、自動化しようとするアプリケーションやサービスのオブジェクト、メソッド、プロパティ、およびイベントに関する型情報が収められている、タイプライブラリ(.tlb)、オブジェクト ライブラリ(.olb)、.exe、.dll、または .ocx のファイルへの参照を、ホストとなるアプリケーションで作成する必要があります。
事前バインディングは、VBE の**[参照]ダイアログ ボックスを使って Office アプリケーション タイプライブラリへの参照を設定することで、作成します。このダイアログ ボックスは[ツール]メニューの[参照]コマンドで開きます。Office アプリケーションにはそれぞれデフォルトで設定されているいくつかの参照があります。次の図は Word の[参照]**ダイアログ ボックスですが、ここでは Outlook のタイプライブラリへの参照を追加しています。表示されている最初の 5 個の参照は Word がデフォルトで設定しているものです。
図 1:[参照]ダイアログ ボックス
オブジェクト変数の作成
オブジェクト変数は、CreateObject 関数または GetObject 関数を使って初期化するか、またはアプリケーションがサポートしていれば New キーワードを使って初期化できます。Office アプリケーションは、次のコードのようにすべて New キーワードを使って初期化できます。
Dim olApp As Outlook.Application
Set olApp As New Outlook.Application
With olApp
' アプリケーション オブジェクトで動作するコードがここに入ります。
End With
New キーワードは DIM ステートメントの中でも使用できますが、このやり方は推奨できません。上のように、オブジェクト変数を Dim 宣言した後に SET ステートメントを使ってインスタンスを生成するほうが、変数の作成する方法やタイミングをより細かく制御できます。
VBA コードを介してほかの Office アプリケーションのオブジェクトを操作する方法は、コードを使ってコード自身のホスト アプリケーション内部にあるオブジェクトを操作する方法に似ています。ほとんどの場合、最初に Application オブジェクトを指すオブジェクト変数を作成します。アプリケーション内部にあるオブジェクトを操作する VBA コードを、同じアプリケーションの中に記述するときは、Application オブジェクトへの参照は暗黙的になります。ほかのアプリケーションを自動化する場合、一般に Application オブジェクトへの参照は必ず明示的でなければいけません。このような明示的なオブジェクト参照を作成すると、ほかのアプリケーションから公開されているほかのすべてのオブジェクトを Application オブジェクトの子オブジェクトとしてアクセスできるようになります。
オブジェクト変数の破棄
プロシージャの内部で宣言した変数はプロシージャの終了時に破棄されますが、オブジェクト変数を使う場合には、自動化しているアプリケーションを終了するときに、明示的にオブジェクト変数に Nothing キーワードを設定してオブジェクトを破棄するようにするとよいでしょう。。次のサンプル プロシージャはこの方法を示したものです。
Sub SendDataToWord()
' オブジェクト変数の次元化
Dim wdApp As Word.Application
Dim wdDoc As Word.Document
' オブジェクト変数のインスタンス化
Set wdApp = New Word.Application
Set wdDoc = wdApp.Documents.Add
' 新規文書にテキストを追加して保存
With wdDoc
.Range.Text = "オートメーションは便利です!"
.SaveAs "C:\My Documents\AutomateWord.doc"
.Close
End With
' オブジェクト変数を破棄
Set wdDoc = Nothing
wdApp.Quit
Set wdApp = Nothing
End Sub
このプロシージャを試してみるには、上のコード モジュールを任意の Office アプリケーションにコピーし、Word オブジェクト ライブラリへの参照を設定して、カーソルをプロシージャ内のどこかに置いた状態で F8 キーを押します。すると、コードがステップ実行されます。
実用的な例の作成
ここでは Word テンプレートを使った例を紹介します。この Word テンプレートには、会社のレターヘッドと、Outlook の[連絡先]フォルダから名前と住所の情報を取得する VBA コードが収められています。このテンプレートをもとに新しい文書を作成すると、ユーザーは連絡先の一覧から手紙の受取人を選択して、その名前と住所を文書内に自動的に挿入できるようになります。
ユーザーが新しい文書を作成したときの画面は次のようになります。
図 2:Outlook データの取得を自動化する Word 文書テンプレートの例
ここではレターヘッド テンプレートの作成方法については省略し、Word からオートメーションを使って Outlook のデータを取得する方法についてのみ、詳しく説明します。
テンプレートの Document_New イベント プロシージャは、GetOutlook プロシージャを呼び出します。GetOutlook プロシージャは、Outlook から連絡先情報を取得してデータを配列に保存します。GetOutlook は、まず Outlook の Application オブジェクトを表すオブジェクト変数を作成します。次に、そのオブジェクトを使い、連絡先データの取得に必要となる NameSpace および MAPIfolder の各オブジェクト変数のインスタンスを生成します。[連絡先]フォルダでは、MAPIFolder オブジェクトの Restrict メソッドを使い、BusinessAddress プロパティが既に設定されている連絡先だけを含むコレクションを返します。そして、会社住所のある連絡先ごとに、連絡先データを gavarContactsArray というグローバル配列に追加します。この配列は項目がアルファベット順になるように QuickSort プロシージャを呼び出して並べ替えます(ここではこのプロシージャの詳細は示していません)。
Sub GetOutlook()
'このプロシージャでは、Outlook の [連絡先] フォルダから勤務先住所のある
' 連絡先がすべて取得され、これらのアイテムが配列 gavarContactsArray
' に入力されます。読み込まれた frmShowAllContacts フォームでは、配列
' gavarContactsArray にあるデータがコンボ ボックスの内容として使用されます。
' ユーザーはこのコンボ ボックスから手紙の宛先として使用する連絡先を選択すること
' ができます。
Dim olapp As Outlook.Application
Dim nspNameSpace As Outlook.NameSpace
Dim fldContacts As Outlook.MAPIFolder
Dim objContacts As Object
Dim objContact As Object
Dim intCntr As Integer
Dim strZLS As String
On Error GoTo GetAll_Err
' Restrict メソッド引数で使用される
' 長さ 0 の文字列変数を初期化します。
strZLS = ""
' Outlook [連絡先] フォルダへの参照を取得します。
Set olapp = New Outlook.Application
Set nspNameSpace = olapp.GetNamespace("MAPI")
Set fldContacts = nspNameSpace.GetDefaultFolder(olFolderContacts)
Set objContacts = fldContacts.Items.Restrict("[BusinessAddress] <> '" & strZLS & "'")
' Outlook 連絡先の数に配列のサイズを変更します。
ReDim gavarContactsArray(objContacts.Count - 1)
For Each objContact In objContacts
' 勤務先住所を含むエントリだけを追加します。
gavarContactsArray(intCntr) = IIf(Len(objContact.FullName) > 0, _
objContact.FullName & vbCrLf, "") & IIf(Len(objContact.CompanyName) > 0, _
objContact.CompanyName & vbCrLf, "") & objContact.BusinessAddress
intCntr = intCntr + 1
Next objContact
' 配列をソートします。
QuickSortArray gavarContactsArray
GetAll_Bye:
Exit Sub
GetAll_Err:
MsgBox Err.Description, vbOKOnly, "エラー = " & Err.Number
Resume GetAll_Bye
End Sub
前出の図に示したフォームを表示するときは、連絡先名を FillUsingOutlookData プロシージャを使ってコンボ ボックスにロードします。
Sub FillUsingOutlookData()
' このプロシージャでは Outlook [連絡先] フォルダからの
' データが配列に入力されます。
Dim intCurrentContact As Integer
' 配列から得た名前をコンボ ボックスに入れます。
For intCurrentContact = 0 To UBound(gavarContactsArray) - 1
cboContacts.AddItem Left(gavarContactsArray(intCurrentContact), _
InStr(gavarContactsArray(intCurrentContact), _
vbCrLf) - 1)
Next intCurrentContact
' リストの先頭にあるアイテムを表示します。
cboContacts.ListIndex = 0
' 表示された名前に対する住所情報を
' 更新します。
UpdateAddress
End Sub
最後に、コンボ ボックスに表示されている名前に対応する住所情報を、UpdateAddress プロシージャを呼び出してフォーム上のテキスト ボックスに追加します。
Sub UpdateAddress()
Dim intIndex As Integer
' コンボ ボックスで選択されたアイテムを連絡先名と
' 住所の配列へのインデックスとして使用し、
' txtAddress テキスト ボックスの住所情報を表示します。
intIndex = cboContacts.ListIndex
txtAddress.Text = Mid(gavarContactsArray(intIndex), _
InStr(gavarContactsArray(intIndex), vbCrLf) + 2)
End Sub
ユーザーがフォーム上で手紙の受取人として使う名前を選択し、[OK] をクリックすると、文書内の Address というブックマークのある場所に名前と住所が挿入されます。
以上の例は簡単なものですが、Outlook の連絡先の管理機能を Word の文書作成機能に追加することで、どちらのアプリケーションでも本来サポートされていないカスタムのソリューションを実現しており、強力なツールとして利用できます。これこそオートメーションの真の力を発揮するものといえるでしょう。
参考資料
Office オートメーションの作業に関する詳細情報については次の各リンク先をご覧ください。
Knowledge Base では、たくさんのサンプル コードも含めて、 Office 2000 Automation に関する最新情報を提供しております。
また、いつものことですが Office Developer サイトの情報と Office ソリューション開発に関する技術記事を、定期的にご覧ください。
David Shank は、Office チームにおいて開発者向けのドキュメンテーションを専門とするプログラマーでありライターでもあります。彼はレドモンドの東に位置する山の上で生活していて、ノースウエストには残り少ないネイティブであるという噂です。