|
|
//
// 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; }
|