ここでは、Visual Studio 拡張機能 (VSIX) を作成することにより、別のアプローチに従う必要がある場合があります。以下で詳細に説明しました。
Visual Studio 2017 でカスタム ツールまたは単一ファイル ジェネレーターを作成する方法:
VS2017 より前にカスタム ツールを作成するにはIVsSingleFileGenerator
、カスタム ツールをシステム レジストリに登録および登録解除するためのインターフェイスとコードを実装する必要がありましたが、VS2017 では、Microsoft はレジストリ構造全体を変更しました。変更点は、システム レジストリが台無しにならないように、VS がプライベート レジストリにレジストリ エントリを作成することです。以前はレジストリ エントリがシステム レジストリに作成されていましたが、現在はシステム レジストリに作成されています。
C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xx\privateregistry.bin
Visual Studio 2017 では、Visual Studio 自体 (F5 キー) からツールを直接実行してテストすることもサポートされています。これにより、 Visual Studio Experimental Instanceと呼ばれる Visual Studio の別のインスタンスが開始され、レジストリ エントリが作成されるため、その中でツールをテストできます。
C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin
以下の手順に従って、VS2017 でカスタム ツールを作成します。
- VSIX 拡張機能を作成する必要があります
- 新しい Visual Studio パッケージを追加する
- 埋め込む
IVsSingleFileGenerator
- レジストリ エントリ コードを追加する
- ツールを VS2017 で実行してコンパイルおよびテストする
- 生成された .VSIX ファイルをダブルクリックして、ツールをインストールします。
例として、「CountLines」という名前の拡張機能/カスタム ツールを作成します。このツールは、ファイル (カスタム ツール プロパティが CountLines に設定されている) を読み取り、ファイルの行数を含む XML ファイルを生成します。例えば<LineCount>1050</LineCount>
1. VSIX 拡張機能
を作成する 拡張機能を作成するには、Visual Studio セットアップのオプション機能として含まれている Visual Studio Extensibility Tools をインストールしておく必要があります。インストールされていない場合は、VS 2017 セットアップを変更してインストールすることもできます。を選択して、新しい VSIX (Visual Studio 拡張機能) プロジェクトを作成します。
新しいプロジェクト -> 拡張性 -> VSIX プロジェクト
「CountLinesVSIX」のような名前を付けます。
2. 新しい Visual Studio パッケージを
追加する VSIX プロジェクトが作成されたら、新しい Visual Studio パッケージを選択して追加します。
追加 -> 新しい項目 -> 拡張性 -> Visual Studio パッケージ
「CountLines.cs」という名前を付けます。既存のコードを削除し、実装CountLines.cs
用のコードに置き換える必要がありますIVsSingleFileGenerator
3. IVsSingleFileGenerator の実装
interface のカスタム実装を記述しIVsSingleFileGenerator
ます。サンプル コードは次のとおりです。
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System.Text;
namespace CountLinesVSIX
{
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration( "CountLines", "Generate XML with line count", "1.0")]
[Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]
[ComVisible(true)]
[ProvideObject(typeof(CountLines))]
[CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]
public sealed class CountLines : IVsSingleFileGenerator
{
#region IVsSingleFileGenerator Members
public int DefaultExtension(out string pbstrDefaultExtension)
{
pbstrDefaultExtension = ".xml";
return pbstrDefaultExtension.Length;
}
public int Generate(string wszInputFilePath, string bstrInputFileContents,
string wszDefaultNamespace, IntPtr[] rgbOutputFileContents,
out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
{
try
{
int lineCount = bstrInputFileContents.Split('\n').Length;
byte[] bytes = Encoding.UTF8.GetBytes("<LineCount>" + lineCount.ToString() + "</LineCount>" );
int length = bytes.Length;
rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);
pcbOutput = (uint)length;
}
catch (Exception ex)
{
pcbOutput = 0;
}
return VSConstants.S_OK;
}
#endregion
}
}
上記のコードのように、拡張機能に一意の GUID を提供する必要があります[Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]
。GUID は VS2017 から「ツール -> GUID の作成」を選択して作成できます。レジストリ形式として GUID 形式を選択します。上記のコードの GUID には中かっこがないことに注意してください。
[ComVisible(true)]
COM 相互運用には必須
[CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]
ツールを登録するためのコードを持つクラス属性です。パラメータは GeneratorType、GeneratorName、および C# 言語 GUID です
カスタム TextTemplate 書式設定をサポートする "TemplatedCodeGenerator" から派生させることもできます。これには、追加のコード実装が必要になる場合があります。
4. レジストリ エントリ コードを追加します。
以下のコードで新しいクラス ファイルを作成し、CodeGeneratorRegistrationAttribute.cs という名前を付けます。
using System;
using System.Globalization;
using Microsoft.VisualStudio.Shell;
namespace CountLinesVSIX
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class CodeGeneratorRegistrationAttribute : RegistrationAttribute
{
private string _contextGuid;
private Type _generatorType;
private Guid _generatorGuid;
private string _generatorName;
private string _generatorRegKeyName;
private bool _generatesDesignTimeSource = false;
private bool _generatesSharedDesignTimeSource = false;
public CodeGeneratorRegistrationAttribute(Type generatorType, string generatorName, string contextGuid)
{
if (generatorType == null)
throw new ArgumentNullException("generatorType");
if (generatorName == null)
throw new ArgumentNullException("generatorName");
if (contextGuid == null)
throw new ArgumentNullException("contextGuid");
_contextGuid = contextGuid;
_generatorType = generatorType;
_generatorName = generatorName;
_generatorRegKeyName = generatorType.Name;
_generatorGuid = generatorType.GUID;
}
/// <summary>
/// Get the generator Type
/// </summary>
public Type GeneratorType
{
get { return _generatorType; }
}
/// <summary>
/// Get the Guid representing the project type
/// </summary>
public string ContextGuid
{
get { return _contextGuid; }
}
/// <summary>
/// Get the Guid representing the generator type
/// </summary>
public Guid GeneratorGuid
{
get { return _generatorGuid; }
}
/// <summary>
/// Get or Set the GeneratesDesignTimeSource value
/// </summary>
public bool GeneratesDesignTimeSource
{
get { return _generatesDesignTimeSource; }
set { _generatesDesignTimeSource = value; }
}
/// <summary>
/// Get or Set the GeneratesSharedDesignTimeSource value
/// </summary>
public bool GeneratesSharedDesignTimeSource
{
get { return _generatesSharedDesignTimeSource; }
set { _generatesSharedDesignTimeSource = value; }
}
/// <summary>
/// Gets the Generator name
/// </summary>
public string GeneratorName
{
get { return _generatorName; }
}
/// <summary>
/// Gets the Generator reg key name under
/// </summary>
public string GeneratorRegKeyName
{
get { return _generatorRegKeyName; }
set { _generatorRegKeyName = value; }
}
/// <summary>
/// Property that gets the generator base key name
/// </summary>
private string GeneratorRegKey
{
get { return string.Format(CultureInfo.InvariantCulture, @"Generators\{0}\{1}", ContextGuid, GeneratorRegKeyName); }
}
/// <summary>
/// Called to register this attribute with the given context. The context
/// contains the location where the registration inforomation should be placed.
/// It also contains other information such as the type being registered and path information.
/// </summary>
public override void Register(RegistrationContext context)
{
using (Key childKey = context.CreateKey(GeneratorRegKey))
{
childKey.SetValue(string.Empty, GeneratorName);
childKey.SetValue("CLSID", GeneratorGuid.ToString("B"));
if (GeneratesDesignTimeSource)
childKey.SetValue("GeneratesDesignTimeSource", 1);
if (GeneratesSharedDesignTimeSource)
childKey.SetValue("GeneratesSharedDesignTimeSource", 1);
}
}
/// <summary>
/// Unregister this file extension.
/// </summary>
/// <param name="context"></param>
public override void Unregister(RegistrationContext context)
{
context.RemoveKey(GeneratorRegKey);
}
}
}
上記のコードは、エントリが VS プライベート レジストリに作成されていることを確認します。
5. VS2017 で実行して、ツールをコンパイルおよびテストします。
「source.extension.vsixmanifest」に「インストール ターゲット」を追加して、異なる VS2017 エディションが拡張機能でサポートされるようにすることができます。VS 2017 でツールを実行して、期待どおりに機能しているかどうかをテストします。VSIX を実行すると、Visual Studio 実験的インスタンスによって拡張機能がインストールされ、レジストリ "C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin" に登録されます。「ツール -> 拡張機能と更新プログラム」を選択すると、インストールされている拡張機能を確認できます。ツールをテストするには、ダミー プロジェクトを開き、ソリューション エクスプローラーでファイルを選択し、そのプロパティに移動して、カスタム ツール プロパティを「CountLines」に更新する必要があります。これが完了すると、VS はツールをバックグラウンドで実行し、出力を生成します。この例では、選択したファイルの下に xml ファイルを生成します。あるいは、
6. 生成された .VSIX ファイルをダブルクリックしてツールをインストールします。
テストが正常に終了したら、「projectName/bin/debug」にある VSIX をインストールしてみてください。ファイルをダブルクリックして VSIX をインストールし、インストール手順に従います。これで、VS2017 でツールを使用できるようになります。ツールの使用方法も同様です。カスタム ツールを実行するファイルを右クリックし、[カスタム ツールの実行] を選択します。
拡張機能をアンインストールする場合は、[ツール] -> [拡張機能と更新プログラム] -> [拡張機能を選択] に移動し、[アンインストール] をクリックします。VS を閉じるまで、ツールはアンインストールされないことに注意してください。閉じると、アンインストールするためのポップアップ ウィンドウが表示されます。[変更] を選択してアンインストールします。