1 #include <windows.h>
2 #include <shlwapi.h>
3 #include <vector>
4
5 #include "utils/stl.h"
6 #include "utils/utils.h"
7
8
9 #include "registry.h"
10
11 namespace {
12
openKey(HKEY root,const QString & path,HKEY * p_key,REGSAM samDesired=KEY_ALL_ACCESS)13 LONG openKey(HKEY root, const QString& path, HKEY *p_key, REGSAM samDesired = KEY_ALL_ACCESS)
14 {
15 LONG result;
16 result = RegOpenKeyExW(root,
17 path.toStdWString().c_str(),
18 0L,
19 samDesired,
20 p_key);
21
22 return result;
23 }
24
softwareSeafile()25 QString softwareSeafile()
26 {
27 return QString("SOFTWARE\\%1").arg(getBrand());
28 }
29
30 } // namespace
31
RegElement(const HKEY & root,const QString & path,const QString & name,const QString & value,bool expand)32 RegElement::RegElement(const HKEY& root, const QString& path,
33 const QString& name, const QString& value, bool expand)
34 : root_(root),
35 path_(path),
36 name_(name),
37 string_value_(value),
38 dword_value_(0),
39 type_(expand ? REG_EXPAND_SZ : REG_SZ)
40 {
41 }
42
RegElement(const HKEY & root,const QString & path,const QString & name,DWORD value)43 RegElement::RegElement(const HKEY& root, const QString& path,
44 const QString& name, DWORD value)
45 : root_(root),
46 path_(path),
47 name_(name),
48 string_value_(""),
49 dword_value_(value),
50 type_(REG_DWORD)
51 {
52 }
53
openParentKey(HKEY * pKey)54 int RegElement::openParentKey(HKEY *pKey)
55 {
56 DWORD disp;
57 HRESULT result;
58
59 result = RegCreateKeyExW (root_,
60 path_.toStdWString().c_str(),
61 0, NULL,
62 REG_OPTION_NON_VOLATILE,
63 KEY_WRITE | KEY_WOW64_64KEY,
64 NULL,
65 pKey,
66 &disp);
67
68 if (result != ERROR_SUCCESS) {
69 return -1;
70 }
71
72 return 0;
73 }
74
add()75 int RegElement::add()
76 {
77 HKEY parent_key;
78 DWORD value_len;
79 LONG result;
80
81 if (openParentKey(&parent_key) < 0) {
82 return -1;
83 }
84
85 if (type_ == REG_SZ || type_ == REG_EXPAND_SZ) {
86 // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms724923(v=vs.85).aspx
87 value_len = sizeof(wchar_t) * (string_value_.toStdWString().length() + 1);
88 result = RegSetValueExW (parent_key,
89 name_.toStdWString().c_str(),
90 0, REG_SZ,
91 (const BYTE *)(string_value_.toStdWString().c_str()),
92 value_len);
93 } else {
94 value_len = sizeof(dword_value_);
95 result = RegSetValueExW (parent_key,
96 name_.toStdWString().c_str(),
97 0, REG_DWORD,
98 (const BYTE *)&dword_value_,
99 value_len);
100 }
101
102 if (result != ERROR_SUCCESS) {
103 return -1;
104 }
105
106 return 0;
107 }
108
removeRegKey(HKEY root,const QString & path,const QString & subkey)109 int RegElement::removeRegKey(HKEY root, const QString& path, const QString& subkey)
110 {
111 HKEY hKey;
112 LONG result = RegOpenKeyExW(root,
113 path.toStdWString().c_str(),
114 0L,
115 KEY_ALL_ACCESS,
116 &hKey);
117
118 if (result != ERROR_SUCCESS) {
119 return -1;
120 }
121
122 result = SHDeleteKeyW(hKey, subkey.toStdWString().c_str());
123 if (result != ERROR_SUCCESS) {
124 return -1;
125 }
126
127 return 0;
128 }
129
exists()130 bool RegElement::exists()
131 {
132 HKEY parent_key;
133 LONG result = openKey(root_, path_, &parent_key, KEY_READ);
134 if (result != ERROR_SUCCESS) {
135 return false;
136 }
137
138 result = RegQueryValueExW (parent_key,
139 name_.toStdWString().c_str(),
140 NULL, /* reserved */
141 NULL, /* output type */
142 NULL, /* output data */
143 NULL); /* output length */
144
145 RegCloseKey(parent_key);
146 if (result != ERROR_SUCCESS) {
147 return false;
148 }
149
150 return true;
151 }
152
read()153 void RegElement::read()
154 {
155 string_value_.clear();
156 dword_value_ = 0;
157 HKEY parent_key;
158 LONG result = openKey(root_, path_, &parent_key, KEY_READ);
159 if (result != ERROR_SUCCESS) {
160 return;
161 }
162 const std::wstring std_name = name_.toStdWString();
163
164 DWORD len;
165 // get value size
166 result = RegQueryValueExW (parent_key,
167 std_name.c_str(),
168 NULL, /* reserved */
169 &type_, /* output type */
170 NULL, /* output data */
171 &len); /* output length */
172 if (result != ERROR_SUCCESS) {
173 RegCloseKey(parent_key);
174 return;
175 }
176 // get value
177 #ifndef UTILS_CXX11_MODE
178 std::vector<wchar_t> buf;
179 #else
180 utils::WBufferArray buf;
181 #endif
182 buf.resize(len);
183 result = RegQueryValueExW (parent_key,
184 std_name.c_str(),
185 NULL, /* reserved */
186 &type_, /* output type */
187 (LPBYTE)&buf[0], /* output data */
188 &len); /* output length */
189 buf.resize(len);
190 if (result != ERROR_SUCCESS) {
191 RegCloseKey(parent_key);
192 return;
193 }
194
195 switch (type_) {
196 case REG_EXPAND_SZ:
197 case REG_SZ:
198 {
199 // expand environment strings
200 wchar_t expanded_buf[MAX_PATH];
201 DWORD size = ExpandEnvironmentStringsW(&buf[0], expanded_buf, MAX_PATH);
202 if (size == 0 || size > MAX_PATH)
203 string_value_ = QString::fromWCharArray(&buf[0], buf.size());
204 else
205 string_value_ = QString::fromWCharArray(expanded_buf, size);
206 }
207 break;
208 case REG_NONE:
209 case REG_BINARY:
210 string_value_ = QString::fromWCharArray(&buf[0], buf.size() / 2);
211 break;
212 case REG_DWORD_BIG_ENDIAN:
213 case REG_DWORD:
214 if (buf.size() != sizeof(int))
215 return;
216 memcpy((char*)&dword_value_, buf.data(), sizeof(int));
217 break;
218 case REG_QWORD: {
219 if (buf.size() != sizeof(int))
220 return;
221 qint64 value;
222 memcpy((char*)&value, buf.data(), sizeof(int));
223 dword_value_ = (int)value;
224 break;
225 }
226 case REG_MULTI_SZ:
227 default:
228 break;
229 }
230
231 RegCloseKey(parent_key);
232
233 // workaround with a bug
234 string_value_ = QString::fromUtf8(string_value_.toUtf8());
235
236 return;
237 }
238
remove()239 void RegElement::remove()
240 {
241 HKEY parent_key;
242 LONG result = openKey(root_, path_, &parent_key, KEY_ALL_ACCESS);
243 if (result != ERROR_SUCCESS) {
244 return;
245 }
246 result = RegDeleteValueW (parent_key, name_.toStdWString().c_str());
247 RegCloseKey(parent_key);
248 }
249
value() const250 QVariant RegElement::value() const
251 {
252 if (type_ == REG_SZ || type_ == REG_EXPAND_SZ
253 || type_ == REG_NONE || type_ == REG_BINARY) {
254 return string_value_;
255 } else {
256 return int(dword_value_);
257 }
258 }
259
getIntValue(HKEY root,const QString & path,const QString & name,bool * exists,int default_val)260 int RegElement::getIntValue(HKEY root,
261 const QString& path,
262 const QString& name,
263 bool *exists,
264 int default_val)
265 {
266 RegElement reg(root, path, name, "");
267 if (!reg.exists()) {
268 if (exists) {
269 *exists = false;
270 }
271 return default_val;
272 }
273 if (exists) {
274 *exists = true;
275 }
276 reg.read();
277
278 if (!reg.stringValue().isEmpty())
279 return reg.stringValue().toInt();
280
281 return reg.dwordValue();
282 }
283
getPreconfigureIntValue(const QString & name)284 int RegElement::getPreconfigureIntValue(const QString& name)
285 {
286 bool exists;
287 int ret = getIntValue(
288 HKEY_CURRENT_USER, softwareSeafile(), name, &exists);
289 if (exists) {
290 return ret;
291 }
292
293 return RegElement::getIntValue(
294 HKEY_LOCAL_MACHINE, softwareSeafile(), name);
295 }
296
getStringValue(HKEY root,const QString & path,const QString & name,bool * exists,QString default_val)297 QString RegElement::getStringValue(HKEY root,
298 const QString& path,
299 const QString& name,
300 bool *exists,
301 QString default_val)
302 {
303 RegElement reg(root, path, name, "");
304 if (!reg.exists()) {
305 if (exists) {
306 *exists = false;
307 }
308 return default_val;
309 }
310 if (exists) {
311 *exists = true;
312 }
313 reg.read();
314 return reg.stringValue();
315 }
316
getPreconfigureStringValue(const QString & name)317 QString RegElement::getPreconfigureStringValue(const QString& name)
318 {
319 bool exists;
320 QString ret = getStringValue(
321 HKEY_CURRENT_USER, softwareSeafile(), name, &exists);
322 if (exists) {
323 return ret;
324 }
325
326 return RegElement::getStringValue(
327 HKEY_LOCAL_MACHINE, softwareSeafile(), name);
328 }
329
getPreconfigureValue(const QString & name)330 QVariant RegElement::getPreconfigureValue(const QString& name)
331 {
332 QVariant v = getValue(HKEY_CURRENT_USER, softwareSeafile(), name);
333 return v.isNull() ? getValue(HKEY_LOCAL_MACHINE, softwareSeafile(), name) : v;
334 }
335
getValue(HKEY root,const QString & path,const QString & name)336 QVariant RegElement::getValue(HKEY root,
337 const QString& path,
338 const QString& name)
339 {
340 RegElement reg(root, path, name, "");
341 if (!reg.exists()) {
342 return QVariant();
343 }
344 reg.read();
345
346 return reg.value();
347 }
348