How to: Persist the Property of a Project Item
You may want to persist a property you add to a project item, such as the author of a source file. You can do this by storing the property in the project file.
The first step to persist a property in a project file is to obtain the hierarchy of the project as an IVsHierarchy interface. You can obtain this interface either by using Automation or by using IVsMonitorSelection. Once you obtain the interface, you can use it to determine which project item is currently selected. Once you have the project item ID, you can use SetItemAttribute to add the property.
In the following procedures, you persist the VsPkg.cs property Author with the value Tom in the project file.
To obtain the project hierarchy by using Automation
Add the following code to your VSPackage:
Dim dte As EnvDTE.DTE = CType(Package.GetGlobalService(GetType(EnvDTE.DTE)), EnvDTE.DTE) Dim project As EnvDTE.Project = dte.Solution.Projects.Item(1) Dim uniqueName As String = project.UniqueName Dim solution As IVsSolution = CType(Package.GetGlobalService(GetType(SVsSolution)), IVsSolution) Dim hierarchy As IVsHierarchy solution.GetProjectOfUniqueName(uniqueName, hierarchy)
EnvDTE.DTE dte = (EnvDTE.DTE)Package.GetGlobalService(typeof(EnvDTE.DTE)); EnvDTE.Project project = dte.Solution.Projects.Item(1); string uniqueName = project.UniqueName; IVsSolution solution = (IVsSolution)Package.GetGlobalService(typeof(SVsSolution)); IVsHierarchy hierarchy; solution.GetProjectOfUniqueName(uniqueName, out hierarchy);
To persist the project item property by using Automation
Add the following code to the code given in the method in the previous procedure:
Dim buildPropertyStorage As IVsBuildPropertyStorage = CType(hierarchy, IVsBuildPropertyStorage) If Not buildPropertyStorage Is Nothing Then Dim itemId As UInteger Dim fullPath As String = CType(project.ProjectItems.Item("VsPkg.vb").Properties.Item("FullPath").Value, String) hierarchy.ParseCanonicalName(fullPath, itemId) buildPropertyStorage.SetItemAttribute(itemId, "Author", "Tom") End If
IVsBuildPropertyStorage buildPropertyStorage = hierarchy as IVsBuildPropertyStorage; if (buildPropertyStorage != null) { uint itemId; string fullPath = (string)project.ProjectItems.Item("VsPkg.cs").Properties.Item("FullPath").Value; hierarchy.ParseCanonicalName(fullPath, out itemId); buildPropertyStorage.SetItemAttribute(itemId, "Author", "Tom"); }
To obtain the project hierarchy by using IVsMonitorSelection
Add the following code to your VSPackage:
Dim hierarchy As IVsHierarchy = Nothing Dim hierarchyPtr As IntPtr = IntPtr.Zero Dim selectionContainer As IntPtr = IntPtr.Zero Dim itemId As UInteger ' Retrieve shell interface in order to get current selection Dim monitorSelection As IVsMonitorSelection = CType(Package.GetGlobalService(GetType(SVsShellMonitorSelection)), IVsMonitorSelection) If monitorSelection Is Nothing Then Throw New InvalidOperationException End If Try ' Get the current project hierarchy, project item, and selection container for the current selection ' If the selection spans multiple hierarchies, hierarchyPtr is Zero Dim multiItemSelect As IVsMultiItemSelect = Nothing ErrorHandler.ThrowOnFailure(monitorSelection.GetCurrentSelection( hierarchyPtr, itemId, multiItemSelect, selectionContainer)) ' We only care if there is only one node selected in the tree If Not (itemId = VSConstants.VSITEMID.Nil _ Or hierarchyPtr = IntPtr.Zero _ Or (Not multiItemSelect Is Nothing) _ Or itemId = VSConstants.VSITEMID.Selection) Then hierarchy = CType(Marshal.GetObjectForIUnknown(hierarchyPtr), IVsHierarchy) End If Finally If hierarchyPtr <> IntPtr.Zero Then Marshal.Release(hierarchyPtr) End If If selectionContainer <> IntPtr.Zero Then Marshal.Release(selectionContainer) End If End Try
IVsHierarchy hierarchy = null; IntPtr hierarchyPtr = IntPtr.Zero; IntPtr selectionContainer = IntPtr.Zero; uint itemid; // Retrieve shell interface in order to get current selection IVsMonitorSelection monitorSelection = Package.GetGlobalService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection; if (monitorSelection == null) throw new InvalidOperationException(); try { // Get the current project hierarchy, project item, and selection container for the current selection // If the selection spans multiple hierachies, hierarchyPtr is Zero IVsMultiItemSelect multiItemSelect = null; ErrorHandler.ThrowOnFailure( monitorSelection.GetCurrentSelection( out hierarchyPtr, out itemid, out multiItemSelect, out selectionContainer)); // We only care if there is only one node selected in the tree if (!(itemid == VSConstants.VSITEMID_NIL || hierarchyPtr == IntPtr.Zero || multiItemSelect != null || itemid == VSConstants.VSITEMID_SELECTION)) { hierarchy = Marshal.GetObjectForIUnknown(hierarchyPtr) as IVsHierarchy; } } finally { if (hierarchyPtr != IntPtr.Zero) Marshal.Release(hierarchyPtr); if (selectionContainer != IntPtr.Zero) Marshal.Release(selectionContainer); }
To persist the selected project item property, given the project hierarchy
Add the following code to the code given in the method in the previous procedure:
Dim buildPropertyStorage As IVsBuildPropertyStorage = CType(hierarchy, IVsBuildPropertyStorage) If Not buildPropertyStorage Is Nothing Then buildPropertyStorage.SetItemAttribute(itemId, "Author", "Tom") End If
IVsBuildPropertyStorage buildPropertyStorage = hierarchy as IVsBuildPropertyStorage; if (buildPropertyStorage != null) { buildPropertyStorage.SetItemAttribute(itemid, "Author", "Tom"); }
To verify that the property is persisted
Start Visual Studio and then open or create a solution.
Select the project item VsPkg.cs in Solution Explorer.
Use a breakpoint or otherwise determine that your VSPackage is loaded and that SetItemAttribute runs.
Notes
You can autoload a VSPackage in the UI context UICONTEXT_SolutionExists. For more information, see How to: Autoload a VSPackage.
Close Visual Studio and then open the project file in Notepad. You should see the <Author> tag with the value Tom, as follows:
<Compile Include="VsPkg.cs"> <Author>Tom</Author> </Compile>