Shell Extension Registry Helpers
A portable registry helper library — create, delete (including recursive via SHDeleteKey), and get/set string, DWORD, and binary values.
The utility layer that the shell extension uses to install and uninstall itself from the registry. It is a complete little API in its own right: CreateRegistryKey (with an explicit security descriptor so it works on NT), DeleteRegistryKey (which tries plain RegDeleteKey first and falls back to dynamically loading shlwapi.dll for SHDeleteKey when the key has children - avoiding a hard dependency on that DLL), plus typed getters and setters for REG_SZ, REG_DWORD, and REG_BINARY values. The getters use the classic two-call pattern: query once to learn the required size, again to fill the buffer. Worth stealing for any installer or self-registering component.
// Returns TRUE if the OS is Windows NT or Windows 2000
int IsWinNT()
{
OSVERSIONINFO os;
os.dwOSVersionInfoSize=sizeof(os);
if(GetVersionEx(&os))
{
if(os.dwPlatformId==2)
{
if(os.dwMajorVersion == 3) //NT 3
return TRUE;
if(os.dwMajorVersion == 4) //NT 4
return TRUE;
if(os.dwMajorVersion == 5 && os.dwMinorVersion == 0) //(W2K)
return TRUE;
if(os.dwMajorVersion == 5 && os.dwMinorVersion == 1) // XP
return TRUE;
// if(os.dwMajorVersion > 5) For Future Versions
}
return FALSE;
}
return -1;
}
// Creates a key specified by pszSubKey
int CreateRegistryKey(HKEY hKeyRoot, LPCTSTR pszSubKey)
{
HKEY hKey;
DWORD dwFunc;
LONG lRet;
SECURITY_DESCRIPTOR SD;
SECURITY_ATTRIBUTES SA;
if(InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION) == FALSE)
return FALSE;
if(SetSecurityDescriptorDacl(&SD, TRUE, 0, FALSE) == FALSE)
return FALSE;
SA.nLength = sizeof(SA);
SA.lpSecurityDescriptor = &SD;
SA.bInheritHandle = FALSE;
lRet = RegCreateKeyEx(
hKeyRoot,
pszSubKey,
0,
(LPTSTR)NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
&SA,
&hKey,
&dwFunc
);
if(lRet == ERROR_SUCCESS)
{
RegCloseKey(hKey);
hKey = (HKEY)NULL;
return TRUE;
}
SetLastError((DWORD)lRet);
return FALSE;
}
int DeleteRegistryKey(HKEY hKeyRoot, LPCTSTR pszSubKey)
{
DWORD dwRet = ERROR_SUCCESS;
if(IsWinNT())
{
// WinNT/2K will not allow you to delete keys which have
// subkeys/values inside them. MS's platform SDK tells you
// to use the SHDeleteKey function in shlwapi.dll. This dll
// is not available on NT platforms without IE 4.0 or later.
// Because of this I first attempt to delete the key in the
// hope that it is empty. If that is not possible I load shlwapi
// and call the function in that. This prevents the app bombing
// out if the dll can't be found.
if(RegDeleteKey(hKeyRoot, pszSubKey) != ERROR_SUCCESS)
{
HINSTANCE hLibInst = LoadLibrary("shlwapi.dll");
#if defined(UNICODE) || defined(_UNICODE)
SHDELKEYPROC DeleteKeyRecursive = (SHDELKEYPROC)GetProcAddress(hLibInst, "SHDeleteKeyW");
#else
SHDELKEYPROC DeleteKeyRecursive = (SHDELKEYPROC)GetProcAddress(hLibInst, "SHDeleteKeyA");
#endif
if(DeleteKeyRecursive)
dwRet = DeleteKeyRecursive(hKeyRoot, pszSubKey);
FreeLibrary(hLibInst);
}
}
else {
// Windows 9x will allow RegDeleteKey to delete keys
// even if they have subkeys/values.
dwRet = RegDeleteKey(hKeyRoot, pszSubKey);
}
if(dwRet == ERROR_SUCCESS)
return TRUE;
SetLastError(dwRet);
return FALSE;
}
The value accessors follow one consistent shape - open with the minimum access needed, query/set, close, propagate SetLastError:
// Fetch a little endian DWORD from the registry
int Get_DWORDRegistryValue(HKEY hKeyRoot, LPCTSTR pszSubKey, LPCTSTR pszValue, DWORD &rdwBuff)
{
HKEY hKey;
DWORD dwType = REG_DWORD;
DWORD dwSize = sizeof(DWORD);
DWORD dwValue = 0;
LONG lRes;
rdwBuff = 0;
lRes = RegOpenKeyEx(hKeyRoot, pszSubKey, 0, KEY_READ, &hKey);
if(lRes != ERROR_SUCCESS)
{
SetLastError(lRes);
return FALSE;
}
lRes = RegQueryValueEx(hKey, pszValue, 0, &dwType, (LPBYTE)&dwValue, &dwSize);
RegCloseKey(hKey);
if(lRes!=ERROR_SUCCESS)
{
SetLastError(lRes);
return FALSE;
}
rdwBuff = dwValue;
return TRUE;
}
// Writes a DWORD value to the registry
int Set_DWORDRegistryValue(HKEY hKeyRoot, LPCTSTR pszSubKey, LPCTSTR pszValue, DWORD dwValue)
{
HKEY hKey;
LONG lRes;
lRes = RegOpenKeyEx(hKeyRoot, pszSubKey, 0, KEY_WRITE, &hKey);
if(lRes != ERROR_SUCCESS)
{
SetLastError(lRes);
return FALSE;
}
lRes = RegSetValueEx(hKey, pszValue,0,REG_DWORD,(unsigned char*)&dwValue,sizeof(DWORD));
RegCloseKey(hKey);
if(lRes!=ERROR_SUCCESS)
{
SetLastError(lRes);
return FALSE;
}
return TRUE;
}
// Writes a string to the registry.
int Set_StringRegistryValue(HKEY hKeyRoot, LPCTSTR pszSubKey, LPCTSTR pszValue, LPCTSTR pszString)
{
HKEY hKey;
LONG lRes;
DWORD dwSize = lstrlen(pszString) * sizeof(TCHAR);
lRes = RegOpenKeyEx(hKeyRoot, pszSubKey, 0, KEY_WRITE, &hKey);
if(lRes != ERROR_SUCCESS)
{
SetLastError(lRes);
return FALSE;
}
lRes = RegSetValueEx(hKey, pszValue, 0, REG_SZ, (unsigned char*)pszString, dwSize);
RegCloseKey(hKey);
if(lRes!=ERROR_SUCCESS)
{
SetLastError(lRes);
return FALSE;
}
return TRUE;
}
Get_BinaryRegistryValue and Get_StringRegistryValue add the size-probing behavior: pass your buffer size by reference and the functions grow rdwSize to the exact requirement if the buffer was too small. DeleteRegistryValue completes the set for single-value removal.