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