共有アドインから Visual Studio Tools for Office アドインへの移行

  

Brian A. Randell (MCW Technologies, LLC)

2006 年 10 月

適用対象:
   Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office system、2007 Microsoft Office system

要約: 2007 Microsoft Office system はアドイン開発者に新しいチャンスをもたらします。ここでは、既存の共有アドインで見られる問題について説明します。また、既存のアドインを Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office system アドインに移行する方法や、新しいリボンをサポートするためにコマンド バーのコードを変換する方法について説明します。

目次

はじめに
VSTO 2005 SE アドインの利点
共有アドインの作成
VSTO 2005 SE アドインの作成
まとめ
追加情報

はじめに

Microsoft Office システムには、これまで充実したカスタマイズのサポートが提供されてきました。Microsoft Office 2000 では、コンポーネント オブジェクト モデル (COM) アドイン (インプロセス DLL) のサポートが追加されました。Microsoft .NET Framework の最初のリリースでは、COM 相互運用機能と呼ばれる相互運用レイヤーを介して、Office 用の COM アドインを作成するためのサポートが提供されました。Microsoft Visual Studio .NET の最初のリリースでは、機能拡張プロジェクトとして共有アドイン プロジェクトが提供され、アドインの作成が容易になりました。また、配布を容易にするセットアップ プロジェクトも提供されました。それ以降、現時点での最新バージョンである Visual Studio 2005 も含め、Visual Studio のすべてのリリースで共有アドインのサポートが継続されています。また、Visual Studio 2005 を使用して、2007 Microsoft Office system で動作する共有アドインを簡単に作成することもできます。

**メモ:   **Visual Studio 2005 Express Edition には、共有アドイン テンプレートは含まれていません。ただし、必要な作業が多くなるだけで、共有アドインを作成することは可能です。

一方で、Microsoft Office ファミリーの製品に基づくソリューションを、より簡単に、問題の少ない方法で構築できるようにするための投資が続けられています。この投資は Microsoft Visual Studio Tools for the Microsoft Office System という形で実現されています。Visual Studio Tools for Office の最初のリリースである Version 2003 によって、Microsoft Office Excel 2003 および Microsoft Office Word 2003 のドキュメントとテンプレートにマネージ コードが提供されました。2 番目のリリースである Visual Studio 2005 Tools for Office では、Word と Excel に対する既存のサポートを継続しながら、Microsoft Office InfoPath 2003 フォームのサポートと、Microsoft Office Outlook 2003 のアプリケーション アドインのサポートが追加されました。Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office system (Visual Studio 2005 Tools for Office Second Edition、または VSTO 2005 SE とも呼ばれます) では、その他の Microsoft Office ホスト アプリケーションについてもアプリケーション アドインのサポートが実現されました。

**メモ:   **この記事は、Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office system の最初のベータ リリースに基づいて作成およびテストされています。新しいリリースを使用している場合は、結果が異なる可能性があります。使用しているリリースを明確にするために、この記事ではこの製品を Visual Studio 2005 Tools for Office Second Edition の略称 VSTO 2005 SE と呼びます。また、Visual Studio 2005 Tools for Office Second Edition のテンプレートを使用して作成したアドインを VSTO 2005 SE アドインと呼びます。

この追加サポートは、対象とするホストがサポートされている場合は、既存の共有アドインの移行を検討したり、Visual Studio 2005 Tools for Office Second Edition を使用して新しいアドインを作成したりするべきであることを意味します。共有アドインおよび Visual Studio 2005 Tools for Office Second Edition でサポートされるホストの一覧については、表 1 を参照してください。

表 1. Office ホスト アプリケーションとアドインのサポート

ホスト 共有アドイン VSTO 2005 SE アドイン
Access 2003 あり なし
Excel 2003 あり あり
FrontPage 2003 あり なし
Outlook 2003* あり あり
PowerPoint 2003 あり あり
Project 2003 あり なし
Publisher 2003 あり なし
Visio 2003 あり あり
Word 2003 あり あり
Access 2007 あり なし
Excel 2007 あり あり
InfoPath 2007 なし** あり
Outlook 2007 あり あり
PowerPoint 2007 あり あり
Project 2007 あり なし
Publisher 2007 あり なし
SharePoint Designer 2007 なし** なし
Visio 2007 あり あり
Word 2007 あり あり

* VSTO 2005 SE を使用せずに、Visual Studio 2005 Tools for Office で Outlook 2003 アプリケーション アドインを作成することもできます。したがって、Outlook 2003 のアドインを作成するには、COM 相互運用機能を使用する共有アドイン、Visual Studio 2005 Tools for Office、および VSTO 2005 SE の 3 つの方法があります。

** Visual Studio 2005 共有アドイン テンプレートには、サポートされるホストとして InfoPath および SharePoint Designer は含まれません。ただし、レジストリ内で必要なキーを手動で作成すると、この 2 つのホストは、テンプレートから作成された共有アドインをロードします。

1990 年代の COM を使用する開発スタイルに問題がなく、アンマネージ コードが気に入っている (または、気に入っているわけではないが、使わざるを得ない) ユーザーは、2007 リリースの Microsoft Office に含まれるアプリケーションはこのようなユーザーおよびアドインにとって使いやすいと知ったらもっと喜ぶに違いありません。実際、C++ を開発言語として使用している場合は、COM を使用する開発スタイルが最適な選択肢です。しかし、新しい開発スタイルを導入し、Microsoft Visual Basic や Microsoft Visual C# を使用したマネージ開発環境の機能と生産性を活用しているのであれば、Visual Studio 2005 Tools for Office Second Edition が適しています。

**メモ:   **この記事で、"Visual Basic" と記述する場合は、マネージ バージョンの Visual Basic (具体的には、Visual Basic 2005) を指します。アンマネージ バージョンに言及する必要がある場合は、"VBA" や "Visual Basic 6.0" という個別の用語を使用します。

VSTO 2005 SE アドインの利点

共有アドイン モデルとの比較において、Visual Studio 2005 Tools for Office Second Edition を使用してマネージ アドインを作成することの利点を理解するには、簡単に作成できる共有アドインを使用する場合の基本的な短所について理解しておくことが重要です。

mscoree.dll: いつもは友人、ときどき敵

mscoree.dll は優れた共通言語ランタイム (CLR) へのメイン エントリ DLL です。CLR が共有アドインよりも前に正しくホスト アプリケーションにロードされるように、mscoree.dll は、マネージ アセンブリではなく、ロードするインプロセス サーバーとしてレジストリに登録されています。これはいくつかの問題の原因となります。

最初の問題は、共有アドイン (またはその他のアドイン) が原因で未処理の例外が発生し、ホストがクラッシュした場合に、ホストは次回のアドインのロードを中止するオプションをユーザーに与えるという点です。ユーザーがこのオプションを選択すると、ホストはそのアドインを無効になっているアドインとして表示します。問題は、ホスト アプリケーションが共有アドインとその他のアドインを区別できないことです。mscoree.dll が無効になるため、ホストのすべての共有マネージ アドインが無効になります。

2 番目の問題は、CLR が初期化されたときに、既定のアプリケーション ドメインが作成され、ホストによってロードされた共有アドインがすべて同じアプリケーション ドメインに配置される点です。これによって、あるアドインが別のアドインのエラーの原因になる可能性があります。たとえば、2 つのアドインが使用しているオブジェクトについて、一方のアドインが ReleaseComObject を呼び出したとします。これは、Excel に ExcelAddinOne と ExcelAddinTwo の 2 つのアドインがロードされているような場合に発生します。既定では、この 2 つのアドインは同じ既定のアプリケーション ドメインに配置されます。一方のアドイン、たとえば ExcelAddinTwo がプロアクティブにメモリ管理を行い、両方のアドインが共有ランタイム呼び出し可能ラッパー (RCW) を介して参照を保持している Excel.Application 参照について、FinalReleaseComObject を呼び出したとします。ExcelAddinOne が Excel への参照にアクセスしようとすると、System.AccessViolationException (保護されているメモリへの読み取りまたは書き込みの試行) のエラーが返されます。

3 番目の問題は信頼の問題です。多くの Office アプリケーション (Office 2003 など) はアドインをそのまま信頼するので (Publisher 2003 は除く)、セキュリティ意識の高いユーザーや管理者は署名されていないアドイン (有効な X.509 署名を持たないアドイン) を許可していない可能性があります。この場合、署名をしていても、共有アドインは動作しません。この原因も mscoree.dll です。Office アプリケーションは、マネージ アセンブリではなく、mscoree.dll が署名されているかどうかを調べるからです。

共有アドインを正しく動作させる

共有アドインの問題を回避するには、2 つの方法があります。可能であれば、Visual Studio Tools for Office を使用してください。前述の問題はすべて回避されます。ただし、1 つのバージョンの Visual Studio Tools for Office がすべての Office ホストで動作するわけではないので (表 1 を参照)、ホストがサポートされていない状況でアプリケーション アドインのサポートが必要な場合は、共有アドインを使用する必要があります。共有アドインを作成する場合は、「COM シム ウィザード Version 2.0 を使用した Microsoft Office 拡張機能の分離」(英語) を参照してください。COM シムを使用することによって、前述の共有アドインに関連する主な問題を回避できます。

Visual Studio 2005 Tools for Office Second Edition の場合

Visual Studio 2005 Tools for Office Second Edition を使用して、Excel などのサポート対象のホストのアドインを作成した場合、どのような利点があるのでしょうか。既に説明したように、共有アドインに関連する問題が回避され、COM シムを使用するための余分な作業をする必要がなくなります。さらに、ネットワーク共有や HTTP エンドポイントからのリモート配置、2007 Microsoft Office system の新しいリボンのサポート、Visual Studio Tools for Office の次期リリースへのアップグレード パス、およびマイクロソフトからのサポートなどの利点もあります。

新しいアドインを最初から作成する場合、特に 2007 リリースの Microsoft Office 用のアドインを作成する場合は、Visual Studio 2005 Tools for Office Second Edition を使用することをお勧めします。既に Office ホストで動作する共有アドインがあり、Visual Studio 2005 Tools for Office Second Edition がそのホストをサポートしている場合に、リボンと統合したり、前述の利点を活用したり、新しいマネージ アプリケーション アドイン モデルを使用したりするには、共有アドインを移行することをお勧めします。

共有アドインの作成

共有アドインを Visual Studio 2005 Tools for Office Second Edition に移行させる方法を確認するために、実際に Visual Studio 2005 を使用して、Microsoft Office Excel 2003 で実行される共有アドインを作成します。この作業が終了した後、作成したアドインを Microsoft Office Excel 2007 で実行して、動作が変更されないことを確認します。次に、このアドインを Excel 2007 に移行します。作成するアドインは特別なものではありません。このアドインの目的は、処理が必要になる主な移行の領域、特にカスタム コマンド バーのコードを新しいリボンに移行する方法を示すことにあります。

