1// Windows/Registry.cpp 2 3#include "StdAfx.h" 4 5#include <wchar.h> 6 7#ifndef _UNICODE 8#include "../Common/StringConvert.h" 9#endif 10#include "Registry.h" 11 12#ifndef _UNICODE 13extern bool g_IsNT; 14#endif 15 16namespace NWindows { 17namespace NRegistry { 18 19#define MYASSERT(expr) // _ASSERTE(expr) 20 21LONG CKey::Create(HKEY parentKey, LPCTSTR keyName, 22 LPTSTR keyClass, DWORD options, REGSAM accessMask, 23 LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw() 24{ 25 MYASSERT(parentKey != NULL); 26 DWORD dispositionReal; 27 HKEY key = NULL; 28 LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass, 29 options, accessMask, securityAttributes, &key, &dispositionReal); 30 if (disposition != NULL) 31 *disposition = dispositionReal; 32 if (res == ERROR_SUCCESS) 33 { 34 res = Close(); 35 _object = key; 36 } 37 return res; 38} 39 40LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw() 41{ 42 MYASSERT(parentKey != NULL); 43 HKEY key = NULL; 44 LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key); 45 if (res == ERROR_SUCCESS) 46 { 47 res = Close(); 48 MYASSERT(res == ERROR_SUCCESS); 49 _object = key; 50 } 51 return res; 52} 53 54LONG CKey::Close() throw() 55{ 56 LONG res = ERROR_SUCCESS; 57 if (_object != NULL) 58 { 59 res = RegCloseKey(_object); 60 _object = NULL; 61 } 62 return res; 63} 64 65// win95, win98: deletes sunkey and all its subkeys 66// winNT to be deleted must not have subkeys 67LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() 68{ 69 MYASSERT(_object != NULL); 70 return RegDeleteKey(_object, subKeyName); 71} 72 73LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() 74{ 75 CKey key; 76 LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE); 77 if (res != ERROR_SUCCESS) 78 return res; 79 FILETIME fileTime; 80 const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL 81 DWORD size = kBufSize; 82 TCHAR buffer[kBufSize]; 83 while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS) 84 { 85 res = key.RecurseDeleteKey(buffer); 86 if (res != ERROR_SUCCESS) 87 return res; 88 size = kBufSize; 89 } 90 key.Close(); 91 return DeleteSubKey(subKeyName); 92} 93 94 95///////////////////////// 96// Value Functions 97 98static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); } 99static inline bool UINT32ToBool(UInt32 value) { return (value != 0); } 100 101 102LONG CKey::DeleteValue(LPCTSTR name) throw() 103{ 104 MYASSERT(_object != NULL); 105 return ::RegDeleteValue(_object, name); 106} 107 108#ifndef _UNICODE 109LONG CKey::DeleteValue(LPCWSTR name) 110{ 111 MYASSERT(_object != NULL); 112 if (g_IsNT) 113 return ::RegDeleteValueW(_object, name); 114 return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name)); 115} 116#endif 117 118LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw() 119{ 120 MYASSERT(_object != NULL); 121 return RegSetValueEx(_object, name, 0, REG_DWORD, 122 (BYTE * const)&value, sizeof(UInt32)); 123} 124 125LONG CKey::SetValue(LPCTSTR name, bool value) throw() 126{ 127 return SetValue(name, BoolToUINT32(value)); 128} 129 130LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() 131{ 132 MYASSERT(value != NULL); 133 MYASSERT(_object != NULL); 134 return RegSetValueEx(_object, name, 0, REG_SZ, 135 (const BYTE * )value, (lstrlen(value) + 1) * sizeof(TCHAR)); 136} 137 138/* 139LONG CKey::SetValue(LPCTSTR name, const CSysString &value) 140{ 141 MYASSERT(value != NULL); 142 MYASSERT(_object != NULL); 143 return RegSetValueEx(_object, name, NULL, REG_SZ, 144 (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); 145} 146*/ 147 148#ifndef _UNICODE 149 150LONG CKey::SetValue(LPCWSTR name, LPCWSTR value) 151{ 152 MYASSERT(value != NULL); 153 MYASSERT(_object != NULL); 154 if (g_IsNT) 155 return RegSetValueExW(_object, name, NULL, REG_SZ, 156 (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t))); 157 return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), 158 value == 0 ? 0 : (LPCSTR)GetSystemString(value)); 159} 160 161#endif 162 163 164LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw() 165{ 166 MYASSERT(value != NULL); 167 MYASSERT(_object != NULL); 168 return RegSetValueEx(_object, name, 0, REG_BINARY, 169 (const BYTE *)value, size); 170} 171 172LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) 173{ 174 MYASSERT(value != NULL); 175 CKey key; 176 LONG res = key.Create(parentKey, keyName); 177 if (res == ERROR_SUCCESS) 178 res = key.SetValue(valueName, value); 179 return res; 180} 181 182LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw() 183{ 184 MYASSERT(value != NULL); 185 CKey key; 186 LONG res = key.Create(_object, keyName); 187 if (res == ERROR_SUCCESS) 188 res = key.SetValue(valueName, value); 189 return res; 190} 191 192LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw() 193{ 194 DWORD type = 0; 195 DWORD count = sizeof(DWORD); 196 LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, 197 (LPBYTE)&value, &count); 198 MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD)); 199 MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32))); 200 return res; 201} 202 203LONG CKey::QueryValue(LPCTSTR name, bool &value) throw() 204{ 205 UInt32 uintValue = BoolToUINT32(value); 206 LONG res = QueryValue(name, uintValue); 207 value = UINT32ToBool(uintValue); 208 return res; 209} 210 211LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() 212{ 213 UInt32 newVal; 214 LONG res = QueryValue(name, newVal); 215 if (res == ERROR_SUCCESS) 216 value = newVal; 217 return res; 218} 219 220LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() 221{ 222 bool newVal; 223 LONG res = QueryValue(name, newVal); 224 if (res == ERROR_SUCCESS) 225 value = newVal; 226 return res; 227} 228 229LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw() 230{ 231 DWORD type = 0; 232 LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count); 233 MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); 234 return res; 235} 236 237LONG CKey::QueryValue(LPCTSTR name, CSysString &value) 238{ 239 value.Empty(); 240 DWORD type = 0; 241 UInt32 curSize = 0; 242 LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&curSize); 243 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 244 return res; 245 UInt32 curSize2 = curSize; 246 res = QueryValue(name, value.GetBuf(curSize), curSize2); 247 if (curSize > curSize2) 248 curSize = curSize2; 249 value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR)); 250 return res; 251} 252 253 254#ifndef _UNICODE 255 256LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count) 257{ 258 DWORD type = 0; 259 LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); 260 MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); 261 return res; 262} 263 264LONG CKey::QueryValue(LPCWSTR name, UString &value) 265{ 266 value.Empty(); 267 DWORD type = 0; 268 UInt32 curSize = 0; 269 270 LONG res; 271 272 if (g_IsNT) 273 { 274 res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&curSize); 275 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 276 return res; 277 UInt32 curSize2 = curSize; 278 res = QueryValue(name, value.GetBuf(curSize), curSize2); 279 if (curSize > curSize2) 280 curSize = curSize2; 281 value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t)); 282 } 283 else 284 { 285 AString vTemp; 286 res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp); 287 value = GetUnicodeString(vTemp); 288 } 289 290 return res; 291} 292 293#endif 294 295 296LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() 297{ 298 DWORD type = 0; 299 LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count); 300 MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY)); 301 return res; 302} 303 304 305LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize) 306{ 307 DWORD type = 0; 308 dataSize = 0; 309 LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&dataSize); 310 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 311 return res; 312 value.Alloc(dataSize); 313 return QueryValue(name, (BYTE *)value, dataSize); 314} 315 316LONG CKey::EnumKeys(CSysStringVector &keyNames) 317{ 318 keyNames.Clear(); 319 CSysString keyName; 320 for (DWORD index = 0; ; index++) 321 { 322 const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL 323 FILETIME lastWriteTime; 324 UInt32 nameSize = kBufSize; 325 LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize), 326 (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime); 327 keyName.ReleaseBuf_CalcLen(kBufSize); 328 if (result == ERROR_NO_MORE_ITEMS) 329 break; 330 if (result != ERROR_SUCCESS) 331 return result; 332 keyNames.Add(keyName); 333 } 334 return ERROR_SUCCESS; 335} 336 337LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) 338{ 339 size_t numChars = 0; 340 341 unsigned i; 342 343 for (i = 0; i < strings.Size(); i++) 344 numChars += strings[i].Len() + 1; 345 346 CObjArray<wchar_t> buffer(numChars); 347 size_t pos = 0; 348 349 for (i = 0; i < strings.Size(); i++) 350 { 351 const UString &s = strings[i]; 352 size_t size = s.Len() + 1; 353 wmemcpy(buffer + pos, s, size); 354 pos += size; 355 } 356 return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); 357} 358 359LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings) 360{ 361 strings.Clear(); 362 CByteBuffer buffer; 363 UInt32 dataSize = 0; 364 LONG res = QueryValue(valueName, buffer, dataSize); 365 if (res != ERROR_SUCCESS) 366 return res; 367 if (dataSize > buffer.Size()) 368 return E_FAIL; 369 if (dataSize % sizeof(wchar_t) != 0) 370 return E_FAIL; 371 372 const wchar_t *data = (const wchar_t *)(const Byte *)buffer; 373 size_t numChars = dataSize / sizeof(wchar_t); 374 size_t prev = 0; 375 UString s; 376 377 for (size_t i = 0; i < numChars; i++) 378 { 379 if (data[i] == 0) 380 { 381 s = data + prev; 382 strings.Add(s); 383 prev = i + 1; 384 } 385 } 386 387 return res; 388} 389 390}} 391