C# Client Library
A C# Client Library for the AnalyzeRe REST API
Loading...
Searching...
No Matches
RegistrySettingsProvider.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Specialized;
3using System.Configuration;
4using System.Diagnostics;
5using System.Globalization;
6using Microsoft.Win32;
7
9{
12 internal class RegistrySettingsProvider : SettingsProvider
13 {
14 // We could read these attributes from the assembly, but we use it in the settings key name so changes would have to be tracked carefully.
15 private const string CompanyName = "Analyze Re";
16 private const string SubKeyPath = @"Software\" + CompanyName;
17
18 // This value is not used anywhere we know
19 public override string ApplicationName { get; set; } = CompanyName;
20 public override string Name => "RegistrySettingsProvider";
21 public override string Description => "Analyze Re - shared registry settings provider";
22
24 private string _initializedName;
25
27 private NameValueCollection _initializedConfig;
28
29 public override void Initialize(string name, NameValueCollection col)
30 {
31 _initializedName = name;
32 _initializedConfig = col;
33 base.Initialize(ApplicationName, col);
34 }
35
36 // SetPropertyValue is invoked when ApplicationSettingsBase.Save is called
37 // ASB makes sure to pass each provider only the values marked for that provider,
38 // whether on a per setting or setting class-wide basis
39 public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
40 {
41 // Iterate through the settings to be stored
42 foreach (SettingsPropertyValue propval in propvals)
43 {
44 // If property hasn't been set, no need to save it
45 if (!propval.IsDirty)
46 {
47 continue;
48 }
49
50 // Application-scoped settings can't change
51 // NOTE: the settings machinery may cause or allow an app-scoped setting
52 // to become dirty, in which case, like the LFSP, we ignore it instead
53 // of throwing an exception
54 if (IsApplicationScoped(propval.Property))
55 {
56 continue;
57 }
58
59 Debug.Print($"RegistrySettingsProvider.SetPropertyValues - Setting {propval.Name} to {propval.SerializedValue}");
60 using (RegistryKey key = CreateRegKey(context, propval.Property))
61 {
62 // If the value has explicitly been set to null, the user probably wishes to clear the value.
63 if (propval.PropertyValue == null)
64 key.DeleteValue(propval.Name);
65 else if (propval.PropertyValue is StringCollection sc)
66 {
67 string[] stringArray = new string[sc.Count];
68 sc.CopyTo(stringArray, 0);
69 key.SetValue(propval.Name, stringArray, RegistryValueKind.MultiString);
70 }
71 else
72 {
73 key.SetValue(propval.Name, propval.SerializedValue);
74 }
75 }
76 }
77 }
78
79 public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection properties)
80 {
81 if (!HasRegKey(context))
82 {
83 // Fall back to reading settings from a LocalFileSettingsProvider, hoping to get old settings for upgrade
84 SettingsPropertyValueCollection localFileValues = GetLocalFilePropertyValues(context, properties);
85
86 // Save those values that don't have default values to the registry
87 foreach (SettingsPropertyValue value in localFileValues)
88 {
89 if (!value.UsingDefaultValue &&
90 value.SerializedValue != value.Property.DefaultValue)
91 {
92 value.IsDirty = true;
93 }
94 }
95
96 SetPropertyValues(context, localFileValues);
97 return localFileValues;
98 }
99
100 SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
101
102 foreach (SettingsProperty prop in properties)
103 {
104 SettingsPropertyValue value = GetPropertyValue(context, prop);
105 Debug.Assert(value != null);
106 values.Add(value);
107 }
108
109 return values;
110 }
111
112 private SettingsPropertyValue GetPropertyValue(SettingsContext context, SettingsProperty prop)
113 {
114 SettingsPropertyValue value = new SettingsPropertyValue(prop);
115
116 // Only User-scoped settings can be found in the Registry.
117 // By leaving the Application-scoped setting's value at null,
118 // we get the "default" value
119 if (IsUserScoped(prop))
120 {
121 using (RegistryKey key = CreateRegKey(context, prop))
122 {
123 object regValue = key.GetValue(prop.Name);
124 if (prop.PropertyType == typeof(StringCollection) &&
125 regValue is string[] regValueStrings)
126 {
127 StringCollection stringCol = new StringCollection();
128 stringCol.AddRange(regValueStrings);
129 value.PropertyValue = stringCol;
130 }
131 else
132 {
133 value.SerializedValue = regValue;
134 }
135 }
136 }
137
138 value.IsDirty = false;
139 return value;
140 }
141
142 // Looks in the "attribute bag" for a given property to determine if it is app-scoped
143 private bool IsApplicationScoped(SettingsProperty prop)
144 {
145 return HasSettingScope(prop, typeof(ApplicationScopedSettingAttribute));
146 }
147
148 // Looks in the "attribute bag" for a given property to determine if it is user-scoped
149 private bool IsUserScoped(SettingsProperty prop)
150 {
151 return HasSettingScope(prop, typeof(UserScopedSettingAttribute));
152 }
153
154 // Checks for app or user-scoped based on the attributeType argument
155 // Also checks for sanity, i.e. a setting not marked as both or neither scope
156 // (just like the LFSP)
157 private bool HasSettingScope(SettingsProperty prop, Type attributeType)
158 {
159 // NOTE: No current support for roaming
160 Debug.Assert(attributeType == typeof(ApplicationScopedSettingAttribute) ||
161 attributeType == typeof(UserScopedSettingAttribute));
162 bool isAppScoped = prop.Attributes[typeof(ApplicationScopedSettingAttribute)] != null;
163 bool isUserScoped = prop.Attributes[typeof(UserScopedSettingAttribute)] != null;
164
165 // Check constraints
166 if (isUserScoped && isAppScoped)
167 throw new Exception("Can't mark a setting as User and Application-scoped: " + prop.Name);
168 if (!isUserScoped && !isAppScoped)
169 throw new Exception("Must mark a setting as User or Application-scoped: " + prop.Name);
170
171 // Return scope check result
172 if (attributeType == typeof(ApplicationScopedSettingAttribute))
173 return isAppScoped;
174 if (attributeType == typeof(UserScopedSettingAttribute))
175 return isUserScoped;
176
177 Debug.Assert(false);
178 return false;
179 }
180
181 private bool HasRegKey(SettingsContext context)
182 {
183 RegistryKey key = Registry.CurrentUser.OpenSubKey($@"{SubKeyPath}\{GetSectionName(context)}", false);
184 return key != null;
185 }
186
187 // Creates a sub-key under HKCU\Software\CompanyName\{GetSectionName(context)}
188 private RegistryKey CreateRegKey(SettingsContext context, SettingsProperty prop)
189 {
190 Debug.Assert(!IsApplicationScoped(prop), "Can't get Registry key for a read-only Application scoped setting: " + prop.Name);
191 return Registry.CurrentUser.CreateSubKey($@"{SubKeyPath}\{GetSectionName(context)}");
192 }
193
194 // From LocalFileSettingsProvider
195 private string GetSectionName(SettingsContext context)
196 {
197 string groupName = (string)context["GroupName"];
198 string key = (string)context["SettingsKey"];
199
200 Debug.Assert(groupName != null, "SettingsContext did not have a GroupName!");
201
202 string sectionName = groupName;
203
204 if (!String.IsNullOrEmpty(key))
205 {
206 sectionName = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", sectionName, key);
207 }
208
209 //return XmlConvert.EncodeLocalName(sectionName);
210 return sectionName;
211 }
212
213 private SettingsPropertyValueCollection GetLocalFilePropertyValues(
214 SettingsContext context, SettingsPropertyCollection properties)
215 {
216 LocalFileSettingsProvider localFile = new LocalFileSettingsProvider();
217 localFile.Initialize(_initializedName, _initializedConfig);
218 return localFile.GetPropertyValues(context, properties);
219 }
220 }
221}