Overview:
Register for notifications at Visual Studio
Derive from notification interfaces:
class VisualStudioConnector
: Microsoft.VisualStudio.Shell.Interop.IVsSelectionEvents
, Microsoft.VisualStudio.Shell.Interop.IVsUpdateSolutionEvents
Advise for notifications:
private void ConnectWithVisualStudio()
{
try
{
ThreadHelper.ThrowIfNotOnUIThread();
bool connectedToSelectionEvents = false;
bool connectedToUpdateSolutionEvents = false;
m_monitorSelection = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.
GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
if (m_monitorSelection != null)
{
m_monitorSelection.AdviseSelectionEvents(
this, out m_selectionEventsCookie);
connectedToSelectionEvents = true;
}
else
{
WriteLine(1, "ConnectWithVisualStudio: GetService(SVsShellMonitorSelection) failed!");
}
m_solutionBuildManager = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.
GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager;
if (m_solutionBuildManager != null)
{
m_solutionBuildManager.AdviseUpdateSolutionEvents(
this, out m_updateSolutionEventsCookie);
connectedToUpdateSolutionEvents = true;
}
else
{
WriteLine(1, "ConnectWithVisualStudio: GetService(SVsSolutionBuildManager) failed!");
}
if (connectedToSelectionEvents && connectedToUpdateSolutionEvents)
{
WriteLine(1, "ConnectWithVisualStudio succeeded");
}
}
catch (Exception ex)
{
WriteLine(1, "ConnectWithVisualStudio failed: EXCEPTION: " + ex.ToString());
}
}
Unadvise from notifications:
public void DisconnectFromVisualStudio()
{
try
{
ThreadHelper.ThrowIfNotOnUIThread();
if (m_monitorSelection != null && m_selectionEventsCookie != 0)
m_monitorSelection.UnadviseSelectionEvents(m_selectionEventsCookie);
if (m_solutionBuildManager != null && m_updateSolutionEventsCookie != 0)
m_solutionBuildManager.UnadviseUpdateSolutionEvents(m_updateSolutionEventsCookie);
}
catch (Exception ex)
{
WriteLine(1, "DisconnectFromVisualStudio: EXCEPTION: " + ex.ToString());
}
}
Receiving notifications from Visual Studio
Notification about a change of startup project:
int IVsSelectionEvents.OnElementValueChanged(
uint elementid, object varValueOld, object varValueNew)
{
if (elementid == (uint)VSConstants.VSSELELEMID.SEID_StartupProject)
{
if (varValueNew != null)
{
WriteLine(2, "Detected new StartupProject");
m_mainEvents.OnRefreshAll();
}
}
return VSConstants.S_OK;
}
int IVsSelectionEvents.OnCmdUIContextChanged(
uint dwCmdUICookie, int fActive)
{
return VSConstants.S_OK;
}
Notification about a change of configuration:
int IVsUpdateSolutionEvents.OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy)
{
WriteLine(2, "Detected OnActiveProjectCfgChange");
m_mainEvents.OnRefreshAll();
return VSConstants.S_OK;
}
Requesting project information via DTE
Get current configuration (e.g Debug or Release)
string configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
Get name of startup project
EnvDTE80.SolutionBuild2 sb = (EnvDTE80.SolutionBuild2)dte.Solution.SolutionBuild;
if (sb == null)
{
WriteLine(1, "SolutionBuild is null (checking for startup project is not possible)");
return false;
}
if (sb.StartupProjects == null)
{
WriteLine(2, "ReadSettingsOfStartupProject-End: StartupProjects not available");
return false;
}
foreach (String item in (Array)sb.StartupProjects)
{
msg += item;
}
WriteLine(3, "startupProjects=" + msg);
Get startup project interface
EnvDTE.Project startupProj = FindProject(nameStartupProject);
Implementation detail: DTE allows iteration over projects
foreach (EnvDTE.Project project in dte.Solution.Projects)
Implementation detail: Hierarchical recursive search through tree of project items within method FindProjectRecursive:
foreach (EnvDTE.ProjectItem item in project.ProjectItems)
{
EnvDTE.Project realProject = item.Object as EnvDTE.Project;
if (realProject != null)
{
if (realProject.Kind == EnvDTE.Constants.vsProjectKindSolutionItems)
{
EnvDTE.Project projectNextLevel = FindProjectRecursive(
realProject, nameProject);
if (projectNextLevel != null)
{
return projectNextLevel;
}
}
else if (realProject.Name == nameProject)
{
return realProject;
}
}
}
Get name and path of generated executable (depends on previously found startupProj and configName)
Microsoft.VisualStudio.VCProjectEngine.VCProject vcProj = null;
try
{
vcProj = (Microsoft.VisualStudio.VCProjectEngine.VCProject)startupProj.Object;
if (vcProj ==null)
{
WriteLine(1, "Project is not of type VCProject and is not supported!");
return false;
}
}
catch (Exception ex)
{
WriteLine(2, "ReadSettingsOfStartupProject-End: EXCEPTION: " + ex.ToString());
WriteLine(1, "Project is not of type VCProject and is not supported!");
return false;
}
Microsoft.VisualStudio.VCProjectEngine.IVCCollection configs =
(Microsoft.VisualStudio.VCProjectEngine.IVCCollection)vcProj.Configurations;
Microsoft.VisualStudio.VCProjectEngine.VCConfiguration config =
FindConfig(configs, configName, m_platFormStartupProject);
if (config == null)
{
WriteLine(1, "Config " + configName + " not found");
return false;
}
msg = "PrimaryOutput (FullExePath)=" + config.PrimaryOutput;
WriteLine(2, msg);
Helper function to find a given configuration
private Microsoft.VisualStudio.VCProjectEngine.VCConfiguration FindConfig(Microsoft.VisualStudio.VCProjectEngine.IVCCollection in_configurations, String in_configName, String in_platform)
{
string expectedConfigName = in_configName + "|" + in_platform;
WriteLine(3, "FindConfig: searching for config " + expectedConfigName);
if ((in_configurations == null) || (in_configurations.Count <= 0))
{
WriteLine(3, "FindConfig: in_configurations is null or empty");
return null;
}
WriteLine(3, "FindConfig: configurations.Count=" + in_configurations.Count);
foreach (Microsoft.VisualStudio.VCProjectEngine.VCConfiguration configItem in in_configurations)
{
WriteLine(3, "FindConfig: configItem.Name=>" + configItem.Name + "< .ConfigurationName=>" + configItem.ConfigurationName);
if (configItem.Name == expectedConfigName)
{
return configItem;
}
}
return null;
}
Automate Visual Studio
Open a text file within Visual Studio
public void OpenFile(string in_fullFilePath, int in_lineNum = 0)
{
WriteLine(3, "OpenFile " + in_fullFilePath + " line " + in_lineNum);
try
{
ThreadHelper.ThrowIfNotOnUIThread();
dte.ItemOperations.OpenFile(in_fullFilePath, EnvDTE.Constants.vsViewKindTextView);
if (in_lineNum>0)
{
dte.ExecuteCommand("Edit.Goto",in_lineNum.ToString());
}
}
catch (Exception ex)
{
WriteLine(1, "Could not open file " + in_fullFilePath + "\nEXCEPTION: " + ex.ToString());
}
}
Start debugging with special command line options
public void StartDebugging(string in_cmdLineParams)
{
try
{
ThreadHelper.ThrowIfNotOnUIThread();
if (m_startupProj != null)
{
string cmdLineParams = "";
if (in_cmdLineParams != null)
{
cmdLineParams = in_cmdLineParams;
}
string configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
Microsoft.VisualStudio.VCProjectEngine.VCProject vcProj =
(Microsoft.VisualStudio.VCProjectEngine.VCProject)m_startupProj.Object;
Microsoft.VisualStudio.VCProjectEngine.IVCCollection configs =
(Microsoft.VisualStudio.VCProjectEngine.IVCCollection)vcProj.Configurations;
Microsoft.VisualStudio.VCProjectEngine.VCConfiguration config =
FindConfig(configs, configName, m_platFormStartupProject);
Microsoft.VisualStudio.VCProjectEngine.VCDebugSettings dbgSettings =
(Microsoft.VisualStudio.VCProjectEngine.VCDebugSettings)config.DebugSettings;
dbgSettings.CommandArguments = cmdLineParams;
WriteLine(2, "StartDebugging: now starting debugger with dbgSettings.CommandArguments=" + dbgSettings.CommandArguments);
dte.Debugger.Go(false );
}
}
catch (Exception ex)
{
WriteLine(1, "Could not start debugging\nEXCEPTION: " + ex.ToString());
}
}