Overview

Microsoft Visual Studio Tools for Applications 2012 (VSTA) gives you a way to enable end users to customize your existing applications using Visual Basic and Visual C#. You can incorporate the use of the Visual Studio integrated development environment (IDE) into yourapplication to enable end user customization. End-user developers can use the IDE to customize the application by creating add-ins that extend the functionality of the application to meet their needs.

Using Visual Studio Tools for Applications 2012

Visual Studio Tools for Applications 2012provides two primary modes of operation: with Visual Studio 2012 Professional, Premium or Ultimate installed and standalone. In standalone mode, VSTA provides your application with the means to load, compile, and run end user customizations. With Visual Studio 2012 Professional, Premium or Ultimate installed, VSTA extends that functionality with the means to edit and debug those customizations.

Visual Studio Tools for Applications 2012 presents a new and simplified API for integrating design-time experiences into your application. Host application integrations can be implemented by using either managed (Visual C# or Visual Basic .NET) or unmanaged (Visual C++) code. The VSTA hosting API enables you to integrate your applicationbecause the API simplifies tasks such as finding the installation of Visual Studio, launching the external process, and synchronizing save state.

Visual Studio Tools for Applications 2012provides the ability to upgrade projects from Visual Studio 2005 Tools for Applications and Visual Studio 2008 Tools for Applications, compile, and run them.

Visual Studio Tools for Applications 2012does not require a runtime library for end user customizations. This gives the integrator the flexibility to choose the method of running user code best tailored to the host application. The Microsoft .NET Framework includes the Managed Add-in Framework, which can be used to run add-ins built on Visual Studio 2008 Tools for Applications.

Minimum system requirements:

  • Windows 7
  • .NET Framework 4.5
  • 2 GB of RAM
  • 4 MB of hard disk space

Runtime requirement:

  • Visual C++ Redistributable for Visual Studio 2012 Update 1

To enable editing and debugging:

  • Microsoft Visual Studio 2012 Professional, Premium or Ultimate

Getting Started

To integrate an application with Visual Studio Tools for Applications 2012,you must understand a few simple concepts.

Definitions

Host Application: An application that is capable of being extended through end user code. A host application “hosts” the end user code by giving it the facilities to be compiled and run, facilitated by the technologies in VSTA.

Integrated Development Environment (IDE):An application (in this case, Visual Studio 2012) that allows a user to compile, edit, and debug code. Visual Studio 2012

Project Template: A collection of source files and XML that are used at runtime for the creation of projects that can be customized by end user code.

Session: An instance of a collection of projects that can be associated with one IDE. This encapsulates all of the services that can be done between zero or more projects and a single running IDE instance.

VSTAX: An Open Packaging Container (OPC) file that contains one or more project templates. A VSTAX file is typically created by the host application vendor, shipped with the application, and used at runtime to create a project for an end user to customize.

VSTA includes versions of the hosting API for both managed and unmanaged integration. This document will demonstrate use of the API in Visual C#, but all scenarios can be accomplished using Visual C++ and Visual Basic.NET as well.

Installing the Visual Studio Tools for Applications 2012 SDK

Before you can install and run this version of VSTA, the Microsoft .NET Framework 4.5 must also be installed.

Microsoft ships a software development kit (SDK) for VSTA apart from the VSTA download. After the VSTA SDK is installed, its components are placed into the Program Files (x86)\Microsoft SDKs\VSTA\11.0folder.

To build an application, you need only the .NET Framework SDK (available as a free download from Microsoft), but examples in this document will be shown using Visual Studio 2012.

Launching an IDE from Your Host Application

After the VSTA SDK is installed, you can launch Visual Studio from your application by using Visual C# if you add a reference to one assembly and then write three lines of code.

To enable an application to launch the IDE:

  1. In Visual Studio 2012, create a WPFapplication,and name it “MyVSTAHost”.
  2. In Solution Explorer, open the shortcut menu for the MyVSTAHost project node, and choose Add Reference.
  3. In the Add Reference dialog box, choose Microsoft.VisualStudio.Tools.Applications version 11.0.0.0, and then choose the Add button.
  4. Add a button to the default form, and then add an event handler to the button.
  5. Add the following statement to your form:

using VSTA = Microsoft.VisualStudio.Tools.Applications;

  1. Add the following code to your event handler:

private VSTA.Session _session;

privatevoid button1_Click(object sender, EventArgs e)

{

if (_session == null)

{

varsessionMgr = VSTA.SessionManager.Create("MyHostApp");

_session = sessionMgr.CreateSession();

}

_session.Ide.Show();

}

Thiscode does the following:

  1. Creates a session if one hasn’t already been created. This starts up the base-level scaffolding required to communicate with an IDE and manage projects.
  2. On the session’s Ide instance, shows the IDE. This will implicitly launch the IDE process, open a communication channel to the IDE, and tell the IDE to show the main window.

NOTES:

  • A session’s name must be unique in the context of the running Host Application instance. In other words, the “if(_session == null)” condition prevents another session from being created with the same name each time a user chooses the button. This situation can lead to a deadlock condition when the Ide object is accessed.
  • Session and SessionManager objects are, in fact,IDisposable. If you use these objects, you must useproper implementation of IDisposable for classes that hold onto instances of these objects. If you failing to hold onto instances of these objects,the .NET garbage collector can dispose of them, which leads to exceptions.

Creating a Project Template

To creating a project in VSTA, you must choose a project template. This template provides the basic framework of project source files needed to enable end users to add their code to the solution.

In VSTA, project templates are packaged in VSTAX files. These files contain one or more templates that can be redistributed with your host application. These project templates work differently from project templates that are deployed with Visual Studio 2012, in that VSTA templates do not need to be installed with Visual Studio. This allows the host application complete control of template deployment.

VSTA templates provide built-in facilities for replacement tokens (for example, “$projectname$”), guid generation (for example, “$guid2$”), and SNK file generation during project creation.

You can create templates for VSTA projects by using TemplateGenerator.exe, a command-line tool included in the VSTA SDK in the folder %ProgramFiles(x86)%\Microsoft SDKs\VSTA\11.0\Tools. You can use this tool to create a VSTAX file, which VSTA can then consume to create projects.

To create a template:

  1. In Visual Studio 2012,create aC# Class Library Project,and name it “TemplateProject”.
  2. Rename Class1 to “AddIn”, and add the following method:

publicstaticvoid Init()

{

// Place add-in start-up code here

}

  1. In the file AddIn.cs,replace all instances of “TemplateProject” with “$safeprojectname$”, which will be replaced with the project’s actual name when it is created from the template.
  2. In the file AssemblyInfo.cs, replace all instances of “TemplateProject” with “$safeprojectname$”, which will be replaced with the project’s actual name when it is created from the template. Replace the GUID in the Guid Attribute with “$guid2$”, which will be replaced with a generated GUID when a project is created from the template.
  3. In the fileTemplateProject.csproj, replace all instances of “TemplateProject” with “$safeprojectname$”, which will be updated with the project’s actual name when it is created from the template. Replace the contents of the ProjectGuidelement with “{$guid1$}”, which will be replaced with a generated GUID when a project is created from the template. In the PropertyGroupelement, add an element ‘ProjectTypeGuids’, as described later in this document. The two GUIDs after this steprepresent the VSTA and C# project types respectively. To create a template for Visual Basic, replace the C# project GUID (FAE04EC0-301F-11D3-BF4B-00C04F79EFBC) with the Visual Basic project GUID (F184B08F-C81C-45F6-A57F-5ABD9991F28F).

ProjectTypeGuids{30D016F9-3734-4E33-A861-5E7D899E18F3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids

  1. After the final Import element (Microsoft.CSharp.targets), insert the ProjectExtensions element:

ProjectExtensions

<VisualStudio

<FlavorPropertiesGUID="{30D016F9-3734-4E33-A861-5E7D899E18F3}"

<ProjectProperties

HostName = "MyHostApp"

HostPackage="{B3A685AA-7EAF-4BC6-9940-57959FA5AC07}"

ApplicationType=""

Language="cs"

TemplatesPath="" />

</FlavorProperties

</VisualStudio

</ProjectExtensions

All of the attributes are required, or the project won't load in VSTA.

  1. In the TemplateProject solution folder, add an XML file that's named manifest.xml:

<?xmlversion="1.0"encoding="utf-8" ?>

VstaTemplatesxmlns="

<ProjectTemplateProjectType="msBuild"TemplateName="csaddin"

<ProjectItems

<ProjectItemReplaceParameters="true"

SourceFilePath="TemplateProject\TemplateProject.csproj"

TemplateFilePath="csaddin\AddIn.csproj"

TargetFilePath="$projectname$.csproj"

TargetItemType="Project" />

<ProjectItemReplaceParameters="true"

SourceFilePath="TemplateProject\AddIn.cs"

TemplateFilePath="csaddin\AddIn.cs"

TargetFilePath="AddIn.cs" />

<ProjectItemReplaceParameters="true"

SourceFilePath="TemplateProject\Properties\AssemblyInfo.cs"

TemplateFilePath="csaddin\AddIn.Designer.cs"

TargetFilePath="Properties\AssemblyInfo.cs" />

</ProjectItems

</ProjectTemplate

</VstaTemplates

  1. Open a command prompt in the TemplateProject solution folder, and run the following command:

"%ProgramFiles(x86)%\Microsoft SDKs\VSTA\11.0\Tools\TemplateGenerator.exe" /manifest:manifest.xml /output:template.vstax

This command will create the template file template.vstax.

NOTES:

  • You can find the schema for the manifest XML file (VstaTemplateManifestSchema.xsd) in the %ProgramFiles(x86)%\Microsoft SDKs\VSTA\11.0\Tools\ folder.This file contains comments on the meaning of the individual elements and attributes.
  • The manifest file allows multiple templates to be specified and packaged into a single VSTAX file.

Creating a Project from a Template

To create a VSTA project from your VSTAX, you must add a small amount of code.

In Visual Studio, perform the following:

  1. Add your VSTAX file to your project, and set its Copy to Output Directory property to Copy always.
  2. Add a button and named “New” to your form, and add an event handler to the button.
  3. Add the following code to the event handler:

private VSTA.Project _project;

privatevoidbutton2_Click(object sender, EventArgs e)

{

if (_session == null || _project != null)

{

//Error handling...

return;

}

var storage = VSTA.ProjectStorage.CreateStorageFromTemplate("template.vstax",

"csaddin",

"VSTASample",

null);

_project = _session.LoadProject(storage);

}

NOTES:

  • In addition to the standard Visual Studioreplacement parameters (such as $safeprojectname$), VSTA supports defining custom replacement parameters by passing in a dictionary of key value pairs to the CreateStorageFromTemplate method. These pairs should be in the following format:

{“$key$”, “value”}

  • SNK file generation requires the .NET Framework SDK to be installed when you create a project from the template.

Saving and Loading a Project

To save and load a project from a file, you must first create a class that implements the VSTA IProjectStorage interface.

IProjectStorage is a simple mechanism that can look up any item by a name and get back a stream. This can be as simple as a table of binaries or a virtual file system. One IProjectStorageis associated with each project, and item names are not guaranteed to be unique across more than one project.

The following example implementsIProjectStorage in a MyProjectStorage class.

In Visual Studio, perform the following:

  1. Add a class named “MyProjectStorage” to your project.
  2. Add a the following statement:

using VSTA = Microsoft.VisualStudio.Tools.Applications;

  1. Implement IProjectStorage to use the file system as a backing store for all items in your project:

classMyProjectStorage : VSTA.IProjectStorage

{

string _rootDirectory;

public MyProjectStorage(string pathRoot)

{

_rootDirectory = pathRoot;

}

publicbool ItemExists(string itemName)

{

string fileName = System.IO.Path.Combine(_rootDirectory, itemName);

return System.IO.File.Exists(fileName);

}

public System.IO.Stream OpenItem(string itemName, bool writeAccess)

{

string fileName = System.IO.Path.Combine(_rootDirectory, itemName);

System.IO.FileMode mode;

if (writeAccess)

mode = System.IO.FileMode.OpenOrCreate;

else

mode = System.IO.FileMode.Open;

return System.IO.File.Open(fileName, mode);

}

}

  1. Add a buttonnamed “Save” to your form, and add an event handler to the button.
  2. Add the following code to the event handler:

if (_project != null)

{

MyProjectStorage outputProject = newMyProjectStorage("ProjectName");

_project.Save(outputProject);

}

When the user chooses the “Save”button in your form, the project and all its items will be saved to a folder named “ProjectName” under the application’s current working directory. You may need to create the “ProjectName” folder and “Properties” folder if they don’t exist in the application’s current working directory.

NOTE: The data in the saved items can often be read as text, but the exact format and encoding depends on the implementation of VSTA and may change. All data saved by VSTA should be treated as “opaque” to the host application. VSTA projectsshould be opened only through the hosting API (Microsoft.VisualStudio.Tools.Applications or the unmanaged equivalents).

Compiling and Running a Project

Afteryou create a project,you build and load the add-in by using the BinaryManager class.

  1. Add a buttonnamed “Run” to your form, and add an event handler to the button.
  2. Add the following statement to your form:

using System.IO;

using System.Reflection;

  1. Add the following code to the event handler:

privatevoidbutton3_Click(object sender, EventArgs e)

{

if (_project == null)

{

//Error handling...

return;

}

var binaryManager = _project.BinaryManager;

// Find the BinaryItem for the output assembly and its .pdb file.

string assemblyName = binaryManager.AssemblyName;

string pdbName = Path.GetFileNameWithoutExtension(assemblyName) + ".pdb";

VSTA.BinaryItem assemblyItem = null;

VSTA.BinaryItem pdbItem = null;

foreach (VSTA.BinaryItem item in binaryManager.GetBinaryItems())

{

string itemName = item.Name;

if (String.Equals(itemName, assemblyName, StringComparison.OrdinalIgnoreCase))

{

assemblyItem = item;

if (pdbItem != null)

break;

}

elseif (String.Equals(itemName, pdbName, StringComparison.OrdinalIgnoreCase))

{

pdbItem = item;

if (assemblyItem != null)

break;

}

}

if (assemblyItem == null)

{

//Error handling...

return;

}

// Get the assembly as a byte[].

Stream assemblyStream = assemblyItem.GetStream();

byte[] assemblyBytes = newbyte[assemblyStream.Length];

assemblyStream.Read(assemblyBytes, 0, assemblyBytes.Length);

// Get the .pdb as a byte[].

Stream pdbStream = pdbItem.GetStream();

byte[] pdbBytes = newbyte[pdbStream.Length];

pdbStream.Read(pdbBytes, 0, pdbBytes.Length);

// Load the raw assembly.

Assembly assembly = Assembly.Load(assemblyBytes, pdbBytes);

// Find the AddIn class.

Type addInType = assembly.GetTypes().FirstOrDefault((t) => t.Name == "AddIn");

if (addInType == null)

{

//Error handling...

return;

}

// Find the Init method.

MethodInfo initMethod = addInType.GetMethod("Init");

if (initMethod == null)

{

//Error handling...

return;

}

// Initialize the add-in

initMethod.Invoke(null, null);

}

NOTES:

  • The example provided is intended to be illustrative, not exhaustive. For example, integrators may want to hand off exposing a host object for the add-in to make calls into or running the add-in in a separate process.
  • This example loads the assembly with its symbols; this is only necessary to support debugging and is not needed in pure run-time scenarios.

Debugging a Project

To debug a project in the IDE, the host must implement the interface VSTA.IExternalDebugHost. This interface allows the IDE to notify the host about debugging checkpoints for loading and unloading add-ins.

The following code illustrates a sample host implementation of VSTA.IExternalDebugHost:

internalclassExternalDebugHostImpl: VSTA.IExternalDebugHost

{

privateProcess _loaderProcess;

privatestaticExternalDebugHostImpl _instance = null;

publicstaticExternalDebugHostImpl Instance

{

get

{

if (_instance == null)

{

_instance = newExternalDebugHostImpl();

}

return _instance;

}

}

privateProcess CreateHostingProcess(string projectId)

{

Process hostingProcess = null;

//Set process properties, and create a process.

//Return the created process.

returnhostingProcess;

}

//Interface methods implementation

uint VSTA.IExternalDebugHost.OnBeforeDebugStarting(string projectId)

{

//Check if the projectId is valid.

//Create an external host process, which will host the Addin during debugging.

_loaderProcess = CreateHostingProcess(projectId);

//If the external debug host process is created successfully, return it

// to host.

if (_loaderProcess != null)

{

return (uint)_loaderProcess.Id;

}

else

{

//In case of any error, throw an exception.

thrownewInvalidProgramException();

}

}

void VSTA.IExternalDebugHost.OnDebugStarting(string projectId)

{

//Ensure the projectId is same that is being debugged.

//Tell the external debug host process to start running the addin code.

}

void VSTA.IExternalDebugHost.OnDebugStopping(string projectId)

{

//Perform the needed cleanup when debugging is stopped/completed.

try

{

if (!_loaderProcess.HasExited)

{

_loaderProcess.Close();

}

if (_loaderProcess.ExitCode != 0)

{

// Performthe appropriate action.

}

//Perform other cleanup needed to stop debugging.

}

catch

{

}

}

void VSTA.IExternalDebugHost.OnDebugAttachFailed(string projectId)

{

//Perform the needed cleanup when debugging attach fails.

try

{

if (!_loaderProcess.HasExited)

{

_loaderProcess.Close();

}

if (_loaderProcess.ExitCode != 0)

{

//Perform the appropriate action.

}

//Perform other cleanup needed for failed attach.

}

catch

{

}

}

}

To properly configure the child sessions and corresponding IDE instancesfor debugging, the host must pass an instance of ExternalDebugHostImplduring the creation of SessionManager.

_sessionManager = VSTA.SessionManager.Create(

"MyHostApp",

newDictionarystring, object>()

{

{ VSTA.SessionManagerOptions.Names.ExternalDebugHost, ExternalDebugHostImpl.Instance }

});

After the SessionManageris created by implementing IExternalDebugHost, the host can use the APIs in theProject class to start and stop the debugging.

  1. Add a button named “StartDebugging”to your form, and add an event handler to the button.
  2. Add the following statement to the form:

using System.IO;

using System.Reflection;

  1. Add the following code to the event handler:

privatevoid button4_Click(object sender, EventArgs e)

{

if (_project == null)

{

//Error handling...

return;

}

//Request the IDE to start debugging

_project.StartDebugging();

}

  1. Add a button named “StopDebugging” to your form, and add an event handler to the button.
  2. Add the following code to the event handler:

privatevoid button5_Click(object sender, EventArgs e)