OSDN Git Service

Bump version.
[mutilities/MUtilities.git] / src / Registry_Win32.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2019 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 //
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
21
22 #pragma once
23
24 //MUtils
25 #include <MUtils/Registry.h>
26 #include <MUtils/Exception.h>
27
28 //Qt
29 #include <QStringList>
30
31 //Win32
32 #define WIN32_LEAN_AND_MEAN
33 #include <Windows.h>
34 #include <Shlwapi.h>
35
36 ///////////////////////////////////////////////////////////////////////////////
37 // INTERNAL FUNCTIONS
38 ///////////////////////////////////////////////////////////////////////////////
39
40 #define ENUM2STR(X,Y) do \
41 { \
42         static const char *_name = #Y; \
43         if((X) == (Y)) return _name; \
44 } \
45 while(0)
46
47 namespace MUtils
48 {
49         namespace Registry
50         {
51                 static HKEY registry_root(const reg_root_t &rootKey)
52                 {
53                         switch(rootKey)
54                         {
55                                 case root_classes: return HKEY_CLASSES_ROOT;  break;
56                                 case root_user:    return HKEY_CURRENT_USER;  break;
57                                 case root_machine: return HKEY_LOCAL_MACHINE; break;
58                                 default: MUTILS_THROW("Unknown root reg value was specified!");
59                         }
60                 }
61
62                 static DWORD registry_access(const reg_access_t &access)
63                 {
64                         switch(access)
65                         {
66                                 case access_readonly:  return KEY_READ;               break;
67                                 case access_writeonly: return KEY_WRITE;              break;
68                                 case access_readwrite: return KEY_READ | KEY_WRITE;   break;
69                                 case access_enumerate: return KEY_ENUMERATE_SUB_KEYS; break;
70                                 default: MUTILS_THROW("Unknown access value was specified!");
71                         }
72                 }
73
74                 static DWORD registry_scope(const reg_scope_t &scope)
75                 {
76                         switch (scope)
77                         {
78                                 case scope_default: return 0;               break;
79                                 case scope_wow_x32: return KEY_WOW64_32KEY; break;
80                                 case scope_wow_x64: return KEY_WOW64_64KEY; break;
81                                 default: MUTILS_THROW("Unknown scope value was specified!");
82                         }
83                 }
84
85                 static const char* reg_root2str(const reg_root_t &rootKey)
86                 {
87                         ENUM2STR(rootKey, root_classes);
88                         ENUM2STR(rootKey, root_user);
89                         ENUM2STR(rootKey, root_machine);
90
91                         static const char *unknown = "<unknown>";
92                         return unknown;
93                 }
94
95                 static const char* reg_access2str(const reg_access_t &access)
96                 {
97                         ENUM2STR(access, access_readonly);
98                         ENUM2STR(access, access_writeonly);
99                         ENUM2STR(access, access_readwrite);
100                         ENUM2STR(access, access_enumerate);
101
102                         static const char *unknown = "<unknown>";
103                         return unknown;
104                 }
105         }
106 }
107
108 ///////////////////////////////////////////////////////////////////////////////
109 // RegistryKeyPrivate Key Class
110 ///////////////////////////////////////////////////////////////////////////////
111
112 namespace MUtils
113 {
114         namespace Registry
115         {
116                 namespace Internal
117                 {
118                         class RegistryKeyPrivate
119                         {
120                                 friend class MUtils::Registry::RegistryKey;
121
122                         private:
123                                 HKEY  m_hKey;
124                                 DWORD m_access;
125                                 bool  m_isOpen;
126                         };
127                 }
128         }
129 }
130
131 #define CHECK_STATUS(X) do \
132 { \
133         if(!p->m_isOpen) \
134         { \
135                 MUTILS_THROW("Cannot read from or write to a key is not currently open!"); \
136         } \
137         if(!(p->m_access & (X))) \
138         { \
139                 MUTILS_THROW("This operation is not support with current access rights!"); \
140         } \
141 } \
142 while(0)
143
144 ///////////////////////////////////////////////////////////////////////////////
145 // Registry Key Class
146 ///////////////////////////////////////////////////////////////////////////////
147
148 MUtils::Registry::RegistryKey::RegistryKey(const reg_root_t &rootKey, const QString &keyName, const reg_access_t &access, const reg_scope_t &scope)
149 :
150         p(new Internal::RegistryKeyPrivate())
151 {
152         p->m_hKey   = NULL;
153         p->m_access = registry_access(access) | registry_scope(scope);
154         p->m_isOpen = false;
155
156         p->m_isOpen = (RegCreateKeyEx(registry_root(rootKey), MUTILS_WCHR(keyName), 0, NULL, 0, p->m_access, NULL, &p->m_hKey, NULL) == ERROR_SUCCESS);
157         if(!p->m_isOpen)
158         {
159                 qWarning("Failed to open registry key \"%s\"! (rootKey: %s, access: %s)", MUTILS_UTF8(keyName), reg_root2str(rootKey), reg_access2str(access));
160         }
161 }
162
163 MUtils::Registry::RegistryKey::~RegistryKey(void)
164 {
165         if(p->m_isOpen)
166         {
167                 CloseHandle(p->m_hKey);
168                 p->m_hKey = NULL;
169                 p->m_isOpen = false;
170         }
171         delete p;
172 }
173
174 inline bool MUtils::Registry::RegistryKey::isOpen(void)
175 {
176         return p->m_isOpen; 
177 }
178
179 bool MUtils::Registry::RegistryKey::value_write(const QString &valueName, const quint32 &value)
180 {
181         CHECK_STATUS(KEY_WRITE);
182         return (RegSetValueEx(p->m_hKey, valueName.isEmpty() ? NULL : MUTILS_WCHR(valueName), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(quint32)) == ERROR_SUCCESS);
183 }
184
185 bool MUtils::Registry::RegistryKey::value_write(const QString &valueName, const QString &value)
186 {
187         CHECK_STATUS(KEY_WRITE);
188         return (RegSetValueEx(p->m_hKey, valueName.isEmpty() ? NULL : MUTILS_WCHR(valueName), 0, REG_SZ, reinterpret_cast<const BYTE*>(value.utf16()), (value.length() + 1) * sizeof(wchar_t)) == ERROR_SUCCESS);
189 }
190
191 bool MUtils::Registry::RegistryKey::value_read(const QString &valueName, quint32 &value) const
192 {
193         value = 0;
194         DWORD size = sizeof(quint32), type = -1;
195         CHECK_STATUS(KEY_READ);
196         return (RegQueryValueEx(p->m_hKey, valueName.isEmpty() ? NULL : MUTILS_WCHR(valueName), 0, &type, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS) && (type == REG_DWORD);
197 }
198
199 bool MUtils::Registry::RegistryKey::value_read(const QString &valueName, QString &value) const
200 {
201         value = QString();
202         wchar_t buffer[2048]; DWORD size = sizeof(wchar_t) * 2048, type = -1;
203         CHECK_STATUS(KEY_READ);
204         if((RegQueryValueEx(p->m_hKey, valueName.isEmpty() ? NULL : MUTILS_WCHR(valueName), 0, &type, reinterpret_cast<BYTE*>(&(buffer[0])), &size) == ERROR_SUCCESS) && ((type == REG_SZ) || (type == REG_EXPAND_SZ)))
205         {
206                 value = QString::fromUtf16(reinterpret_cast<const ushort*>(buffer));
207                 return true;
208         }
209         return false;
210 }
211
212 bool MUtils::Registry::RegistryKey::enum_values(QStringList &list) const
213 {
214         wchar_t buffer[2048];
215         list.clear();
216         CHECK_STATUS(KEY_QUERY_VALUE);
217         for(DWORD i = 0; i < UINT_MAX; i++)
218         {
219                 DWORD size = 2048;
220                 const DWORD ret = RegEnumValue(p->m_hKey, i, buffer, &size, NULL, NULL, NULL, NULL);
221                 if(ret == ERROR_SUCCESS)
222                 {
223                         list << QString::fromUtf16(reinterpret_cast<const ushort*>(buffer));
224                         continue;
225                 }
226                 return (ret == ERROR_NO_MORE_ITEMS);
227         }
228         return false;
229 }
230
231 bool MUtils::Registry::RegistryKey::enum_subkeys(QStringList &list) const
232 {
233         wchar_t buffer[2048];
234         list.clear();
235         CHECK_STATUS(KEY_ENUMERATE_SUB_KEYS);
236         for(DWORD i = 0; i < UINT_MAX; i++)
237         {
238                 DWORD size = 2048;
239                 const DWORD ret = RegEnumKeyEx(p->m_hKey, i, buffer, &size, NULL, NULL, NULL, NULL);
240                 if(ret == ERROR_SUCCESS)
241                 {
242                         list << QString::fromUtf16(reinterpret_cast<const ushort*>(buffer));
243                         continue;
244                 }
245                 return (ret == ERROR_NO_MORE_ITEMS);
246         }
247         return false;
248 }
249
250 ///////////////////////////////////////////////////////////////////////////////
251 // HELPER FUNCTIONS
252 ///////////////////////////////////////////////////////////////////////////////
253
254 /*
255  * Write registry value
256  */
257 bool MUtils::Registry::reg_value_write(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, const quint32 &value, const reg_scope_t &scope)
258 {
259         bool success = false;
260         RegistryKey regKey(rootKey, keyName, access_readwrite, scope);
261         if(regKey.isOpen())
262         {
263                 success = regKey.value_write(valueName, value);
264         }
265         return success;
266 }
267
268 /*
269  * Write registry value
270  */
271 bool MUtils::Registry::reg_value_write(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, const QString &value, const reg_scope_t &scope)
272 {
273         bool success = false;
274         RegistryKey regKey(rootKey, keyName, access_readwrite, scope);
275         if(regKey.isOpen())
276         {
277                 success = regKey.value_write(valueName, value);
278         }
279         return success;
280 }
281
282 /*
283  * Read registry value
284  */
285 bool MUtils::Registry::reg_value_read(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, quint32 &value, const reg_scope_t &scope)
286 {
287         bool success = false;
288         RegistryKey regKey(rootKey, keyName, access_readonly, scope);
289         if(regKey.isOpen())
290         {
291                 success = regKey.value_read(valueName, value);
292         }
293         else
294         {
295                 value = 0;
296         }
297         return success;
298 }
299
300 /*
301  * Read registry value
302  */
303 bool MUtils::Registry::reg_value_read(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, QString &value, const reg_scope_t &scope)
304 {
305         bool success = false;
306         RegistryKey regKey(rootKey, keyName, access_readonly, scope);
307         if(regKey.isOpen())
308         {
309                 success = regKey.value_read(valueName, value);
310         }
311         else
312         {
313                 value = QString();
314         }
315         return success;
316 }
317
318 /*
319  * Enumerate value names
320  */
321 bool MUtils::Registry::reg_enum_values(const reg_root_t &rootKey, const QString &keyName, QStringList &values, const reg_scope_t &scope)
322 {
323         bool success = false;
324         RegistryKey regKey(rootKey, keyName, access_readonly, scope);
325         if(regKey.isOpen())
326         {
327                 success = regKey.enum_values(values);
328         }
329         else
330         {
331                 values.clear();
332         }
333         return success;
334 }
335
336 /*
337  * Enumerate subkey names
338  */
339 bool MUtils::Registry::reg_enum_subkeys(const reg_root_t &rootKey, const QString &keyName, QStringList &subkeys, const reg_scope_t &scope)
340 {
341         bool success = false;
342         RegistryKey regKey(rootKey, keyName, access_enumerate, scope);
343         if(regKey.isOpen())
344         {
345                 success = regKey.enum_subkeys(subkeys);
346         }
347         else
348         {
349                 subkeys.clear();
350         }
351         return success;
352 }
353
354 /*
355  * Check registry key existence
356  */
357 bool MUtils::Registry::reg_key_exists(const reg_root_t &rootKey, const QString &keyName, const reg_scope_t &scope)
358 {
359         HKEY hKey = NULL;
360         if(RegOpenKeyEx(registry_root(rootKey), MUTILS_WCHR(keyName), 0, STANDARD_RIGHTS_READ | registry_scope(scope), &hKey) == ERROR_SUCCESS)
361         {
362                 RegCloseKey(hKey);
363                 return true;
364         }
365         return false;
366 }
367
368 /*
369  * Delete registry key
370  */
371 bool MUtils::Registry::reg_key_delete(const reg_root_t &rootKey, const QString &keyName, const bool &recusrive, const bool &ascend, const reg_scope_t &scope)
372 {
373         bool okay = false;
374
375         if (scope != scope_default)
376         {
377                 MUTILS_THROW("Scope option not currently supported by reg_key_delete() function!");
378         }
379
380         if(recusrive)
381         {
382                 okay = (SHDeleteKey(registry_root(rootKey), MUTILS_WCHR(keyName)) == ERROR_SUCCESS);
383         }
384         else
385         {
386                 okay = (RegDeleteKey(registry_root(rootKey), MUTILS_WCHR(keyName)) == ERROR_SUCCESS);
387         }
388
389         if(ascend && okay)
390         {
391                 const int pos = qMax(keyName.lastIndexOf(QLatin1Char('/')), keyName.lastIndexOf(QLatin1Char('\\')));
392                 if(pos > 0)
393                 {
394                         reg_key_delete(rootKey, keyName.left(pos), false, true);
395                 }
396         }
397
398         return okay;
399 }