Visual Studio アドイン

Last Updated 2011/09/21


.Net Framework アプリケーションの開発者の多くは、Visual Studio を使っていると思います。好みの問題はありますが、開発環境としてはおおむねよくできていると思います。しかし、人間の欲は深いもので、さらに便利にしたくなるものです。Visual Studio はそういう人のために開発環境に独自の機能を組み込む仕組みを用意しました。このページで紹介するアドインがその一つです。なお、このページは Visual Studio 2010(Visual Studio 2008 または 2005 でもほぼ同じです)に基づいています。また、サンプルコードは C# で作りました。

【注意】
.Net Framework 3.5 に追加された System.AddIns 名前空間は通常のアプリケーションに組み込むアドインに関係するクラスを含むもので、Visual Studio アドインとは関係ありません。


Visual Studio 2005 の開発環境を拡張する機能

Visual Studio 2005/2008 のアドインを 2010 に移行する

アドインとは何か?

アドインウィザードによるアドインの作成

アドインのビルド

テスト用プロジェクト

メニュー項目用ビットマップ

アドインの格納

アドインの登録

アドインの削除

アドインの配布

アドインのサンプル


Visual Studio の開発環境を拡張する機能

Visual Studio の開発環境を拡張する機能として、次の 3 種類の方法があります。

「マクロを作成する」と「Visual Studio のオートメーションを利用する」は開発言語として Visual Basic を使わなければなりません。マクロが Office 製品の VBA "Visual Basic Automation" として発達したことに起因するのでしょうが、不便なことではあります。

私は Windows プログラミングを Visual Basic から始めましたから、Visual Basic は知っているのですが、いまさら使いたいとは思いません。そこで、Visual C# で開発可能なアドインを開発環境の拡張の本命と考えます。

なお、.Net Framework 4.0 SDK の中のアドインに関係する項目は以下の項目の中にあります。

Visual Studio 2010
. Visual Studio
... Visual Studio でのアプリケーション開発
..... 開発環境のカスタマイズとオートメーション
....... Visual Studio のオートメーションおよび機能拡張
......... Visual Studio 環境の拡張
........... アドインおよびウィザードの作成

Visual Studio 2005/2008 のアドインを 2010 に移行する

ズバリの解決策だけを書きます。Visual Studio 2010 で作り直しましょう。コード自体はコピーすればいいですから面倒な作業ではありません。裏技的には手があるとは思いますが、おすすめしません。

私は Visual Studio 2008 で作成したアドインのコードをそのままコピーしましたが、まったく問題なく動作します。


アドインとは何か?

アドオン "add-on" という言葉もあります。これは通常ハードウエアの機能を強化するための部品をさします。たとえば、最近はグラフィックス関係の機能を強化するためにグラフィックスカードを追加することが多くなりましたが(というより、高機能なグラフィックスカードがないと、Windows Vista/7 は動きません)、これは広い意味でのアドオンといえます。いずれにしろ、アドオンはハードウエアをさすことが一般的だと思います。一方、アドイン "add-in" はソフトウエア的に機能を拡張するものをさします。アドインのことをプラグイン "plug-in" と呼ぶ場合もあります。

Note アドインとプラグインとの機能は同じだと考えますが、正確な定義は知りません。

アドインの例は Visual Studio の IDE の中にすでにあります。たとえば、選択範囲のコードをコメントアウトしたり、インデント量を調整する機能はアドインです。また、タブオーダーを調整する機能もそうです。このようにアドインを組み込むと、ソースコードを操作したり、フォームデザイナに独自の機能を追加することなども可能になります。


アドインウィザードによるアドインの作成

アドインを作る場合はアドインウィザードを使う方法が確実です。というのは、Microsoft は処理の内容をブラックボックス化する傾向があるため、独自の手順で作ると正常に動作するかどうかが分からないからです。

Note アドインは、Visual Studio と一体となって動作します。したがって、アドインに不都合があると、Visual Studio の動作も不安定になる可能性があります。

