August 2017

Volume 32 Number 8

Visual Studio - Visual Studio の複数バージョン向け拡張機能の作成

Carlos Quintero | August 2017

拡張機能 (パッケージ、アドイン、テンプレートなど) の開発者にとって、Visual Studio の新しいバージョンのリリースは毎回が試練です。たとえば、Visual Studio 2010 では新しく VSIX (Visual Studio Installer for eXtensions) ファイルが導入され、Visual Studio 2012 では淡色/濃色テーマが導入されました。また、Visual Studio 2015 ではアドインがなくなりました (アドイン マネージャーもなくなりました)。さらに、新しい Visual Studio バージョンが登場するたびに、新しい SDK、新しい拡張アセンブリ、新しい API などがリリースされていることは言うまでもありません。Visual Studio 2017 では、この試練がさらに巨大なものになっています。というのも、セットアップがワークロードと個別のコンポーネントに基づくモジュール式となり、VSIX 配置方法で使用するマニフェストが新しいバージョンになったためです。一部の開発者 (特に、マイクロソフト所属の開発者) は Visual Studio バージョンごとに新しい拡張機能を個別にリリースしています。しかし、ほとんどの開発者が好むのは、1 つの拡張機能を更新してリリースし、広範な Visual Studio バージョンに対応できるようにする方法でしょう。

