windows-nt/Source/XPSP1/NT/enduser/windows.com/lib/wusafefn/safereg.cpp

323 lines
8.6 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//
// 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;
}