323 lines
8.6 KiB
C++
323 lines
8.6 KiB
C++
|
//
|
||
|
// SafeReg.cpp
|
||
|
//
|
||
|
// Functions to ensure strings read from the registry are null-terminated.
|
||
|
//
|
||
|
// History:
|
||
|
//
|
||
|
// 2002-03-20 KenSh Created
|
||
|
//
|
||
|
// Copyright (c) 2002 Microsoft Corporation
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "SafeReg.h"
|
||
|
|
||
|
|
||
|
// SafeRegQueryValueCchHelper [private]
|
||
|
//
|
||
|
// Implementation of both "safe" kinds of string registry reads.
|
||
|
//
|
||
|
static HRESULT SafeRegQueryValueCchHelper
|
||
|
(
|
||
|
IN DWORD dwExpectedType,
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR pszBuf,
|
||
|
IN int cchBuf,
|
||
|
OUT OPTIONAL int* pcchValueSize,
|
||
|
OUT OPTIONAL BOOL* pfExpandSz
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
int cchValueSize = 0;
|
||
|
BOOL fExpandSz = FALSE;
|
||
|
|
||
|
// BLOCK
|
||
|
{
|
||
|
if ((!pszBuf && cchBuf != 0) || cchBuf < 0) // note: pszValueName can be null
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
DWORD dwType;
|
||
|
DWORD cbData = cchBuf * sizeof(TCHAR);
|
||
|
DWORD dwResult = RegQueryValueEx(
|
||
|
hkey, pszValueName, NULL, &dwType, (LPBYTE)pszBuf, &cbData);
|
||
|
if (dwResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(dwResult);
|
||
|
}
|
||
|
else if (!pszBuf && cbData > 0)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
fExpandSz = (dwType == REG_EXPAND_SZ);
|
||
|
|
||
|
if ((dwType != dwExpectedType) &&
|
||
|
!(dwExpectedType == REG_SZ && dwType == REG_EXPAND_SZ))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA))
|
||
|
{
|
||
|
// Add 1-2 extra chars in case the registry data is not big enough.
|
||
|
cchValueSize = cbData / sizeof(TCHAR);
|
||
|
cchValueSize += (dwExpectedType == REG_MULTI_SZ) ? 2 : 1;
|
||
|
}
|
||
|
else if (SUCCEEDED(hr))
|
||
|
{
|
||
|
cchValueSize = cbData / sizeof(TCHAR);
|
||
|
|
||
|
// check for lack of null-termination
|
||
|
if (cchValueSize == 0 || pszBuf[cchValueSize-1] != _T('\0'))
|
||
|
cchValueSize++;
|
||
|
|
||
|
// check for lack of double null-termination (multi-sz only)
|
||
|
if (dwExpectedType == REG_MULTI_SZ && (cchValueSize < 2 || pszBuf[cchValueSize-2] != _T('\0')))
|
||
|
cchValueSize++;
|
||
|
|
||
|
// check for overflow
|
||
|
if (cchValueSize > cchBuf)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cchValueSize--; // when successful, count doesn't include trailing null
|
||
|
pszBuf[cchValueSize] = _T('\0');
|
||
|
|
||
|
if (dwExpectedType == REG_MULTI_SZ)
|
||
|
pszBuf[cchValueSize-1] = _T('\0');
|
||
|
}
|
||
|
}
|
||
|
} // end BLOCK
|
||
|
|
||
|
done:
|
||
|
if (FAILED(hr) && pszBuf && cchBuf > 0)
|
||
|
pszBuf[0] = _T('\0');
|
||
|
if (pcchValueSize)
|
||
|
*pcchValueSize = cchValueSize;
|
||
|
if (pfExpandSz)
|
||
|
*pfExpandSz = fExpandSz;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// SafeRegQueryValueCchAllocHelper [private]
|
||
|
//
|
||
|
// Implementation of the 2 "alloc" versions of the safe reg string functions.
|
||
|
//
|
||
|
HRESULT WINAPI SafeRegQueryValueCchAllocHelper
|
||
|
(
|
||
|
IN DWORD dwExpectedType,
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR* ppszBuf,
|
||
|
OUT OPTIONAL int* pcchValueSize,
|
||
|
OUT OPTIONAL BOOL* pfExpandSz
|
||
|
)
|
||
|
{
|
||
|
LPTSTR pszResult = NULL;
|
||
|
int cchValueSize = 0;
|
||
|
BOOL fExpandSz = FALSE;
|
||
|
HRESULT hr = E_INVALIDARG;
|
||
|
|
||
|
// BLOCK
|
||
|
{
|
||
|
if (!ppszBuf)
|
||
|
{
|
||
|
goto done; // hr is already E_INVALIDARG
|
||
|
}
|
||
|
|
||
|
DWORD cbNeeded = 0;
|
||
|
DWORD dwErr = RegQueryValueEx(hkey, pszValueName, NULL, NULL, NULL, &cbNeeded);
|
||
|
if (dwErr != 0 && dwErr != ERROR_MORE_DATA)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(dwErr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
int cchBuf = (cbNeeded / sizeof(TCHAR)) + 2;
|
||
|
pszResult = (LPTSTR)SafeRegMalloc(sizeof(TCHAR) * cchBuf);
|
||
|
if (!pszResult)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
hr = SafeRegQueryValueCchHelper(dwExpectedType, hkey, pszValueName, pszResult, cchBuf, &cchValueSize, &fExpandSz);
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
SafeRegFree(pszResult);
|
||
|
pszResult = NULL;
|
||
|
}
|
||
|
|
||
|
if (ppszBuf)
|
||
|
*ppszBuf = pszResult;
|
||
|
if (pcchValueSize)
|
||
|
*pcchValueSize = cchValueSize;
|
||
|
if (pfExpandSz)
|
||
|
*pfExpandSz = fExpandSz;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// SafeRegQueryStringValueCch [public]
|
||
|
//
|
||
|
// Reads a string out of the registry and ensures the result is null-
|
||
|
// terminated. Optionally returns the number of characters retrieved,
|
||
|
// excluding the trailing null.
|
||
|
//
|
||
|
// If the buffer is not big enough, the function returns REG_E_MORE_DATA
|
||
|
// and stores the required size, in characters, in the pcchValueSize
|
||
|
// parameter (including room for the trailing null). Note that the size
|
||
|
// returned may be bigger than the actual size of the data in the registry.
|
||
|
//
|
||
|
HRESULT WINAPI SafeRegQueryStringValueCch
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR pszBuf,
|
||
|
IN int cchBuf,
|
||
|
OUT OPTIONAL int* pcchValueSize, // S_OK: chars written, excluding trailing null
|
||
|
// REG_E_MORE_DATA: required size, including null
|
||
|
OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
|
||
|
)
|
||
|
{
|
||
|
return SafeRegQueryValueCchHelper(REG_SZ, hkey, pszValueName, pszBuf, cchBuf, pcchValueSize, pfExpandSz);
|
||
|
}
|
||
|
|
||
|
HRESULT WINAPI SafeRegQueryStringValueCb
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR pszBuf,
|
||
|
IN int cbBuf,
|
||
|
OUT OPTIONAL int* pcbValueSize, // S_OK: bytes written, excluding trailing null
|
||
|
// REG_E_MORE_DATA: required size, including null
|
||
|
OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
|
||
|
)
|
||
|
{
|
||
|
int cchBuf = cbBuf / sizeof(TCHAR); // note: odd #'s for cbBuf are rounded down
|
||
|
HRESULT hr = SafeRegQueryValueCchHelper(REG_SZ, hkey, pszValueName, pszBuf, cchBuf, pcbValueSize, pfExpandSz);
|
||
|
if (pcbValueSize)
|
||
|
*pcbValueSize *= sizeof(TCHAR);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// SafeRegQueryMultiStringValueCch [public]
|
||
|
//
|
||
|
// Reads a multi-string out of the registry and ensures the result is double
|
||
|
// null-terminated. Optionally returns the number of characters retrieved,
|
||
|
// excluding the second trailing NULL.
|
||
|
//
|
||
|
// If the buffer is not big enough, the function returns REG_E_MORE_DATA
|
||
|
// and stores the required size, in characters, in the pcchValueSize
|
||
|
// parameter (including room for the trailing nulls). Note that the size
|
||
|
// returned may be bigger than the actual size of the data in the registry.
|
||
|
//
|
||
|
HRESULT WINAPI SafeRegQueryMultiStringValueCch
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR pszBuf,
|
||
|
IN int cchBuf,
|
||
|
OUT OPTIONAL int* pcchValueSize // S_OK: chars written, excluding final trailing null
|
||
|
// REG_E_MORE_DATA: required size, including nulls
|
||
|
)
|
||
|
{
|
||
|
return SafeRegQueryValueCchHelper(REG_MULTI_SZ, hkey, pszValueName, pszBuf, cchBuf, pcchValueSize, NULL);
|
||
|
}
|
||
|
|
||
|
HRESULT WINAPI SafeRegQueryMultiStringValueCb
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR pszBuf,
|
||
|
IN int cbBuf,
|
||
|
OUT OPTIONAL int* pcbValueSize // S_OK: bytes written, excluding final trailing null
|
||
|
// REG_E_MORE_DATA: required size, including nulls
|
||
|
)
|
||
|
{
|
||
|
int cchBuf = cbBuf / sizeof(TCHAR); // note: odd #'s for cbBuf are rounded down
|
||
|
HRESULT hr = SafeRegQueryValueCchHelper(REG_MULTI_SZ, hkey, pszValueName, pszBuf, cchBuf, pcbValueSize, NULL);
|
||
|
if (pcbValueSize)
|
||
|
*pcbValueSize *= sizeof(TCHAR);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// SafeRegQueryStringValueCchAlloc [public]
|
||
|
//
|
||
|
// Allocates room for the registry string via SafeRegMalloc, and returns
|
||
|
// the resulting string. Caller should free via SafeRegFree.
|
||
|
//
|
||
|
HRESULT WINAPI SafeRegQueryStringValueCchAlloc
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR* ppszBuf,
|
||
|
OUT OPTIONAL int* pcchValueSize, // chars written, excluding trailing null
|
||
|
OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
|
||
|
)
|
||
|
{
|
||
|
return SafeRegQueryValueCchAllocHelper(REG_SZ, hkey, pszValueName, ppszBuf, pcchValueSize, pfExpandSz);
|
||
|
}
|
||
|
|
||
|
HRESULT WINAPI SafeRegQueryStringValueCbAlloc
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR* ppszBuf,
|
||
|
OUT OPTIONAL int* pcbValueSize, // bytes written, excluding trailing null
|
||
|
OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = SafeRegQueryValueCchAllocHelper(REG_SZ, hkey, pszValueName, ppszBuf, pcbValueSize, pfExpandSz);
|
||
|
if (pcbValueSize)
|
||
|
*pcbValueSize *= sizeof(TCHAR);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// SafeRegQueryMultiStringValueCchAlloc [public]
|
||
|
//
|
||
|
// Allocates room for the registry string via SafeRegMalloc, and returns
|
||
|
// the resulting string. Caller should free via SafeRegFree.
|
||
|
//
|
||
|
HRESULT WINAPI SafeRegQueryMultiStringValueCchAlloc
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR* ppszBuf,
|
||
|
OUT OPTIONAL int* pcchValueSize // chars written, excluding final trailing null
|
||
|
)
|
||
|
{
|
||
|
return SafeRegQueryValueCchAllocHelper(REG_MULTI_SZ, hkey, pszValueName, ppszBuf, pcchValueSize, NULL);
|
||
|
}
|
||
|
|
||
|
HRESULT WINAPI SafeRegQueryMultiStringValueCbAlloc
|
||
|
(
|
||
|
IN HKEY hkey,
|
||
|
IN LPCTSTR pszValueName,
|
||
|
OUT LPTSTR* ppszBuf,
|
||
|
OUT OPTIONAL int* pcbValueSize // bytes written, excluding final trailing null
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = SafeRegQueryValueCchAllocHelper(REG_MULTI_SZ, hkey, pszValueName, ppszBuf, pcbValueSize, NULL);
|
||
|
if (pcbValueSize)
|
||
|
*pcbValueSize *= sizeof(TCHAR);
|
||
|
return hr;
|
||
|
}
|