Visual Studio のメニュー [ファイル]-[新規作成]-[プロジェクト] を選択し、[プロジェクトの種類]-[その他のプロジェクトの種類]-[機能拡張] を選択します。次に、[Visual Studio アドイン] を選択します。[プロジェクト名] と [場所] には適当に入力してください。

【重 要】[プロジェクト名] は、アドインプロジェクトのアセンブリ名名前空間名にもなりますので、重要な情報です。間違えないように慎重に入力してください。

これで [OK] すると、アドインウィザードが始まります。下図はその最初の画面です。

AddIn1

[次へ] を選択すると、「プログラミング言語の選択」のページが開きますので、適当なものを選択してください。下図では、Visual C# を指定しています。

AddIn2

[次へ] を選択すると、「アプリケーションホストの選択」のページになります。「アプリケーション」は Visual Studio の IDE と考えていいでしょう。「ホスト」はアドインの面倒を見るものぐらいの解釈でいいと思います。つまり、アドインを読み込んで実行する環境を提供するアプリケーションです。

この画面では、"Microsoft Visual Studio 2010" と "Microsoft Visual Studio 2010 Macros" が並んでいますが、"Macros" のほうはマクロの操作と管理をアドインで行う場合に関係します。今回はマクロを使わない方針ですから、"Macros" のチェックははずしてください。

AddIn3

次は、「名前および説明の入力」です。[アドインの名前] は、アドインマネージャの [使用できるアドイン] にリストアップされるアドインの名前となります。 [アドインの説明] はアドインマネージャにリストアップされたアドインの 1 つにフォーカスを与えると、そのアドインの機能などの内容を説明する説明文となります。

AddIn4

次は、「アドインオプション」です。[アドイン用のコマンドバー UI を作成しますか?] は、アドインを起動するためのメニュー項目やツールボタンを Visual Studio IDE に追加するかどうかを指定します。したがって、Visual Studio を立ち上げたときにアドインを起動し、明示的にアドインを起動する必要がない場合は UI を使う必要はありません。デフォルトの動作は、IDE のメニュー [ツール] の中に、メニュー項目を追加しますが、アドイン本体のほうでどうするかを設定することができます。

[アドイン読み込み時の設定] は。アドインを Visual Studio の起動時に同時に読み込むかどうか、あるいはコマンドラインから起動するかどうかを指定します。これらの設定はアドインマネージャを使えば、あとから設定できますので、ここでは両方ともチェックを入れないで、[次へ] を選択してください。

AddIn4

自作のアドインを自分で使うだけなら必要ありませんが、第三者に配布する場合はアドインのバージョン情報とか、ユーザーに知らせたい情報があるなら、[バージョン情報ダイアログボックスの設定を生成しますか?] にチェックを入れてください。下図は、[バージョン情報] 生成しない設定になっています。

AddIn6

チェックを入れると、下図にしめすように、下側にあるテキストボックスが入力可能になりますので、すでに表示されているテキストにならって適当に入力してください。準備がよければ、[次へ] を選択すると、ここまでの設定内容が表示されます。

AddIn8

下図はウィザードの最後のページで、ここまでの設定内容の「概要」を表示します。

AddIn7

訂正があれば、[戻る] を選択してくさい。これでよければ、[完了] を選択してください。ウィザードは終了し、アドインプロジェクトのテンプレートが作成され、コードが編集可能状態になります。

Note [完了] を選択してから次のステップにすすむまでにチョット時間がかかります。フリーズしたのかと思うぐらい。

さて、ここで、ソリューションエクスプローラを見てください。以下のファイルが自動的に作成されているはずです。

Note Visual Studio 2005/2008 までは CommandBar.resx も作成されましたが、2010 ではなくなりました。

"Connect.cs" はアドイン用クラスを定義するファイルで、Connect はクラス名でもあります。別の名前に変更することは可能ですが、ここはそのままにしておきましょう。

