Index: reactos/sdk/lib/atl/atlbase.h =================================================================== --- reactos/sdk/lib/atl/atlbase.h (revision 72582) +++ reactos/sdk/lib/atl/atlbase.h (working copy) @@ -54,6 +54,10 @@ #define ATL_NO_VTABLE __declspec(novtable) #endif +#ifndef ATL_DEPRECATED +#define ATL_DEPRECATED __declspec(deprecated) +#endif + #define offsetofclass(base, derived) (reinterpret_cast(static_cast(reinterpret_cast(_ATL_PACKING))) - _ATL_PACKING) namespace ATL @@ -891,23 +895,31 @@ { public: HKEY m_hKey; +#if 0 + // FIXME & TODO: + CAtlTransactionManager* m_pTM; +#endif public: + CRegKey() throw() : m_hKey(NULL) + { + } - CRegKey() throw() - : m_hKey(NULL) + CRegKey(CRegKey& key) throw() : m_hKey(key.Detach()) { } - CRegKey(CRegKey& key) throw() + explicit CRegKey(HKEY hKey) throw() : m_hKey(hKey) { - Attach(key.Detach()); } - explicit CRegKey(HKEY hKey) throw() - :m_hKey(hKey) +#if 0 + // FIXME & TODO: + CRegKey(CAtlTransactionManager* pTM) throw() { + ... } +#endif ~CRegKey() throw() { @@ -923,7 +935,7 @@ if (m_hKey) { HKEY hKey = Detach(); - return RegCloseKey(hKey); + return ::RegCloseKey(hKey); } return ERROR_SUCCESS; } @@ -935,11 +947,19 @@ return hKey; } - LONG Open(HKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired = KEY_READ | KEY_WRITE) throw() + LONG Open(HKEY hKeyParent, LPCTSTR lpszKeyName, + REGSAM samDesired = KEY_READ | KEY_WRITE) throw() { + ATLASSERT(hKeyParent); + ATLASSERT(lpszKeyName); + HKEY hKey = NULL; - - LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyName, NULL, samDesired, &hKey); + LONG lRes = ::RegOpenKeyEx(hKeyParent, lpszKeyName, NULL, samDesired, &hKey); + if (lRes != ERROR_SUCCESS) + { + samDesired |= KEY_WOW64_64KEY; + lRes = ::RegOpenKeyEx(hKeyParent, lpszKeyName, NULL, samDesired, &hKey); + } if (lRes == ERROR_SUCCESS) { Close(); @@ -948,11 +968,27 @@ return lRes; } - LONG Create(HKEY hKeyParent, LPCTSTR lpszKeyName, LPTSTR lpszClass = REG_NONE, DWORD dwOptions = REG_OPTION_NON_VOLATILE, REGSAM samDesired = KEY_READ | KEY_WRITE, LPSECURITY_ATTRIBUTES lpSecAttr = NULL, LPDWORD lpdwDisposition = NULL) throw() + LONG Create(HKEY hKeyParent, LPCTSTR lpszKeyName, + LPTSTR lpszClass = REG_NONE, + DWORD dwOptions = REG_OPTION_NON_VOLATILE, + REGSAM samDesired = KEY_READ | KEY_WRITE, + LPSECURITY_ATTRIBUTES lpSecAttr = NULL, + LPDWORD lpdwDisposition = NULL) throw() { + ATLASSERT(hKeyParent); + ATLASSERT(lpszKeyName); + HKEY hKey = NULL; - - LONG lRes = RegCreateKeyEx(hKeyParent, lpszKeyName, NULL, lpszClass, dwOptions, samDesired, lpSecAttr, &hKey, lpdwDisposition); + LONG lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, NULL, lpszClass, + dwOptions, samDesired, lpSecAttr, &hKey, + lpdwDisposition); + if (lRes != ERROR_SUCCESS) + { + samDesired |= KEY_WOW64_64KEY; + lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, NULL, lpszClass, + dwOptions, samDesired, lpSecAttr, &hKey, + lpdwDisposition); + } if (lRes == ERROR_SUCCESS) { Close(); @@ -961,16 +997,18 @@ return lRes; } - LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) throw() { - return RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, (LPBYTE)pData, pnBytes); + ATLASSERT(m_hKey); + if (pdwType) + *pdwType = 0; + return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, (LPBYTE)pData, pnBytes); } LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) throw() { ULONG size = sizeof(DWORD); - DWORD type = 0; + DWORD type; LONG lRet = QueryValue(pszValueName, &type, &dwValue, &size); if (lRet == ERROR_SUCCESS && type != REG_DWORD) @@ -981,7 +1019,7 @@ LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) throw() { - DWORD type = 0; + DWORD type; LONG lRet = QueryValue(pszValueName, &type, pValue, pnBytes); if (lRet == ERROR_SUCCESS && type != REG_BINARY) @@ -993,10 +1031,10 @@ LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) throw() { ULONG size = (*pnChars) * sizeof(TCHAR); - DWORD type = 0; + DWORD type; LONG lRet = QueryValue(pszValueName, &type, pszValue, &size); - if (lRet == ERROR_SUCCESS && type != REG_SZ) + if (lRet == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ) lRet = ERROR_INVALID_DATA; *pnChars = size / sizeof(TCHAR); @@ -1022,15 +1060,42 @@ if (lRet != ERROR_SUCCESS) return lRet; - if (!SUCCEEDED(CLSIDFromString(buf, &guidValue))) + if (!SUCCEEDED(::CLSIDFromString(buf, &guidValue))) return ERROR_INVALID_DATA; return lRet; } + LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) throw() + { + ULONG size = sizeof(ULONGLONG); + DWORD type; + LONG lRet = QueryValue(pszValueName, &type, &qwValue, &size); + + if (lRet == ERROR_SUCCESS && type != REG_QWORD) + lRet = ERROR_INVALID_DATA; + + return lRet; + } + + LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue, + ULONG* pnChars) throw() + { + ULONG size = (*pnChars) * sizeof(TCHAR); + DWORD type; + LONG lRet = QueryValue(pszValueName, &type, pszValue, &size); + + if (lRet == ERROR_SUCCESS && type != REG_MULTI_SZ) + lRet = ERROR_INVALID_DATA; + + *pnChars = size / sizeof(TCHAR); + return lRet; + } + LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) throw() { - return RegSetValueEx(m_hKey, pszValueName, NULL, dwType, (const BYTE*)pValue, nBytes); + ATLASSERT(m_hKey); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, (const BYTE*)pValue, nBytes); } LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) throw() @@ -1040,17 +1105,24 @@ LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) throw() { - if (dwType != REG_SZ) - return ERROR_INVALID_DATA; // not implemented yet. - - ULONG length = (_tcslen(pszValue) + 1) * sizeof(TCHAR); - return SetValue(pszValueName, dwType, pszValue, length); + ULONG length; + switch (dwType) + { + case REG_SZ: + case REG_EXPAND_SZ: + length = (_tcslen(pszValue) + 1) * sizeof(TCHAR); + return SetValue(pszValueName, dwType, pszValue, length); + case REG_MULTI_SZ: + return SetMultiStringValue(pszValueName, pszValue); + default: + return ERROR_INVALID_DATA; + } } LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) throw() { OLECHAR buf[40] = {0}; - StringFromGUID2(guidValue, buf, 39); + ::StringFromGUID2(guidValue, buf, 39); #ifdef UNICODE return SetStringValue(pszValueName, buf); #else @@ -1065,9 +1137,50 @@ return SetValue(pszValueName, REG_BINARY, pValue, nBytes); } - LONG SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL) throw() + LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) throw() { + ULONG dwSize = CRegKey::_GetMultiStringSize(pszValue); + return SetValue(pszValueName, REG_MULTI_SZ, pszValue, dwSize); + } + + LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) throw() + { + ULONG dwSize = sizeof(ULONGLONG); + return SetValue(pszValueName, REG_QWORD, &qwValue, dwSize); + } + + LONG NotifyChangeKeyValue(BOOL bWatchSubtree, DWORD dwNotifyFilter, + HANDLE hEvent, BOOL bAsync = TRUE) throw() + { + ATLASSERT(m_hKey); + LONG ret = ::RegNotifyChangeKeyValue(m_hKey, bWatchSubtree, + dwNotifyFilter, hEvent, bAsync); + return ret; + } + + LONG Flush() throw() + { + ATLASSERT(m_hKey); + LONG ret = ::RegFlushKey(m_hKey); + return ret; + } + + static LONG WINAPI SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName, + LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL) + { CRegKey key; + LONG lRet = key.Create(hKeyParent, lpszKeyName); + if (lRet == ERROR_SUCCESS) + { + lRet = key.SetStringValue(lpszValueName, lpszValue); + } + return lRet; + } + + LONG SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, + LPCTSTR lpszValueName = NULL) throw() + { + CRegKey key; LONG lRet = key.Create(m_hKey, lpszKeyName); if (lRet == ERROR_SUCCESS) { @@ -1078,28 +1191,148 @@ LONG DeleteValue(LPCTSTR lpszValue) throw() { - return RegDeleteValue(m_hKey, lpszValue); + ATLASSERT(m_hKey); + return ::RegDeleteValue(m_hKey, lpszValue); } LONG DeleteSubKey(LPCTSTR lpszSubKey) throw() { - return RegDeleteKey(m_hKey, lpszSubKey); + ATLASSERT(m_hKey); + ATLASSERT(lpszSubKey); + return ::RegDeleteKey(m_hKey, lpszSubKey); } + LONG RecurseDeleteKey(LPCTSTR lpszKey) throw() + { + ATLASSERT(m_hKey); + ATLASSERT(lpszKey); + return CRegKey::_DoDeleteKeyTree(m_hKey, lpszKey); + } + + LONG EnumKey(DWORD iIndex, LPTSTR pszName, LPDWORD pnNameLength, + FILETIME* pftLastWriteTime = NULL) throw() + { + ATLASSERT(m_hKey); + LONG ret = ::RegEnumKeyEx(m_hKey, iIndex, pszName, pnNameLength, NULL, + NULL, NULL, pftLastWriteTime); + return ret; + } + + LONG GetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd, + LPDWORD pnBytes) throw() + { + ATLASSERT(m_hKey); + LONG ret = ::RegGetKeySecurity(m_hKey, si, psd, pnBytes); + return ret; + } + + LONG SetKeySecurity(SECURITY_INFORMATION si, + PSECURITY_DESCRIPTOR psd) throw() + { + ATLASSERT(m_hKey); + LONG ret = ::RegSetKeySecurity(m_hKey, si, psd); + return ret; + } + operator HKEY() const throw() { return m_hKey; } - CRegKey& operator =(CRegKey& key) throw() + CRegKey& operator=(CRegKey& key) throw() { - Attach(Detach()); + Attach(key.Detach()); return *this; } +protected: + // get the total size of a multistring + static ULONG _GetMultiStringSize(LPCTSTR pszz) + { + int count = 0; + do + { + int len = _tcslen(pszz); + count += len + 1; + pszz += len + 1; + } while (*pszz != TEXT('\0')); + ++count; + return count * sizeof(TCHAR); + } + + // delete key recursively + static LONG _DoDeleteKeyTree(HKEY hParentKey, LPCTSTR lpszKey) + { + ATLASSERT(hParentKey); + ATLASSERT(lpszKey); + + // open the key + CRegKey key; + LONG ret = key.Open(hParentKey, lpszKey); + if (ret != ERROR_SUCCESS) + { + return ret; // failure + } + + // get the longest length of subkey names + DWORD NameMax; + ret = ::RegQueryInfoKey(key, NULL, NULL, NULL, NULL, &NameMax, NULL, + NULL, NULL, NULL, NULL, NULL); + if (ret != ERROR_SUCCESS) + { + return ret; // failure + } + ++NameMax; // for NUL + + // allocate the string buffer for names if necessary + TCHAR szNameBuf[MAX_PATH], *pszName; + if (NameMax > MAX_PATH) + { + pszName = (TCHAR *)malloc(NameMax * sizeof(TCHAR)); + ATLASSERT(pszName); + if (pszName == NULL) + { + return ERROR_OUTOFMEMORY; // failure + } + } + else + { + NameMax = MAX_PATH; + pszName = szNameBuf; + } + + // enumerate every subkey and delete + for (;;) + { + DWORD Count = NameMax; + ret = key.EnumKey(0, pszName, &Count); + if (ret != ERROR_SUCCESS) + { + if (ret == ERROR_NO_MORE_ITEMS) + ret = ERROR_SUCCESS; + break; + } + + ret = CRegKey::_DoDeleteKeyTree(key, pszName); + if (ret != ERROR_SUCCESS) + break; + } + + // close key + key.Close(); + + // delete the subkey + if (ret == ERROR_SUCCESS) + ret = ::RegDeleteKey(hParentKey, lpszKey); + + // delete the buffer if any + if (pszName != szNameBuf) + free(pszName); + + return ret; + } }; - template class CComHeapPtr : public CHeapPtr { Index: rostests/apitests/atl/CRegKey.cpp =================================================================== --- rostests/apitests/atl/CRegKey.cpp (revision 72582) +++ rostests/apitests/atl/CRegKey.cpp (working copy) @@ -2,7 +2,8 @@ * PROJECT: ReactOS api tests * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory * PURPOSE: Test for CRegKey - * PROGRAMMER: Mark Jansen + * PROGRAMMERS: Mark Jansen + * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ #include @@ -185,4 +186,23 @@ lret = key.DeleteValue(_T("BIN_NAME")); ok(lret == ERROR_SUCCESS, "Expected lret to be ERROR_SUCCESS, was: %lu\n", lret); + + { + CRegKey test1; + lret = test1.Create(HKEY_CURRENT_USER, _T("TEST1")); + ok(lret == ERROR_SUCCESS, "Expected lret to be ERROR_SUCCESS, was: %lu\n", lret); + + CRegKey test2; + lret = test2.Create(test1, _T("TEST2")); + ok(lret == ERROR_SUCCESS, "Expected lret to be ERROR_SUCCESS, was: %lu\n", lret); + + CRegKey test3; + lret = test3.Create(test2, _T("TEST3")); + ok(lret == ERROR_SUCCESS, "Expected lret to be ERROR_SUCCESS, was: %lu\n", lret); + } + { + CRegKey key(HKEY_CURRENT_USER); + lret = key.RecurseDeleteKey(_T("TEST1")); + ok(lret == ERROR_SUCCESS, "Expected lret to be ERROR_SUCCESS, was: %lu\n", lret); + } }