Программно получать текущую директорию решения IDE Visual Studio из добавлений
У меня есть некоторые инструменты, которые выполняют обновления в .NET-решениях, но им нужно знать каталог, в котором находится решение.
Я добавил эти инструменты в качестве внешних инструментов, где они появляются в меню инструментов IDE, и поставляя $(SolutionDir)
в качестве аргумента. Это прекрасно работает.
Тем не менее, я хочу, чтобы эти инструменты были легче получить доступ в среде IDE для пользователя через пользовательское меню верхнего уровня (для которого я создал проект пакета интеграции Visual Studio) и через контекстное меню на узлах решения (для которых я создал проект надстройки Visual Studio). Я ищу способ получить текущую директорию решений через эти контексты.
Я попытался получить информацию о решении из объекта VisualStudio.DTE
:
EnvDTE.DTE dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
string solutionDir = System.IO.Path.GetDirectoryName(dte.Solution.FullName);
Но это возвращает каталог решений для add ins, а не текущее решение.
Я попытался повторить $(SolutionDir)
и прочесть его:
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "echo $(SolutionDir)");
// The following commands are needed to redirect the standard output.
// This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
Но это вернуло каталог для IDE, а не текущее решение.
Я не видел никакой важной информации в решении node CommandBar
.
В качестве альтернативы, если бы был способ программного доступа к определенным внешним инструментам Visual Studio и запускать их (используя уже определенные макрокоманды), это сработало бы.
Какое решение?
Ответы
Ответ 1
EnvDTE.DTE dte = (EnvDTE.DTE) System.Runtime.InteropServices.Marshal.GetActiveObject( "VisualStudio.DTE" ); string solutionDir = System.IO.Path.GetDirectoryName(dte.Solution.FullName);
Но это возвращает решение каталог для добавок, а не текущее решение.
Ваш подход к получению каталога хорош. Неправильно то, как вы получаете объект VisualStudio.DTE
. Где этот код называется? Я предполагаю, что это в вашей надстройке. Вы выполняете (отлаживаете) свою надстройку в Visual Studio, которая открывает другой экземпляр Visual Studio, где вы открываете свое решение? Таким образом, у вас есть два экземпляра Visual Studio.
GetActiveObject("VisualStudio.DTE")
получает случайный экземпляр Visual Studio. В вашем случае это, по-видимому, Visual Studio с проектом надстройки, так как вы получаете путь к своей надстройке. Это для объяснения, что послужило бы причиной вашей проблемы.
Правильный способ получить DTE
очень прост. Фактически, ваша надстройка уже имеет ссылку на DTE, в которой она работает (то есть, в которой открывается решение). Он хранится в глобальной переменной _applicationObject в вашем классе подключения надстройки. Он устанавливается, когда надстройка запускается в обработчике событий OnConnection
. Так что вам нужно только позвонить:
string solutionDir = System.IO.Path.GetDirectoryName(_applicationObject.Solution.FullName);
Ответ 2
С нажатием кнопки Peter в правильном направлении я настраиваю контекстное меню addin для запуска внешнего инструмента с каталогом решений и вывода результатов на панель вывода. Пример примера из добавления:
///--------------------------------------------------------------------------------
/// <summary>This method implements the OnConnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being loaded.</summary>
///
/// <param term='application'>Root object of the host application.</param>
/// <param term='connectMode'>Describes how the Add-in is being loaded.</param>
/// <param term='addInInst'>Object representing this Add-in.</param>
/// <seealso class='IDTExtensibility2' />
///--------------------------------------------------------------------------------
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
// Get the solution command bar
CommandBar solutionCommandBar = ((CommandBars)_applicationObject.CommandBars)["Solution"];
// Set up the main InCode
CommandBarPopup solutionPopup = (CommandBarPopup)solutionCommandBar.Controls.Add(MsoControlType.msoControlPopup, System.Reflection.Missing.Value, System.Reflection.Missing.Value, 1, true);
solutionPopup.Caption = "InCode";
// Add solution updater submenu
CommandBarControl solutionUpdaterControl = solutionPopup.Controls.Add(MsoControlType.msoControlButton, System.Reflection.Missing.Value, System.Reflection.Missing.Value, 1, true);
solutionUpdaterControl.Caption = "Update Solution";
updateSolutionMenuItemHandler = (CommandBarEvents)_applicationObject.Events.get_CommandBarEvents(solutionUpdaterControl);
updateSolutionMenuItemHandler.Click += new _dispCommandBarControlEvents_ClickEventHandler(updateSolution_Click);
}
// The event handlers for the solution submenu items
CommandBarEvents updateSolutionMenuItemHandler;
///--------------------------------------------------------------------------------
/// <summary>This property gets the solution updater output pane.</summary>
///--------------------------------------------------------------------------------
protected OutputWindowPane _solutionUpdaterPane = null;
protected OutputWindowPane SolutionUpdaterPane
{
get
{
if (_solutionUpdaterPane == null)
{
OutputWindow outputWindow = _applicationObject.ToolWindows.OutputWindow;
foreach (OutputWindowPane loopPane in outputWindow.OutputWindowPanes)
{
if (loopPane.Name == "Solution Updater")
{
_solutionUpdaterPane = loopPane;
return _solutionUpdaterPane;
}
}
_solutionUpdaterPane = outputWindow.OutputWindowPanes.Add("Solution Updater");
}
return _solutionUpdaterPane;
}
}
///--------------------------------------------------------------------------------
/// <summary>This method handles clicking on the Update Solution submenu.</summary>
///
/// <param term='inputCommandBarControl'>The control that is source of the click.</param>
/// <param term='handled'>Handled flag.</param>
/// <param term='cancelDefault'>Cancel default flag.</param>
///--------------------------------------------------------------------------------
protected void updateSolution_Click(object inputCommandBarControl, ref bool handled, ref bool cancelDefault)
{
try
{
// set up and execute solution updater thread
UpdateSolutionDelegate updateSolutionDelegate = UpdateSolution;
updateSolutionDelegate.BeginInvoke(UpdateSolutionCompleted, updateSolutionDelegate);
}
catch (System.Exception ex)
{
// put exception message in output pane
SolutionUpdaterPane.OutputString(ex.Message);
}
}
protected delegate void UpdateSolutionDelegate();
///--------------------------------------------------------------------------------
/// <summary>This method launches the solution updater to update the solution.</summary>
///--------------------------------------------------------------------------------
protected void UpdateSolution()
{
try
{
// set up solution updater process
string solutionDir = System.IO.Path.GetDirectoryName(_applicationObject.Solution.FullName);
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo(@"SolutionUpdater.exe", solutionDir);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
// execute the solution updater
proc.Start();
// put solution updater output to output pane
SolutionUpdaterPane.OutputString(proc.StandardOutput.ReadToEnd());
SolutionUpdaterPane.OutputString("Solution update complete.");
}
catch (System.Exception ex)
{
// put exception message in output pane
SolutionUpdaterPane.OutputString(ex.Message);
}
}
///--------------------------------------------------------------------------------
/// <summary>This method completing the update solution thread.</summary>
///
/// <param name="ar">IAsyncResult.</param>
///--------------------------------------------------------------------------------
protected void UpdateSolutionCompleted(IAsyncResult ar)
{
try
{
if (ar == null) throw new ArgumentNullException("ar");
UpdateSolutionDelegate updateSolutionDelegate = ar.AsyncState as UpdateSolutionDelegate;
Trace.Assert(updateSolutionDelegate != null, "Invalid object type");
updateSolutionDelegate.EndInvoke(ar);
}
catch (System.Exception ex)
{
// put exception message in output pane
SolutionUpdaterPane.OutputString(ex.Message);
}
}