Работа со свойствами проекта Visual C++
Рассмотрим, как использовать интерфейсы в Microsoft.VisualStudio.VCProjectEngine.dll (в частности, IVCRulePropertyStorage) для получения и установки свойств проекта Visual C++ и свойств экземпляра проекта. Рекомендуем использовать эти интерфейсы, поскольку свойства проекта Visual C++ недоступны через GetProperty, а их стабильность в других версиях не гарантируется.
Свойства проекта Visual C++ определяются в файлах директории %ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\1033\. Например, файл general.xml содержит общие свойства проекта, файл debugger_general.xml — общие свойства отладчика и т. д. Для чтения и записи только тех свойств, для которых используется один из этих файлов, можно использовать интерфейс IVCRulePropertyStorage.
Для установки и получения свойств экземпляра проекта Visual C++ используется свойство Tool.
Разные типы файлов экземпляра имеют разные наборы свойств. Чтобы найти тип экземпляра файла в Обозревателе решений Visual Studio, откройте контекстное меню файла и выберите Свойства. Например, тип экземпляра файла с расширением .CPP отображается как Компилятор C/C++. Как найти все свойства определенного типа экземпляра:
Найдите отображаемое имя типа экземпляра в директории %ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\1033\. Например, если вы ищете "Компилятор C/C++", то файл ProjectItemsSchema.xml показывает, что имя соответствующего типа экземпляра — ClCompile.
В той же директории находятся правила файла для этого типа экземпляра. (Поскольку ClCompile встречается во многих несвязанных файлах .TARGETS и .PROPS, в данном случае можно ограничить поиск файлами с расширением .XML.) Файл правил для типа экземпляра ClCompile — cl.xml.
Найдите файл правил для искомого свойства. Например, свойство с отображаемым именем Дополнительные каталоги включаемых файлов имеет имя свойства AdditionalIncludeDirectories.
Файл правил также определяет, сохранено ли данное свойство. Свойства, связанные с типом экземпляра ClCompile, сохраняются в файл проекта. (Ищите атрибут Persistence.) Измененные значения свойств хранятся в файле проекта.
Дополнительные сведения об использовании и расширении страниц свойств Visual C++ см. в следующих разделах. В них упоминается Visual Studio 2010, но информация о свойствах проекта еще действительна.
Чтобы посмотреть, как работает данный код, можно интегрировать его в VSPackage с именем TestVCProjectProperties, где есть команда меню "Свойства тестового проекта". Дополнительные сведения об этой операции см. в разделе Пошаговое руководство: Создание команды меню ресурсов с помощью шаблона пакета Visual Studio.
Получение и установка свойств проекта Visual C++
В диалоговом окне Свойства проекта на вкладке Расширения добавьте ссылку на Microsoft.VisualStudio.VCProjectEngine, а на вкладке Платформа — ссылку на System.Windows.Forms.
Откройте файл TestVCProjectPropertiesPackage.cs. Добавьте следующие директивы using:
using EnvDTE; using EnvDTE80; using System.Windows.Forms; using Microsoft.VisualStudio.VCProjectEngine;
Добавьте ссылку на объект приложения (в данном случае DTE2) в класс TestVCProjectPropertiesPackage и приведите его в методе Initialize:
public sealed class TestProjectPropertiesPackage : Package { DTE2 dte2; . . . protected override void Initialize() { Debug.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString())); base.Initialize(); // Add command handlers for the menu (commands must exist in the .vsct file) OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; if ( null != mcs ) { // Create the command for the menu item. CommandID menuCommandID = new CommandID(GuidList.guidTestProjectPropertiesCmdSet, (int)PkgCmdIDList.cmdidMyCommand); MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID ); mcs.AddCommand( menuItem ); } dte2 = (DTE2)GetService(typeof(DTE)); } }
Удалите существующий код из метода MenuItemCallback. Добавьте код для получения открытых проектов. Убедитесь, что проект действительно открыт.
private void MenuItemCallback(object sender, EventArgs e) { VCProject prj; Projects projColl = dte2.Solution.Projects; if (projColl.Count == 0) { MessageBox.Show("You must have a project open in the experimental instance."); return; } if (projColl.Count > 0) { // To be filled in later } }
Получите первый проект и найдите конфигурацию проекта с именем Win32|Debug:
private void MenuItemCallback(object sender, EventArgs e) { VCProject prj; Projects projColl = dte2.Solution.Projects; if (projColl.Count == 0) { MessageBox.Show("You must have a project open in the experimental instance."); return; } if (projColl.Count > 0) { prj = (VCProject)dte2.Solution.Projects.Item(1).Object; VCConfiguration config = prj.Configurations.Item("Debug|Win32"); } }
На данном этапе вы получаете свойство IncludePath из правила ConfigurationDirectories и добавляете к текущему значению D:\Include.
Примечание
Для получения значений свойства можно использовать один из двух методов.Метод GetUnevaluatedPropertyValue получает значение без оценки каких-либо свойства (например, $(SolutionDir)), а метод GetEvaluatedPropertyValue раскрывает эти свойства.
private void MenuItemCallback(object sender, EventArgs e) { VCProject prj; Projects projColl = dte2.Solution.Projects; if (projColl.Count == 0) { MessageBox.Show("You must have a project open in the experimental instance."); return; } if (projColl.Count > 0) { prj = (VCProject)dte2.Solution.Projects.Item(1).Object; VCConfiguration config = prj.Configurations.Item("Debug|Win32"); IVCRulePropertyStorage rule = config.Rules.Item("ConfigurationDirectories") as IVCRulePropertyStorage; string rawValue = rule.GetUnevaluatedPropertyValue("IncludePath"); string evaluatedValue = rule.GetEvaluatedPropertyValue("IncludePath"); rule.SetPropertyValue("IncludePath", rawValue + "D:\\Include;"); // Get the new property value MessageBox.Show(rule.GetUnevaluatedPropertyValue("IncludePath")); } }
Постройте решение и запустите отладку. Построение появится во втором экземпляре Visual Studio, который называется экспериментальным. Откройте проект Visual C++ в экспериментальном экземпляре. В строке меню выберите Сервис, Свойства тестового проекта. В диалоговом окне появится значение $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include;.
Получение и установка свойств экземпляра проекта Visual C++
В проекте TestVCProjectProperties, созданном в ходе выполнения предыдущей процедуры, перейдите к методу MenuItemCallback. Добавьте следующий код, чтобы найти файл .CPP в проекте, получите свойство Дополнительные каталоги включаемых файлов и установите его в D:\Include. Откройте диалоговое окно, в котором отображается новое значение:
private void MenuItemCallback(object sender, EventArgs e) { VCProject prj; Projects projColl = dte2.Solution.Projects; if (projColl.Count == 0) { MessageBox.Show("You must have a project open in the experimental instance."); return; } if (projColl.Count > 0) { prj = (VCProject)dte2.Solution.Projects.Item(1).Object; VCConfiguration config = prj.Configurations.Item("Debug|Win32"); IVCRulePropertyStorage rule = config.Rules.Item("ConfigurationDirectories") as IVCRulePropertyStorage; string rawValue = rule.GetUnevaluatedPropertyValue("IncludePath"); string evaluatedValue = rule.GetEvaluatedPropertyValue("IncludePath"); rule.SetPropertyValue("IncludePath", rawValue + "D:\\Include;"); // Get the new property value MessageBox.Show(rule.GetUnevaluatedPropertyValue("IncludePath")); foreach (VCFile file in prj.Files) { if (file.FileType == eFileType.eFileTypeCppCode) { VCFileConfiguration fileConfig = file.FileConfigurations.Item("Debug|Win32") as VCFileConfiguration; IVCRulePropertyStorage fileRule = fileConfig.Tool as IVCRulePropertyStorage; string evaluatedValue2 = fileRule.GetEvaluatedPropertyValue("AdditionalIncludeDirectories"); fileRule.SetPropertyValue("AdditionalIncludeDirectories", "D:\\Include"); MessageBox.Show(fileRule.GetEvaluatedPropertyValue("AdditionalIncludeDirectories")); } } } }
Постройте решение и запустите отладку. Откройте проект Visual C++ в экспериментальном экземпляре. В строке меню выберите Сервис, Свойства тестового проекта. В одном диалоговом окне отображается значение $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include;, а в другом — D:\Include.
Чтобы проверить, куда сохранилось данное свойство, сохраните все файлы открытого проекта в экспериментальном экземпляре. Новое значение появится в файле .VCXPROJ.
Определение изменений в значениях свойства
Вы можете подписаться на событие ItemPropertyChange2, чтобы узнать, когда свойство проекта Visual C++ или свойство экземпляра проекта получат другое значение.
В классе TestVCProjectPropertiesPackage создайте обработчик для этого события. В данном случае обработчик просто отображает диалоговое окно с указанием измененного свойства.
void OnVCProjectEngineItemPropertyChange(Object item, string strPropertySheet, string strItemType, string PropertyName) { MessageBox.Show("got property change event for " + PropertyName); }
В методе Initialize получите VCProjectEngineEventsObject из событий объекта приложения и добавьте только что созданный обработчик событий:
protected override void Initialize() { Debug.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString())); base.Initialize(); // Add the command handlers for the menu (commands must exist in the .vsct file) OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; if ( null != mcs ) { // Create the command for the menu item CommandID menuCommandID = new CommandID(GuidList.guidTestProjectPropertiesCmdSet, (int)PkgCmdIDList.cmdidMyCommand); MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID ); mcs.AddCommand( menuItem ); } dte2 = (DTE2)GetService(typeof(DTE)); VCProjectEngineEvents vcProjectEvents = dte2.Events.GetObject("VCProjectEngineEventsObject") as VCProjectEngineEvents; vcProjectEvents.ItemPropertyChange2 += new _dispVCProjectEngineEvents_ItemPropertyChange2EventHandler(OnVCProjectEngineItemPropertyChange); }
Постройте решение и запустите отладку. Откройте проект Visual C++ в экспериментальном экземпляре. В строке меню выберите Сервис, Свойства тестового проекта. В одном диалоговом окне отображается значение $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include;, в другом — Получено событие изменения свойства для IncludePath, в третьем — D:\Include, а в четвертом — Получено событие изменения свойства для AdditionalIncludeDirectories.
Примечание
События изменения свойства не выдаются, если изменения в коде уже сохранены.Чтобы увидеть событие, измените значение свойства.