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