Note アドインは名前空間とクラス名との組み合わせで識別しますので、複数のアドインのクラス名が同じであっても問題ありません。

"MyAddIn1 - For Testing.AddIn" はアドインの内容を設定するファイルですが、Visual Studio がテスト用に使用します。このファイルは以下のディレクトリ内にあります。

    Windows Vista/7 の場合:C:\Users\<username>\Documents\Visual Studio 2010\Addins

"MyAddIn1.AddIn" は "Connect.cs" と同じディレクトリ内にあります。これは通常、アドインの配布用に使います。

"MyAddIn1 - For Testing.AddIn" と "MyAddIn1.AddIn" との違いは、アセンブリ(.dll ファイル)の格納場所だけです。この意味については「アドインの配布」の項で取り上げます。

別のフォルダに格納したい場合は、Visual Studio の [ツール]-[オプション]-[環境] のページを開いて、「アドイン/マクロセキュりティ」にパスを追加してください。下図は、現在の設定内容を表示しています。

AddIn10

さて、テンプレートコードである Connect クラスのコードは見てのとおり、コメントがたくさん付いていて、一見すると親切に見えますが、コメントはほとんど役に立ちません。誤解しやすいコメントもありますので、私が編集したものを以下に示します。アドインはほとんど同じ形式で間に合いますから、このコードはテンプレートとして再利用できます。

ここで紹介するアドインは、フォーム上に配置した複数のコントロールの Tag プロパティを 0 からの追番で自動的に番号付けするものです。Visual C# ではコントロールの配列を直接扱うことができませんが、Tag プロパティを利用すれば配列と似た操作が可能です。たとえば、10 個のボタンコントロールを配置し、それらをコントロールの配列として操作する場合、Tag プロパティにボタンを識別する番号を付けておいて、すべてのボタンコントロールの Click イベントを 1 つのイベントハンドラに関連付けておきます。Click イベントハンドラの sender を Button オブジェクトにキャストし、その Tag プロパティを調べればどのボタンをクリックしたかが分かります。

以下のコード中にある (*1) などは後述する補足説明の番号です。

using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using System.Resources;
using System.Reflection;
using System.Globalization;

using System.ComponentModel; // IComponent
using System.ComponentModel.Design; // ISelectionService
using System.Windows.Forms; // MessageBox

namespace TagAddIn // ← アドインウィザードの 3 ページ目の [アドインの名前] になる
{
  public class Connect : IDTExtensibility2, IDTCommandTarget
  {
    // メンバ変数(メンバ変数には Field をあらわす "F" を付けた)
    private DTE2 FApplicationObject;
    private AddIn FAddInInstance;

    //-----------------------------------------------------------------------------------
    // コンストラクタ
    public Connect()
    {
    }

    //-----------------------------------------------------------------------------------
    // アドインを IDE と接続する時に呼び出されるメソッド
    // application    : アドインをホストするアプリケーションで、DTE2 オブジェクト
    // connectionMode : アドインを読み込んだ方法をあらわす ext_ConnectMode enum 型 (*1)
    // addInst        : アドインのインスタンスである AddIn オブジェクト
    // custom         : ホスト固有のデータ(使わない)
    public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
    {
      FApplicationObject = (DTE2)application;
      FAddInInstance = (AddIn)addInInst;

      // コマンドボタンなどの UI から起動したとき、またはアドインマネージャでアドインを有効にした時 (*2)
      if ((connectMode == ext_ConnectMode.ext_cm_UISetup) || (connectMode == ext_ConnectMode.ext_cm_AfterStartup))
      {
        object[] contextGUIDS = new object[] { }; // (いずれにしろ、これは使わない)

        // IDE のメニュー項目のコマンドのコレクション
        Commands2 commands = (Commands2)FApplicationObject.Commands;
        string toolsMenuName;
        toolsMenuName = "ツール";

        // "MenuBar" は IDE のメニューバーオブジェクトである
        Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar =
            ((Microsoft.VisualStudio.CommandBars.CommandBars)FApplicationObject.CommandBars)["MenuBar"];

        // CommandBarControl は "Tools" メニュー項目
        CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];

        // CommandBarPopup はポップアップメニュー項目(ドロップダウンするメサブメニュー)
        CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

        try
        {
          // メニュー項目のコマンドのコレクションにコマンドを追加する
          // 59 はメニュー項目に表示する画像として Smiley 画像を指定する(詳しくは (*4))
          Command command = commands.AddNamedCommand2(FAddInInstance, "TagAddIn", "Tag プロパティの調整",
            "Tag プロパティの調整", true, 59, ref contextGUIDS,
            (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled,
            (int)vsCommandStyle.vsCommandStylePictAndText,
            vsCommandControlType.vsCommandControlTypeButton);

          if((command != null) && (toolsPopup != null))
          {
            // メニューバーにコマンド(メニュー項目)を追加する(1 は [ツール] メニュー項目の先頭を意味する。0 ではないことに注意)
            command.AddControl(toolsPopup.CommandBar, 1);
          }
        }
        catch(System.ArgumentException)
        {
        }
      }
    }

