588 lines
17 KiB
C++
588 lines
17 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: N C R E G Q . C P P
|
||
|
//
|
||
|
// Contents: HrRegQuery functions.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: shaunco 5 Jun 1998
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.h>
|
||
|
#pragma hdrstop
|
||
|
#include "ncdebug.h"
|
||
|
#include "ncreg.h"
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryDword
|
||
|
//
|
||
|
// Purpose: Gets a DWORD from the registry. Checks that its type and
|
||
|
// size are correct. Easier to understand than HrRegQueryValueEx
|
||
|
// with 5 parameters. Type safe (no LPBYTE stuff).
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in] The registry key.
|
||
|
// pszValueName [in] The name of the value to get.
|
||
|
// pdwValue [out] The returned DWORD value if successful. Zero
|
||
|
// if not.
|
||
|
//
|
||
|
// Returns: S_OK or HRESULT_FROM_WIN32.
|
||
|
//
|
||
|
// Author: shaunco 27 Mar 1997
|
||
|
//
|
||
|
// Side Effects: On error, the output DWORD is set to zero to line-up
|
||
|
// with the rules of COM in this regard.
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryDword (
|
||
|
HKEY hkey,
|
||
|
PCTSTR pszValueName,
|
||
|
LPDWORD pdwValue)
|
||
|
{
|
||
|
Assert (hkey);
|
||
|
Assert (pszValueName);
|
||
|
Assert (pdwValue);
|
||
|
|
||
|
// Get the value.
|
||
|
DWORD dwType;
|
||
|
DWORD cbData = sizeof(DWORD);
|
||
|
HRESULT hr = HrRegQueryValueEx (hkey, pszValueName, &dwType,
|
||
|
(LPBYTE)pdwValue, &cbData);
|
||
|
|
||
|
// It's type should be REG_DWORD. (duh).
|
||
|
//
|
||
|
if ((S_OK == hr) && (REG_DWORD != dwType))
|
||
|
{
|
||
|
TraceTag (ttidError, "Expected a type of REG_DWORD for %S.",
|
||
|
pszValueName);
|
||
|
hr = HRESULT_FROM_WIN32 (ERROR_INVALID_DATATYPE);
|
||
|
}
|
||
|
|
||
|
// It's size should be correct too.
|
||
|
//
|
||
|
AssertSz (FImplies(S_OK == hr, sizeof(DWORD) == cbData),
|
||
|
"Expected sizeof(DWORD) bytes to be returned.");
|
||
|
|
||
|
// Make sure we initialize the output value on error.
|
||
|
// (We don't know for sure that RegQueryValueEx does this.)
|
||
|
//
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
*pdwValue = 0;
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
|
||
|
"HrRegQueryDword");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryExpandString
|
||
|
//
|
||
|
// Purpose: Query a REG_EXPAND_SZ value from the registry and
|
||
|
// expand it using ExpandEnvironmentStrings. Return the
|
||
|
// result in a tstring.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in] The parent HKEY of szValueName
|
||
|
// pszValueName [in] The name of the value to query.
|
||
|
// pstrValue [out] The returned (expanded) value.
|
||
|
//
|
||
|
// Returns: S_OK or an error code.
|
||
|
//
|
||
|
// Author: shaunco 6 Jun 1998
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryExpandString (
|
||
|
HKEY hkey,
|
||
|
PCTSTR pszValueName,
|
||
|
tstring* pstrValue)
|
||
|
{
|
||
|
Assert (hkey);
|
||
|
Assert (pszValueName);
|
||
|
Assert (pstrValue);
|
||
|
|
||
|
tstring strToExpand;
|
||
|
HRESULT hr = HrRegQueryTypeString (hkey, pszValueName,
|
||
|
REG_EXPAND_SZ, &strToExpand);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
ExpandEnvironmentStringsIntoTstring (strToExpand.c_str(), pstrValue);
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ||
|
||
|
(HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE) == hr),
|
||
|
"HrRegQueryExpandString");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryInfoKey
|
||
|
//
|
||
|
// Purpose: Retrieves information about a registry key by calling
|
||
|
// RegQueryInfoKey.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in]
|
||
|
// pszClass [out]
|
||
|
// pcbClass [inout]
|
||
|
// pcSubKeys [out]
|
||
|
// pcbMaxSubKeyLen [out] See the Win32 documentation for the
|
||
|
// pcbMaxClassLen [out] RegQueryInfoKey function.
|
||
|
// pcValues [out]
|
||
|
// pcbMaxValueNameLen [out]
|
||
|
// pcbMaxValueLen [out]
|
||
|
// pcbSecurityDescriptor [out]
|
||
|
// pftLastWriteTime [out]
|
||
|
//
|
||
|
// Returns: S_OK or an HRESULT_FROM_WIN32 error code.
|
||
|
//
|
||
|
// Author: BillBe 28 Aug 1998
|
||
|
//
|
||
|
// Notes: Note that pcbClass is an *in/out* param. Set this to the size
|
||
|
// of the buffer pointed to by pszClass *before* calling this
|
||
|
// function!
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryInfoKey (
|
||
|
IN HKEY hkey,
|
||
|
OUT PWSTR pszClass,
|
||
|
IN OUT LPDWORD pcbClass,
|
||
|
OUT LPDWORD pcSubKeys,
|
||
|
OUT LPDWORD pcbMaxSubKeyLen,
|
||
|
OUT LPDWORD pcbMaxClassLen,
|
||
|
OUT LPDWORD pcValues,
|
||
|
OUT LPDWORD pcbMaxValueNameLen,
|
||
|
OUT LPDWORD pcbMaxValueLen,
|
||
|
OUT LPDWORD pcbSecurityDescriptor,
|
||
|
OUT PFILETIME pftLastWriteTime)
|
||
|
{
|
||
|
Assert(hkey);
|
||
|
|
||
|
LONG lr = RegQueryInfoKeyW(hkey, pszClass, pcbClass, NULL,pcSubKeys,
|
||
|
pcbMaxSubKeyLen, pcbMaxClassLen, pcValues, pcbMaxValueNameLen,
|
||
|
pcbMaxValueLen, pcbSecurityDescriptor, pftLastWriteTime);
|
||
|
|
||
|
HRESULT hr = HRESULT_FROM_WIN32 (lr);
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "HrRegQueryInfoKey");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryStringAsUlong
|
||
|
//
|
||
|
// Purpose: Reads a REG_SZ from the registry and converts it to a ulong
|
||
|
// before returning
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in] The registry key.
|
||
|
// pszValueName [in] The name of the value to get.
|
||
|
// nBase [in] The numeric base to convert to
|
||
|
// pulValue [out] The returned converted string if successful.
|
||
|
//
|
||
|
// Returns: S_OK or an HRESULT_FROM_WIN32 error code.
|
||
|
//
|
||
|
// Author: billbe 13 Jun 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryStringAsUlong (
|
||
|
IN HKEY hkey,
|
||
|
IN PCTSTR pszValueName,
|
||
|
IN int nBase,
|
||
|
OUT ULONG* pulValue)
|
||
|
{
|
||
|
Assert (hkey);
|
||
|
Assert (pszValueName);
|
||
|
Assert (nBase);
|
||
|
Assert (pulValue);
|
||
|
|
||
|
// Get the value.
|
||
|
//
|
||
|
tstring strValue;
|
||
|
HRESULT hr = HrRegQueryString (hkey, pszValueName, &strValue);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Convert and assign the output parameters.
|
||
|
PWSTR pszStopString;
|
||
|
*pulValue = wcstoul (strValue.c_str(), &pszStopString, nBase);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pulValue = 0;
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
|
||
|
"HrRegQueryStringAsUlong");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryTypeString
|
||
|
//
|
||
|
// Purpose: Query a REG_SZ or REG_EXPAND_SZ value and returns it
|
||
|
// in a tstring.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in] The parent HKEY of szValueName
|
||
|
// pszValueName [in] The name of the value to query.
|
||
|
// dwType [in] REG_SZ or REG_EXPAND_SZ
|
||
|
// pstr [out] The returned value.
|
||
|
//
|
||
|
// Returns: S_OK or an error code.
|
||
|
//
|
||
|
// Author: shaunco 6 Jun 1998
|
||
|
//
|
||
|
// Notes: REG_EXPAND_SZ values ARE NOT expanded using
|
||
|
// ExpandEnvironentStrings. Use HrRegQueryExpandString instead.
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryTypeString (
|
||
|
IN HKEY hkey,
|
||
|
IN PCTSTR pszValueName,
|
||
|
IN DWORD dwType,
|
||
|
OUT tstring* pstr)
|
||
|
{
|
||
|
Assert (hkey);
|
||
|
Assert (pszValueName);
|
||
|
Assert (pstr);
|
||
|
|
||
|
AssertSz ((REG_SZ == dwType) ||
|
||
|
(REG_EXPAND_SZ == dwType), "Only REG_SZ or REG_EXPAND_SZ "
|
||
|
"types accepted.");
|
||
|
|
||
|
BOOL fErase = TRUE;
|
||
|
|
||
|
// Get size of the data.
|
||
|
//
|
||
|
DWORD dwTypeRet;
|
||
|
DWORD cbData = 0;
|
||
|
HRESULT hr = HrRegQueryValueEx (hkey, pszValueName, &dwTypeRet,
|
||
|
NULL, &cbData);
|
||
|
|
||
|
// Make sure it has the correct type.
|
||
|
//
|
||
|
if ((S_OK == hr) && (dwTypeRet != dwType))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Compute the number of characters in the data including the
|
||
|
// NULL terminator. After dividing the number of bytes by
|
||
|
// the sizeof a TCHAR, add 1 if there is a remainder. If we didn't,
|
||
|
// and the number of bytes was not a multiple of the sizeof a TCHAR,
|
||
|
// we'd come up short because integer division rounds down.
|
||
|
// (The only time I can think of cbData would not be a multiple
|
||
|
// of sizeof(TCHAR) is if the registry data were somehow corrupted.
|
||
|
// It's not that I think corruption deserves a special case, but
|
||
|
// we shouldn't AV in light of it.)
|
||
|
//
|
||
|
DWORD cchIncludingNull;
|
||
|
|
||
|
cchIncludingNull = cbData / sizeof(TCHAR);
|
||
|
if (cbData % sizeof(TCHAR))
|
||
|
{
|
||
|
cchIncludingNull++;
|
||
|
}
|
||
|
|
||
|
// If we have more than just the terminator, allocate and
|
||
|
// get the string. Otherwise, we want it empty.
|
||
|
//
|
||
|
if (cchIncludingNull > 1)
|
||
|
{
|
||
|
// Reserve room for the correct number of characters.
|
||
|
// cch is the count of characters without the terminator
|
||
|
// since that is what tstring operates with.
|
||
|
//
|
||
|
DWORD cch = cchIncludingNull - 1;
|
||
|
Assert (cch > 0);
|
||
|
|
||
|
// assign will reserve cch characters and set them all to 0.
|
||
|
// checking capacity afterwards ensures the allocation made
|
||
|
// internally didn't fail.
|
||
|
//
|
||
|
pstr->assign (cch, 0);
|
||
|
if (cch <= pstr->capacity ())
|
||
|
{
|
||
|
hr = HrRegQueryValueEx (hkey, pszValueName, &dwType,
|
||
|
(LPBYTE)pstr->data (), &cbData);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// If everything went according to plan, the length
|
||
|
// of the string should now match what wcslen
|
||
|
// returns on the string itself. The reason it will
|
||
|
// match is because we passed cch to assign.
|
||
|
//
|
||
|
Assert (pstr->length() == (size_t)wcslen (pstr->c_str()));
|
||
|
fErase = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Empty the output string on failure or if we think it should be
|
||
|
// empty.
|
||
|
//
|
||
|
if (FAILED(hr) || fErase)
|
||
|
{
|
||
|
pstr->erase();
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ||
|
||
|
(HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE) == hr),
|
||
|
"HrRegQueryTypeString");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryTypeSzBuffer
|
||
|
//
|
||
|
// Purpose: Gets a string from the registry using the given buffer. Checks
|
||
|
// that its type is correct. Type safe (no LPBYTE stuff).
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in] The registry key.
|
||
|
// pszValueName [in] The name of the value to get.
|
||
|
// dwType [in] Desired type. (REG_SZ, REG_EXPAND_SZ, etc.)
|
||
|
// szData [out] String buffer to hold the data.
|
||
|
// pcbData [in,out] IN: Number of *bytes* in buffer pointed to by
|
||
|
// szData. OUT: Number of bytes actually copied
|
||
|
// into the buffer.
|
||
|
//
|
||
|
// Returns: S_OK or an HRESULT_FROM_WIN32 error code.
|
||
|
//
|
||
|
// Author: danielwe 3 Apr 1997
|
||
|
//
|
||
|
// Notes: If the function fails, the buffer passed in is guaranteed to
|
||
|
// be an empty string.
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryTypeSzBuffer (
|
||
|
IN HKEY hkey,
|
||
|
IN PCTSTR pszValueName,
|
||
|
IN DWORD dwType,
|
||
|
OUT PWSTR pszData,
|
||
|
OUT DWORD* pcbData)
|
||
|
{
|
||
|
Assert (hkey);
|
||
|
Assert (pszValueName);
|
||
|
Assert (pcbData);
|
||
|
|
||
|
DWORD dwTypeRet;
|
||
|
HRESULT hr = HrRegQueryValueEx (hkey, pszValueName, &dwTypeRet,
|
||
|
(LPBYTE)pszData, pcbData);
|
||
|
|
||
|
if ((S_OK == hr) && (dwTypeRet != dwType))
|
||
|
{
|
||
|
TraceTag (ttidError, "Expected a type of 0x%x for %S.",
|
||
|
dwType, pszValueName);
|
||
|
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr) && pszData)
|
||
|
{
|
||
|
// Make sure empty string is returned on failure.
|
||
|
//
|
||
|
*pszData = 0;
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
|
||
|
"HrRegQueryTypeSzBuffer");
|
||
|
return hr;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryValueEx
|
||
|
//
|
||
|
// Purpose: Retrieves the data from the given registry value by calling
|
||
|
// RegQueryValueEx.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in]
|
||
|
// pszValueName [in]
|
||
|
// pdwType [out] See the Win32 documentation for the
|
||
|
// pbData [out] RegQueryValueEx function.
|
||
|
// pcbData [in,out]
|
||
|
//
|
||
|
// Returns: S_OK or an HRESULT_FROM_WIN32 error code.
|
||
|
//
|
||
|
// Author: shaunco 25 Feb 1997
|
||
|
//
|
||
|
// Notes: Note that pcbData is an *in/out* param. Set this to the size
|
||
|
// of the buffer pointed to by pbData *before* calling this
|
||
|
// function!
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryValueEx (
|
||
|
IN HKEY hkey,
|
||
|
IN PCTSTR pszValueName,
|
||
|
OUT LPDWORD pdwType,
|
||
|
OUT LPBYTE pbData,
|
||
|
OUT LPDWORD pcbData)
|
||
|
{
|
||
|
Assert (hkey);
|
||
|
|
||
|
AssertSz (FImplies(pbData && pcbData, pdwType),
|
||
|
"pdwType not provided to HrRegQueryValueEx. You should be "
|
||
|
"retrieving the type as well so you can make sure it is "
|
||
|
"correct.");
|
||
|
|
||
|
LONG lr = RegQueryValueEx (hkey, pszValueName, NULL, pdwType,
|
||
|
pbData, pcbData);
|
||
|
HRESULT hr = HRESULT_FROM_WIN32 (lr);
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
(ERROR_MORE_DATA == lr) || (ERROR_FILE_NOT_FOUND == lr),
|
||
|
"HrRegQueryValueEx (%S)", pszValueName);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegQueryValueWithAlloc
|
||
|
//
|
||
|
// Purpose: Retrieve a registry value in a buffer allocated by this
|
||
|
// function. This goes through the mess of checking the value
|
||
|
// size, allocating the buffer, and then calling back to get the
|
||
|
// actual value. Returns the buffer to the user.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkey [in] An open HKEY (the one that contains the value
|
||
|
// to be read)
|
||
|
// pszValueName [in] Name of the registry value
|
||
|
// pdwType [in/out] The REG_ type that we plan to be reading
|
||
|
// ppbBuffer [out] Pointer to an LPBYTE buffer that will contain
|
||
|
// the registry value
|
||
|
// pdwSize [out] Pointer to a DWORD that will contain the size
|
||
|
// of the ppbBuffer.
|
||
|
//
|
||
|
// Returns: S_OK or an HRESULT_FROM_WIN32 error code.
|
||
|
//
|
||
|
// Author: jeffspr 27 Mar 1997
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRegQueryValueWithAlloc (
|
||
|
IN HKEY hkey,
|
||
|
IN PCTSTR pszValueName,
|
||
|
LPDWORD pdwType,
|
||
|
LPBYTE* ppbBuffer,
|
||
|
LPDWORD pdwSize)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
BYTE abData [256];
|
||
|
DWORD cbData;
|
||
|
BOOL fReQuery = FALSE;
|
||
|
|
||
|
Assert (hkey);
|
||
|
Assert (pdwType);
|
||
|
Assert (ppbBuffer);
|
||
|
|
||
|
// Initialize the output parameters.
|
||
|
//
|
||
|
*ppbBuffer = NULL;
|
||
|
if (pdwSize)
|
||
|
{
|
||
|
*pdwSize = 0;
|
||
|
}
|
||
|
|
||
|
// Get the size of the data, and if it will fit, the data too.
|
||
|
//
|
||
|
cbData = sizeof(abData);
|
||
|
hr = HrRegQueryValueEx (
|
||
|
hkey,
|
||
|
pszValueName,
|
||
|
pdwType,
|
||
|
abData,
|
||
|
&cbData);
|
||
|
if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
|
||
|
{
|
||
|
// The data didn't fit, so we'll have to requery for it after
|
||
|
// we allocate our buffer.
|
||
|
//
|
||
|
fReQuery = TRUE;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Allocate the buffer for the required size.
|
||
|
//
|
||
|
BYTE* pbBuffer = (BYTE*)MemAlloc (cbData);
|
||
|
if (pbBuffer)
|
||
|
{
|
||
|
if (fReQuery)
|
||
|
{
|
||
|
hr = HrRegQueryValueEx (
|
||
|
hkey,
|
||
|
pszValueName,
|
||
|
pdwType,
|
||
|
pbBuffer,
|
||
|
&cbData);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyMemory (pbBuffer, abData, cbData);
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Fill in the return values.
|
||
|
//
|
||
|
*ppbBuffer = pbBuffer;
|
||
|
|
||
|
if (pdwSize)
|
||
|
{
|
||
|
*pdwSize = cbData;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MemFree (pbBuffer);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
|
||
|
"HrRegQueryValueWithAlloc");
|
||
|
return hr;
|
||
|
}
|