今回は、これを実現する方法を説明します。説明では、最も一般的なシナリオである、マネージ言語 (今回は C#) で作成して VSIX ファイルとして配置する、コマンドを含むパッケージを取り上げます。

達成すべき目標は以下のとおりです。

  • 1 つの Visual Studio プロジェクトを使用してパッケージを作成する。
  • Visual Studio 2017 を使用して開発とデバッグを行う。
  • ビルドの結果としてパッケージ DLL を 1 つ生成する。
  • この DLL ファイルを 1 つの VSIX ファイルの内部に配置する。
  • この VSIX ファイルを Visual Studio 2017 および以前のさまざまなバージョン (2015、2013 など) にインストールできるようにする。

DLL ファイル (パッケージ) と VSIX ファイル (パッケージを配置する手段) という 2 つの成果物が必要になります。そのため、それぞれについて個別に説明していきます。DLL と VSIX がインストール時や実行時にどのように動作するかを説明した後、それぞれの開発方法について説明します。

VSIX ファイル

先ほど説明したように、VSIX は Visual Studio 拡張機能をインストールするための配置方法として Visual Studio 2010 で導入されました。それ以来、好んで利用されています。VSIX ファイルは .vsix という拡張子を持ち、さまざまな方法でインストールできます。VSIX が Visual Studio Marketplace (以前の Visual Studio ギャラリー) に公開されていて、自身の Visual Studio バージョンおよびエディションと互換性がある場合、[拡張機能と更新プログラム] ダイアログを使用してインストールできます。[ツール] メニューで [拡張機能と更新プログラム] をクリックし、[オンライン]、[Visual Studio Marketplace] の順に進みます (図 1 の [拡張機能と更新プログラム] ダイアログ ウィンドウを参照)。

[拡張機能と更新プログラム] ダイアログ ウィンドウ
図 1 [拡張機能と更新プログラム] ダイアログ ウィンドウ

VSIX ファイルをダブルクリックしてもかまいません。この方法では、.vsix ファイル拡張子に関連付けられた Visual Studio ランチャー (C:\Program Files (x86)\Common Files\Microsoft Shared\MSEnv\VSLauncher.exe) が実行され、インストールされている最新の Visual Studio バージョンの VSIXInstaller.exe ユーティリティが検出されます (すべての旧バージョンにインストールできるようにするために最新バージョンが必要です)。次に、VSIX インストーラーによって、図 2 の [VSIX インストーラー] ダイアログが表示されます。ここで、拡張機能のインストール先とする、互換性のある Visual Studio バージョンとエディションを選択できます。

VSIX インストーラー
図 2 VSIX インストーラー

VSIX ファイルをプログラムからインストールすることもできます。それには VSIXInstaller.exe ユーティリティを使用して、コマンドライン オプションで対象の Visual Studio バージョン (2017、2015 など) とエディション (Community、Professional など) を指定します。このユーティリティは、お使いの Visual Studio のインストール フォルダーのサブフォルダー Common7\IDE にあります。

いずれの場合でも、Visual Studio または VSIXInstaller.exe ユーティリティでは、VSIX ファイルがサポートしている Visual Studio のバージョンとエディションを認識する必要があります。この情報は、VISX ファイルに含まれるマニフェスト ファイルでわかります。実は、VSIX ファイルは .zip ファイルです。そのため、.vsix ファイル拡張子を .zip に変更してファイルを開くと、そのコンテンツを確認できます (図 3「VSIX ファイルのコンテンツ」を参照)。

VSIX ファイルのコンテンツ
図 3 VSIX ファイルのコンテンツ

ご覧のように、中にはいくつかのファイルが含まれています。.dll ファイルはパッケージ DLL です。.pkgdef ファイルは、Visual Studio が DLL をパッケージとして認識できるようにするいくつかのキーを Windows レジストリに追加するために、インストール時に使用されます。[Content_Types].xml ファイルは、ファイル拡張子 (.dll、.json など) ごとにコンテンツの種類を記述します。cata­l­og.json ファイルと manifest.json ファイルは Visual Studio 2017 に必須です。exten­sion.vsixmanifest ファイルは拡張機能の名前、バージョンのほか、サポートしている Visual Studio のバージョンとエディションを記述します。

extension.vsixmanifest ファイルを展開してテキスト エディターで開くと、ファイルのコンテンツを確認できます。このコンテンツは、図 4「マニフェスト ファイルのコンテンツ」のようになります。

マニフェスト ファイルのコンテンツ
図 4 マニフェスト ファイルのコンテンツ

ご覧のように、マニフェストでは InstallationTarget XML 要素を使って、サポートする Visual Studio エディションが記述されます。ここで、"Microsoft.Visual­Studio.Pro" という値は、Professional エディション以上 (Premium、Ultimate、Enterprise およびそれに類するエディション) をサポートとしていることを表します。さらに、Community エディションもサポートされている点に注意してください。Community エディションは、一部の機能が提供されておらず、ライセンス制限もいくつかありますが、基本的には Professional エディションです。また、サポートしている Visual Studio バージョンの範囲も記述されます (10.0 (2010)、11.0 (2012)、12.0 (2013)、14.0 (2015)、15.0 (2017))。

ユーザー単位拡張機能の VSIX ファイルをインストールすると (Visual Studio と VXIS インストーラーのどちらを使用する場合でも)、VSIX ファイルに含まれるファイルが展開され、C:\Users\<ユーザー>\AppData\Local\Microsoft\VisualStudio\<バージョン番号>\Extensions\<ランダム フォルダー> にコピーされます。<バージョン番号> には、"実験的なインスタンス" (後で説明) を表す "Exp" サフィックスを追加できます。Visual Studio 2017 の場合は、インストールされている Visual Studio の "インスタンス ID" も含めます。このインスタンス ID は Visual Studio インストール時にランダムに生成されるもので、同じ Visual Studio バージョン (2017) の異なるエディションをサイドバイサイドでインストールできるようにするために追加されました。これは、以前のバージョンではできなかった機能です。PC 全体で使用される拡張機能では、サブフォルダー Common7\IDE\Extensions が使用されます。いずれの場合でも、拡張機能に対して Visual Studio バージョンそれぞれが独自のフォルダーを使用することに留意してください。

すべての Visual Studio バージョンが同じマニフェスト形式をサポートしていれば助かるのですが、残念ながらそのようにはなっていません。Visual Studio 2010 では、VSIX とバージョン 1 のマニフェストが導入されました。Visual Studio 2012 で導入されたバージョン 2 のマニフェストは、バージョン 1 とまったく異なり、互換性がありません。しかし、Visual Studio 2012、2013、2015 はいずれもバージョン 2 をサポートする一方で、バージョン 1 のマニフェストも引き続きサポートしています。そのため、バージョン 1 のマニフェストを含む VSIX ファイルを作成して、Visual Studio 2010 ~ Visual Studio 2015 を対象にすることができます。しかし、Visual Studio 2017 はバージョン 1 とバージョン 2 のいずれもサポートしていません。代わりに、バージョン 3 のマニフェストが必要になります。さいわい、バージョン 3 は PackageManifest XML 要素の Version 属性に引き続き値 "2.0.0.0" を使用でき、<Prerequisites> という XML 要素を追加しただけのものです (なお、VSIX ファイルに catalog.json と manifest.json という 2 つの新しいファイルも追加します)。したがって、バージョン 3 はバージョン 2 と完全な旧バージョンとの互換性があります。バージョン 2 は Visual Studio 2012、2013、2015 でサポートされていますが、Visual Studio 2010 ではサポートされていません (Visual Studio 2010 がサポートしているのはバージョン 1 だけです)。そのため、1 つの VSIX ファイルで Visual Studio 2010 ~ 2017 をサポートすることはできません。ここからは、Visual Studio 2010 をサポートすることは諦め、Visual Studio 2012、2013、2015、および 2017 をサポートする VSIX ファイルについて説明を続けます。

パッケージ DLL

マネージ Visual Studio パッケージとは、Microsoft.VisualStudio.Shell.Package を継承したクラスを含む DLL です。この DLL は、ビルド時に .pkgdef ファイルを生成するのに役立つ特定の属性で修飾されています (既に述べたように、.pkgdef ファイルは VSIX ファイル内や拡張機能のインストール フォルダー内にあります)。.pkgdef はスタートアップ時 (以前の Visual Studio バージョンの場合) またはインストール時 (Visual Studio 2017 バージョン 15.3 の場合) に使用され、DLL を Visual Studio のパッケージとして登録します。DLL が登録されたら、Visual Studio ではあるタイミングでパッケージの読み込みを試みます。そのタイミングとは、スタートアップ時か、パッケージで遅延読み込みを使用する場合は Visual Studio のなんらかのコマンドの実行時です (ベスト プラクティスは後者です)。マネージ DLL を読み込んでパッケージを初期化する間に、3 つの処理が行われます。Microsoft .NET Framework バージョンの共通言語ランタイム (CLR) による DLL の読み込み、.NET Framework で提供されるいくつかの DLL の使用、Visual Studio で提供されるいくつかの DLL の使用です。それぞれの処理について順に説明していきましょう。

.NET Framework は、CLR とライブラリ (基底クラスと追加のライブラリの両方) を組み合わせたものです。CLR はランタイム (JIT コンパイラ、ガベージ コレクターなど) で、マネージ DLL を読み込みます。かつて、.NET Framework バージョン 1.0、1.1、2.0 (Visual Studio.NET 2002、Visual Studio.NET 2003、Visual Studio 2005 で使用) では、それぞれに固有の CLR バージョン (1.0、1.1、2.0) が用意されていました。しかし、Visual Studio 2008 で使用された .NET Frameworks 3.0 および 3.5 では、新しい CLR バージョンは導入されず、.NET Framework 2.0 とまったく同じ CLR 2.0 が引き続き使用されました。Visual Studio 2010 では .NET Framework 4 と CLR 4.0 が導入されましたが、それ以降の新しい .NET Framework 4.x でも CLR 4.0 が使用されています (ただし、.NET Framework 4 の CLR 4.0 そのものを再利用するのではなく、旧バージョンとの互換性があるバージョンに "インプレースで" 置き換えています)。Visual Studio 2012 以降はいずれも CLR 4.0 が使用されているため、拡張機能の DLL のサポート対象が Visual Studio 2012、2013、2015、および 2017 の場合、CLR のバージョンは問題になりません。

.NET Framework を構成しているもう 1 つの要素がライブラリです。ライブラリは Visual Studio プロジェクトによって参照される DLL で、実行時に使用されます。複数バージョンの Visual Studio をサポートする単一の拡張機能を開発するには、サポート対象のうち最も低いバージョンの Visual Studio に既定でインストールされている最高の .NET Framework を使用する必要があります。つまり、Visual Studio 2012 以降をサポートする場合は、.NET Framework 4.5 を使用する必要があります。たとえば、Visual Studio 2013 で導入された .NET Framework 4.5.1 は使用できません。というのも、このバージョンで導入された DLL はいずれも Visual Studio 2012 しかインストールされていない PC には存在しないためです。その DLL が本当に必要でない限りは、拡張機能を使用するために .NET Framework 4.5.1 のインストールをユーザーに強制すべきではありません (強制すると、売り上げ/ダウンロード数の伸び悩みやサポートのトラブルにつながるおそれがあります)。

拡張機能には Visual Studio で提供される DLL も必要です (通常、Microsoft.VisualStudio.* という名前です)。実行時、Visual Studio では、Common7\IDE フォルダーとそのサブフォルダーの Common7\IDE\PublicAssemblies、Common7\IDE\PrivateAssemblies など、いくつか既知の場所やグローバル アセンブリ キャッシュ (GAC) から DLL を検索します。.NET Framework 4.x の GAC は C:\Windows\Microsoft.NET\assembly にあります(別の GAC が C:\Windows\assembly にありますが、これは以前の .NET Framework 用です)。Visual Studio 2017 では、さらに独立性の高いインストールを利用するようになっており、GAC の代わりに先述のフォルダーを使用します。

VSIX ファイルを開発、生成するときに従うべきいくつか重要な原則があります。1 つ目の原則は、拡張機能がサポートする最も低いバージョンの Visual Studio で提供されるバージョンのリソースを使用することです。つまり、Visual Studio 2012 以降をサポートする場合は Visual Studio 2012 バージョン (以前) で提供されるアセンブリや拡張 API のみを使用する必要があります。Visual Studio 2013 以降に導入された DLL を拡張機能で使用する場合、その拡張機能は Visual Studio 2012 しかインストールされていない PC では機能しません。2 つ目の原則は、拡張機能では Visual Studio DLL を先述の場所 (Visual Studio のフォルダーや GAC) や拡張機能のインストール フォルダーに配置してはいけないことです。Visual Studio DLL はサポート対象の Visual Studio から提供されるものなので、VSIX ファイルに含めてはいけません。

多くの Visual Studio DLL には、Microsoft.VisualStudio.Shell.11.0.dll や Microsoft.VisualStudio.Shell.Immutable.10.0.dll のように、バージョン番号 (8.0 ~ 15.0) が名前に含まれています。この番号は、その DLL が導入された Visual Studio バージョンを識別しやすくするためのものですが、騙されないように注意してください。これは名前であって、Visual Studio バージョンではありません。たとえば、Microsoft.Visual.Studio.Shell.11.0.dll には 4 つのバージョン (11.0.0.0、12.0.0.0、14.0.0.0、15.0.0.0) があり、それぞれ Visual Studio バージョン (2012、2013、2015、2017) で提供されています。最初の 3 つ (11.0.0.0 ~ 14.0.0.0) は対応する Visual Studio によって GAC にインストールされますが、Visual Studio 2017 で使用される 4 つ目のバージョン 15.0.0.0 は Common\IDE\PrivateAssemblies フォルダーにインストールされます。

Visual Studio 2012 以降をサポートする拡張機能は (1 つ目の原則で述べたとおり) バージョン 11.0.0.0 の Visual Studio アセンブリを使用する必要があるため、参照 Microsoft.Visual.Studio.Shell.11.0.dll はバージョン 11.0.0.0 である必要があります。しかし、このバージョンは Visual Studio 2013 以降ではインストールされません (Visual Studio 2013 以降ではバージョン 12.0.0.0 がインストールされます)。加えて、拡張機能で Visual Studio DLL を配置する必要がない (2 つ目の原則) 場合、拡張機能でその Visual Studio DLL を使用しようとしたら、拡張機能にエラーは発生しないのでしょうか。 答えは、「発生しません」です。これは、.NET Framework のアセンブリ バインディングのリダイレクト メカニズムによって、開発者が「このバージョンのアセンブリの要求があった場合は、こちらの新しいバージョンを使用する」などの規則を指定できるためです。 もちろん、新しいバージョンには以前のバージョンとの完全な互換性がなくてはなりません。アセンブリを以前のバージョンから別のバージョンにリダイレクトするには、いくつか方法があります。その一例はこうです。実行可能ファイル (ファイル拡張子 .exe) では、リダイレクトを指定する付属の構成ファイル (ファイル拡張子 .exe.config) を指示できます。そのため、Visual Studio インストール フォルダーの Common7\IDE に移動すると、Visual Studio の devenv.exe 実行可能ファイルと devenv.exe.config ファイルが見つかります。テキスト エディターで .config ファイルを開くと、次のようにアセンブリのリダイレクトが多数含まれていることがわかります。

<dependentAssembly>
  <assemblyIdentity
    name="Microsoft.VisualStudio.Shell.11.0"
    publicKeyToken="b03f5f7f11d50a3a"
    culture="neutral"/>
  <bindingRedirect
    oldVersion="2.0.0.0-14.0.0.0
    newVersion="15.0.0.0"/>
</dependentAssembly>

Visual Studio 2017 (15.0) にはこのように、Microsoft.VisualStudio.Shell.11.0 に関して古い 2.0.0.0 ~ 14.0.0.0 のバージョンが要求される場合には代わりに新しい 15.0.0.0 バージョンを使用することを記述したアセンブリ バージョンのリダイレクトがあります。これが、Visual Studio 2013 以降で Microsoft.VisualStudio.Shell.11.0 バージョン 11.0.0.0 を参照する (その Visual Studio のバージョンを参照しない) 拡張機能を利用できるしくみです。

拡張機能の開発

実行時の動作がわかったので、パッケージの開発に取りかかりましょう。概要はこうです。Visual Studio 2017 で、Visual Studio バージョン 12.0 ~ 15.0 をサポート対象とするマニフェストを含む VSIX プロジェクトを作成します。VSIX ファイルにはパッケージとコマンドを含め、参照は Visual Studio 2012 にインストールされるバージョン 11.0.0.0 (以下) だけを使用します。

この時点で、開発用 PC にどのバージョンの Visual Studio をインストールすべきか迷うかもしれません。ベスト プラクティスは、開発用 PC を 2 台用意することです。1 台には、(ディスク容量に十分な空きがある場合) すべての Visual Studio バージョン (2012、2013、2015、2017) をインストールします。同じ PC にすべての Visual Studio バージョンが共存できるため、それらの Visual Studio を使用して開発中にテストできます。以前の Visual Studio バージョンではエディション違いの共存はできませんでしたが、Visual Studio 2017 では、Community、Professional、Enterprise など、エディション違いも同時に共存できるようになりました。空き領域に懸念がある場合は、以前のバージョンのコンポーネントを最小限インストールするか、サポート範囲の中間となるバージョン (2013 または 2015) を省略します。

もう 1 台には、Visual Studio 2017 だけをインストールします。2 台目としてより望ましいのは、リリース用に拡張機能をビルドするための、Visual Studio バージョンを何もインストールしていない (Build Tools 2017 だけをインストールした) ビルド サーバーにすることです。この方法は、以前の Visual Studio バージョンによってインストールされたフォルダーの DLL やその他の依存関係を誤って使用しないようにするうえで役立ちます。また、Visual Studio 2012 だけがインストールされた PC で開発やビルドを行えば安全ではないかと思われるかもしれません。しかし、それはできません。Visual Studio 2017 用の VSIX ファイルを生成する (バージョン 3 のマニフェストを作成し、catalog.json ファイルと manifest.json ファイルを追加する) には、Visual Studio 2017 の Visual Studio SDK 15.0 か、Visual Studio 2015 の Visual Studio SDK 14.0 (と少しの手間) が必要です。Visual Studio 2013 の Visual Studio SDK 12.0 や Visual Studio 2012 の Visual Studio SDK 11.0 では Visual Studio 2017 用の VSIX ファイルは生成できません。

(本格的な) テストを実施するうえでのベスト プラクティスは、Visual Studio バージョンごとに独立した PC (仮想またはクラウドベース) を使用することです (つまり、Visual Studio 2012 ~ Visual Studio 2017 で拡張機能を個別にテストするには 4 台の PC が必要になります)。このベスト プラクティスに従ったことで、今回用のコード サンプルに含まれるエラーをいくつか見つけることができました。

パッケージ (または他の種類の拡張機能) の作成に使用する Visual Studio 2017 プロジェクト テンプレートを入手するには、"Visual Studio 拡張機能の開発" ワークロードが必要です。Visual Studio 2017 の初回インストール時にこのワークロードをインストールしなかった場合は、C:\Program Files (x86)\Microsoft Visual Studio\Installer フォルダーに移動して vs_Installer.exe を起動します。そこで [変更] ボタンをクリックして一覧の下部にある目的のワークロードを選択します。

[ファイル]、[新規作成]、[プロジェクト] メニューの順にクリックして、新しい VSIX プロジェクトを作成します。テンプレートを [Visual C#]、[Extensibility] (拡張性) の順に選択し、上部のドロップダウン リストで [.NET Framework 4.5] が選択されていることを確認します。[VSIX Project] (VSIX プロジェクト) テンプレートを選択します。プロジェクトに VSIXProjectVS2012_2017 という名前を付けます。source.extension.vsixmanifest ファイルをダブルクリックし、カスタム エディターで開きます。[Metadata] (メタデータ) タブで、製品名、作成者、バージョンなどを設定します。[Install Targets] (対象のインストール) タブで、[Edit] (編集) ボタンをクリックし、[Microsoft.VisualStudio.Pro] 識別子を選択します (この値は Community エディションも対象としています。Community エディションは基本的には Professional エディションと同じです)。また、対象インストール範囲を [11.0,15.0] に設定します (図 5 参照)。角かっこは、その値を含むことを意味します。丸かっこは、その値を除外することを意味します。かっこを使用して、[11.0,16.0) と設定することもできます。ビルド番号 (15.0.26208.1 など) を使用して、マイナー バージョン (15.3 など) を対象とすることもできます。

インストールの対象
図 5 インストールの対象

[Dependencies] (依存関係) タブで、すべての項目を削除します。[Prerequisites] (前提条件) タブで、[Edit] (編集) ボタンをクリックして、開発する拡張機能で必要最小限の Visual Studio 2017 コンポーネントを設定します。この例で必要なのは、Visual Studio のコア エディターだけです。このセクションは、Visual Studio 2017 とバージョン 3 のマニフェストで新しく導入されました。そのため、バージョン 15.0 だけに適用されます (図 6「前提条件」参照)。

前提条件
図 6 前提条件

ソリューション エクスプローラーで VSIX プロジェクトにパッケージを追加します。それには、VSIX プロジェクトを右クリックして、[追加]、[新しい項目] メニューをクリックし、[新しい項目の追加] ダイアログを表示します。[Visual Studio C# アイテム]、[Extensibility]、[VSPackage] ノードの順に移動して、[Visual Studio Package] (Visual Studio パッケージ) テンプレートを選択し、MyPackage.cs という名前にします。次に、パッケージにコマンドを追加します。それには、先ほどの手順の操作を繰り返しますが、今回は [Custom Command] (カスタム コマンド) テンプレートを選択します。このテンプレートの名前は MyCommand1.cs とします。

使用する依存関係を必要最小限に抑えるという原則に従い、MyPackage.cs と MyCommand1.cs のソース コードから、使用しない (灰色表示の) 名前空間を削除します。次に、ソリューション エクスプローラーの VSIX プロジェクト ノードを右クリックして、[ソリューションの NuGet パッケージの管理] エントリをクリックします。[インストール済み] セクションで、すべてのパッケージを次に示す順にアンインストールします。

Microsoft.VisualStudio.Shell.15.0
Microsoft.VisualStudio.Shell.Framework
Microsoft.VisualStudio.CoreUtility
Microsoft.VisualStudio.Imaging
Microsoft.VisualStudio.Shell.Interop.12.0
Microsoft.VisualStudio.Shell.Interop.11.0
Microsoft.VisualStudio.Shell.Interop.10.0
Microsoft.VisualStudio.Threading
Microsoft.VisualStudio.Shell.Interop.9.0
Microsoft.VisualStudio.Shell.Interop.8.0
Microsoft.VisualStudio.TextManager.Interop.8.0
Microsoft.VisualStudio.Shell.Interop
Microsoft.VisualStudio.TextManager.Interop
Microsoft.VisualStudio.Validation
Microsoft.VisualStudio.Utilities
Microsoft.VisualStudio.OLE.Interop

(Visual Studio SDK である Microsoft.VSSDK.BuildTools パッケージはアンインストールしないでください)

ソリューション エクスプローラーのプロジェクトの [参照] ノードで、System と System.Design を除く残りの参照 (NuGet パッケージとして取得されなかった参照) をすべてアンインストールします。これでソリューションをリビルドできます。コンパイル エラーが発生しますが、図 7 に示す参照を追加することで解消できます。

図 7 Visual Studio 2012 の参照

アセンブリ名 アセンブリ バージョン Visual Studio 2012 SDK サブフォルダー
Microsoft.VisualStudio.OLE.Interop 7.1.40304.0 v2.0
Microsoft.VisualStudio.Shell.Interop 7.1.40304.0 v2.0
Microsoft.VisualStudio.Shell.Interop.8.0 8.0.0.0 v2.0
Microsoft.VisualStudio.Shell.Interop.9.0 9.0.0.0 v2.0
Microsoft.VisualStudio.Shell.Interop.10.0 10.0.0.0 v2.0
Microsoft.VisualStudio.Shell.Immutable.10.0 10.0.0.0 v4.0
Microsoft.VisualStudio.Shell.11.0 11.0.0.0 v4.0

残念ながら、マイクロソフトは Microsoft.VisualStudio.Shell.11.0 の公式 NuGet パッケージを提供していません (ただし、非公式 NuGet VSSDK.Shell.11 パッケージは存在します)。PC に Visual Studio 2012 がインストールされている場合 (拡張機能がサポートする最小バージョンが Visual Studio 2012 の場合はインストールしておく必要があります)、前に説明したように GAC から取得できます。または、Visual Studio 2012 SDK (bit.ly/2rnGsfq) をインストールすることで、必要なすべてのアセンブリを取得できます。アセンブリは、C:\Program Files (x86)\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Common\Assemblies フォルダーの v2.0 サブフォルダーと v4.0 サブフォルダーに含まれています。表の最後の列に、各アセンブリが含まれる Visual Studio 2012 SDK のサブフォルダーを示しています。

非公式の NuGet パッケージや特定のローカル フォルダー (Visual Studio SDK または Visual Studio インストールのフォルダー) との依存関係を避けるうえで最適な方法は、アセンブリを取得して、プロジェクトのルート フォルダーの下に VS2012Assemblies という名前のフォルダーを作成することです。その後、そのフォルダーに DLL をコピーして、そこから DLL を参照します (プロジェクトの参照マネージャー ダイアログの [参照] ボタンを使用)。ソース コード管理に VS2012Assemblies フォルダーを追加し、DLL がそこに追加されていることを確認します (通常、ソース コード管理ツールでは、既定で DLL が追加されることはありません)。したがって、この時点で、必要な Visual Studio アセンブリはソース コードの一部となっています。

VSIX ファイル (および出力フォルダー) にアセンブリ参照を含めないという原則に従うため、各参照を選択し、[プロパティ] ウィンドウで [ローカルにコピー] プロパティが False に設定されていることを確認します。この時点で、エラーが発生することなくソリューションをリビルドできます。エクスプローラーで、出力フォルダーに移動します。生成されるファイルは、extension.vsixmanifest、VSIXProjectVS2012_2017.dll、VSIXProjectVS2012_2017.pkgdef、VSIXProjectVS2012_2017.vsix だけです。

プロジェクトをビルドすると、MSBuild ターゲットの 1 つによって、拡張機能が Visual Studio の実験的なインスタンスに配置されます。実験的なインスタンスとは、開発中に拡張機能に問題が発生しても通常のインスタンスが使用不可能にならないように、Visual Studio の通常のインスタンスとは異なるフォルダーとレジストリ エントリを使用するインスタンスです (実験的なインスタンスは、スタート ボタンをクリックして「Visual Studio 2017 の」と入力し、[Visual Studio 2017 の実験的なインスタンスのリセット] コマンドを実行することでいつでもリセットできます)。 プロジェクトの [プロパティ] ページにある [デバッグ] タブに移動すると、[外部プログラムの開始] フィールドに Visual Studio 2017 devenv.exe ファイルを設定できます (アップグレードした場合は以前のバージョンの Visual Studio を参照しているため、この設定を変更することが重要です)。 また、コマンド ライン引数がルート サフィックスとして "Exp" を指定しており (図 8 の「実験的なインスタンスのデバッグ」を参照)、デバッグでも実験的なインスタンスが使用されるようになっていることもわかります。

 実験的なインスタンスのデバッグ
図 8 実験的なインスタンスのデバッグ

[デバッグ]、[デバッグの開始] メニュー エントリの順にクリックすると、新しい Visual Studio インスタンスが起動します (キャプションに "実験的なインスタンス" と表示されるのがわかります)。[ツール]、[Invoke MyCommand1] (MyCommand1 を起動) メニュー エントリを順にクリックすると、パッケージが読み込まれ、コマンドが実行されて、メッセージ ボックスが表示されます。

Visual Studio 2017 を使用して以前の Visual Studio バージョンで拡張機能をデバッグする場合、2 つ変更を加える必要があります。1 つは、Microsoft.VSSDK.BuildTools バージョン 15.0 の NuGet パッケージを削除して、Visual Studio 2015 用のバージョン 14.0 か、Visual Studio 2013 用のバージョン 12.0 を使用することです。これは、拡張機能がビルドされたら、拡張機能はプロジェクトのビルドに使用された SDK バージョンの Visual Studio の実験的なインスタンスに配置されるためです。Visual Studio 2012 には VSSDK の NuGet パッケージはないため、.csproj ファイルを編集して、VSToolsPath 変数が VSSDK 11.0 の場所 (C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0) を参照するようにする必要があります。VSSDK 11.0 は別途インストールする必要があります。もう 1 つは、プロジェクトの [プロパティ] ページの [デバッグ] タブに移動して、[外部プログラムの開始] フィールドを Common7\IDE\devenv.exe 実行可能ファイルと一致するように設定することです。

ご存じかもしれませんが、多くの Visual Studio プロジェクトがラウンドトリップをサポートしています。つまり、複数の Visual Studio バージョンで、面倒な変更を加えることなくプロジェクトを開いてデバッグできます。これは、拡張機能プロジェクトには "そのままの状態では" 当てはまりません。 MSBuild と Visual Studio SDK を熟知していれば実現できる可能性がありますが、それでも難しい方法であることは必至です。

開発とデバッグが終わったら、Release 構成で拡張機能をビルドして、テスト用 PC の独立したインスタンスにインストールされた各 Visual Studio バージョンでテストできます。何も問題が発生しなければ、Visual Studio Marketplace に拡張機能を公開できます。          


Carlos Quintero は、Microsoft Most Valuable Professional アワードを 14 回受賞しており、現在は Visual Studio and Development Technologies カテゴリの MVP です。他の開発者が Visual Studio 向けの拡張機能を作成する支援を 2002 年から続けています。2006 年から拡張機能作成に関するブログ (visualstudioextensibility.com、英語) を公開しており、最近は Twitter (@VSExtensibility、英語) で情報発信しています。

この記事のレビューに協力してくれた技術スタッフの Justin Clareburt、Alex Eyler、および Mads Kristensen に心より感謝いたします。


この記事について MSDN マガジン フォーラムで議論する