Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The following example shows an implementation of Visual Studio Tools for Applications IDE integration and basic non-destructive debugging that opens a new instance of the host application. It is based on the ShapeApp sample application. The concepts behind this example are described in detail in Add-In Debugging.
There is another example that demonstrates Visual Studio Tools for Applications IDE integration and advanced non-destructive debugging in a running instance of the host application. For more information, see How to: Build and Run the ShapeAppMacroRecordingCSharp Sample.
Example
using System;
using System.Text;
using System.Globalization;
using System.Runtime.Remoting;
using Microsoft.VisualStudio.Tools.Applications;
using Microsoft.VisualStudio.Tools.Applications.DesignTime;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using Microsoft.VisualStudio.Tools.Applications.Hosting;
using System.AddIn;
using System.AddIn.Hosting;
using System.ComponentModel.Design;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Collections;
using VSTADTEProvider.Interop;
using System.Threading;
namespace AIMExtension
{
[System.Runtime.InteropServices.Guid("80A50594-7B6A-4840-B055-1322E487B2B0")]
[System.Runtime.InteropServices.ComVisible(true)]
public class AIMExtension : System.MarshalByRefObject,
ShapeApp.IExtension,
IExternalDebugHost
{
#region Constructors, Destructors
public AIMExtension()
{
addInList = new List<IEntryPoint>();
}
// Define constructors and destructors.
#endregion
#region MarshalByRefObject
public override object InitializeLifetimeService()
{
// Allow remoting from Visual Studio.
return null; }
#endregion MarshalByRefObject
#region IExtension Members
void ShapeApp.IExtension.Connect(
ShapeApp.Application pApplication)
{
// Set the ShapeApp instance.
this.shapeappApp = pApplication;
// Create the service provider.
InstantiateServiceProvider();
string hostDebugReadyEventName = "";
string hostDebugUri = "";
// Load the add-in into an external process.
// Decide whether this is a non-destructive debugging case.
for (int i = 1; i < args.Length; ++i)
{
if (args[i].StartsWith(exAddInPrefix))
{
string assemblyName = args[i].Remove(0,
exAddInPrefix.Length);
string[] addInInfoPartial =
assemblyName.Split(',');
LoadAddInFromDirectory(serviceProvider,
addInInfoPartial[0],
addInInfoPartial[1]);
}
else if (args[i].StartsWith(addInPathPrefix))
{
this.addInPath = args[i].Remove(0,
addInPathPrefix.Length);
}
else if (args[i].StartsWith(vstaHostDebugReadyPrefix))
{
hostDebugReadyEventName = args[i].Remove(0,
vstaHostDebugReadyPrefix.Length);
}
else if (args[i].StartsWith(vstaHostDebugUriPrefix))
{
hostDebugUri = args[i].Remove(0,
vstaHostDebugUriPrefix.Length);
}
}
// Enable non-destructive debugging.
if (!((String.IsNullOrEmpty(hostDebugUri) ||
String.IsNullOrEmpty(hostDebugReadyEventName))))
{
isNDD = true;
ExternalDebugging.RegisterExternalDebugHost(
(IExternalDebugHost)this,
new Uri(hostDebugUri));
}
EventWaitHandle readyEvent = new EventWaitHandle(false,
EventResetMode.ManualReset,
hostDebugReadyEventName);
readyEvent.Set();
}
void ShapeApp.IExtension.Disconnect()
{
if (addInProcess != null)
{
foreach (IEntryPoint ep in this.addInList)
{
ep.OnShutdown();
}
addInList.Clear();
addInProcess.Shutdown();
addInProcess = null;
}
}
// IExtension members.
#endregion
#region IExternalDebugHost
public int OnBeforeDebugStarting()
{
CreateAddInProcess();
int addinProcessID = addInProcess.ProcessId;
isDebugging = true;
return addinProcessID;
}
public void OnDebugStarting()
{
LoadAddInFromDirectory(this.serviceProvider,
this.addInPath);
}
public void OnDebugStopping()
{
if (isDebugging)
{
StopDebugging();
isDebugging = false;
}
}
#endregion //IExternalDebugHost
#region Private Methods
private void InstantiateServiceProvider()
{
itemProvider = new HostItemProvider(shapeappApp);
typeMapProvider = new HostTypeMapProvider();
ServiceContainer container = new ServiceContainer();
container.AddService(typeof(IHostItemProvider),
itemProvider);
container.AddService(typeof(ITypeMapProvider),
typeMapProvider);
serviceProvider = container;
}
private void AddInProcessExiting(object sender,
System.ComponentModel.CancelEventArgs args)
{
if (isNDD)
{
// Clean up before shutting down.
System.Environment.Exit(0);
}
}
private AddInToken CustomFindAddIn(string addInPath,string className)
{
Collection<AddInToken> token = AddInStore.FindAddIn(typeof(IEntryPoint), AddInStoreExtensions.DefaultPipelinePath, addInPath,className);
return token[0];
}
private AddInToken CustomFindAddIn(string addInPath)
{
if (!System.IO.File.Exists(addInPath))
throw new ArgumentException();
string addInDir = System.IO.Path.GetDirectoryName(addInPath);
string addInRoot = null;
addInRoot = System.IO.Path.Combine(addInDir, "..");
AddInStore.UpdateAddIns(addInRoot);
Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(IEntryPoint), AddInStoreExtensions.DefaultPipelinePath, addInRoot);
Collection<AddInToken> addinTokens = null;
foreach (AddInToken token in tokens)
{
addinTokens = AddInStore.FindAddIn(typeof(IEntryPoint), AddInStoreExtensions.DefaultPipelinePath, addInPath, token.AddInFullName);
if (addinTokens.Count > 0)
return addinTokens[0];
}
return null;
}
private void CreateAddInProcess()
{
// Create the process and start it.
this.addInProcess = new AddInProcess();
this.addInProcess.Start();
// Create the event handlers.
addInProcess.ShuttingDown += new EventHandler<System.ComponentModel.CancelEventArgs>(AddInProcessExiting);
}
private void LoadAddInFromDirectory(IServiceProvider
serviceProvider, string addInPath,string className)
{
AddInToken addinToken = CustomFindAddIn(addInPath,
className);
LoadToken(addinToken);
}
private void LoadAddInFromDirectory(IServiceProvider
serviceProvider, string addInPath)
{
AddInToken addinToken = CustomFindAddIn(addInPath);
LoadToken(addinToken);
}
private void LoadToken(AddInToken addinToken)
{
IEntryPoint addin = null;
if (this.addInProcess == null)
{
CreateAddInProcess();
}
// Host the add-ins in the external process.
// Activate the add-in.
addin = addinToken.Activate<IEntryPoint>(this.addInProcess, AddInSecurityLevel.FullTrust);
addin.Initialize(serviceProvider);
addin.InitializeDataBindings();
addin.FinishInitialization();
addInList.Add(addin);
}
private void AddInProcessExited(object sender, EventArgs args)
{
addInProcess = null;
}
private void StopDebugging()
{
if (!this.isDebugging)
return;
if (addInProcess != null)
{
addInProcess.Shutdown();
}
this.isDebugging = false;
}
private void ForcingUnloadCurrentAddins()
{
foreach (IEntryPoint inProcAddin in addInList)
{
if (inProcAddin != null)
{
AddInController controller =
AddInController.GetAddInController(inProcAddin);
controller.Shutdown();
}
addInList.Clear();
}
}
#endregion //Private Methods
#region Private Fields
public delegate void DelegateToUnloadAddIns();
private AddInProcess addInProcess;
private const string exAddInPrefix = "/exAddIn:";
private const string addInPathPrefix = "/addInPath:";
private const string vstaHostDebugUriPrefix = "/vstaHostDebugUri:";
private const string vstaHostDebugReadyPrefix = "/vstaHostDebugReady:";
private IServiceProvider serviceProvider;
private IHostItemProvider itemProvider;
private ITypeMapProvider typeMapProvider;
private ShapeApp.Application shapeappApp;
private List<IEntryPoint> addInList;
private string addInPath;
private bool isDebugging = false;
private bool isNDD = true;
#endregion //Private Fields
#region PInvoke
[DllImport("ole32.dll")]
public static extern int GetRunningObjectTable(int reserved,
out IRunningObjectTable prot);
[DllImport("ole32.dll")]
public static extern int CreateBindCtx(int reserved,
out IBindCtx ppbc);
#endregion
}
#region DTE
[System.Runtime.InteropServices.ComImport]
[System.Runtime.InteropServices.Guid("BA018599-1DB3-44f9-83B4-461454C84BF8")]
public class DTE
{
}
#endregion //DTE
public class HostItemProvider : IHostItemProvider
{
#region Constructors, Destructors
public HostItemProvider(ShapeApp.Application application)
{
this.application = application;
}
#endregion //Constructors, Destructors
#region IHostItemProvider Members
public object GetHostObject(Type primaryType, string primaryCookie)
{
if (primaryType == typeof(ShapeApp.Application))
{
return this.application;
}
else
{
throw new ArgumentOutOfRangeException();
}
}
#endregion //IHostItemProvider Members
#region Private Fields
private ShapeApp.Application application;
#endregion //Private Fields
}
public class HostTypeMapProvider : ITypeMapProvider
{
public HostTypeMapProvider()
{
}
// Get the type name that corresponds to
// the canonical name from the host-provided maps.
public Type GetTypeForCanonicalName(string canonicalName)
{
if (canonicalName == "ShapeApp, ShapeApp.Application")
{
return typeof(ShapeApp.Application);
}
if (canonicalName == "ShapeApp,
ShapeApp.IApplicationEvents")
{
return typeof(ShapeApp.IApplicationEvents);
}
return null;
}
// Query the canonical name.
public string GetCanonicalNameForType(Type type)
{
return null;
}
}
}
See Also
Tasks
Walkthrough: Incorporating the IDE for a Managed Object Model
Concepts
Incorporating the Integrated Development Environment