How to dynamically Import/Export settings in Visual Studio 2005.
Since .vssettings files were first introduced in Visual Studio 2005, I've seen many questions about how the Import/Export settings mechanism can be controlled through code. This was something that bothered me too since VS2005 Beta 1 but it didn't take long till I figure out the solution. I have now created two methods that I use in all VSPackages that I create, that do the job.
The Import/Export mechanism in Visual Studio 2005 can be controlled with the use of a number of interfaces, provided with the Visual Studio SDK. These interfaces are not documented and, for some of them, the usual "This interface supports the VSIP infrastructure and is not intended to be used directly from your code." phrase, is the only info in the documentation.
The interfaces used (in managed code) all come from the Microsoft.VisualStudio.Shell.Interop.8.0.dll assembly and these are:
Microsoft.VisualStudio.Shell.Interop.IVsProfileSettingsTree
Microsoft.VisualStudio.Shell.Interop.IVsSettingsErrorInformation
Microsoft.VisualStudio.Shell.Interop.IVsProfileSettingsFileCollection
Microsoft.VisualStudio.Shell.Interop.IVsProfileSettingsFileInfo
Before proceeding, we must:
i) Be sure that our VSPackage implements at least one of the methods needed to provide VS with the settings we want to import or export. This is either a Microsoft.VisualStudio.Shell.DialogPage class implementing a number of properties, or an implementation of Microsoft.VisualStudio.Shell.IProfileManager. For information on how to create a profile manager by implementing Microsoft.VisualStudio.Shell.IProfileManager in managed code, see How to: Export Settings Using the Managed Package Framework in the Visual Studio SDK documentation. The easiest way however is to add additional properties we wish to save, to an existing Microsoft.VisualStudio.Shell.DialogPage and add a System.ComponentModel.BrowsableAttribute to them, set to False, if we don't want them to appear to the user through the Options window. In any case, a Microsoft.VisualStudio.Shell.ProvideProfileAttribute must be added to our VSPackage class (the class implementing Microsoft.VisualStudio.Shell.Interop.IVsPackage). We must also be sure that the SupportsProfiles property of any Microsoft.VisualStudio.Shell.ProvideOptionPageAttribute attributes added to our VSPackage, is set to True.
<MSVSIP.ProvideOptionPageAttribute(GetType(OptionsPageGeneral), "Amadeus IDEWindowsState", "General", 105, 106, True, SupportsProfiles:=True)> _
<MSVSIP.ProvideProfileAttribute(GetType(OptionsPageGeneral), "Amadeus IDEWindowsState", "IDEWindowsState General Settings", 105, 108, True, GroupName:="Amadeus", GroupResourceID:=104, DescriptionResourceID:=103)> _
ii) Know the path of our settings in the settings file. This is almost the same as the value we use to access our settings through automation. To determine the exact path, we use the info we initially provided to the Microsoft.VisualStudio.Shell.ProvideProfileAttribute. This path is:
[GroupName]\categoryName_objectName
In the example above, the path would be "Amadeus\Amadeus IDEWindowsState_IDEWindowsState General Settings". If we have provided a GroupName (which is a group in the tree of options in the Options window, our options pages are grouped under) as in the example above, we can only provide the GroupName as path, in which case all the settings of our VSPackage will be exported.
I will now provide the code of two methods (in Visual Basic) that can be used to import/export settings through code.
The first method is:
| Function ExportSettings(Optional ByVal externalFile As String = "", Optional ByVal settingsPath As String = "") As Boolean |
| externalFile: The name of the file where our settings will be saved. Not a path and without the extension. If not defined, settingsPath is ignored and all VS settings will be exported in the default file (usually currentsettings.vssetings). |
| settingsPath: The path to our settings in the settings file. (see above) |
1: #Region " ExportSettings "
2: Friend Function ExportSettings(Optional ByVal externalFile As String = "", Optional ByVal settingsPath As String = "") As Boolean
3: Try
4: ' The profile manager that provides programmatic control of settings.
5: Dim prf As IVsProfileDataManager = CType(m_Package.GetVSService(GetType(SVsProfileDataManager)), _
6: IVsProfileDataManager)
7:
8: ' All the settings in a .vssettings file.
9: Dim sets As IVsProfileSettingsTree = Nothing
10: ' The specific settings we wish to export.
11: Dim wl As IVsProfileSettingsTree = Nothing
12: ' Interface used to retrieve progress status.
13: Dim ret As IVsSettingsErrorInformation = Nothing
14: ' Variable that holds the extension of .vssettings files.
15: Dim ext As String = ""
16: ' The path to the default directory that contains the files.
17: Dim path As String = ""
18: ' The name of the file were settings will be exported.
19: Dim file As String = ""
20:
21: If prf IsNot Nothing Then
22: m_Package.ShowFeedback("Exporting Settings...") 23:
24: With prf
25: ' Get the path to the default directory that contains the settings files.
26: ' This is the one defined by the user in Tools->Options->Environment->
27: ' General->Import and Export Settings.
28: .GetDefaultSettingsLocation(path)
29: ' Get the standard extension of the settings file.
30: .GetSettingsFileExtension(ext)
31: ' Get all the settings that can be exported at this moment.
32: ' This will call all properties in any DialogPage classes of the
33: ' VSPackage.
34: .GetSettingsForExport(sets)
35:
36: ' If the caller has provided a filename, we use this.
37: ' Otherwise we use currentsettings which is the default file
38: ' VS uses to store settings.
39: If externalFile <> "" Then
40: If Not PackageUtilities.ContainsInvalidFileNameChars(externalFile) Then
41: file = externalFile
42: Else
43: Throw New ArgumentException("Invalid file name specified.", _ 44: "externalFile")
45: End If
46:
47: ' If the caller only wishes to export specific settings
48: ' (like the settings of this VSPackage), we need to disable
49: ' exporting of any other settings and enable only the settings
50: ' we want to export. Otherwise, all VS settings will be exported.
51: If settingsPath <> "" Then
52: ' First disable all settings.
53: sets.SetEnabled(0, 1)
54: ' Find the specified child tree of settings.
55: ' (The settings file has XML structure.)
56: sets.FindChildTree(settingsPath, wl)
57: If wl IsNot Nothing Then
58: ' If the child tree is found, enable it.
59: wl.SetEnabled(1, 1)
60: Else
61: ' The specified settings path, does not exist in the
62: ' collection of settings retrieved from all VSPackages.
63: Throw New ArgumentException("Settings path does not exist.", _ 64: "settingsPath")
65: End If
66: End If
67: Else
68: ' The caller has not specified a specific filename.
69: ' We will export all settings to the default file. We will
70: ' not use this file for specific settings. VS uses this file
71: ' to store all settings.
72: file = "currentsettings"
73: End If
74:
75: ' Export settings. Success/Fail info can be retrieved
76: ' from the IVsSettingsErrorInformation interface we provide
77: ' in the ppsettingsErrorInformation argument. But the call
78: ' will also return an error code we can use to determine errors.
79: Dim retCode As Int32 = .ExportSettings((path & file & ext), sets, ret)
80: ' Now we can check success.
81: Dim ex As Exception = Marshal.GetExceptionForHR(retCode)
82:
83: ' You can respond to possible failure, anyway you want.
84: If ex IsNot Nothing Then
85: My.TraceInfo.Write(CStr(ex.Message))
86: m_Package.ShowFeedback("Exporting Settings..." & ex.Message) 87: Return False
88: Else
89: m_Package.ShowFeedback("Exporting Settings...Complete.") 90: Return True
91: End If
92: End With
93: Else
94: ' The profile manager was not obtained.
95: Return False
96: End If
97: Catch exM As Exception
98: ' Any other exceptions?
99: m_Package.ShowFeedback("Exporting Settings..." & exM.Message) 100: My.TraceInfo.Write(CStr(exM.Message))
101: Return False
102: End Try
103: End Function
104: #End Region
The second method is:
| Function ImportSettings(Optional ByVal externalFile As String = "", Optional ByVal settingsPath As String = "") As Boolean |
| externalFile: The name of the file where our settings will be saved. Not a path and without the extension. If not defined, our settings will be retrieved from the default file VS uses to store settings (usually currentsettings.vssetings). |
| settingsPath: The path to our settings in the settings file. (see above) |
1: #Region " ImportSettings "
2: Friend Function ImportSettings(Optional ByVal externalFile As String = "", Optional ByVal settingsPath As String = "") As Boolean
3: Try
4: ' The profile manager that provides programmatic control of settings.
5: Dim prf As IVsProfileDataManager = CType(m_Package.GetVSService(GetType(SVsProfileDataManager)), _
6: IVsProfileDataManager)
7:
8: ' All the settings in a .vssettings file.
9: Dim sets As IVsProfileSettingsTree = Nothing
10: ' The specific settings we wish to import.
11: Dim wl As IVsProfileSettingsTree = Nothing
12: ' Interface used to retrieve progress status.
13: Dim ret As IVsSettingsErrorInformation = Nothing
14: ' The collection of .vssettings files in a directory.
15: Dim col As IVsProfileSettingsFileCollection = Nothing
16: ' Info of a .vssettings file.
17: Dim prfInfo As IVsProfileSettingsFileInfo = Nothing
18: ' Variable that holds the extension of settings files.
19: Dim ext As String = ""
20: ' The number of .vssettings files in directory.
21: Dim setFiles As Int32
22: ' The path of the .vssettings file that contains the settings we wish to import.
23: Dim setFile As String = ""
24: ' The name of the file that contains the settings we wish to import.
25: Dim file As String = ""
26:
27: If prf IsNot Nothing Then
28: ' If the caller has provided a filename, we use this.
29: ' Otherwise we use currentsettings which is the default file
30: ' VS uses to store settings.
31: If externalFile <> "" Then
32: file = externalFile
33: Else
34: file = "currentsettings"
35: End If
36:
37: ' Get the standard extension of the settings file.
38: prf.GetSettingsFileExtension(ext)
39: ' Get the collection of settings files in the directory defined by the
40: ' user in Tools->Options->Environment->General->Import and Export Settings.
41: prf.GetSettingsFiles(CUInt(ShellInterop.__VSPROFILELOCATIONS.PFL_SettingsDir), col)
42: ' Get the number of files in the collection.
43: col.GetCount(setFiles)
44:
45: ' Enumerate the collection to find the requested file.
46: For ii As Int32 = 0 To setFiles
47: col.GetSettingsFile(ii, prfInfo)
48:
49: If prfInfo IsNot Nothing Then
50: prfInfo.GetFilePath(setFile)
51: End If
52:
53: If setFile.Contains(file & ext) Then
54: Exit For
55: End If
56: Next
57:
58: ' If the file is found, we can proceed.
59: If prfInfo IsNot Nothing Then
60: Dim retCode As Int32
61:
62: ' Get all the settings available in the file.
63: prfInfo.GetSettingsForImport(sets)
64:
65: ' If the caller does not request for specific settings,
66: ' proceed with importing all the settings in the file.
67: ' Otherwise we will search for the specified child tree of
68: ' settings in the file. (The settings file has XML structure.)
69: If settingsPath = "" Then
70: ' Import settings. Success/Fail info can be retrieved
71: ' from the IVsSettingsErrorInformation interface we provide
72: ' in the ppsettingsErrorInformation argument. But the call
73: ' will also return an error code we can use to determine errors.
74: retCode = prf.ImportSettings(sets, ret)
75: Else
76: ' Find the specified child tree.
77: sets.FindChildTree(settingsPath, wl)
78:
79: If wl IsNot Nothing Then
80: ' Import settings. Success/Fail info can be retrieved
81: ' from the IVsSettingsErrorInformation interface we provide
82: ' in the ppsettingsErrorInformation argument. But the call
83: ' will also return an error code we can use to determine errors.
84: retCode = prf.ImportSettings(wl, ret)
85: Else
86: ' The specified settings path, does not exist in this file.
87: Throw New ArgumentException("Settings path does not exist.", _ 88: "settingsPath")
89: End If
90: End If
91:
92: ' Now we can check success.
93: Dim ex As Exception = Marshal.GetExceptionForHR(retCode)
94:
95: ' You can respond to possible failure, anyway you want.
96: If ex IsNot Nothing Then
97: My.TraceInfo.Write(CStr(ex.Message))
98: Return False
99: Else
100: Return True
101: End If
102: Else
103: ' The specified settings file could not be found in the settings directory.
104: Throw New ArgumentException("Invalid file name specified.", _ 105: "externalFile")
106: End If
107: Else
108: ' The profile manager was not obtained.
109: Return False
110: End If
111: Catch exM As Exception
112: ' Any other exceptions?
113: My.TraceInfo.Write(CStr(exM.Message))
114: Return False
115: End Try
116: End Function
117: #End Region
OK, now these will do the job, as long as the settings have been properly implemented in our VSPackage. These may also be changed to accommodate your needs. Some methods seen in these example ( like My.TraceInfo.Write() or m_Package.ShowFeedback() ) are only used for simplicity. They are implemented by the VSPackage implementer and cannot be found in the interop assemblies provided with Visual Studio SDK.