    //-----------------------------------------------------------------------------------
    // アドインを IDE からアンロードするときに呼び出されるメソッド
    // アドインマネージャで使用できるアドインからはずしたときにも発生する
    public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
    {
    }

    //-----------------------------------------------------------------------------------
    // IDE が保持するアドインのコレクションの内容を変更した時に呼び出されるメソッド
    public void OnAddInsUpdate(ref Array custom)
    {
    }

    //-----------------------------------------------------------------------------------
    // IDE の起動が終了した時に呼び出されるメソッド
    public void OnStartupComplete(ref Array custom)
    {
    }

    //-----------------------------------------------------------------------------------
    // IDE のシャットダウンを開始した時に呼び出されるメソッド
    public void OnBeginShutdown(ref Array custom)
    {
    }

    //-----------------------------------------------------------------------------------
    // コマンドに対する有効・無効などの状態を返すときに呼び出されるメソッド
    // commandName : コマンド名
    // neededText  : 要求する情報の種類をあらわす vsCommandStatusTextWanted enum 型
    // status      : コマンドの有効・無効をあらわす vsCommandStatus enum 型
    // commandText : テキストを受け取るバッファ
    public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
    {
      // 情報の種類の指定のない時
      if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
      {
        // コマンドの名前
        if (commandName == "TagAddIn.Connect.TagAddIn")
        {
          // コマンドはサポートする、また有効と設定する
          status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
          return;
        }
      }
    }

    //-----------------------------------------------------------------------------------
    // アドインを起動するコマンドを実行した時に呼び出されるメソッド
    // commandName   : コマンド名
    // executeOption : コマンドの実行方法をあらわす vsCommandExecOption enum 型
    // varIn         : コマンドに渡す引数
    // varOut        : メソッド実行後の戻り値
    // handled       : コマンドを処理した時 true
    public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
    {
      handled = false;

      // デフォルトの動作の時
      if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
      {
        if (commandName == "TagAddIn.Connect.TagAddIn")
        {
          this.SetTags(); // このアドインで実行するメソッド
          handled = true; // 処理済み
          return;
        }
      }
    }

    //-----------------------------------------------------------------------------------
    // アドインで実行するメソッド
    private void SetTags()
    {
      int tagIndex = 0;

      try
      {
        Window window = FApplicationObject.ActiveDocument.ActiveWindow;
        IServiceProvider serviceProvider = (IServiceProvider)window.Object;
        ISelectionService selectionService = (ISelectionService)serviceProvider.GetService(typeof(ISelectionService));

//      この行を生かすと、選択状態のコントロール数を表示する
//       MessageBox.Show(String.Format("現在 {0} 個のコントロールが選択されています",
//						selectionService.SelectionCount));

        // コントロールの選択は選択矩形を使わずに、[Ctrl] を押しながらクリックで 1 つずつ選択する
        // これで選択した順番に 0 からの追番になる
        foreach (IComponent component in selectionService.GetSelectedComponents())
        {
          // Form でない、UserControl でないとき
          if (!(component is Form) &&  !(component is UserControl))
          {
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(component);
            PropertyDescriptor prop = props["Tag"];

            if (prop != null)
            {
              prop.SetValue(component, tagIndex);
              ++tagIndex;
            }
          }
        }
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message);
      }
    }

  } // end of Connect class
} // end of namespace

