Arbeiten mit Visual C++-Projekteigenschaften
Im Folgenden wird beschrieben, wie die Schnittstellen in "Microsoft.VisualStudio.VCProjectEngine.dll" - insbesondere IVCRulePropertyStorage - verwendet werden, um Visual C++-Projekteigenschaften und Projektelementeigenschaften abzurufen. Es wird empfohlen, diese Schnittstellen zu verwenden, da Visual C++-Projekteigenschaften nicht über GetProperty verfügbar sind und nicht garantiert werden kann, dass sie über verschiedene Versionen hinweg stabil sind.
Visual C++-Projekteigenschaften sind in den Dateien unter "%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\1033\" definiert. Die Datei "general.xml" enthält beispielsweise Projekteigenschaften, "debugger_general.xml" enthält allgemeine Debuggereigenschaften usw. Sie können die IVCRulePropertyStorage-Schnittstelle verwenden, um nur diese Eigenschaften zu lesen und zu schreiben, für die eine dieser Dateien vorhanden ist.
Die Visual C++-Projektelementeigenschaften werden in der Tool-Eigenschaft festgelegt und daraus abgerufen.
Unterschiedliche Dateielementtypen haben unterschiedliche Eigenschaftensätze. Um den Elementtyp einer Datei im Projektmappen-Explorer von Visual Studio zu suchen, öffnen Sie das Kontextmenü für die Datei, und wählen Sie Eigenschaften aus. Der Elementtyp einer CPP-Datei wird beispielsweise als C/C++-Compiler angezeigt. Gehen Sie folgendermaßen vor, um alle Eigenschaften eines bestimmten Elementtyps zu suchen:
Suchen Sie im Verzeichnis "%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\1033\" nach dem Anzeigenamen des Elementtyps. Wenn Sie beispielsweise nach "C/C++-Compiler" suchen, wird in der Datei "ProjectItemsSchema.xml" angezeigt, dass der Name des entsprechenden Elementtyps "CICompile" lautet.
Um die Regeldateien für diesen Elementtyp zu suchen, durchsuchen Sie dasselbe Verzeichnis. (In diesem Fall können Sie die Suche auf XML-Dateien beschränken, da "CICompile" in vielen unzusammenhängenden TARGETS- und PROPS-Dateien vorkommt.) Die Regeldatei für den CICompile-Elementtyp ist "cl.xml".
Suchen Sie die Regeldatei für die Eigenschaft, die Sie suchen möchten. Die Eigenschaft mit dem Anzeigenamen Zusätzliche Includeverzeichnisse weist beispielsweise den Eigenschaftennamen AdditionalIncludeDirectories auf.
Durch die Regeldatei wird auch bestimmt, wo eine bestimmte Eigenschaft gespeichert wird. Die dem ClCompile-Elementtyp zugeordneten Eigenschaften werden in der Projektdatei gespeichert. (Halten Sie nach dem Persistence-Attribut Ausschau.) Die geänderten Eigenschaftswerte werden in der Projektdatei gespeichert.
Informationen zur Verwendung und Erweiterung von Visual C++-Eigenschaftenseiten finden Sie in den folgenden Artikeln. Darin ist von Visual Studio 2010 die Rede, die Informationen zu den Projekteigenschaften gelten aber immer noch.
Um zu beobachten, wie der folgende Code funktioniert, können Sie ihn in ein VSPackage mit dem Namen "TestVCProjectProperties" integrieren, das einen Menübefehl mit dem Namen "Testprojekteigenschaften" aufweist. Informationen dazu finden Sie unter Exemplarische Vorgehensweise: Wenn Sie einen Menübefehl mit der Visual Studio-Paket-Vorlage erstellen.
Abrufen und Festlegen von Visual C++-Projekteigenschaften
Fügen Sie im Dialogfeld Projekteigenschaften auf der Registerkarte Erweiterungen einen Verweis auf "Microsoft.VisualStudio.VCProjectEngine" und auf der Registerkarte Framework einen Verweis auf "System.Windows.Forms" hinzu.
Öffnen Sie die Datei "TestVCProjectPropertiesPackage.cs". Fügen Sie die folgenden using-Direktiven hinzu:
using EnvDTE; using EnvDTE80; using System.Windows.Forms; using Microsoft.VisualStudio.VCProjectEngine;
Fügen Sie einen Verweis auf das Anwendungsobjekt, in diesem Fall DTE2, auf dieTestVCProjectPropertiesPackage-Klasse hinzu, und instanziieren Sie diesen in der Initialize-Methode:
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)); } }
Entfernen Sie folgenden Code aus der MenuItemCallback-Methode. Fügen Sie Code hinzu, um die geöffneten Projekte abzurufen. Vergewissern Sie sich, dass ein Projekt tatsächlich geöffnet ist.
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 } }
Rufen Sie das erste Projekt ab, und suchen Sie die Projektkonfiguration mit dem Namen 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"); } }
In diesem Schritt können Sie die IncludePath-Eigenschaft aus der ConfigurationDirectories-Regel abrufen und D:\Include zu dem aktuellen Wert hinzufügen.
Hinweis
Sie können eine der beiden Methoden verwenden, um die Eigenschaftswerte abzurufen.Die GetUnevaluatedPropertyValue-Methode ruft den Wert ab, ohne Eigenschaften auszuwerten, zum Beispiel $(SolutionDir), und die GetEvaluatedPropertyValue-Methode erweitert diese Eigenschaften.
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")); } }
Erstellen Sie die Projektmappe, und beginnen Sie mit dem Debuggen. Der Buildvorgang wird in einer zweiten Instanz von Visual Studio angezeigt, die als experimentelle Instanz bezeichnet wird. Öffnen Sie ein Visual C++-Projekt in der experimentellen Instanz. Wählen Sie in der Menüleiste Werkzeuge und dann Testprojekteigenschaften aus. In einem Dialogfeld wird der Wert $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include; angezeigt.
Abrufen und Festlegen von Visual C++-Projektelementeigenschaften
Wechseln Sie in dem TestVCProjectProperties-Projekt, das Sie in der vorherigen Vorgehensweise erstellt haben, zu der MenuItemCallback-Methode. Fügen Sie den folgenden Code hinzu, um eine CPP-Datei in dem Projekt zu suchen, rufen Sie die Additional Include Directories-Eigenschaft ab, und legen Sie sie auf D:\Include fest, und zeigen Sie ein Dialogfeld an, in dem der neue Wert dargestellt wird:
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")); } } } }
Erstellen Sie die Projektmappe, und beginnen Sie mit dem Debuggen. Öffnen Sie ein Visual C++-Projekt in der experimentellen Instanz. Wählen Sie in der Menüleiste Werkzeuge und dann Testprojekteigenschaften aus. In einem Dialogfeld wird der Wert $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include; angezeigt; in einem zweiten Dialogfeld wird der Wert D:\Include angezeigt.
Um zu überprüfen, wo dieser Wert gespeichert wird, speichern Sie alle Dateien in dem geöffneten Projekt in der experimentellen Instanz. Der neue Wert wird in der Datei "VCXPROJ" angezeigt.
Erkennen von Eigenschaftswertänderungen
Sie können das ItemPropertyChange2-Ereignis abonnieren, um zu erkennen, wann eine Visual C++-Projekteigenschaft oder eine Projektelementeigenschaft einen anderen Wert annimmt.
Erstellen Sie in der TestVCProjectPropertiesPackage-Klasse einen Ereignishandler für dieses Ereignis. In diesem Fall zeigt der Handler nur ein Dialogfeld an, in dem die Eigenschaft angezeigt wird, die geändert wurde.
void OnVCProjectEngineItemPropertyChange(Object item, string strPropertySheet, string strItemType, string PropertyName) { MessageBox.Show("got property change event for " + PropertyName); }
Rufen Sie in der Initialize-Methode das VCProjectEngineEventsObject aus den Ereignissen des Anwendungsobjekts ab, und fügen Sie den Ereignishandler hinzu, den Sie soeben erstellen haben:
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); }
Erstellen Sie die Projektmappe, und beginnen Sie mit dem Debuggen. Öffnen Sie ein Visual C++-Projekt in der experimentellen Instanz. Wählen Sie in der Menüleiste Werkzeuge und dann Testprojekteigenschaften aus. In einem Dialogfeld wird $(VC_IncludePath);$(WindowsSDK_IncludePath);D:\Include;D:\Include; angezeigt, in einem zweiten Dialogfeld wird Got property change event for IncludePath, in einem dritten Dialogfeld wird D:\Include, und in einem vierten Dialogfeld wird Got property change event for AdditionalIncludeDirectories angezeigt.
Hinweis
Nachdem die Änderungen in diesem Code gespeichert wurden, können Sie das Ereignis der Eigenschaftenänderung nicht abrufen.Um das Ereignis anzuzeigen, ändern Sie den Eigenschaftswert in einen anderen Wert.