First off,
your Single-File Generator class needs to have the appropriate class-level attributes:
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
using VSLangProj80;
[ComVisible(true)]
[Guid("your-unique-identifier")]
[CodeGeneratorRegistration(
typeof(MyCustomTool),
"MyCustomTool",
vsContextGuids.vsContextGuidVCSProject,
GeneratesDesignTimeSource = true,
GeneratorRegKeyName = "MyCustomTool"
)]
[ProvideObject(
typeof(MyCustomTool),
RegisterUsing = RegistrationMethod.CodeBase
)]
public sealed class MyCustomTool : IVsSingleFileGenerator {
All of these attributes will ensure that a .pkgdef file is correctly generated within your VSIX. The .pkgdef file contains the registry entries that are used to register your single-file generator with Visual Studio.
Second,
add a text file "source.extension.vsixmanifest" to your project. Its "Build Action" should be "None." Give it some default text of:
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="MyCustomTool.MyCompany.another-random-guid" Version="1.0" Language="en-US" Publisher="MyCompany" />
<DisplayName>MyCustomTool</DisplayName>
<Description>Helpful information</Description>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[15.0]" />
</Installation>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.5,)" />
</Dependencies>
<Prerequisites>
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[15.0,16.0)" DisplayName="Visual Studio core editor" />
</Prerequisites>
</PackageManifest>
Most of this stuff is pretty esoteric. In the next step, we'll make it so you can edit this file with a designer.
Third
(and to answer the original question), you need to manhandle the .csproj file (your C# Class Library file). Specifically, you need to add the following:
<PropertyGroup>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<ItemGroup>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<PropertyGroup>
<UseCodebase>true</UseCodebase>
</PropertyGroup>
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
So, what have we done here? Let's break it down.
First, we setup a path to the location of the Visual Studio toolset. Afterall, this is now an "extensions project." So, it needs to know where the VS-SDK is located.
Then, we changed the "ProjectTypeGuids" (which probably wasn't in your project file to begin with). Originally, it just included the guid for C# (which is the "FAE04EC0-..." guid). Now, it also includes the guid for VSIX (which is the "82b43b9b-..." guid).
We also made sure the "source.extension.vsixmanifest" file uses its new, fancy designer (instead of editing the file by hand).
The "UseCodeBase" element is important. This element prevents you from being forced to register your Generator with the system's COM registry. Instead, Visual Studio will simply load up your Generator from its installation location.
At the bottom, we import the MsBuild stuff for the VS-SDK.
Fourth,
Load your project back up. Go to the Project Properties screen and you'll see a new "VSIX" section at the bottom. Open that section and check the "Create VSIX Container during build" checkbox.
At this point, you can also double-check the "source.extension.vsixmanifest" file. Depending on how fancy your Generator is, you can change whatever you need. (The contents of the file that I pasted above is pretty much exactly what I used for my project.)
And finally,
you can compile your project. In the bin folder, you'll find MyCustomTool.dll and MyCustomTool.vsix. The .vsix file is simply a zip file. Inside the .vsix, you'll find MyCustomTool.pkgdef.
If we've done everything correctly, the .pkgdef file should look something like this:
[$RootKey$\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}\MyCustomTool]
@="MyCustomTool"
"CLSID"="{your-unique-identifier}"
"GeneratesDesignTimeSource"=dword:00000001
[$RootKey$\CLSID\{your-unique-identifier}]
@="MyCustomTool"
"InprocServer32"="$WinDir$\SYSTEM32\MSCOREE.DLL"
"Class"="MyCustomTool"
"CodeBase"="$PackageFolder$\MyCustomTool.dll"
"ThreadingModel"="Both"
And, I think this is the longest SO answer I've written. And probably, only 5 people will ever read this :)