コードの補足

(*1) ext_ConnectMode enum 型

定数 意味
ext_cm_AfterStartup 0 IDE 起動後に読み込んだ(たとえば、アドインマネージャを使って)
ext_cm_Startup 1 IDE の起動時に読み込んだ
ext_cm_External 2 IDE 以外の別のプログラムから読み込まれた
ext_cm_CommandLine 3 devenv コマンドを使って読み込んだ
ext_cm_Solution 4 アドインを必要とするソリューションをロードするときに読み込んだ
ext_cm_UISetup 5 コマンドボタンなどの UI から起動した

ext_cm_Startup の設定は避けたほうが安全だと思います。というのは、アドインにトラブルがあれば Visual Studio 自体が起動できなくなる可能性があります。もしそうなった場合は、.AddIn ファイルを削除して、Visual Studio を再起動してください。

ext_cm_AfterStartup はアドインマネージャで使用するアドインを有効にした時にこのモードになります。アドイン用メニュー項目がまだ追加されていない場合は、このモードを受け入れると、OnConnect メソッドが呼び出され、メニュー項目が追加されます。

ext_cm_UISetup はすでにアドイン用メニュー項目がある場合にこのモードになります。アドインマネージャでこのアドインが無効になっていない場合でもこのモードを受け入れるとアドインは有効になります。

 

(*2) アドインウィザードによるテンプレートコードでは ext_ConnectMode.ext_cm_UISetup の場合にだけ対応していますが、これはメニュー項目がある場合にのみ有効です。逆に言うと、まだメニュー項目がない場合はアドインを起動することはできないということになります。アドインを自作する場合はこれでもいいのですが、別のパソコンに持っていく場合には対応できません。そこで、上記のようなコードにしました。

 

(*4)
public Command object.AddNamedCommand2(
  AddIn                addInInstance,        // AddIn オブジェクト
  string               name,                 // コマンド名の省略形
  string               buttonText,           // メニュー項目またはツールボタンのキャプション
  string               tooltip,              // 同、ツールチップ
  bool                 mSOButton,            // MS-Office 画像の時 true(独自の画像の時 false)
  object               bitmap,               // 画像の ID
  ref object[]         contextUIGUIDs,       // コマンドを有効にする環境コンテキスト
  int                  vsCommandStatusValue, // vsCommandStatus enum 型の組み合わせ
  int                  commandStyleFlags,    // コントロールのスタイルを指定する vsCommandStyle enum 型
  vsCommandControlType controlType           // コントロールの種類を指定する vsCommandControlType enum 型
);

完全なコマンド名は、<アドインの名前空間>.<アドインのクラス名>.コマンド名の省略形 の書式になります。今回の場合は、"TagAddIn.Connect.TagAddin" です。したがって、コマンド名の省略形は "TagAddIn" となります。要するに、コマンド名の省略形を指定すれば、AddNamedCommand2 メソッドの内部で完全なコマンド名に変換するというわけです。

bitmap の 59 の意味は、「メニュー項目用ビットマップ」で詳しく説明します。


アドインのビルド

ここまでの手順が終わったところで、アドインをビルドします。ただし、デフォルトの状態では System.Windows.Forms.dll への参照がありませんので、プロジェクトに追加してください。準備がよければ、ビルドしてください。このとき、ソリューションエクスプローラ内のプロジェクト項目をマウスで右クリックすると表示されるコンテキストメニューの [ビルド] を使いましょう。