共有アドインを作成する

  1. Visual Studio 2005 を起動します。

  2. [ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。

    **メモ:   **この記事では、既定の標準的な開発設定を使用して、Visual Studio をインストールしていることを前提としています。Visual Basic の開発設定を選択した場合は、メニュー項目のレイアウトが若干異なります。自分の環境に合わせて、操作手順を読み替えてください。

  3. [新しいプロジェクト] ダイアログ ボックスで、プロジェクトの種類の一覧の [その他のプロジェクトの種類] ノードを探して展開します。プロジェクトの種類の一覧の [機能拡張] をクリックします。

  4. [テンプレート] ペインで、[共有アドイン] をクリックします。アドインの名前 (「SharedAddInDemo」など) と保存場所を入力し、[OK] をクリックしてアドイン ウィザードを開始します。

  5. [アドイン ウィザードへようこそ] ページで [次へ] をクリックします。

  6. [プログラミング言語の選択] ページで、Visual C# または Visual Basic を選択します。[次へ] をクリックします。

  7. [アプリケーション ホストの選択] ページで、[Microsoft Excel] 以外のすべてのチェック ボックスをオフにします。[次へ] をクリックします。

  8. [名前および説明の入力] ページで、それぞれのフィールドに「SharedAddInDemo」および「Shared Add-in Demo」と入力します。これらの値は省略できますが、指定しておくとホスト アプリケーションでのアドインの操作が容易になります。[次へ] をクリックします。

  9. [アドイン オプションを選択します。] ページで、最初のオプションだけを選択します。

    最初のオプションを選択すると、ホスト アプリケーションがロードされるときに、自動的にアドインがロードされます。これによって、デバッグが容易になります。ここでは、デモンストレーションの目的に基づき選択を行いますが、他のアドインでは、このオプションは慎重に検討する必要があります。手動でアドインをロードする方法については、後で説明します。2 番目のオプションは、アドインを操作できるユーザーを指定します。アドインをインストールしたユーザーのみ、またはコンピュータ上のすべてのユーザーを選択します。開発では、作業は現在のユーザーのみに限定することをお勧めします。[次へ] をクリックします。

  10. [概要] ページで選択した内容を確認し、[完了] をクリックしてアドイン プロジェクトを作成します。

    **メモ:   **アドイン プロジェクトを作成すると、Visual Studio によって、実際にはアドインと同じ名前のソリューション内に、2 つのプロジェクトが作成されます。最初のプロジェクトは作成したアドインです。もう 1 つのプロジェクトは、アドインを他のユーザー向けに配置したり、開発用ではないクリーンなコンピュータでアドインをテストしたりするために使用できるセットアップ プロジェクトです。

共有アドイン テンプレートでは、Connect と呼ばれるクラスが作成されます。コードの内容は以下のようになります。

Imports Extensibility
Imports System.Runtime.InteropServices

' Region "Read me for add-in installation and setup information."
' Removed

<GuidAttribute("C6A96E1D-DA75-45BC-B504-983A8096733B"), _ 
  ProgIdAttribute("SharedAddInDemoVB.Connect")> _
Public Class Connect
  Implements Extensibility.IDTExtensibility2

  Dim applicationObject As Object
  Dim addInInstance As Object

  Public Sub OnBeginShutdown(ByRef custom As System.Array) _
    Implements Extensibility.IDTExtensibility2.OnBeginShutdown
  End Sub

  Public Sub OnAddInsUpdate(ByRef custom As System.Array) _
    Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
  End Sub

  Public Sub OnStartupComplete(ByRef custom As System.Array) _
    Implements Extensibility.IDTExtensibility2.OnStartupComplete
  End Sub

  Public Sub OnDisconnection(ByVal RemoveMode As _
    Extensibility.ext_DisconnectMode, ByRef custom As System.Array) _
    Implements Extensibility.IDTExtensibility2.OnDisconnection
  End Sub

  Public Sub OnConnection(ByVal application As Object, _
    ByVal connectMode As Extensibility.ext_ConnectMode, _
    ByVal addInInst As Object, ByRef custom As System.Array) _
    Implements Extensibility.IDTExtensibility2.OnConnection

    applicationObject = application
    addInInstance = addInInst
  End Sub
End Class

namespace SharedAddInDemoCS
{
  using System;
  using Extensibility;
  using System.Runtime.InteropServices;

  // Region "Read me for add-in installation and setup information."
  // Removed

  // All XML comments removed.
  [GuidAttribute("F7698139-E63C-4F10-8A9B-47B1BD042C3D"), 
   ProgId("SharedAddInDemoCS.Connect")]
  public class Connect : Object, Extensibility.IDTExtensibility2
  {
    public Connect()
    {
    }

    public void OnConnection(object application, 
      Extensibility.ext_ConnectMode connectMode, 
      object addInInst, ref System.Array custom)
    {
      applicationObject = application;
      addInInstance = addInInst;
    }

    public void OnDisconnection(Extensibility.ext_DisconnectMode 
      disconnectMode, ref System.Array custom)
    {
    }

    public void OnAddInsUpdate(ref System.Array custom)
    {
    }

    public void OnStartupComplete(ref System.Array custom)
    {
    }

    public void OnBeginShutdown(ref System.Array custom)
    {
    }
    
    private object applicationObject;
    private object addInInstance;
  }
}

アドイン プロジェクトを作成したら、ホストの適切なプライマリ相互運用機能アセンブリへの参照を追加する必要があります。このサンプル アドインでは、Microsoft Excel 11.0 Object Library への参照を追加する必要があります。作成するサンプルは、Visual C# の MessageBox クラスを使用します。したがって、Visual C# を使用している場合は、System.WindowsForms アセンブリへの参照が必要です。

**メモ:   **Visual Basic と Visual C# ではよく似た方法でコードを記述できますが、作成するコードでは通常、.NET Framework の言語コンストラクトではなく、組み込みの言語コンストラクト (Visual Basic MsgBox や WithEvents 機能など) を使用します。

参照を使用することによって、必要なコードの変更を行うことができます。これには、適切な Imports (Visual Basic) ステートメントや using (Visual C#) ステートメントを追加して、入力作業を減らすことなどがあります。

Imports Microsoft.Office
Imports Microsoft.Office.Interop

using Core = Microsoft.Office.Core;
using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Forms;

テンプレートによって定義された既定のクラス レベルの変数 (applicationObject および addInInstance) を、厳密に型指定された参照 (それぞれ Excel.Application および Core.COMAddin) に変更する必要があります。Visual Basic を使用している場合は、Dim キーワードを Private に変更します。

**メモ:   **C# のサンプルでは、System.Object 型の missing と呼ばれる新しいクラス レベルの変数を追加します。Microsoft Office の COM および VBA の資産を活用するために、Office のほとんどのホストの API では、オプションのパラメータを受け付けるメソッドをサポートしていますが、C# ではこれをサポートしていません。したがって、コード例で、パラメータをスキップする場合は、変数 missing を渡します。

Private applicationObject As Excel.Application
Private addInInstance As Core.COMAddIn

private Excel.Application applicationObject;
private Core.COMAddIn addInInstance;
private Object missing = Type.Missing;

最後に、OnConnection および OnDisconnection メソッドにコードを追加します。この 2 つのメソッドは、アドインをリンクおよびリンク解除するために使用されます。OnConnection では、ホストへの参照を取得することができます。OnDisconnection では、クリーンアップ (追加した UI 要素と解放した変数の削除) が実行されます。

OnConnection メソッドでは、渡されたアプリケーション オブジェクトの参照を調べて、Excel への参照か、他のホストへの参照かを確認する必要があります。Excel への参照である場合は、その参照への参照を格納します。次に、メッセージ ボックスを使用して、ホスト名とバージョン情報を表示します。OnDisconnection メソッドでは、OnConnection メソッドでフックされた 2 つのクラス レベルの変数を解放します。コードが既定のアプリケーション ドメインにロードされており、ユーザーがホスト アプリケーションを終了せずにアドインをアンロードすることを選択した場合、このステップは重要です。COM シムを使用している場合は、アドインは独自のアプリケーション ドメインにロードされ、ホストがメソッドを呼び出してアドインが解放されるとアンロードされるため、このステップは不要です。

次のコード ブロックは、必要な変更をすべて示しています。追加または変更された部分だけが含まれています。変更は太字のコード書式で表示されています。

**ヒント:   **このデモンストレーションでは、Visual Basic プログラマがプロジェクトの Option Strict の設定をオンにしている (またはプロジェクトの各モジュールに Option Strict ステートメントを追加している) ことを前提としています。これは必須ではなく、Option Strict 設定をオンに設定することによってコードは増えますが、安全ではない型変換を行う必要がなくなります。このオプションを使用せずに進めることもできますが、最終的には、このオプションを利用するために必要な作業は、コード記述の難しさに十分に見合う価値があります。

Public Sub OnDisconnection(ByVal RemoveMode As _
  Extensibility.ext_DisconnectMode, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnDisconnection

addInInstance = Nothing
applicationObject = Nothing
End Sub

Public Sub OnConnection(ByVal application As Object, _
  ByVal connectMode As Extensibility.ext_ConnectMode, _
  ByVal addInInst As Object, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnConnection

If TypeOf application Is Excel.Application Then
applicationObject = DirectCast(application, Excel.Application)
addInInstance = DirectCast(addInInst, Core.COMAddIn)

MsgBox(addInInstance.Description & " is connected to " & _
applicationObject.Name & " v." & applicationObject.Version, _
MsgBoxStyle.Information, "Shared Add-in") End If
End Sub

// All XML comments removed.
public void OnConnection(object application,
  Extensibility.ext_ConnectMode connectMode,
  object addInInst, ref System.Array custom)
{
if (application is Excel.Application)
{
applicationObject = ((Excel.Application)(application));
addInInstance = ((Core.COMAddIn)(addInInst));

MessageBox.Show(addInInstance.Description + " is connected to "
+ applicationObject.Name + " v." + applicationObject.Version,
"Shared Add-in",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}

public void OnDisconnection(Extensibility.ext_DisconnectMode
  disconnectMode, ref System.Array custom)
{
addInInstance = null;
applicationObject = null;
}

これらの変更によって、アドインをテストする準備ができました。このアドインをデバッグするには、アドインのプロジェクト プロパティの [デバッグ] タブで設定を変更し、ロードするホスト アプリケーションを Visual Studio 2005 に指示する必要があります。

Excel 用のデバッグを設定する

  1. ソリューション エクスプローラで、アドイン プロジェクトを選択します。
  2. [プロジェクト] メニューの [SharedAddInDemo のプロパティ] をクリックします。
  3. [デバッグ] タブをクリックします。
  4. [開始動作] を [外部プログラムの開始] に変更します。
  5. パスをコンピュータ上の Excel 2003 のインストール先 (通常、C:\Program Files\Microsoft Office\OFFICE11\EXCEL.EXE) に変更します。
  6. [ファイル] メニューの [選択されたファイルを上書き保存] をクリックします。
  7. [ファイル] メニューの [閉じる] をクリックし、プロジェクト デザイナを閉じます。
  8. [デバッグ] メニューの [デバッグ開始] をクリックして、Excel を起動し、アドインをロードします。

Excel が起動した後、OnConnection メソッドにメッセージ ボックスが追加されます。Excel を終了すると、Visual Studio 2005 に戻ります。バックグラウンドで動作し、ユーザーに直接操作する手段を提供しないアドインを作成することもできますが、通常、アドインはすべての Office ホスト アプリケーションによって公開されるコマンド バー インフラストラクチャにフックし、メニュー コマンド、ボタン、またはコマンド バー全体を追加します。アドインは、ホスト アプリケーションのイベントにのみ応答することによって処理を実行することもできますが、その場合イベント コードは通常同じように動作するので、それほど説明することはありません。

次に作成するコードは、アドインを更新して、カスタム メニュー項目とメニュー項目のコントロールを Excel の組み込みメニュー バーに追加します。この処理を行うために、3 つの新しいクラス レベルの変数を定義します。MainMenuBar は Excel ワークシートのメニュー バーを表します。MenuBarItem は、ワークシートのメニューおよび MenuItem に (Visual Basic の WithEvents 機能を使用して) 追加される新しいメニュー項目を表します。

Private MainMenuBar As Core.CommandBar
Private MenuBarItem As Core.CommandBarControl
Private WithEvents MenuItem As Core.CommandBarButton

private Core.CommandBar MainMenuBar;
private Core.CommandBarControl MenuBarItem;
private Core.CommandBarButton MenuItem;

メニュー バー項目およびそのメニュー項目を追加するために必要なコードと、ユーザーが Excel を終了せずにアドインをアンロードすることを選択した場合に追加した項目をクリーンアップして消去するためのコードで形成される複数のヘルパ メソッドを定義します。

Private Function CreateMenuButton( _
  ByVal Parent As Core.CommandBarPopup, _
  ByVal Caption As String) As Core.CommandBarButton

  Try
    Dim cbc As Core.CommandBarControl
    cbc = Parent.Controls.Add( _
        Core.MsoControlType.msoControlButton, Temporary:=True)
    cbc.Caption = Caption
    cbc.Visible = True

    Return DirectCast(cbc, Core.CommandBarButton)
  Catch ex As Exception
    MsgBox(ex.Message, MsgBoxStyle.Critical, ex.Source)
    Return Nothing
  End Try
End Function

Private Sub InitMenuBarItems(ByVal Caption As String)
  Try
    MainMenuBar = applicationObject.CommandBars( _
        "Worksheet Menu Bar")
    MenuBarItem = DirectCast(MainMenuBar.Controls.Add( _
        Core.MsoControlType.msoControlPopup, Temporary:=True), _
        Core.CommandBarControl)
    MenuBarItem.Caption = Caption

  Catch ex As Exception
    MsgBox(ex.Message, MsgBoxStyle.Critical, ex.Source)
  End Try
End Sub

Private Sub CleanUpMenuItems()
  MenuItem.Delete(False)
  MenuBarItem.Delete(False)

  MenuItem = Nothing
  MenuBarItem = Nothing
  MainMenuBar = Nothing
End Sub

private Core.CommandBarButton CreateMenuButton(
  Core.CommandBarPopup Parent, string Caption)
{
  try
  {
    Core.CommandBarControl cbc = null;
    cbc = Parent.Controls.Add(Core.MsoControlType.msoControlButton,
      missing, missing, missing, true);
    cbc.Caption = Caption;
    cbc.Visible = true;

    return (Core.CommandBarButton)(cbc);
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message, ex.Source,
      MessageBoxButtons.OK, MessageBoxIcon.Error);
    return null;
  }
}
private void InitMenuBarItems(string Caption)
{
  try
  {
    MainMenuBar = applicationObject.CommandBars["Worksheet Menu Bar"];
    MenuBarItem = (Core.CommandBarControl)(
      MainMenuBar.Controls.Add(Core.MsoControlType.msoControlPopup,
      missing, missing, missing, true));
    MenuBarItem.Caption = Caption;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message, ex.Source,
      MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}
private void CleanUpMenuItems()
{
  MenuItem.Delete(false);
      MenuBarItem.Delete(false);

      MenuItem = null;
      MenuBarItem = null;
      MainMenuBar = null;
    }

次に、OnConnection メソッドと OnDisconnection メソッドを編集します。それぞれロード時にメニュー バー項目を作成し、終了時に項目をクリーンアップするようにします。Visual C# のコードを作成している場合は、メニュー項目の Click イベント ハンドラをフックするコードを追加する必要があります。最後に、メッセージ ボックスのコードを OnConnection メソッドから MenuItem の Click イベントハンドラに移動します。

メモ:   次のコード ブロックは、変更箇所を含むコード ブロックのみを示しています。変更は太字のコード書式で表示されています。

Public Sub OnDisconnection(ByVal RemoveMode As _
  Extensibility.ext_DisconnectMode, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnDisconnection

If TypeOf applicationObject Is Excel.Application Then
CleanUpMenuItems()
End If
  addInInstance = Nothing
  applicationObject = Nothing
End Sub

Public Sub OnConnection(ByVal application As Object, _
  ByVal connectMode As Extensibility.ext_ConnectMode, _
  ByVal addInInst As Object, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnConnection

Try
    If TypeOf application Is Excel.Application Then
      applicationObject = DirectCast(application, Excel.Application)
      addInInstance = DirectCast(addInInst, Core.COMAddIn)

InitMenuBarItems("Shared")
MenuItem = CreateMenuButton( _
DirectCast(MenuBarItem, Core.CommandBarPopup), _
"&Add-in Information")
    End If
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, ex.Source)
End Try
End Sub

Private Sub MenuItem_Click(ByVal Ctrl As Core.CommandBarButton, _
ByRef CancelDefault As Boolean) Handles MenuItem.Click

MsgBox(addInInstance.Description & " is connected to " & _
applicationObject.Name & " v." & applicationObject.Version, _
MsgBoxStyle.Information, "Shared Add-in")
End Sub

public void OnConnection(object application,
  Extensibility.ext_ConnectMode connectMode,
  object addInInst, ref System.Array custom)
{
try
{
    if (application is Excel.Application)
    {
      applicationObject = ((Excel.Application)(application));
      addInInstance = ((Core.COMAddIn)(addInInst));

InitMenuBarItems("Shared");

MenuItem = CreateMenuButton(
((Core.CommandBarPopup)(MenuBarItem)),"&Add-in Information");
MenuItem.Click +=
new Core._CommandBarButtonEvents_ClickEventHandler(
MenuItem_Click);
    }
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ex.Source,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

public void OnDisconnection(Extensibility.ext_DisconnectMode
  disconnectMode, ref System.Array custom)
{
if (applicationObject is Excel.Application)
{
CleanUpMenuItems();
}
  addInInstance = null;
  applicationObject = null;
}

private void MenuItem_Click(
  Core.CommandBarButton Ctrl, ref bool CancelDefault)
{
  MessageBox.Show(addInInstance.Description + " is connected to "
    + applicationObject.Name + " v." + applicationObject.Version,
    "Shared Add-in",
    MessageBoxButtons.OK, MessageBoxIcon.Information);
}

前述のように、アドインで、ボタンやその他のサポートされるコントロールを含むコマンド バー全体を定義することは特別なことではありません。次に行う変更では、新しいコマンド バー AppCommandBar を作成し、コマンド バーにボタン AppButton を追加するコードを追加します。この 2 つのオブジェクトを、クラス レベルの変数として定義する必要があります。

Private AppCommandBar As Core.CommandBar
Private WithEvents AppButton As Core.CommandBarButton

private Core.CommandBar AppCommandBar;
private Core.CommandBarButton AppButton;

さらに、(新しいヘルパ メソッド ShowVersionInfo を介して) 前に使用したものと同じメッセージ ボックスを表示する AppButton の Click イベント ハンドラを追加します。コマンド バーを作成するコードは、CreateCommandBar および CreateCreateCommandBarButton で定義される追加のヘルパ コードと共に、OnConnection で定義されます。OnDisconnection は、新しい CleanUpCommandBars メソッドを呼び出すように変更されています。このメソッドは、新しいコマンド バー オブジェクトおよびサポートのコントロールをクリーンアップします。

Public Sub OnDisconnection(ByVal RemoveMode As _
  Extensibility.ext_DisconnectMode, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnDisconnection

  If TypeOf applicationObject Is Excel.Application Then
CleanUpCommandBars()
    CleanUpMenuItems()
  End If

  addInInstance = Nothing
  applicationObject = Nothing
End Sub

Public Sub OnConnection(ByVal application As Object, _
  ByVal connectMode As Extensibility.ext_ConnectMode, _
  ByVal addInInst As Object, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnConnection

  Try
    If TypeOf application Is Excel.Application Then
      applicationObject = DirectCast(application, Excel.Application)
      addInInstance = DirectCast(addInInst, Core.COMAddIn)

      InitMenuBarItems("Shared")

      MenuItem = CreateMenuButton( _
        DirectCast(MenuBarItem, Core.CommandBarPopup), _
        "&Add-in Information")

      AppCommandBar = CreateCommandBar("Shared CommandBar")
      AppButton = CreateCommandBarButton("Add-In Information", _
        59, Core.MsoButtonStyle.msoButtonIconAndCaption, _
        "AddInInfo", "Get Add-in Information")

      AppCommandBar.Visible = True
    End If
  Catch ex As Exception
    MsgBox(ex.Message, MsgBoxStyle.Critical, ex.Source)
  End Try
End Sub

Private Sub MenuItem_Click(ByVal Ctrl As Core.CommandBarButton, _
  ByRef CancelDefault As Boolean) Handles MenuItem.Click

  ShowVersionInfo()
End Sub

Private Function CreateCommandBar( _ 
  ByVal Name As String) As Core.CommandBar

  Return applicationObject.CommandBars.Add(Name, _
    Core.MsoBarPosition.msoBarFloating, False, True)
End Function
Private Function CreateCommandBarButton(ByVal Caption As String, _
  ByVal FaceId As Integer, _
  ByVal Style As Core.MsoButtonStyle, _
  ByVal Tag As String, _
  ByVal ToolTipText As String _
  ) As Core.CommandBarButton

  Dim btn As Core.CommandBarButton = _
    DirectCast(AppCommandBar.Controls.Add( _
    Core.MsoControlType.msoControlButton, Temporary:=True), _
    Core.CommandBarButton)

  With btn
    .Caption = Caption
    .FaceId = FaceId
    .Style = Core.MsoButtonStyle.msoButtonIconAndCaption
    .Tag = Tag
    .TooltipText = ToolTipText
  End With

  Return btn
End Function

Private Sub CleanUpCommandBars()
  AppCommandBar.Delete()
End Sub

Private Sub ShowVersionInfo()
  MsgBox(addInInstance.Description & " is connected to " & _
    applicationObject.Name & " v." & applicationObject.Version, _
    MsgBoxStyle.Information, "Shared Add-in")
End Sub

Private Sub AppButton_Click(ByVal Ctrl As Core.CommandBarButton, _
  ByRef CancelDefault As Boolean) Handles AppButton.Click

  ShowVersionInfo()
End Sub

public void OnConnection(object application,
  Extensibility.ext_ConnectMode connectMode,
  object addInInst, ref System.Array custom)
{
  try
  {
    if (application is Excel.Application)
    {
      applicationObject = ((Excel.Application)(application));
      addInInstance = ((Core.COMAddIn)(addInInst));

      InitMenuBarItems("Shared");

      MenuItem = CreateMenuButton(
        ((Core.CommandBarPopup)(MenuBarItem)),"&Add-in Information");
      MenuItem.Click +=
        new Core._CommandBarButtonEvents_ClickEventHandler(
          MenuItem_Click);

      AppCommandBar = CreateCommandBar("Shared CommandBar");
      AppButton = CreateCommandBarButton("Add-In Information", 59,
        Core.MsoButtonStyle.msoButtonIconAndCaption, "AddInInfo",
        "Get Add-in Information");
      AppButton.Click +=
        new Core._CommandBarButtonEvents_ClickEventHandler(
          AppButton_Click);

      AppCommandBar.Visible = true;
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message, ex.Source,
      MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

public void OnDisconnection(Extensibility.ext_DisconnectMode
  disconnectMode, ref System.Array custom)
{
  if (applicationObject is Excel.Application)
  {
    CleanUpCommandBars();
    CleanUpMenuItems();
  }
  addInInstance = null;
  applicationObject = null;
}

private void MenuItem_Click(
  Core.CommandBarButton Ctrl, ref bool CancelDefault)
{
  ShowVersionInfo();
}

private Core.CommandBar CreateCommandBar(string Name)
{
  return applicationObject.CommandBars.Add(Name,
    Core.MsoBarPosition.msoBarFloating, false, true);
}

private Core.CommandBarButton CreateCommandBarButton(
  string Caption, int FaceId, Core.MsoButtonStyle Style,
  string Tag, string ToolTipText)
{
  Core.CommandBarButton btn = (Core.CommandBarButton)
    AppCommandBar.Controls.Add(Core.MsoControlType.msoControlButton,
    missing, missing, missing, true);

  btn.Caption = Caption;
  btn.FaceId = FaceId;
  btn.Style = Core.MsoButtonStyle.msoButtonIconAndCaption;
  btn.Tag = Tag;
  btn.TooltipText = ToolTipText;

  return btn;
}

private void CleanUpCommandBars()
{
  AppCommandBar.Delete();
}

private void ShowVersionInfo()
{
  MessageBox.Show(addInInstance.Description + " is connected to "
    + applicationObject.Name + " v." + applicationObject.Version,
    "Shared Add-in",
    MessageBoxButtons.OK, MessageBoxIcon.Information);
}

private void AppButton_Click(
  Core.CommandBarButton Ctrl, ref bool CancelDefault)
{
  ShowVersionInfo();
}

この時点で、このアドインはコマンド バーのインフラストラクチャに対する標準の追加機能をサポートしています。ただし、状況によっては、アドインによって既存のメニューまたはコマンド バーにコマンドを配置するだけでよい場合もあります。作成しているコードの次のセクションでは、この処理を行います。[ファイル] メニューに "Extra Extra!" というキャプションのメニュー項目を追加します。また、数字の 8 が描かれたボール型のアイコンを使用して、[標準] コマンド バーにコマンド バー ボタンを追加します。

' Add as class-level variables.
Private extraMenuItem As Core.CommandBarButton
Private extraStdButton As Core.CommandBarButton

Public Sub OnDisconnection(ByVal RemoveMode As _
  Extensibility.ext_DisconnectMode, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnDisconnection

  If TypeOf applicationObject Is Excel.Application Then
CleanupExtraAdditions()
    CleanUpCommandBars()
    CleanUpMenuItems()
  End If

  addInInstance = Nothing
  applicationObject = Nothing
End Sub

Public Sub OnConnection(ByVal application As Object, _
  ByVal connectMode As Extensibility.ext_ConnectMode, _
  ByVal addInInst As Object, ByRef custom As System.Array) _
  Implements Extensibility.IDTExtensibility2.OnConnection

  Try
    If TypeOf application Is Excel.Application Then
      applicationObject = DirectCast(application, Excel.Application)
      addInInstance = DirectCast(addInInst, Core.COMAddIn)

      InitMenuBarItems("Shared")

      MenuItem = CreateMenuButton( _
        DirectCast(MenuBarItem, Core.CommandBarPopup), _
        "&Add-in Information")

      AppCommandBar = CreateCommandBar("Shared CommandBar")
      AppButton = CreateCommandBarButton("Add-In Information", _
        59, Core.MsoButtonStyle.msoButtonIconAndCaption, _
        "AddInInfo", "Get Add-in Information")

      AppCommandBar.Visible = True

AddExtraUIAdditions()
    End If
  Catch ex As Exception
    MsgBox(ex.Message, MsgBoxStyle.Critical, ex.Source)
  End Try
End Sub

Private Sub AddExtraUIAdditions()
Try
' Add a menu item to the File menu.
Dim fileMenu As Core.CommandBarControl = _
MainMenuBar.Controls("File")
extraMenuItem = CreateMenuButton( _
DirectCast(fileMenu, Core.CommandBarPopup), "Extra Extra!")

With extraMenuItem
.BeginGroup = True
.FaceId = 279
.Tag = "PushPin"
.TooltipText = "Get Extra Information"
End With

' Add a CommandBarButton to the Standard CommandBar.
Dim stdToolbar As Core.CommandBar = _
applicationObject.CommandBars("Standard")
extraStdButton = DirectCast(stdToolbar.Controls.Add( _
Core.MsoControlType.msoControlButton, Temporary:=True), _
Core.CommandBarButton)

With extraStdButton
.FaceId = 1845
.Style = Core.MsoButtonStyle.msoButtonIcon
.TooltipText = "CommandBarButton Added to Standard CommandBar"
.Tag = "EightBall"
End With
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, ex.Source)
End Try
End Sub

Private Sub CleanupExtraAdditions()
extraStdButton.Delete(True)
extraStdButton = Nothing

extraMenuItem.Delete(True)
extraMenuItem = Nothing
End Sub

// Add as class-level variables.
private Core.CommandBarButton extraMenuItem;
private Core.CommandBarButton extraStdButton;

public void OnConnection(object application,
   Extensibility.ext_ConnectMode connectMode,
   object addInInst, ref System.Array custom)
{
   try
   {
     if (application is Excel.Application)
     {
       applicationObject = ((Excel.Application)(application));
       addInInstance = ((Core.COMAddIn)(addInInst));

       InitMenuBarItems("Shared");

       MenuItem = CreateMenuButton(
         ((Core.CommandBarPopup)(MenuBarItem)),"&Add-in Information");
       MenuItem.Click +=
         new Core._CommandBarButtonEvents_ClickEventHandler(
           MenuItem_Click);

       AppCommandBar = CreateCommandBar("Shared CommandBar");
       AppButton = CreateCommandBarButton("Add-In Information", 59,
         Core.MsoButtonStyle.msoButtonIconAndCaption, "AddInInfo",
         "Get Add-in Information");
       AppButton.Click +=
         new Core._CommandBarButtonEvents_ClickEventHandler(
           AppButton_Click);

       AppCommandBar.Visible = true;

AddExtraUIAdditions();
     }
   }
   catch (Exception ex)
   {
     MessageBox.Show(ex.Message, ex.Source,
       MessageBoxButtons.OK, MessageBoxIcon.Error);
   }
}

public void OnDisconnection(Extensibility.ext_DisconnectMode
   disconnectMode, ref System.Array custom)
{
   if (applicationObject is Excel.Application)
   {
CleanupExtraAdditions();
     CleanUpCommandBars();
     CleanUpMenuItems();
   }
   addInInstance = null;
   applicationObject = null;
}

private void AddExtraUIAdditions()
{
try
{
// Add a menu item to the File menu.
Core.CommandBarControl fileMenu = MainMenuBar.Controls["File"];
extraMenuItem = CreateMenuButton(
(Core.CommandBarPopup)(fileMenu), "Extra Extra!");

extraMenuItem.BeginGroup = true;
extraMenuItem.FaceId = 279;
extraMenuItem.Tag = "PushPin";
extraMenuItem.TooltipText = "Get Extra Information";

// Add a CommandBarButton to the Standard CommandBar.
Core.CommandBar stdToolbar =
applicationObject.CommandBars["Standard"];

extraStdButton = (Core.CommandBarButton)(
stdToolbar.Controls.Add(Core.MsoControlType.msoControlButton,
missing, missing, missing, true));

extraStdButton.FaceId = 1845;
extraStdButton.Style = Core.MsoButtonStyle.msoButtonIcon;
extraStdButton.TooltipText =
"CommandBarButton Added to Standard CommandBar";
extraStdButton.Tag = "EightBall";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ex.Source,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

private void CleanupExtraAdditions()
{
extraStdButton.Delete(true);
extraStdButton = null;

extraMenuItem.Delete(true);
extraMenuItem = null;
}

これで、アドインを実行するのに十分なコードが作成されました。ただし、コマンド バーはその他のコントロールもサポートしています。ドメイン ロジックによっては、アドインで複数のコマンド バーを作成することもできます。最後に、この処理を行う共有アドインに固有のコードを追加します。サポート対象の追加のコントロールのうち使用していないすべてのコントロールを、以前に作成した既存のカスタム コマンド バーに追加します。さらに、3 つの追加のコマンド バーを作成するコードも記述します。なぜ 3 つなのか疑問に思うかも知れませんが、このアドインを Excel 2007 で実行すると、その意味がわかります。

' Add as class-level variables.
Private extraCtlComboBox As Core.CommandBarComboBox
Private extraCtlDropDown As Core.CommandBarComboBox
Private extraCtlEdit As Core.CommandBarComboBox
Private extraCtlPopUp As Core.CommandBarPopup
Private extraPopUpCtlButton1 As Core.CommandBarButton
Private extraPopUpCtlButton2 As Core.CommandBarButton
Private extraCommandBar As Core.CommandBar
Private extraCtlButton As Core.CommandBarButton
Private extraCommandBar2 As Core.CommandBar
Private extraCtlButton2 As Core.CommandBarButton
Private extraCommandBar3 As Core.CommandBar
Private extraCtlButton3 As Core.CommandBarButton

Private Sub AddExtraUIAdditions()
  Try
    ' Add a menu item to the File menu.
    Dim fileMenu As Core.CommandBarControl = _ 
      MainMenuBar.Controls("File")
    extraMenuItem = CreateMenuButton( _
      DirectCast(fileMenu, Core.CommandBarPopup), "Extra Extra!")

    With extraMenuItem
      .BeginGroup = True
      .FaceId = 279
      .Tag = "PushPin"
      .TooltipText = "Get Extra Information"
    End With

    ' Add a CommandBarButton to the Standard CommandBar
    Dim stdToolbar As Core.CommandBar = _
      applicationObject.CommandBars("Standard")
    extraStdButton = DirectCast(stdToolbar.Controls.Add( _
        Core.MsoControlType.msoControlButton, Temporary:=True), _
        Core.CommandBarButton)

    With extraStdButton
      .FaceId = 1845
      .Style = Core.MsoButtonStyle.msoButtonIcon
      .TooltipText = "CommandBarButton Added to Standard CommandBar"
      .Tag = "EightBall"
    End With

' Add all existing controls to the first custom CommandBar.
extraCtlComboBox = DirectCast(AppCommandBar.Controls.Add( _
Core.MsoControlType.msoControlComboBox, Temporary:=True), _
Core.CommandBarComboBox)
With extraCtlComboBox
.AddItem("Red")
.AddItem("Green")
.AddItem("Blue")
.Caption = "Color"
.Style = Core.MsoComboStyle.msoComboNormal
.Tag = "Colors"
.TooltipText = "Select or type a color"
.Text = "Color"
End With

extraCtlDropDown = DirectCast(AppCommandBar.Controls.Add( _
Core.MsoControlType.msoControlDropdown, Temporary:=True), _
Core.CommandBarComboBox)
With extraCtlDropDown
.AddItem("Earth")
.AddItem("Air")
.AddItem("Fire")
.AddItem("Water")
.Caption = "Elements"
.Style = Core.MsoComboStyle.msoComboLabel
.Tag = "FourElements"
.TooltipText = "Select an element"
End With

extraCtlEdit = DirectCast(AppCommandBar.Controls.Add( _
Core.MsoControlType.msoControlEdit, Temporary:=True), _
Core.CommandBarComboBox)
With extraCtlEdit
.Caption = "Ask a question"
.Tag = "AskQuestion"
.Text = "Text Box"
.TooltipText = "Ask a question"
End With

extraCtlPopUp = DirectCast(AppCommandBar.Controls.Add( _
Core.MsoControlType.msoControlPopup, Temporary:=True), _
Core.CommandBarPopup)
With extraCtlPopUp
.Caption = "Other Options"
.Tag = "OtherOptions"
.TooltipText = "Click for additional controls"

extraPopUpCtlButton1 = DirectCast(.Controls.Add( _
Core.MsoControlType.msoControlButton, Temporary:=True), _
Core.CommandBarButton)
extraPopUpCtlButton2 = DirectCast(.Controls.Add( _
Core.MsoControlType.msoControlButton, Temporary:=True), _
Core.CommandBarButton)
End With

With extraPopUpCtlButton1
.Caption = "Popup Button"
.FaceId = 59
.Style = Core.MsoButtonStyle.msoButtonIconAndCaption
End With
With extraPopUpCtlButton2
.Caption = "Another Popup Button"
.Style = Core.MsoButtonStyle.msoButtonCaption
End With

extraCommandBar = CreateCommandBar("Second Shared CommandBar")
extraCtlButton = DirectCast(extraCommandBar.Controls.Add( _
Core.MsoControlType.msoControlButton, Temporary:=True), _
Core.CommandBarButton)

With extraCtlButton
.Caption = "Heart"
.FaceId = 481
.Style = Core.MsoButtonStyle.msoButtonIconAndCaption
.TooltipText = "Button added to second custom CommandBar"
.Tag = "Heart"
End With
extraCommandBar.Visible = True

extraCommandBar2 = CreateCommandBar("Third Shared CommandBar")
extraCtlButton2 = DirectCast(extraCommandBar2.Controls.Add( _
Core.MsoControlType.msoControlButton, Temporary:=True), _
Core.CommandBarButton)

With extraCtlButton2
.Caption = "Diamond"
.FaceId = 482
.Style = Core.MsoButtonStyle.msoButtonIconAndCaption
.TooltipText = "Button added to third custom CommandBar"
.Tag = "Diamond"
End With
extraCommandBar2.Visible = True

extraCommandBar3 = CreateCommandBar("Fourth Shared CommandBar")
extraCtlButton3 = DirectCast(extraCommandBar3.Controls.Add( _
Core.MsoControlType.msoControlButton, Temporary:=True), _
Core.CommandBarButton)

With extraCtlButton3
.Caption = "Spade"
.FaceId = 483
.Style = Core.MsoButtonStyle.msoButtonIconAndCaption
.TooltipText = "Button added to fourth custom CommandBar"
.Tag = "Spade"
End With

extraCommandBar3.Visible = True
  Catch ex As Exception
    MsgBox(ex.Message, MsgBoxStyle.Critical, ex.Source)
  End Try
End Sub

Private Sub CleanupExtraAdditions()
extraCtlButton3.Delete(True)
extraCtlButton3 = Nothing

extraCommandBar3.Delete()
extraCommandBar3 = Nothing

extraCtlButton2.Delete(True)
extraCtlButton2 = Nothing

extraCommandBar2.Delete()
extraCommandBar2 = Nothing

extraCtlButton.Delete(True)
extraCtlButton = Nothing

extraCommandBar.Delete()
extraCommandBar = Nothing

extraPopUpCtlButton2.Delete(True)
extraPopUpCtlButton2 = Nothing

extraPopUpCtlButton1.Delete(True)
extraPopUpCtlButton1 = Nothing

extraCtlPopUp.Delete(True)
extraCtlPopUp = Nothing

extraCtlEdit.Delete(True)
extraCtlEdit = Nothing

extraCtlDropDown.Delete(True)
extraCtlDropDown = Nothing

extraCtlComboBox.Delete(True)
extraCtlComboBox = Nothing

  extraStdButton.Delete(True)
  extraStdButton = Nothing

  extraMenuItem.Delete(True)
  extraMenuItem = Nothing
End Sub

// Add as class-level variables.
private Core.CommandBarComboBox extraCtlComboBox;
private Core.CommandBarComboBox extraCtlDropDown;
private Core.CommandBarComboBox extraCtlEdit;
private Core.CommandBarPopup extraCtlPopUp;
private Core.CommandBarButton extraPopUpCtlButton1;
private Core.CommandBarButton extraPopUpCtlButton2;
private Core.CommandBar extraCommandBar;
private Core.CommandBarButton extraCtlButton;
private Core.CommandBar extraCommandBar2;
private Core.CommandBarButton extraCtlButton2;
private Core.CommandBar extraCommandBar3;
private Core.CommandBarButton extraCtlButton3;

private void AddExtraUIAdditions()
{
  try
  {
    //  Add a menu item to the File menu.
    Core.CommandBarControl fileMenu = MainMenuBar.Controls["File"];
    extraMenuItem = CreateMenuButton(
      (Core.CommandBarPopup)(fileMenu), "Extra Extra!");

    extraMenuItem.BeginGroup = true;
    extraMenuItem.FaceId = 279;
    extraMenuItem.Tag = "PushPin";
    extraMenuItem.TooltipText = "Get Extra Information";

    //  Add a CommandBarButton to the Standard CommandBar.
    Core.CommandBar stdToolbar =
      applicationObject.CommandBars["Standard"];

    extraStdButton = (Core.CommandBarButton)(
      stdToolbar.Controls.Add(Core.MsoControlType.msoControlButton,
      missing, missing, missing, true));

    extraStdButton.FaceId = 1845;
    extraStdButton.Style = Core.MsoButtonStyle.msoButtonIcon;
    extraStdButton.TooltipText =
      "CommandBarButton Added to Standard CommandBar";
    extraStdButton.Tag = "EightBall";

// Add all existing controls to the first custom CommandBar.
extraCtlComboBox = (Core.CommandBarComboBox)(
AppCommandBar.Controls.Add(
Core.MsoControlType.msoControlComboBox,
missing, missing, missing, true));

extraCtlComboBox.AddItem("Red", missing);
extraCtlComboBox.AddItem("Green", missing);
extraCtlComboBox.AddItem("Blue", missing);
extraCtlComboBox.Caption = "Color";
extraCtlComboBox.Style = Core.MsoComboStyle.msoComboNormal;
extraCtlComboBox.Tag = "Colors";
extraCtlComboBox.TooltipText = "Select or type a color";
extraCtlComboBox.Text = "Color";

extraCtlDropDown = (Core.CommandBarComboBox)(
AppCommandBar.Controls.Add(
Core.MsoControlType.msoControlDropdown,
missing, missing, missing, true));

extraCtlDropDown.AddItem("Earth", missing);
extraCtlDropDown.AddItem("Air", missing);
extraCtlDropDown.AddItem("Fire", missing);
extraCtlDropDown.AddItem("Water", missing);
extraCtlDropDown.Caption = "Elements";
extraCtlDropDown.Style = Core.MsoComboStyle.msoComboLabel;
extraCtlDropDown.Tag = "FourElements";
extraCtlDropDown.TooltipText = "Select an element";

extraCtlEdit = (Core.CommandBarComboBox)(
AppCommandBar.Controls.Add(Core.MsoControlType.msoControlEdit,
missing, missing, missing, true));

extraCtlEdit.Caption = "Ask a question";
extraCtlEdit.Tag = "AskQuestion";
extraCtlEdit.Text = "Text Box";
extraCtlEdit.TooltipText = "Ask a question";

extraCtlPopUp = (Core.CommandBarPopup)(
AppCommandBar.Controls.Add(Core.MsoControlType.msoControlPopup,
missing, missing, missing, true));

extraCtlPopUp.Caption = "Other Options";
extraCtlPopUp.Tag = "OtherOptions";
extraCtlPopUp.TooltipText = "Click for additional controls";

extraPopUpCtlButton1 = (Core.CommandBarButton)(
extraCtlPopUp.Controls.Add(Core.MsoControlType.msoControlButton,
missing, missing, missing, true));
extraPopUpCtlButton2 = (Core.CommandBarButton)(
extraCtlPopUp.Controls.Add(Core.MsoControlType.msoControlButton,
missing, missing, missing, true));

extraPopUpCtlButton1.Caption = "Popup Button";
extraPopUpCtlButton1.FaceId = 59;
extraPopUpCtlButton1.Style =
Core.MsoButtonStyle.msoButtonIconAndCaption;

extraPopUpCtlButton2.Caption = "Another Popup Button";
extraPopUpCtlButton2.Style = Core.MsoButtonStyle.msoButtonCaption;

extraCommandBar = CreateCommandBar("Second Shared CommandBar");
extraCtlButton = (Core.CommandBarButton)(
extraCommandBar.Controls.Add(
Core.MsoControlType.msoControlButton,
missing, missing, missing, true));

extraCtlButton.Caption = "Heart";
extraCtlButton.FaceId = 481;
extraCtlButton.Style =
Core.MsoButtonStyle.msoButtonIconAndCaption;
extraCtlButton.TooltipText =
"Button added to second custom CommandBar";
extraCtlButton.Tag = "Heart";

extraCommandBar.Visible = true;

extraCommandBar2 = CreateCommandBar("Third Shared CommandBar");
extraCtlButton2 = (Core.CommandBarButton)(
extraCommandBar2.Controls.Add(
Core.MsoControlType.msoControlButton,
missing, missing, missing, true));

extraCtlButton2.Caption = "Diamond";
extraCtlButton2.FaceId = 482;
extraCtlButton2.Style =
Core.MsoButtonStyle.msoButtonIconAndCaption;
extraCtlButton2.TooltipText =
"Button added to third custom CommandBar";
extraCtlButton2.Tag = "Diamond";

extraCommandBar2.Visible = true;

extraCommandBar3 = CreateCommandBar("Fourth Shared CommandBar");
extraCtlButton3 = (Core.CommandBarButton)(
extraCommandBar3.Controls.Add(
Core.MsoControlType.msoControlButton,
missing, missing, missing, true));

extraCtlButton3.Caption = "Spade";
extraCtlButton3.FaceId = 483;
extraCtlButton3.Style =
Core.MsoButtonStyle.msoButtonIconAndCaption;
extraCtlButton3.TooltipText =
"Button added to fourth custom CommandBar";
extraCtlButton3.Tag = "Spade";

extraCommandBar3.Visible = true;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message, ex.Source,
      MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

private void CleanupExtraAdditions()
{
extraCtlButton3.Delete(true);
extraCtlButton3 = null;

extraCommandBar3.Delete();
extraCommandBar3 = null;

extraCtlButton2.Delete(true);
extraCtlButton2 = null;

extraCommandBar2.Delete();
extraCommandBar2 = null;

extraCtlButton.Delete(true);
extraCtlButton = null;

extraCommandBar.Delete();
extraCommandBar = null;

extraPopUpCtlButton2.Delete(true);
extraPopUpCtlButton2 = null;

extraPopUpCtlButton1.Delete(true);
extraPopUpCtlButton1 = null;

extraCtlPopUp.Delete(true);
extraCtlPopUp = null;

extraCtlEdit.Delete(true);
extraCtlEdit = null;

extraCtlDropDown.Delete(true);
extraCtlDropDown = null;

extraCtlComboBox.Delete(true);
extraCtlComboBox = null;

  extraStdButton.Delete(true);
  extraStdButton = null;

  extraMenuItem.Delete(true);
  extraMenuItem = null;
}

Excel 2003 では、最初に Excel を起動してこのアドインをロードすると、図 1 のように表示されます。

図 1. 共有アドインをロードした Excel 2003
Aa663367.aa663367_fig01(ja-jp,office.12).gif

図 2 は、変更された Excel 2003 の [ファイル] メニューの詳細を示しています。

図 2. 変更された Excel 2003 の [ファイル] メニュー
Aa663367.aa663367_fig02(ja-jp,office.12).gif

Excel 2007 での共有アドインの実行

Excel 2007 でアドインをセットアップしてロードする前に、Excel 2007 を起動し、スクリーン ショットを作成するなどして、Excel 2007 のユーザー インターフェイス (UI) がどのように表示されているか把握しておきます。準備ができたら、Excel 2007 を終了します。これまでのシナリオで作業してきたコンピュータに Excel 2003 と Excel 2007 の両方がインストールされている場合は、[スタート] メニューから Excel 2007 を起動して、アドインがどのように実行されるかを確認できます。別のコンピュータや仮想マシンを使用している場合にこのアドインを試すには、共有アドイン ウィザードを使用してセットアップ プログラムを作成し、それを該当のマシンで実行するのが最も簡単です。アドインをインストールした後、Excel 2007 を実行して、アドインによる UI の変更を確認できます。

このアドインを Excel 2007 Beta 2 で実行した場合は、図 3 のように表示されます。

図 3. 共有アドインをロードした Excel 2007 Beta 2
Aa663367.aa663367_fig03(ja-jp,office.12).gif

最初に気付く点は、移動可能なコマンド バーがないことです。次に、図 4 のように、[Add-Ins] というキャプションの新しいタブがリボンに表示されている点に気付きます。

図 4. 共有アドインをロードした Excel 2007 Beta 2 の詳細
Aa663367.aa663367_fig04(ja-jp,office.12).gif

[Add-Ins] タブをクリックすると、コマンド バーに表示されていた内容がすべて表示されます (図 5 参照)。

図 5. アクティブ化され、カスタム コマンド バーとカスタム項目が表示された [Add-Ins] タブ
Aa663367.aa663367_fig05(ja-jp,office.12).gif

適当なコントロールをクリックすると、イベント ハンドラが前と同様に機能することがわかります。リボンをサポートする Microsoft Office アプリケーションでは、既存の COM アドインをロードするときにも同じ種類のロジックを使用します。こうした Office アプリケーションでは、メニュー バーに対するカスタマイズ内容は、[Menu Commands] というラベルのセクションに表示されます (図 6 参照)。

図 6. リボンの [Menu Commands] セクション
Aa663367.aa663367_fig06(ja-jp,office.12).gif

組み込みのコマンド バーに対するカスタマイズ内容は、[Toolbar Commands] というラベルのセクションに表示されます (図 7 参照)。

図 7. リボンの [Toolbar Commands] セクション
Aa663367.aa663367_fig07(ja-jp,office.12).gif

そして、カスタム コマンド バーは、[Custom Toolbars] というラベルのセクションに作成された順序で表示されます (図 8 参照)。

図 8. リボンの [Custom Toolbars] セクション
Aa663367.aa663367_fig08(ja-jp,office.12).gif

コントロールにポインタを置いてツールヒント (Microsoft Office ではヒントと呼ばれます) を表示すると、書式が変更されていることがわかります。これによって、コマンド バーを他のコマンド バーと見分けることもできます。コマンド バーの名前は、プレフィックスとして、コントロールのヒント テキストの前に追加されます (図 9 参照)。

図 9. カスタム コマンド バーを見分けるための新しいヒントの書式
Aa663367.aa663367_fig09(ja-jp,office.12).gif

サンプル アドインが動作すれば、既存のアドインもすべて動作します。しかし、既定の UI の動作では、リボン以前の UI は、本格的に調整および統合されたというよりは、ただ追加されただけのように見えます。このような場合、Visual Studio 2005 Tools for Office Second Edition を使用します。既に説明したように、VSTO 2005 SE によって、コンパイルやカスタム COM シムを必要とすることなく共有アドインの多くの問題を解決できるほか、アドインでのリボンのカスタマイズもサポートできるようになります。

VSTO 2005 SE アドインの作成

VSTO 2005 SE アドインは、各 Microsoft Office アプリケーションに対して固有です。プロジェクトを定義し、ホストのサポートを選択するために、ウィザードを実行する必要はありません。代わりに、選択する Visual Studio プロジェクトの種類によって、サポートするホストを選択します。

以下の手順に従って、Excel ベースの Excel 2007 用アドインを作成します。Excel を実行している場合は、すべて終了してください。

Excel 用のアドインを作成する

  1. Visual Studio 2005 を実行していない場合は、Visual Studio 2005 を起動します。
  2. [ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。
  3. [新しいプロジェクト] ダイアログ ボックスのプロジェクトの種類の一覧で [Visual Basic] または [Visual C#] ノードを展開し、[Office] ノードを展開します。
  4. [2007 アドイン] ノードを選択します。
  5. [テンプレート] ペインで、[Excel アドイン] をクリックします。
  6. [プロジェクト名] ボックスに、「ManagedAddInDemo」と入力します。
  7. アドインの保存先を選択し、[OK] をクリックします。

Visual Studio によって、Excel アドイン プロジェクトとセットアップ プロジェクトの 2 つのプロジェクトを含む新しいソリューションが作成されます。Connect クラスの代わりに、このアドインには ThisAddIn という名前のクラスが含まれています。Connect クラスは、IDTExtensibility2 インターフェイスによって定義される 5 つのメソッド用に 5 つのメソッド スタブを定義していましたが、ThisAddIn クラスは、StartupShutdown の 2 つのイベント ハンドラを公開します。これらの 2 つのメンバは、IDTExtensibility2OnConnection メソッドおよび OnDisconnection メソッドと同じ目的で使用されます。Visual Studio 2005 で既定では非表示になっているパーシャル クラスを調べることによって、ThisAddIn クラスの背後で行われるプラミングのほとんどを確認することができます。このプラミングの利点の 1 つは、Application クラスが既に有効になっていて使用できることです。また、Visual Basic を使用している場合には、コード エディタのオブジェクトおよびイベント コンボ ボックスでアプリケーション レベルのイベントにアクセスできます。

共有アドインから VSTO 2005 SE アドインに移行する場合は、コードを分解しておくと便利です。1 つの方法としては、コードを、アドイン管理、UI 管理、ホスト操作、およびコア機能の 4 つの独立したユニットに分解することができます。アドイン管理は、ホストへの接続、ホスト固有のイベント、およびアドイン構成の設定などのアドインの全体的な内容に関連するコードです。UI 管理は、コマンド バーやリボンなどの Office UI フレームワークにアドインのコードをフックすることに関連するすべてのコードです。ホスト操作は、ドキュメント クラス、ドキュメント イベント、およびドキュメントの操作など、ホスト固有の機能を処理するコードです。アドインの有効期間や構成に関連する項目は、ここには含まれません。最後のコア機能には、前の 3 種類で対象とされなかったすべてのコードが該当します。たとえば、Microsoft Windows フォームのコード、アクション ペインのユーザー コントロール、Web サービスの呼び出しなどです。少なくとも、動作を複数のクラスに分割することが必要です。Office ホスト間でコードが再利用可能である場合は、独立したアセンブリの作成を検討する必要があります。

リボンのサポート

VSTO 2005 SE アドインのリボンのサポートでは、レイアウトの宣言型 XML と動作 (イベント処理など) に関するコードの組み合わせも対象になります。この新しいモデルによって、記述する必要があるコードの量が削減されます。たとえば、前に作成したサンプルの共有アドインでは、反復的な UI の作成を容易にするために、多くのヘルパ メソッドを使用しました。リボンを使用すると、これらのメソッドは不要になります。このモデルの変更のもう 1 つの利点は、明示的にクリーンアップを行う必要がなくなったことです。アドインがシャットダウンされるときに、Office ホストによって UI の変更がすべてクリーンアップされます。つまり、イベントは従来どおりコードで処理されますが、その後明示的にイベントをフックする作業を行う必要はありません。

リボンのサポートを実現する最初の手順は、プロジェクトにリボン項目を追加することです。アドイン プロジェクトを選択してアクティブにし、次の手順を実行します。

プロジェクトにリボン項目を追加する

  1. [プロジェクト] メニューの [新しい項目の追加] をクリックします。
  2. [新しい項目の追加] ダイアログ ボックスで、[Ribbon support] をクリックし、[追加] をクリックします。

Visual Studio によって、プロジェクトに 2 つのファイルが追加されます。Ribbon1.vb (Visual Basic) または Ribbon1.cs (Visual C#) には、イベント処理のコード スタブが含まれます。Ribbon1.xml には、リボンに表示されるオブジェクトとイベントのバインディング情報を定義する宣言型 XML が含まれます。例については、次のリストを参照してください。

' Regions removed from code listing.

Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Text
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports Office = Microsoft.Office.Core

' TODO:
' This is an override of the RequestService method in ThisAddin class.
' To hook up your custom Ribbon, uncomment this code.
'Partial Public Class ThisAddIn
'
'    Private ribbon As Ribbon1
'
'    Protected Overrides Function RequestService( _ 
'      ByVal serviceGuid As System.Guid) As Object
'
'        If (serviceGuid = GetType(Office.IRibbonExtensibility).GUID) Then
'            If ribbon Is Nothing Then
'                ribbon = New Ribbon1()
'            End If
'
'            Return ribbon
'        End If
'
'        Return MyBase.RequestService(serviceGuid)
'    End Function
'
'End Class


<ComVisible(True)> _
Public Class Ribbon1
  Implements Office.IRibbonExtensibility

  Private ribbon As Office.IRibbonUI

  Public Sub New()
  End Sub

  Public Function GetCustomUI(ByVal ribbonID As String) As _ 
    String Implements Office.IRibbonExtensibility.GetCustomUI
    Return GetResourceText("Ribbon1.xml")
  End Function

  Public Sub OnLoad(ByVal ribbonUI As Office.IRibbonUI)
    Me.ribbon = ribbonUI
  End Sub

  Public Sub OnToggleButton1( _
    ByVal control As Office.IRibbonControl, _
    ByVal isPressed As Boolean)

    If (isPressed) Then
      MessageBox.Show("Pressed!")
    Else
      MessageBox.Show("Released!")
    End If

  End Sub

  Public Shared Function GetResourceText( _
    ByVal resourceName As String) As String

    Dim asm As Assembly = Assembly.GetExecutingAssembly()
    Dim resources As String() = asm.GetManifestResourceNames()
    For Each resource As String In resources
      If resource.EndsWith(resourceName) Then
        Dim resourceReader As System.IO.StreamReader
        resourceReader = New System.IO.StreamReader( _
          asm.GetManifestResourceStream(resource))
        If Not resourceReader Is Nothing Then
          Return resourceReader.ReadToEnd()
        End If
      End If
    Next
    Return Nothing
  End Function
End Class

#region Using directives

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Office = Microsoft.Office.Core;


#endregion

namespace ManagedAddInDemoCS
{
  // TODO:
  // This is an override of the RequestService method in ThisAddin class.
  // To hook up your custom Ribbon, uncomment this code.
  //public partial class ThisAddIn
  //{
  //     Ribbon1 ribbon;
  //     protected override object RequestService(Guid serviceGuid)
  //     {
  //         if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID)
  //         {
  //             if (ribbon == null)
  //                 ribbon = new Ribbon1();
  //             return ribbon;
  //         }
  //
  //         return base.RequestService(serviceGuid);
  //     }
  //}


  [ComVisible(true)]
  public class Ribbon1 : Office.IRibbonExtensibility
  {

    #region fields

    private Office.IRibbonUI ribbon;

    #endregion


    #region Initialization

    public Ribbon1()
    {
    }

    public string GetCustomUI(string ribbonID)
    {
      return GetResourceText("Ribbon1.xml");
    }

    public void OnLoad(Office.IRibbonUI ribbonUI)
    {
      this.ribbon = ribbonUI;
    }

    #endregion

    public void OnToggleButton1(Office.IRibbonControl control, 
      bool isPressed)
    {
      if (isPressed == true)
        MessageBox.Show("Pressed!");
      else
        MessageBox.Show("Released!");
    }

    #region Helpers
    public static string GetResourceText(string resourceName)
    {
      Assembly asm = Assembly.GetExecutingAssembly();
      string[] resources = asm.GetManifestResourceNames();
      foreach (string resource in resources)
      {
        if (resource.EndsWith(resourceName))
        {
          System.IO.StreamReader resourceReader =
              New System.IO.StreamReader(
              asm.GetManifestResourceStream(resource));
          if (resourceReader != null)
          {
            return resourceReader.ReadToEnd();
          }
        }
      }
      return null;
    }
    #endregion
  }
}

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
  onLoad="OnLoad">
  <ribbon startFromScratch="false">
    <tabs>
      <tab id="VSTO.Tab" label="VSTO Add-in Tab" visible="1">
        <group id="VSTO.Group" label="VSTO Group" visible="1">
          <toggleButton id="toggleButton1" label="Toggle Button 1"
                        screentip="ToggleButton1 Screentip" 
                          onAction="OnToggleButton1" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

リボンのカスタマイズを統合するには、コメントされたコードの先頭部分のコメントを解除する必要があります。その後、F5 キーを押してアドインをデバッグします。Visual Studio は、プロジェクト作成時、デバッグ セッションでアドイン プロジェクトを接続し、Excel 2007 を起動します。Excel が起動すると、[VSTO Add-in Tab] というラベルの新しいタブが表示されます (図 10 参照)。

図 10. 既定のリボンのカスタマイズ内容がロードされた VSTO 2005 SE アドイン
Aa663367.aa663367_fig10(ja-jp,office.12).gif

[VSTO Add-in Tab] をクリックすると、[VSTO Group] という名前のグループに [Toggle Button 1] というラベルのボタンが 1 つ表示されます (図 11 参照)。このボタンをクリックすると、クリックのたびに、ボタンの状態を示すメッセージ ボックスが表示されます。

図 11. カスタマイズされたグループとトグル ボタン
Aa663367.aa663367_fig11(ja-jp,office.12).gif

**メモ:   **ショートカット メニュー、ミニ ツールバー、ステータス バー、およびギャラリーを使用したリアルタイムのプレビューなどの一部の機能は、リボン UI をアドインでカスタマイズした場合は使用できません。

コマンド バーの移行

コマンド バーで既定の動作からの移行を行うことは、コードを移動することよりも少し複雑です。最大の問題はデザインです。リボンをカスタマイズする場合のデザインの注意事項を理解しておく必要があります。ボタンやその他のコントロールをリボンにランダムに挿入すると、カスタム UI の受容性や全体的な操作性が具体的に損なわれる可能性があります。詳細については、「<開発者向け> the 2007 Office system のユーザー インターフェイスに関する概要」および「2007 Office System ドキュメント: ソリューションおよびアドインの UI スタイル ガイド」(英語) で説明されているので、ここでは説明を省略します。また、この記事では、リボンのカスタマイズで可能な組み合わせをすべて取り上げて説明することは意図していません。ここでは、共有アドインで定義済みのコードを VSTO 2005 SE アドインに移行する方法を提示して、その仕組みを理解できるようにします。

1 つ目の大きな変更点は、コマンド バーの定義コードの XML への "変換" です。以前は、コマンド バーを定義するために次のようなスニペットが使用されていました。

Return applicationObject.CommandBars.Add(Name, _
  Core.MsoBarPosition.msoBarFloating, False, True)
  return applicationObject.CommandBars.Add(Name,
  Core.MsoBarPosition.msoBarFloating, false, true);

新しいコマンド バーの作成では、事実上は、これらのパラメータのすべてが省略可能です。しかし、可能な限りパラメータは明示的に設定します。最初のパラメータは "Name" です。これは、新しいコマンド バーの論理名を指定します。この名前を指定しなかった場合、Office ホストによって既定の名前である Custom 1 が割り当てられます。2 番目のパラメータは "Position" です。これは、コマンド バーの位置を指定します。新しい UI では、コマンド バーやリボンの任意の位置への移動はサポートされていないため、アプリケーションではこのパラメータは無視されます。3 番目のパラメータは "Menubar" です。これは、既定のメニュー バーを新しく定義したコマンド バーに置き換えることを指定します。リボンをサポートしている Office アプリケーションでは、このパラメータも無視されます。最後のパラメータは "Temporary" です。これは、True の場合に、コンテナ アプリケーションが閉じられた時点でコマンド バーを削除することを指定します。リボンのタブはコマンド バーに相当します。Visual Studio を使用してリボンを追加すると、生成された XML にはカスタム タブの作成に必要な情報が組み込まれます。

Excel 2003 アドインでは、例で見たように、さまざまな場所のコマンド バーにコントロールを追加していました。具体的には、AddExtraUIAdditions プロシージャによって、サポート対象のすべての種類のコントロールが、カスタム コマンド バーや [標準] および [書式設定] コマンド バーに追加されています。次の XML は、リボン項目によって生成される変更されたバージョンのベース XML です。この XML には、前の例で使用した既定のコントロール、トグル ボタン、およびすべての標準ボタンが含まれています。

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"
 onLoad="OnLoad">
  <ribbon startFromScratch="false">
    <tabs>
      <tab id="tabSharedCommandBar" 
           label="Shared CommandBar" visible="1">
        <group id="Shared.Group" label="Shared Group" visible="1">
          <toggleButton id="toggleButton1" label="Toggle Button 1"
           screentip="ToggleButton1 Screentip" 
           onAction="OnToggleButton1" />
          <button id="AddInInfo" label="AddInInfo" 
           screentip ="Get Add-in Information" imageMso="HappyFace" />
          <comboBox id="Colors" label="Colors" 
            screentip="Select or type a color" tag ="Colors">
            <item id="Red" label="Red"/>
            <item id="Green" label="Green"/>
            <item id="Blue" label="Blue"/>
          </comboBox>
          <dropDown id="Elements" label="Elements" 
            screentip="Select an element" tag ="Elements">
            <item id="Earth" label="Earth"/>
            <item id="Wind" label="Wind"/>
            <item id="Fire" label="Fire"/>
            <item id="Water" label="Water"/>
          </dropDown>
          <editBox id="AskQuestion" 
           label="Ask a question" tag="AskQuestion"/>
          <menu id="OtherOptionsButton" label="Other Options" 
           tag="OtherOptions">
           <button id="PopupButton1" imageMso="HappyFace" 
            label="Popup Button" />
           <button id="PopupButton2" 
            label="Another Popup Button"/>
          </menu>
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

この XML を見ると、全体的に単純であることがわかります。多くのコントロールには、標準的な要素名が使用されています。COM コマンド バー API を使用して作成されたコントロールでは一意の ID を指定する必要はありませんでしたが、リボン の XML スキーマではその必要があります。これは、コンボ ボックス コントロールやドロップダウン コントロールに表示される項目についても同様です。FaceID プロパティは使用されなくなり、代わりに imageMso 属性を使用します。imageMso 属性には、以前のバージョンの Microsoft Office で使用されていたランダムに見える整数の代わりに、文字列名が必要です。最後に、msoControlPopup コントロールに最も近いのがメニュー コントロールです。

この時点で、Excel 内でアドインを実行し、[Shared CommandBar] タブをクリックすると、図 12 のような UI が表示されます。

図 12. カスタマイズされたタブによって変更されたリボン
Aa663367.aa663367_fig12(ja-jp,office.12).gif

外見的には完成していますが、応答するコードがあるコントロールはトグル ボタンだけです。共有アドインの例では、Click イベントに応答するコードを持つボタン コントロールがありました。この Click イベント ハンドラは、コード内でコントロールに関連付けていました。リボンのコントロールでこれを実現するには、2 つの作業が必要です。最初に、XML を変更して Click イベントを特定のコールバック プロシージャにマップします。次に、ソース ファイル内で実際のコールバック プロシージャを定義します。ボタンに関して変更を行った XML は次のとおりです。

<button id="AddInInfo" label="AddInInfo" 
  screentip ="Get Add-in Information" imageMso="HappyFace" 
  onAction="OnAddInInfo"/>

次に、Ribbon1 ソース ファイルの Ribbon1 クラス内で、新しいコールバック メソッドを追加します。

Public Sub OnAddInInfo(ByVal control As Office.IRibbonControl)
  MsgBox("Hello from" & control.ID)
End Sub

public void OnAddInInfo(Office.IRibbonControl control)
{
  MessageBox.Show("Hello from " + control.Id);
}

この時点で、新しい VSTO 2005 SE アドインで複製しなければならない共有アドインのコードがあと 3 つ残っています。それぞれが 1 つのボタンを含んだ、3 つのコマンド バーを複製する必要があります。また、Excel の組み込み UI、つまり [ファイル] メニューのメニュー項目と [標準] ツールバーのコマンド ボタンへの追加項目をフックする必要があります。3 つのコマンド バーを複製するには、いくつかの方法があります。前述の「2007 Office System ドキュメント: ソリューションおよびアドインの UI スタイル ガイド」(英語) の記事を確認してください。この記事の重要なポイントは、ソリューションを可能な限りリボンに統合するべきであるということです。この意味するところは、アドインの UI 要素を、可能な限り、既存のタブの固有のグループに追加するべきであるということです。アドインのコントロールを既存のグループに追加することはできません。アドインに、既存のどのタブのコンテキストでも意味をなさない UI が含まれている場合は、アドイン独自のタブを追加します。ただし、タブは論理的に整理して、必要な場合にのみ新しいタブを追加します。したがって、この場合、3 つの新しいコマンド バーについては、既存のアドイン タブに新しいグループを配置します。次の XML のブロックは、そのために必要となる変更を示しています。XML の一部は、スペース上の理由から編集されていることに注意してください。

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
  onLoad="OnLoad">
  <ribbon startFromScratch="false">
    <tabs>
      <tab id="tabSharedCommandBar" 
           label="Shared CommandBar" visible="1">
<!-- XML deleted -->
        <group id="Second.Shared.CommandBar" 
               label="Second Shared CommandBar" visible="1">
          <button id="Heart" label="Heart" 
                  screentip ="Second.Shared.CommandBar" 
                  imageMso="Heart" tag="Heart"/>
        </group>
        <group id="Third.Shared.CommandBar" 
               label="Third Shared CommandBar" visible="1">
          <button id="Diamond" label="Diamond" 
                  screentip ="Button added to third custom CommandBar" 
                  imageMso="Heart" tag="Diamond"/>
        </group>
        <group id="Fourth.Shared.CommandBar" 
               label="Fourth Shared CommandBar" visible="1">
          <button id="Spade" label="Spade" 
                  screentip ="Button added to fourth custom CommandBar" 
                  imageMso="Spade" tag="Spade"/>
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

追加された XML には、3 つの新しい group 要素があり、それぞれに button 要素が含まれています。このコードを共有アドインのコードと比較する際に注意する点は、id 属性にスペースを含めることができないことです。このため、コードでは、単語の区切りにピリオドが使用されます。図 13 は、完成したタブの状態を示しています。

図 13. 3 つのコマンド バーがすべてグループに変換された、カスタマイズ済みのタブ
Aa663367.aa663367_fig13(ja-jp,office.12).gif

[ファイル] メニューと [標準] ツールバーの変更では、デザイン上の決定を行う必要があります。図 6 と図 7 を見ると、共有アドインを Excel 2007 にロードした場合、[Add-in] タブの個別のグループに 2 つの変更内容が配置されていることがわかります。Excel 2003 に存在していた [ファイル] メニューは存在しません。また、[標準] ツールバーも存在しません。共有アドインの変更の複製に最も近い方法は、Office メニューを編集して、組み込みの [ホーム] タブに追加のボタンを配置する方法です。

次の XML スニペットは、Office メニューにボタンを追加する方法を示しています。

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
          onLoad="OnLoad">
  <ribbon startFromScratch="false">
    <officeMenu>
      <button id="ExtraExtra" label="Extra Extra!" imageMso ="Pushpin"/>
    </officeMenu>
<!-- XML deleted -->

この変更を行った後でアドインを実行すると、図 14 のような結果が得られます。

図 14. カスタマイズされた Office メニュー
Aa663367.aa663367_fig14(ja-jp,office.12).gif

問題は、画鋲の画像が大きく、少しぼやけていることです。別の画像を選択するか、独自の画像を作成することをお勧めします。アドインを移行する場合は、この点に注意が必要です。以上が完了したら、既存の [ホーム] タブを参照し、グループを定義し、ボタンを定義して、最後のボタンを追加します。結果については、図 15 を参照してください。

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
  onLoad="OnLoad">
  <ribbon startFromScratch="false">
    <officeMenu>
      <button id="ExtraExtra" label="Extra Extra!" imageMso ="HappyFace"/>
    </officeMenu>
    <tabs>
      <tab idMso="TabHome">
        <group id="Shared.Group.Home" label="Shared" visible ="1">
          <button id="EightBall" label="Button added to the Home tab" 
           showLabel ="0" imageMso="MagicEightBall"/>
        </group>
      </tab>
<!-- XML deleted -->

図 15. カスタマイズされた [ホーム] タブ
Aa663367.aa663367_fig15(ja-jp,office.12).gif

ただし、前述のように、この仕組みには特に驚くべき点はありません。難しいのはデザインです。アドインを独自のタブに表示する必要があるか、アドインの UI 要素を既存のタブの UI 要素と統合する必要があるか、アドインでどの新しいコントロールを使用するか、といった判断を適切に行う必要があります。この新しい Microsoft Office 環境では、少ないことが豊かなことである、と言えます。UI の変更では、アドインがアプリケーション全体の一要素として表示されるようにします。できる限り、独自のタブを作成するのではなく、既存のタブにグループを追加します。アドインで独自のタブが必要である場合は、項目を論理的に分類し、より少ない項目でより多くの機能を実現できるコントロールの組み合わせを使用します。

まとめ

共有アドインは、Microsoft Office アプリケーションでマネージ拡張機能を実現する優れた方法です。COM シム (COM シム ウィザードを使用して作成できます) を使用した展開によって、共有アドインのマイナス面のほとんどが解消されます。2007 リリースの Microsoft Office への移行において、Visual Studio 2005 Tools for Office Second Edition は、アドイン開発者に対してより洗練された包括的なエクスペリエンスを提供します。ゼロから開発を始めるケースにおいて、Visual Studio 2005 Tools for Office Second Edition がホストをサポートしている場合は、Visual Basic または Visual C# のマネージ開発環境で Visual Studio 2005 Tools for Office Second Edition を選択することは難しいことではありません。Visual Studio 2005 Tools for Office Second Edition は、共有アドインと比較した場合に、移行する根拠となるだけの利点を持っています。移行の成功の鍵は、接続と接続解除、UI 操作、およびホスト ドキュメントの操作に関連する現在のソリューションのコードの効果的な分割にあります。今すぐ移行を行うことで、一歩先んじて、アプリケーションの作業ウィンドウのサポート、リモート展開のサポート、およびリボンなどの機能を活用することが容易になります。今すぐ移行を行わない場合も、新しい機能のサポートとマネージ アドインの安全なロード/アンロードの組み合わせは、最終的に Visual Studio 2005 Tools for Office Second Edition への移行を決断する論拠となるでしょう。

著者について

Brian A. Randell 氏は、MCW Technologies, LLC のシニア コンサルタントです。Brian 氏は、Microsoft .NET ベースのテクノロジを開発者に指導したり、2007 Microsoft Office system、Visual Studio 2005、および Visual Studio Team System などの最新のテクノロジを扱う仕事に従事しています。また、システムの設計や実装で世界中のクライアント (Microsoft、American Honda、DELL など) を支援しています。Brian 氏は Microsoft MVP として、人々がソフトウェアを最大限に活用するためのサポートに取り組んでいます。そのために、VSLive!、Tech・Ed、および PDC などのイベントでトレーニング、コンサルティング、講演を行っています。さらに、執筆活動も行っています。『Effective Visual Basic』の共著者であり、『MSDN Magazine』やマイクロソフトでも記事を書いています。Brian 氏は Pluralsight のテクニカル スタッフの一員であり、Pluralsight の Applied Team System コースの企画担当でもあります。Brian 氏には、彼のブログでコンタクトをとることができます (英語)。

追加情報

このセクションでは、記事内で言及または使用されている製品やテクノロジの詳細を知るために活用できるリソースを示します。