使用 Visual C++ 项目属性

下面介绍了如何使用 Microsoft.VisualStudio.VCProjectEngine.dll(特别是 IVCRulePropertyStorage)中的接口来获取并设置 Visual C++ 项目属性和项目项属性。 建议你使用这些接口,因为不能通过 GetProperty 使用 Visual C++ 项目属性,并且无法保证它们在各个版本中都是固定不变的。

Visual C++ 项目属性将定义在 %ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\1033\ 的文件中。 例如,general.xml 包含常规项目属性;debugger_general.xml 包含常规调试器属性,等等。 你可以使用 IVCRulePropertyStorage 接口仅读写存在这些文件之一的属性。

你可以从 Tool 属性设置和获取 Visual C++ 项目项属性。

不同的文件项目类型具有不同的属性集。 若要在 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 项目类型相关联的属性将保留在项目文件中。 (查找**“持久性”**特性。)你更改的属性值将保留在项目文件中。

有关如何使用和扩展 Visual C++ 属性页的信息,请参阅以下文章。 这些文章提到了 Visual Studio 2010,但是有关项目属性的信息仍然有效。

若要观察以下代码的工作方式,你可以将其集成到名为 TestVCProjectProperties 的 VSPackage 中,它具有名为“测试项目属性”的菜单命令。 有关如何执行此操作的信息,请参阅演练:使用 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. 在此步骤中,你将从 ConfigurationDirectories 规则中获取 IncludePath 属性,并将 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 的属性更改事件”**。

    备注

    在已经保留了此代码中的更改后,你将无法获取属性更改事件。若要查看该事件,请将属性值更改为其他值。