/**
* This code is by OShah. all code will have the following licence.
* Copyright Shexec32. All code bears the following licence:
**/
/**
* Copyright Shexec32 2004-2005. All rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
**/
/** Registry_Value.h. Contains the reg class by D. Anderson and OShah.
* D. Anderson's code is apparently public domain.
**/
#ifndef REGISTRY_VALUE_H
#define REGISTRY_VALUE_H
#pragma once
class registry_value
{/**
* This is the reg class provided by D. Anderson (From codeproject).
* This code was altered in 2004 by OShah to use CStdStrs instead of std::strings.
* I have completed the exercise to make the class unicode-aware.
* Also, the class throws exceptions instead of returning status values.
*
* This class does not work for HKEY_PERFORMANCE_DATA. It will except if you attempt this.
**/
public:
registry_value(HKEY base_ = HKEY_CURRENT_USER, const std::basic_string<TCHAR> & name = _T("Software\\Shexec32\\FilePermsBox"))
: key(0), base(base_), keyname(name), TError(_T(""))
{/* [Default] constructor. Stores the key name in base\name, using the init helper function. */
::InitializeCriticalSection(&RegSection);
};
registry_value(const registry_value &OldClass)
: key(0), base(OldClass.base), keyname(OldClass.keyname)
{/* Copy constructor and assignment operator. Initialize our own critical section and Feed Terror into here. */
TError << OldClass.TError.str().c_str();
::InitializeCriticalSection(&RegSection);
};
registry_value &operator=(const registry_value &OldClass)
{/* Assignment operator. Erase this object and copy the new contents into here. */
key = 0;
base = OldClass.base;
keyname = OldClass.keyname;
TError << OldClass.TError.str().c_str();
};
virtual void InitPath(HKEY base_ = HKEY_CURRENT_USER, const std::basic_string<TCHAR> & name = _T("Software\\Shexec32\\FilePermsBox"))
{/* [Re-]Constructor Helper function. Recycle this object for another cause. */
::EnterCriticalSection(&RegSection);
{
if(key != 0) ::RegCloseKey(key);
key = 0;
}
::LeaveCriticalSection(&RegSection);
base = base_;
keyname = name;
};
virtual HKEY get_key(REGSAM samDesired = KEY_WRITE | KEY_READ)
{/* Accessor for key. Transfer of ownership semantics. */
::EnterCriticalSection(&RegSection);
{/* Caution: do not call any other methods for this object once you do this. They will invalidate this HKEY. */
if(key != 0) ::RegCloseKey(key);
key = 0;
::RegOpenKeyEx(base, keyname.c_str(), 0, samDesired, &key);
}
::LeaveCriticalSection(&RegSection);
return key;
};
virtual ~registry_value()
{/* Destructor. Closes the key when finished. */
::EnterCriticalSection(&RegSection);
{
if(key != 0) ::RegCloseKey(key);
key = 0;
}
::LeaveCriticalSection(&RegSection);
::DeleteCriticalSection(&RegSection);
};
virtual const std::basic_stringstream<TCHAR> &get_TError(void)
{/* TError accessor */
return TError;
};
BOOL exists(REGSAM samDesired = KEY_READ)
{/* Tests for access */
DWORD dwErr = open(samDesired);
::EnterCriticalSection(&RegSection);
{
if(key != 0) ::RegCloseKey(key);
key = 0;
}
::LeaveCriticalSection(&RegSection);
return (dwErr==ERROR_SUCCESS);
};
DWORD create(REGSAM samDesired = KEY_READ | KEY_WRITE)
{/* If we want write access, we can just create the key. The key will open up once we do it. */
DWORD RegErr = 0;
DWORD disposition = 0;
{/* Determine if we need to create it deep. */
size_t Anchor = keyname.find_last_of(_T("\\"));
if(Anchor < keyname.size())
{/* It was a child. Get its parent. */
std::basic_string<TCHAR> keynameold = keyname;/* save off the old string. */
keyname = keyname.substr(0, Anchor);
if( !exists(KEY_READ) )
{/* The parent don't exist, create the parent. */
create(samDesired);
}/* It does exist (doesn't matter if we can't access it). Carry on creating us. */
keyname = keynameold;
}
}
::EnterCriticalSection(&RegSection);
{/* Create key with RegCreateKeyEx() */
if(key != 0) ::RegCloseKey(key);
key = 0; /* Close the old key (if applicable) */
RegErr = ::RegCreateKeyEx(base, keyname.c_str(), 0, _T(""), REG_OPTION_NON_VOLATILE,
samDesired, 0, &key, &disposition);
}
::LeaveCriticalSection(&RegSection);
::SetLastError(RegErr); /* Make Reg error consistent with Win32 */
if(RegErr != ERROR_SUCCESS)
TError << keyname.c_str() << _T(": This key could not be created. ")
<< static_cast<const TCHAR *>(::GetLastErrorText(RegErr)) << std::endl;
::EnterCriticalSection(&RegSection);
{/* We no longer need this key. close it. */
if(key != 0) ::RegCloseKey(key);
key = 0;
}
::LeaveCriticalSection(&RegSection);
return RegErr;
};
DWORD remove_value(const std::basic_string<TCHAR> &ValueName)
{
DWORD dwErr = 0;
if(ValueName.empty() == true)
throw STD(_T("Cannot delete default value"));
/* get a handle to the key */
dwErr = open(KEY_READ | KEY_WRITE | DELETE);
if(dwErr != ERROR_SUCCESS)/* status? */
return dwErr;
::EnterCriticalSection(&RegSection);
{/* Call RegDeleteValue to delete it */
dwErr = ::RegDeleteValue(key, ValueName.c_str());
if(dwErr == ERROR_FILE_NOT_FOUND) dwErr = ERROR_SUCCESS;
if(dwErr != ERROR_SUCCESS)
TError << keyname.c_str() << _T("\\") << ValueName.c_str() << _T(": this value could not be deleted. ")
<< static_cast<const TCHAR *>(::GetLastErrorText(dwErr)) << std::endl;
}
::LeaveCriticalSection(&RegSection);
return dwErr;
};
DWORD remove_key(BOOL bRecurse)
{/* Remove key. bRecurse indicates whether we should delete subkeys too. */
DWORD dwErr = 0;
::EnterCriticalSection(&RegSection);
{
if(key != 0)
{/* Close the old key (if applicable). */
::RegCloseKey(key);
key = 0;
}
if(bRecurse == TRUE)
{/* Remove subkeys too. */
try {/**Not Much of a worry, shlwapi is already mapped into the process,
* so it won't make much difference
**/
dwErr = RemoveKeyRecursive(base, keyname);
if(dwErr == ERROR_FILE_NOT_FOUND) dwErr = ERROR_SUCCESS;
if(dwErr == ERROR_SUCCESS)
{/* All done, let's leave. */
::LeaveCriticalSection(&RegSection);
base = 0;
key = 0;
return dwErr;
}
} catch(...) {/* If Shlwapi is unavailable, use older advapi32 instead. */
}
}
else
{/* Use Older advapi32 (has different behaviour on Win9x and NT). */
::RegDeleteKey(base, keyname.c_str());
if(dwErr == ERROR_FILE_NOT_FOUND) dwErr = ERROR_SUCCESS;
if(dwErr != ERROR_SUCCESS)
TError << keyname.c_str() << _T(": this key could not be deleted. ")
<< static_cast<const TCHAR *>(GetLastErrorText(dwErr)) << std::endl;
}
}
::LeaveCriticalSection(&RegSection);
base = 0;
key = 0;
return dwErr;
};
protected:
DWORD RemoveKeyRecursive(HKEY hKey, const std::basic_string<TCHAR> &KeyName)
{/** This is a static method that is called in the context of the critical section.
* It serves as a emulator (or wrapper if available) for SHLWAPI's SHDeleteKey().
* Returns the error from the registry of the last operation.
**/
DWORD dwErr = 0;
try {
dwErr = ::SHDeleteKey(hKey, KeyName.c_str());
} catch (...) {/* shlwapi not found, or old. */
HKEY hKey2 = NULL;
dwErr = ::RegOpenKeyEx(hKey, KeyName.c_str(), 0, KEY_READ | DELETE, &hKey2);
if(dwErr != ERROR_SUCCESS)
{/* so that's why we failed. */
return dwErr;
}
FILETIME LastWriteTime = {0};
/* We only want lpcSubKeys from RegQueryInfoKey */
DWORD NumSubKeys;
dwErr = ::RegQueryInfoKey(hKey2, NULL, NULL, NULL, &NumSubKeys, NULL, NULL, NULL, NULL, NULL,
NULL, &LastWriteTime);
if(dwErr != ERROR_SUCCESS)
{/* Set the number of subkeys to 16383 (the biggest number in the msdn article: Registry limits). */
NumSubKeys = 16383;
}
for(DWORD dwIndex = 0; dwIndex < NumSubKeys; dwIndex++)
{
DWORD dwSize = 0;
::RegEnumKeyEx(hKey2, dwIndex, NULL, &dwSize, NULL, NULL, NULL, &LastWriteTime);
/* We expect this to fail. */
sized_array<TCHAR> lpName (dwSize);
dwErr = ::RegEnumKeyEx(hKey2, dwIndex, lpName.get(), &dwSize, NULL, NULL, NULL, &LastWriteTime);
if(dwErr == ERROR_SUCCESS)
{/* delete depth first */
std::basic_string<TCHAR> NewKeyName (KeyName);
NewKeyName.append(_T("\\"));
NewKeyName.append(lpName.get());
dwErr = this->RemoveKeyRecursive(hKey2, NewKeyName);
}
else if(dwErr == ERROR_NO_MORE_ITEMS)
{/* Now it is empty. RegDeleteKey now works. */
break;
}
dwIndex++;/* and loop */
}
::RegCloseKey(hKey2); hKey2 = NULL;
dwErr = ::RegDeleteKey(hKey, KeyName.c_str());
}
return dwErr;
};
DWORD open(REGSAM samDesired = KEY_READ)
{/* Opens a key: (optionally writable, with write_access==true). */
DWORD RegErr = 0;
::EnterCriticalSection(&RegSection);
{/* Call RegOpenKeyEx on the value. */
if(key != 0)
{/* Close the old key (if applicable). */
::RegCloseKey(key);
key = 0;
}
RegErr = ::RegOpenKeyEx(base, keyname.c_str(), 0, samDesired, &key);
::SetLastError(RegErr); /* Make registry error tally with Win32. */
}
::LeaveCriticalSection(&RegSection);
if(RegErr != ERROR_SUCCESS)
{
TError << keyname.c_str() << _T("could not open key. ") <<
static_cast<const TCHAR *>(::GetLastErrorText(RegErr)) << std::endl;
}
return RegErr;
};
DWORD query_value(const std::basic_string<TCHAR> &ValueName, DWORD &type, DWORD &size, BYTE *buffer)
{/* Caution: size will be returned in bytes (you may have to divide in sizeof() */
DWORD dwErr = 0;
if(key == 0) throw STD(_T("Tried to read from a uninitialised key"));
::EnterCriticalSection(&RegSection);
{
dwErr = ::RegQueryValueEx(key, ValueName.c_str(), 0, &type, buffer, &size);
}
::LeaveCriticalSection(&RegSection);
if(dwErr != ERROR_SUCCESS)
TError << keyname.c_str() << _T("\\") << _T(": this value could not be read. ")
<< static_cast<const TCHAR *>(::GetLastErrorText(dwErr)) << std::endl;
return dwErr;
};
DWORD set_value(const std::basic_string<TCHAR> &ValueName, DWORD type, DWORD size, const BYTE * buffer)
{/* Caution: size MUST be in bytes (use a sizeof()) */
DWORD dwErr = 0;
if(key == 0) throw STD(_T("Tried to set value on an uninitialised key"));
::EnterCriticalSection(&RegSection);
{
dwErr = ::RegSetValueEx(key, ValueName.c_str(), 0, type, buffer, size);
}
::LeaveCriticalSection(&RegSection);
if(dwErr != ERROR_SUCCESS)
TError << keyname.c_str() << _T("\\") << _T(": this value could not be set. ")
<< static_cast<const TCHAR *>(::GetLastErrorText(dwErr)) << std::endl;
return dwErr;
};
HKEY key;
HKEY base;
std::basic_string<TCHAR> keyname;
CRITICAL_SECTION RegSection;
std::basic_stringstream<TCHAR> TError;
};
class registry_string : public registry_value
{
public:
registry_string(HKEY base, const std::basic_string<TCHAR> & name) : registry_value(base, name)
{
};
std::basic_string<TCHAR> get_value(const std::basic_string<TCHAR> ValueName = _T(""))
{
std::basic_string<TCHAR> returnval;
DWORD type = 0, size = 0, dwErr = 0;
if(open(KEY_READ)) return _T("FilePermsBox Error");
if(query_value(ValueName, type, size, 0) != ERROR_SUCCESS)
{
TError << keyname.c_str() << _T("\\") << ValueName.c_str() << _T(": could not read registry value");
return _T("FilePermsBox Error");
}
if(type != REG_SZ) throw STD(_T("Registry value is not a string"));
sized_array<TCHAR> data ( (size + 1)/ sizeof(TCHAR) );
dwErr = query_value( ValueName, type, size, reinterpret_cast<BYTE *>(data.get()) );
if(dwErr != ERROR_SUCCESS)
{
TError << keyname.c_str() << _T("") << ValueName.c_str() << ("Registry value contains unreliable data");
return _T("FilePermsBox Error");
}
returnval = data.get();
return returnval;
};
DWORD put_value(const std::basic_string<TCHAR> &ValueName = _T(""), const std::basic_string<TCHAR> & value = _T(""))
{
DWORD dwErr = open(KEY_READ | KEY_WRITE);
if(dwErr != ERROR_SUCCESS) return dwErr;
dwErr = set_value( ValueName, REG_SZ, DWORD(value.length() + 1) * sizeof(TCHAR), reinterpret_cast<const BYTE *>(value.c_str()) );
return dwErr;
/* Let it throw on error. */
};
};
template<class T>
class registry_int : public registry_value
{
public:
registry_int(HKEY base, const std::basic_string<TCHAR> & name) : registry_value(base, name)
{
};
const T get_value(const std::basic_string<TCHAR> &ValueName = _T(""))
{
DWORD returnval = DWORD(0);
DWORD type = 0, size = sizeof(DWORD);
open(KEY_READ);
if(query_value(ValueName, &type, &size, &returnval) == ERROR_SUCCESS)
{/* We already know how big this type is. */
if(type != REG_DWORD) throw STD(_T("Registry value is not an integer"));
}
else throw STD(_T("Error reading integer registry value"));
return T(returnval);
};
DWORD put_value(const std::basic_string<TCHAR> &ValueName = _T(""), const T & value)
{
DWORD data(value), dwErr;
dwErr = open(KEY_READ|KEY_WRITE);
if(dwErr != ERROR_SUCCESS) return dwErr;
dwErr = set_value(ValueName, REG_DWORD, sizeof(DWORD), &data);
return dwErr;
};
};
#endif /* REGISTRY_VALUE_H */