Note 上記のコードでは XML コメントを削除しましたので、そのままビルドすると怒られます。無視してもいいのですが、気になる人はプロジェクトの [プロパティ] を開いて、[ビルド]-[出力]-[XML ドキュメントファイル] のチェックをはずしてください。

アドインのビルドが正常終了したら、[ツール]-[アドインマネージャー] を選択すると表示されるダイアログボックスに作成したアドインがリストアップされるはずです。目的のアドインにチェックを入れて [OK] すると、[ツール] メニューの先頭のメニュー項目としてアドインを起動する項目が表示されます。続きは、「テスト用プロジェクト」を参照してください。

ここで重要なことを説明します。

アドインプロジェクトをビルドすると、プロジェクトを格納するフォルダ内の bin フォルダにアドイン用 .dll ファイルが作成されます。このとき、bin\debug フォルダ内にも同じ内容の .dll ファイルが作成されます。bin フォルダ内のものは、先に説明した MyAddIn1 - For Testing.AddIn の <assembly> に設定されているものです。つまり、これはテスト用アドインです。

Note テスト用と書きましたが、本番用として利用してもかまいません。内容はまったく同じですから。

のちに説明しますが、テスト段階におけるアドインの登録は bin フォルダのものです。したがって、アドインの内容を変更して再ビルドするときはすでに Visual Studio に組み込まれた状態になっているため、古い .dll ファイルを残しておくと再ビルドの妨げになります。そこで、一旦 Visual Studio を終了したあと、bin フォルダ内の .dll ファイルを削除し、あらためて Visual Studio を起動しなければなりません。

Note アドインマネージャを開いて、目的のアドインのチェックをはずして無効にしてもすでに配置済みのアドインを削除することはできません。アドインマネージャでチェックをはずすと、アドインの OnDisconnection イベントが発生しますので、ここでアドインを削除するコードを書けばいいはずだと考え、いろいろと考えてみましたが、アドインを削除する手順が分かりませんでした。もちろん、アドインを無効にしたければ .AddIn ファイルを削除するか、拡張子を変更して Visual Studio が認識できないようにすればいいのですが、Visual Studio を起動したままでは無理なようです。

さて、ビルドが終わったところで、アドインをテストしなければなりません。しかし、アドインはそれ自体を起動することはできませんので、テスト用のプロジェクトを作成し、その上でアドインを実行することになります。続きは、「テスト用プロジェクト」を参照してください。


テスト用プロジェクト

現在のソリューションに新しいプロジェクト(Windows フォームアプリケーション)を追加します。フォームに 3 つほどのボタンコントロールを配置してください。まず、ボタンの Tag プロパティには何も設定されていないことを確認してください。次に、[Ctrl] を押しながら複数のボタンをマウスでクリックしたあと、アドインを起動してください。ボタンをクリックした順番で Tag プロパティが 0 からの追番になっているはずです。

Note 複数のボタンを選択する時、マウスのドラッグで範囲を指定する方法は可能ですが、この場合は Tag プロパティが期待通りの順番にならない場合があります。

アドインをテストするときに何らかの不都合が発生した場合は、「アドインのビルド」に戻ってください。


メニュー項目用ビットマップ

まず、コマンドバー "command bar" という言葉の説明をしておきましょう。これはメニューバーおよびツールバーに対する総称と考えてください。コマンドはたとえば、メニュー項目を選択した時に IDE が受け取るコマンド(Click イベント)です。つまり、アドインを起動するためのキッカケはメニュー項目またはツールボタンを選択することで得られます(一般的にはですが)。

さて、アドインを起動するためのメニュー項目やツールバーボタンを追加する場合、識別を容易にするために画像を表示することができます。上記のサンプルコードの OnConnect メソッド内に "59" という数値がありますが、これはコマンドバーのための画像データの ID です。

