Поделиться через


Работа со свойствами проекта 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++. Как найти все свойства определенного типа экземпляра:

  1. Найдите отображаемое имя типа экземпляра в директории %ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\1033\. Например, если вы ищете "Компилятор C/C++", то файл ProjectItemsSchema.xml показывает, что имя соответствующего типа экземпляра — ClCompile.

  2. В той же директории находятся правила файла для этого типа экземпляра. (Поскольку ClCompile встречается во многих несвязанных файлах .TARGETS и .PROPS, в данном случае можно ограничить поиск файлами с расширением .XML.) Файл правил для типа экземпляра ClCompile — cl.xml.

  3. Найдите файл правил для искомого свойства. Например, свойство с отображаемым именем Дополнительные каталоги включаемых файлов имеет имя свойства AdditionalIncludeDirectories.

  4. Файл правил также определяет, сохранено ли данное свойство. Свойства, связанные с типом экземпляра ClCompile, сохраняются в файл проекта. (Ищите атрибут Persistence.) Измененные значения свойств хранятся в файле проекта.

Дополнительные сведения об использовании и расширении страниц свойств Visual C++ см. в следующих разделах. В них упоминается Visual Studio 2010, но информация о свойствах проекта еще действительна.

Чтобы посмотреть, как работает данный код, можно интегрировать его в VSPackage с именем TestVCProjectProperties, где есть команда меню "Свойства тестового проекта". Дополнительные сведения об этой операции см. в разделе Пошаговое руководство: Создание команды меню ресурсов с помощью шаблона пакета Visual Studio.

Получение и установка свойств проекта Visual C++

  1. В диалоговом окне Свойства проекта на вкладке Расширения добавьте ссылку на Microsoft.VisualStudio.VCProjectEngine, а на вкладке Платформа — ссылку на System.Windows.Forms.

  2. Откройте файл TestVCProjectPropertiesPackage.cs. Добавьте следующие директивы using:

    using EnvDTE;
    using EnvDTE80;
    using System.Windows.Forms;
    using Microsoft.VisualStudio.VCProjectEngine;
    
  3. Добавьте ссылку на объект приложения (в данном случае 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));
        }
    }
    
  4. Удалите существующий код из метода 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
        }
    }
    
  5. Получите первый проект и найдите конфигурацию проекта с именем 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");
        }
    }
    
  6. На данном этапе вы получаете свойство 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"));
        }
    }
    
  7. Постройте решение и запустите отладку. Построение появится во втором экземпляре Visual Studio, который называется экспериментальным. Откройте проект Visual C++ в экспериментальном экземпляре. В строке меню выберите Сервис, Свойства тестового проекта. В диалоговом окне появится значение $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include;.

Получение и установка свойств экземпляра проекта Visual C++

  1. В проекте 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"));
                }
            }  
        }
    }
    
  2. Постройте решение и запустите отладку. Откройте проект Visual C++ в экспериментальном экземпляре. В строке меню выберите Сервис, Свойства тестового проекта. В одном диалоговом окне отображается значение $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include;, а в другом — D:\Include.

  3. Чтобы проверить, куда сохранилось данное свойство, сохраните все файлы открытого проекта в экспериментальном экземпляре. Новое значение появится в файле .VCXPROJ.

Определение изменений в значениях свойства

  1. Вы можете подписаться на событие ItemPropertyChange2, чтобы узнать, когда свойство проекта Visual C++ или свойство экземпляра проекта получат другое значение.

    В классе TestVCProjectPropertiesPackage создайте обработчик для этого события. В данном случае обработчик просто отображает диалоговое окно с указанием измененного свойства.

    void OnVCProjectEngineItemPropertyChange(Object item, string strPropertySheet, string strItemType, string PropertyName)
    {
        MessageBox.Show("got property change event for " + PropertyName);
    }
    
  2. В методе 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);
    }
    
  3. Постройте решение и запустите отладку. Откройте проект Visual C++ в экспериментальном экземпляре. В строке меню выберите Сервис, Свойства тестового проекта. В одном диалоговом окне отображается значение $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include;, в другом — Получено событие изменения свойства для IncludePath, в третьем — D:\Include, а в четвертом — Получено событие изменения свойства для AdditionalIncludeDirectories.

    Примечание

    События изменения свойства не выдаются, если изменения в коде уже сохранены.Чтобы увидеть событие, измените значение свойства.