OSDN Git Service

Some improvements to registry code.
[mutilities/MUtilities.git] / src / Registry_Win32.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2015 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 const char* reg_root2str(const reg_root_t &rootKey)
75                 {
76                         ENUM2STR(rootKey, root_classes);
77                         ENUM2STR(rootKey, root_user);
78                         ENUM2STR(rootKey, root_machine);
79
80                         static const char *unknown = "<unknown>";
81                         return unknown;
82                 }
83
84                 static const char* reg_access2str(const reg_access_t &access)
85                 {
86                         ENUM2STR(access, access_readonly);
87                         ENUM2STR(access, access_writeonly);
88                         ENUM2STR(access, access_readwrite);
89                         ENUM2STR(access, access_enumerate);
90
91                         static const char *unknown = "<unknown>";
92                         return unknown;
93                 }
94         }
95 }
96
97 ///////////////////////////////////////////////////////////////////////////////
98 // RegistryKeyPrivate Key Class
99 ///////////////////////////////////////////////////////////////////////////////
100
101 namespace MUtils
102 {
103         namespace Registry
104         {
105                 namespace Internal
106                 {
107                         class RegistryKeyPrivate
108                         {
109                                 friend class MUtils::Registry::RegistryKey;
110
111                         private:
112                                 HKEY  m_hKey;
113                                 DWORD m_access;
114                                 bool  m_isOpen;
115                         };
116                 }
117         }
118 }
119
120 #define CHECK_STATUS(X) do \
121 { \
122         if(!p->m_isOpen) \
123         { \
124                 MUTILS_THROW("Cannot read from or write to a key is not currently open!"); \
125         } \
126         if(!(p->m_access & (X))) \
127         { \
128                 MUTILS_THROW("This operation is not support with current access rights!"); \
129         } \
130 } \
131 while(0)
132
133 ///////////////////////////////////////////////////////////////////////////////
134 // Registry Key Class
135 ///////////////////////////////////////////////////////////////////////////////
136
137 MUtils::Registry::RegistryKey::RegistryKey(const reg_root_t &rootKey, const QString &keyName, const reg_access_t &access)
138 :
139         p(new Internal::RegistryKeyPrivate())
140 {
141         p->m_hKey   = NULL;
142         p->m_access = registry_access(access);
143         p->m_isOpen = false;
144
145         p->m_isOpen = (RegCreateKeyEx(registry_root(rootKey), MUTILS_WCHR(keyName), 0, NULL, 0, p->m_access, NULL, &p->m_hKey, NULL) == ERROR_SUCCESS);
146         if(!p->m_isOpen)
147         {
148                 qWarning("Failed to open registry key \"%s\"! (rootKey: %s, access: %s)", MUTILS_UTF8(keyName), reg_root2str(rootKey), reg_access2str(access));
149         }
150 }
151
152 MUtils::Registry::RegistryKey::~RegistryKey(void)
153 {
154         if(p->m_isOpen)
155         {
156                 CloseHandle(p->m_hKey);
157                 p->m_hKey = NULL;
158                 p->m_isOpen = false;
159         }
160         delete p;
161 }
162
163 inline bool MUtils::Registry::RegistryKey::isOpen(void)
164 {
165         return p->m_isOpen; 
166 }
167
168 bool MUtils::Registry::RegistryKey::value_write(const QString &valueName, const quint32 &value)
169 {
170         CHECK_STATUS(KEY_WRITE);
171         return (RegSetValueEx(p->m_hKey, valueName.isEmpty() ? NULL : MUTILS_WCHR(valueName), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(quint32)) == ERROR_SUCCESS);
172 }
173
174 bool MUtils::Registry::RegistryKey::value_write(const QString &valueName, const QString &value)
175 {
176         CHECK_STATUS(KEY_WRITE);
177         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);
178 }
179
180 bool MUtils::Registry::RegistryKey::value_read(const QString &valueName, quint32 &value) const
181 {
182         value = 0;
183         DWORD size = sizeof(quint32), type = -1;
184         CHECK_STATUS(KEY_READ);
185         return (RegQueryValueEx(p->m_hKey, valueName.isEmpty() ? NULL : MUTILS_WCHR(valueName), 0, &type, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS) && (type == REG_DWORD);
186 }
187
188 bool MUtils::Registry::RegistryKey::value_read(const QString &valueName, QString &value) const
189 {
190         value = QString();
191         wchar_t buffer[2048]; DWORD size = sizeof(wchar_t) * 2048, type = -1;
192         CHECK_STATUS(KEY_READ);
193         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)))
194         {
195                 value = QString::fromUtf16(reinterpret_cast<const ushort*>(buffer));
196                 return true;
197         }
198         return false;
199 }
200
201 bool MUtils::Registry::RegistryKey::enum_values(QStringList &list) const
202 {
203         wchar_t buffer[2048];
204         list.clear();
205         CHECK_STATUS(KEY_QUERY_VALUE);
206         for(DWORD i = 0; i < UINT_MAX; i++)
207         {
208                 DWORD size = 2048;
209                 const DWORD ret = RegEnumValue(p->m_hKey, i, buffer, &size, NULL, NULL, NULL, NULL);
210                 if(ret == ERROR_SUCCESS)
211                 {
212                         list << QString::fromUtf16(reinterpret_cast<const ushort*>(buffer));
213                         continue;
214                 }
215                 return (ret == ERROR_NO_MORE_ITEMS);
216         }
217         return false;
218 }
219
220 bool MUtils::Registry::RegistryKey::enum_subkeys(QStringList &list) const
221 {
222         wchar_t buffer[2048];
223         list.clear();
224         CHECK_STATUS(KEY_ENUMERATE_SUB_KEYS);
225         for(DWORD i = 0; i < UINT_MAX; i++)
226         {
227                 DWORD size = 2048;
228                 const DWORD ret = RegEnumKeyEx(p->m_hKey, i, buffer, &size, NULL, NULL, NULL, NULL);
229                 if(ret == ERROR_SUCCESS)
230                 {
231                         list << QString::fromUtf16(reinterpret_cast<const ushort*>(buffer));
232                         continue;
233                 }
234                 return (ret == ERROR_NO_MORE_ITEMS);
235         }
236         return false;
237 }
238
239 ///////////////////////////////////////////////////////////////////////////////
240 // HELPER FUNCTIONS
241 ///////////////////////////////////////////////////////////////////////////////
242
243 /*
244  * Write registry value
245  */
246 bool MUtils::Registry::reg_value_write(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, const quint32 &value)
247 {
248         bool success = false;
249         RegistryKey regKey(rootKey, keyName, access_readwrite);
250         if(regKey.isOpen())
251         {
252                 success = regKey.value_write(valueName, value);
253         }
254         return success;
255 }
256
257 /*
258  * Write registry value
259  */
260 bool MUtils::Registry::reg_value_write(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, const QString &value)
261 {
262         bool success = false;
263         RegistryKey regKey(rootKey, keyName, access_readwrite);
264         if(regKey.isOpen())
265         {
266                 success = regKey.value_write(valueName, value);
267         }
268         return success;
269 }
270
271 /*
272  * Read registry value
273  */
274 bool MUtils::Registry::reg_value_read(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, quint32 &value)
275 {
276         bool success = false;
277         RegistryKey regKey(rootKey, keyName, access_readonly);
278         if(regKey.isOpen())
279         {
280                 success = regKey.value_read(valueName, value);
281         }
282         else
283         {
284                 value = 0;
285         }
286         return success;
287 }
288
289 /*
290  * Read registry value
291  */
292 bool MUtils::Registry::reg_value_read(const reg_root_t &rootKey, const QString &keyName, const QString &valueName, QString &value)
293 {
294         bool success = false;
295         RegistryKey regKey(rootKey, keyName, access_readonly);
296         if(regKey.isOpen())
297         {
298                 success = regKey.value_read(valueName, value);
299         }
300         else
301         {
302                 value = QString();
303         }
304         return success;
305 }
306
307 /*
308  * Enumerate value names
309  */
310 bool MUtils::Registry::reg_enum_values(const reg_root_t &rootKey, const QString &keyName, QStringList &values)
311 {
312         bool success = false;
313         RegistryKey regKey(rootKey, keyName, access_readonly);
314         if(regKey.isOpen())
315         {
316                 success = regKey.enum_values(values);
317         }
318         else
319         {
320                 values.clear();
321         }
322         return success;
323 }
324
325 /*
326  * Enumerate subkey names
327  */
328 bool MUtils::Registry::reg_enum_subkeys(const reg_root_t &rootKey, const QString &keyName, QStringList &subkeys)
329 {
330         bool success = false;
331         RegistryKey regKey(rootKey, keyName, access_enumerate);
332         if(regKey.isOpen())
333         {
334                 success = regKey.enum_subkeys(subkeys);
335         }
336         else
337         {
338                 subkeys.clear();
339         }
340         return success;
341 }
342
343 /*
344  * Delete registry key
345  */
346 bool MUtils::Registry::reg_key_delete(const reg_root_t &rootKey, const QString &keyName)
347 {
348         return (SHDeleteKey(registry_root(rootKey), MUTILS_WCHR(keyName)) == ERROR_SUCCESS);
349 }