280 lines
5.5 KiB
C
280 lines
5.5 KiB
C
|
#include "stdafx.h"
|
||
|
|
||
|
#define STRSAFE_NO_DEPRECATE
|
||
|
#include <Strsafe.h>
|
||
|
|
||
|
// Used by CopyRegValue specifically for copying
|
||
|
// REG_MULTI_SZ values, because those in particular are
|
||
|
// really funky.
|
||
|
static BOOL
|
||
|
CopyMultiValue(HKEY hKey,
|
||
|
PVOID pVal,
|
||
|
LPCTSTR szName,
|
||
|
DWORD dwSize)
|
||
|
{
|
||
|
int iStrCount = 0;
|
||
|
LPTSTR szMulti = NULL,
|
||
|
ptr;
|
||
|
BOOL bWasNull = FALSE;
|
||
|
LONG lRes;
|
||
|
MultiString *msData = (MultiString *)pVal;
|
||
|
|
||
|
HANDLE hHeap = GetProcessHeap();
|
||
|
|
||
|
szMulti = HeapAlloc(hHeap,
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
dwSize + sizeof(TCHAR));
|
||
|
if (!szMulti) return FALSE;
|
||
|
|
||
|
// Get the multi-string value
|
||
|
if (!(lRes = RegQueryValueEx(hKey,
|
||
|
szName,
|
||
|
0,
|
||
|
NULL,
|
||
|
szMulti,
|
||
|
&dwSize)))
|
||
|
{
|
||
|
HeapFree(hHeap, 0, szMulti);
|
||
|
SetLastError(lRes);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for (ptr = szMulti; (ptr - szMulti) < (LONG)dwSize; ptr++) {
|
||
|
if (*ptr == 0) {
|
||
|
if (bWasNull) {
|
||
|
// Two NULLs in a row, we're done!
|
||
|
break;
|
||
|
} else {
|
||
|
// End of string, add to the list
|
||
|
bWasNull = TRUE;
|
||
|
iStrCount++;
|
||
|
}
|
||
|
}
|
||
|
bWasNull = FALSE;
|
||
|
}
|
||
|
|
||
|
if (!bWasNull) {
|
||
|
// Not properly NULL terminated, sigh...
|
||
|
// Make sure to count the last string.
|
||
|
iStrCount++;
|
||
|
}
|
||
|
|
||
|
if (!MultiString_Init(msData, iStrCount)) {
|
||
|
HeapFree(hHeap, 0, szMulti);
|
||
|
return FALSE;
|
||
|
} else {
|
||
|
int i;
|
||
|
for (i = 0, ptr = szMulti; i < iStrCount; i++, ptr += strlen(ptr) + 1) {
|
||
|
if (!MultiString_Append(msData, ptr)) {
|
||
|
DWORD err = GetLastError();
|
||
|
|
||
|
HeapFree(hHeap, 0, szMulti);
|
||
|
MultiString_Dispose(msData);
|
||
|
|
||
|
SetLastError(err);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HeapFree(hHeap, 0, szMulti);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
CopyRegValue(HKEY hKey,
|
||
|
PVOID pVal,
|
||
|
LPCTSTR szName,
|
||
|
DWORD dwType,
|
||
|
DWORD dwSize)
|
||
|
{
|
||
|
HANDLE hHeap = GetProcessHeap();
|
||
|
PVOID pData = pVal;
|
||
|
LONG lRes;
|
||
|
|
||
|
if (pVal == NULL ||
|
||
|
szName == NULL ||
|
||
|
hKey == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (dwType == REG_BINARY ||
|
||
|
dwType == REG_SZ) {
|
||
|
pData = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize);
|
||
|
if (!pData) return FALSE;
|
||
|
*(PVOID *)pVal = pData;
|
||
|
} else if (dwType == REG_MULTI_SZ) {
|
||
|
// REG_MULTI_SZ is complex enough to warrant its own
|
||
|
// function
|
||
|
return CopyMultiValue(hKey, pVal, szName, dwSize);
|
||
|
}
|
||
|
|
||
|
if ((lRes = RegQueryValueEx(hKey,
|
||
|
szName,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
pData,
|
||
|
&dwSize)) != ERROR_SUCCESS)
|
||
|
{
|
||
|
SetLastError(lRes);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// Enumerates across all values in a key, running the given
|
||
|
// RegEnumCallback. Use `pData` to pass application-defined
|
||
|
// data to your enumerator callback.
|
||
|
BOOL RegGetAllValues(HKEY hKey,
|
||
|
RegEnumCallback cb,
|
||
|
PVOID pData)
|
||
|
{
|
||
|
LONG lRes;
|
||
|
TCHAR szValName[512];
|
||
|
DWORD dwNameLen = 512,
|
||
|
dwIdx,
|
||
|
dwValType,
|
||
|
dwValSize;
|
||
|
if (!hKey || !cb) return FALSE;
|
||
|
|
||
|
for (dwIdx = 0;
|
||
|
dwNameLen = 512, // reset dwNameLen first
|
||
|
!(lRes = RegEnumValue(hKey,
|
||
|
dwIdx,
|
||
|
szValName,
|
||
|
&dwNameLen,
|
||
|
0,
|
||
|
&dwValType,
|
||
|
NULL,
|
||
|
&dwValSize));
|
||
|
dwIdx++) {
|
||
|
// Enforce null termination
|
||
|
szValName[min(511, dwNameLen)] = 0;
|
||
|
// pass to callback
|
||
|
if (!cb(hKey,
|
||
|
szValName,
|
||
|
dwValSize,
|
||
|
dwValType,
|
||
|
pData)) {
|
||
|
// Callback returned failure, bail out
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (lRes != ERROR_NO_MORE_ITEMS) {
|
||
|
// Some enumeration error happened, store it
|
||
|
// and report the failure
|
||
|
SetLastError(lRes);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
RegStoreMultiString(HKEY hKey,
|
||
|
LPTSTR szValName,
|
||
|
MultiString *msData)
|
||
|
{
|
||
|
LPTSTR szMulti;
|
||
|
DWORD dwMultiSize;
|
||
|
LONG lRes;
|
||
|
HANDLE hHeap = GetProcessHeap();
|
||
|
|
||
|
if (!msData->TotalLength) return FALSE;
|
||
|
|
||
|
// Total size + second NULL terminator
|
||
|
dwMultiSize = (DWORD)msData->TotalLength + 1;
|
||
|
szMulti = HeapAlloc(hHeap,
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
dwMultiSize * sizeof(TCHAR));
|
||
|
if (!szMulti) return FALSE;
|
||
|
|
||
|
// Copy all the strings into one buffer, as per REG_MULTI_SZ
|
||
|
{
|
||
|
DWORD i, dwCurLen;
|
||
|
for (i = 0, dwCurLen = 0;
|
||
|
i < msData->Count && dwCurLen < dwMultiSize;
|
||
|
dwCurLen += (DWORD)_tcslen(msData->Values[i++]) + 1) {
|
||
|
HRESULT hrRes = StringCchCopy(&szMulti[dwCurLen],
|
||
|
_tcslen(msData->Values[i]) + 1,
|
||
|
msData->Values[i]);
|
||
|
if (FAILED(hrRes)) {
|
||
|
HeapFree(hHeap, 0, szMulti);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lRes = RegSetValueEx(hKey,
|
||
|
szValName,
|
||
|
0,
|
||
|
REG_MULTI_SZ,
|
||
|
szMulti,
|
||
|
dwMultiSize);
|
||
|
|
||
|
HeapFree(hHeap, 0, szMulti);
|
||
|
|
||
|
if (lRes != ERROR_SUCCESS) {
|
||
|
SetLastError(lRes);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// Stores a value in the registry, making assumptions based on the
|
||
|
// key type.
|
||
|
BOOL
|
||
|
RegStoreValue(HKEY hKey,
|
||
|
LPTSTR szValName,
|
||
|
PVOID pData,
|
||
|
DWORD dwValType)
|
||
|
{
|
||
|
DWORD dwStoreSize;
|
||
|
LONG lRes;
|
||
|
if (!hKey || !szValName || !pData) return FALSE;
|
||
|
|
||
|
switch (dwValType) {
|
||
|
case REG_SZ:
|
||
|
case REG_EXPAND_SZ:
|
||
|
dwStoreSize = (DWORD)_tcslen((LPTSTR)pData) + sizeof(TCHAR);
|
||
|
break;
|
||
|
case REG_DWORD:
|
||
|
dwStoreSize = sizeof(DWORD);
|
||
|
break;
|
||
|
#ifdef QWORD
|
||
|
case REG_QWORD:
|
||
|
dwStoreSize = sizeof(QWORD);
|
||
|
break;
|
||
|
#endif
|
||
|
case REG_BINARY:
|
||
|
// TODO: handle REG_BINARY? will we ever use it?
|
||
|
OutputDebugString(_T("REG_BINARY attempted to be stored! Unsupported"));
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
case REG_MULTI_SZ:
|
||
|
return RegStoreMultiString(hKey,
|
||
|
szValName,
|
||
|
(MultiString *)pData);
|
||
|
default:
|
||
|
// ignore
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
lRes = RegSetValueEx(hKey,
|
||
|
szValName,
|
||
|
0,
|
||
|
dwValType,
|
||
|
pData,
|
||
|
dwStoreSize);
|
||
|
if (lRes != ERROR_SUCCESS) {
|
||
|
SetLastError(lRes);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|