.Net Framework SDK の「方法 : アドインの既定のアイコンを変更する」の項の中に、「既定のアイコン インデックス番号 (59) を、Microsoft.VisualStudio.CommandBars アセンブリに含まれる ...」とありますが、標準のビットマップは 3,000 種類ほど含まれているようです。どのような画像が含まれているかを調べるには Office 対応のアドインを作る必要がありますが、以下のサイトで画像の一覧を公開していますので、参考にしてください。

WEB サイトのタイトルは、"Visual Studio 2005 Tools for Office CommandBarButton FaceId Property" です。

http://www.kebabshopblues.co.uk/2007/01/04/visual-studio-2005-tools-for-office-commandbarbutton-faceid-property/

アドイン用ビットマップを指定するときは標準のビットマップの中から好みのビットマップの ID 番号を指定するだけですから、標準のビットマップを使う方法が簡単です。しかし、独自のビットマップを指定したい場合はチョットした手続きが必要となります。

.Net Framework SDK の「方法 : アドイン ボタンにカスタム アイコンを表示する」の中に独自のビットマップを設定する方法が書いてあります。と言いたいところですが、こんな面倒なことをさせるなよといいたくなるほどの面倒くささです。サンプルコードもあって結構詳しく書いてありますから興味のある人は読んでください。なお、「アドインのサンプル」は独自の画像を指定する例を含みます。


アドインの格納

アドインをどこかから手に入れたとか、アドインを自作した場合でも別のパソコンにインストールしたい場合、アドインをどこに格納すればいいのでしょうか。いずれにしろ、アドインは Visual Studio IDE が認識できる場所に格納しなければなりません。

IDE のメニュー [ツール]-[オプション]-[アドイン/マクロセキュリティ] を開くと、下図のようなダイアログボックスが開きます。

AddIn10

[アドインファイルパス] の環境変数の意味は次のとおりです。ただし、以下は Windows Vista/7 の場合です。Windows XP の場合は、"Users" の部分を "Documents and Settings" に、また "Documents" を "My Documents" と読み替えてください。

定義済みのトークンパス
%ALLUSERSDOCUMENTS%C:\Users\Public\Documents
%ALLUSERSPROFILE%C:\Users\Public
%APPDATA%C:\Users\<username>
%VSAPPDATA%C:\Users\<username>
%VSCOMMONAPPDATA%C:\Users\Public
%VSMYDOCUMENTS%C:\Users\<username>\Documents\Visual Studio 2010

アドインを作成するときの .AddIn ファイルのデフォルトの格納場所は、%VSMYDOCUMENTS%\AddIns です。

さて、上図を見ると、[追加] ボタンがあることに気付きます。これを利用すると、アドインの検索場所として、ユーザーは任意のディレクトリを指定できます。アドインを自作する場合は Visual Studio のデフォルトの状態でいいと思いますが、それ以外の場合は、「アドインの配布」を参照してください。


アドインの登録

アドインは Visual Studio の IDE に組み込んで使うものですから、IDE がその存在を知らなければなりません。その処理をアドインの登録と呼びます。

アドインを自作する場合はアドインをビルドすると自動的に使える状態になります。それ以外の場合は、「アドインの配布」を参照してください。


アドインの削除

.Net Framework SDK の「方法 : アドインを非アクティブにして削除する」の項の中に、アドインマネージャにリストアップされたアドインのチェックをはずすとアドインをアンロードできるとあります。しかし、「アンロード」はすでに作成済みのアドインを起動する UI(メニュー項目やツールボタン)を削除することを意味しません。

アドインを起動するためのメニュー項目を削除するにはアドインをそのように作らなければなりません。つまり、アドインマネージャでアドインのチェックをはずすとアドインの OnDisconnect メソッドが呼び出されますから、その中で処理する必要があります。と書きたいところですが、OnDisconnection イベント内でどんなコードを書けばアドイン用の UI(メニュー項目とかツールボタン)を削除できるのかが不明です。.NET Framework SDK のどこにも解説がないばかりか、機能自体がないのではないかと思います。

