下面介绍了如何使用 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++ 编译器”**。 下面介绍了如何查找给定项目类型的所有属性:
在 %ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\1033\ 目录中搜索项目类型显示名称。 例如,如果你搜索“C/C++ 编译器”,则 ProjectItemsSchema.xml 文件将显示相应项目类型的名称为 ClCompile。
若要查找该项目类型的规则文件,请在同一目录中进行搜索。 (在这种情况下,因为 ClCompile 会出现在很多不相关的 .targets 和 .props 文件中,因此你可以将搜索限制在 .xml 文件中。)ClCompile 项目类型的规则文件是 cl.xml。
在规则文件中搜索你希望查找的属性。 例如,具有显示名称**“附加包含目录”的属性具有属性名称“AdditionalIncludeDirectories”**。
规则文件还可确定保留给定属性的位置。 与 ClCompile 项目类型相关联的属性将保留在项目文件中。 (查找**“持久性”**特性。)你更改的属性值将保留在项目文件中。
有关如何使用和扩展 Visual C++ 属性页的信息,请参阅以下文章。 这些文章提到了 Visual Studio 2010,但是有关项目属性的信息仍然有效。
若要观察以下代码的工作方式,你可以将其集成到名为 TestVCProjectProperties 的 VSPackage 中,它具有名为“测试项目属性”的菜单命令。 有关如何执行此操作的信息,请参阅演练:使用 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"); } }
在此步骤中,你将从 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")); } }
生成解决方案并启动调试。 生成将在 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 的属性更改事件”**。
备注
在已经保留了此代码中的更改后,你将无法获取属性更改事件。若要查看该事件,请将属性值更改为其他值。