Note RemoveCommandBars メソッドや Delete メソッドがアドインに関係する一部のクラスにあって、アドインを削除する機能を付けようとした形跡はありますが、有効ではないようです。

さて、アドインを IDE から削除するには、対応する .AddIn ファイルを削除するか、.AddIn ファイルのファイル名を変更するか、または IDE が認識できないディレクトリに移動します。アドインのアセンブリも不要であれば、.dll ファイルを削除してください。なお、アドインを登録すると、以下に示すレジストリにアドインに関する情報が記録されますが、.AddIn ファイルを削除したあと、IDE を一旦終了すると自動的に削除されるようです。

    HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\PreloadAddinStateManaged

このレジストリをどのように使っているかは不明です。本来、必要ないはずだと思うのですが、Visual Studio の都合なのでしょうか。一つ考えられることは、.Net Framework 1.0/1.1 の時代はレジストリに登録していたようですから、そのときのナゴリなのかもしれません。いずれにしろ、.Net Framework 2.0 以後では気にする必要はないと思います。


アドインの配布

作成したアドインを他者に配布、あるいは別のパソコンにインストールする手順を説明します。アドインのアセンブリはどこに格納してもかまいません。私は、Visual Studio をインストールしたディレクトリの下に下記のサブディレクトリを作って格納しています。

    C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\AddIns

対応する .AddIn ファイルも同じディレクトリ内に格納してください。.dll ファイルへのパスは、<Assembly> 〜 </Assembly> で指定しますが、.AddIn ファイルと同じディレクトリに格納する場合はフルパスにする必要はありません。なお、このディレクトリに格納する場合は、「アドインの格納」で説明したように、[ツール]-[オプション] で、このディレクトリへのパスを登録しておかなければなりません。


アドインのサンプル

Microsoft のサイトでアドインのサンプルを公開しています。タイトルは、"Visual Studio.NET 2003 Automation Samples" です。以下のサイトにあります。"VSAutoSamples" はすべてのサンプルを含みます。Visual Studio 2003 対応ですが、2010 の場合と基本的には同じです。ただし、コードは C# だけでなく、VB や C++ も含みますので、すべてを使えるかどうかはユーザーさんの技量次第です。

http://www.microsoft.com/downloads/en/details.aspx?familyid=3ff9c915-30e5-430e-95b3-621dccd25150&displaylang=en

Note 紹介しておいてこう言うのも変ですが、参考にはなってもそれ以上ではありません。

以下は私が作成したアドインですが、いくつかは実用的に使えると思います。

  1. 著作権をあらわすテキストをソースファイルの先頭に挿入する(CopyrightAddIn)
  2. Visual Studio IDE のコマンドおよびメニュー項目を列挙する(CommandAddIn)
  3. "///" タイプのコメント行を削除する(DeleteComment)
  4. "#region" 行を削除する(DeleteRegion)
  5. コードエディタのコンテキストメニューにアドイン用メニュー項目を追加する(ContextMenuAddIn)
  6. 標準ツールバーにアドインを起動するツールボタンを追加する(ToolButtonAddIn)
  7. アドイン用ツールバーを追加する(ToolBarAddIn)
  8. 出力ウインドウのペインの名前を列挙する(LifeCycleAddIn)

以下の ZIP ファイルはアドインのサンプルソリューションのソースファイルを含みます。ただし、暗号化していますので、解凍するにはパスワードが必要です。私が公開している NETClass および WPFClass のいずれのユーザーさんはパスワードが同じですから、ご利用になれます。

AddInSource.zip(207,786 bytes)

以下は、.dll ファイルと .addin ファイルのみを含みます。フリーウエアですからどなたでもご利用になれます。インストールは「アドインの配布」を参考にして実行してください。

AddIn.zip(31,444 bytes)

それぞれのアドインの概要は ZIP ファイルに含まれる Readme.txt を参照してください。

−以上−