windows-nt/Source/XPSP1/NT/net/config/common/ncbase/ncbase.cpp
2020-09-26 16:20:57 +08:00

790 lines
20 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: N C B A S E . C P P
//
// Contents: Basic common code.
//
// Notes: Pollute this under penalty of death.
//
// Author: shaunco 20 Sep 1997
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "ncbase.h"
#include "ncdebug.h"
#include "ncperms.h"
#include "ncstring.h"
//+---------------------------------------------------------------------------
//
// Function: AddRefObj
//
// Purpose: AddRef's the object pointed to by punk by calling
// punk->AddRef();
//
// Arguments:
// punk [in] Object to be AddRef'd. Can be NULL.
//
// Returns: Result of AddRef call.
//
// Author: danielwe 25 Feb 1997
//
// Notes: Using this function to AddRef an object will reduce
// our code size.
//
NOTHROW
ULONG
AddRefObj (
IUnknown* punk)
{
return (punk) ? punk->AddRef () : 0;
}
//+---------------------------------------------------------------------------
//
// Function: ReleaseObj
//
// Purpose: Releases the object pointed to by punk by calling
// punk->Release();
//
// Arguments:
// punk [in] Object to be released. Can be NULL.
//
// Returns: Result of Release call.
//
// Author: danielwe 25 Feb 1997
//
// Notes: Using this function to release a (possibly NULL) object will
// reduce our code size.
//
NOTHROW
ULONG
ReleaseObj (
IUnknown* punk)
{
return (punk) ? punk->Release () : 0;
}
//+--------------------------------------------------------------------------
//
// Function: DwWin32ErrorFromHr
//
// Purpose: Converts the HRESULT to a Win32 error or SetupApi error.
//
// Arguments:
// hr [in] The HRESULT to convert
//
// Returns: Converted DWORD value.
//
// Author: billbe 22 Apr 1997
//
// Notes:
//
NOTHROW
DWORD
DwWin32ErrorFromHr (
HRESULT hr)
{
DWORD dw = ERROR_SUCCESS;
// All success codes convert to ERROR_SUCCESS so we only need to handle
// failures.
if (FAILED(hr))
{
DWORD dwFacility = HRESULT_FACILITY(hr);
if (FACILITY_SETUPAPI == dwFacility)
{
// reconstruct the SetupApi error using the correct masks
dw = HRESULT_CODE(hr) | APPLICATION_ERROR_MASK |
ERROR_SEVERITY_ERROR;
// Check to make sure dw maps to a known SetupApi error
AssertSz(FDwordWithinRange(ERROR_EXPECTED_SECTION_NAME,
dw, ERROR_GENERAL_SYNTAX) ||
FDwordWithinRange(ERROR_WRONG_INF_STYLE,
dw, ERROR_NO_BACKUP) ||
FDwordWithinRange(ERROR_NO_ASSOCIATED_CLASS,
dw, ERROR_SET_SYSTEM_RESTORE_POINT),
"The mapped SetupApi error is not known "
"(or is new)!!!");
}
else if (FACILITY_WIN32 == dwFacility)
{
dw = HRESULT_CODE(hr);
}
else if (FACILITY_ITF == dwFacility)
{
dw = ERROR_GEN_FAILURE;
}
else
{
// cannot convert it
AssertSz(FALSE, "Facility was not SETUP or WIN32!");
dw = hr;
}
}
return dw;
}
//+---------------------------------------------------------------------------
//
// Function: HrCoTaskMemAlloc
//
// Purpose: Call CoTaskMemAlloc but return an HRESULT.
//
// Arguments:
// cb [in] Count of bytes to allocate.
// ppv [out] Returned pointer to bytes.
//
// Returns: S_OK or E_OUTOFMEMORY.
//
// Author: shaunco 31 May 1997
//
// Notes:
//
HRESULT
HrCoTaskMemAlloc (
ULONG cb,
VOID** ppv)
{
HRESULT hr = S_OK;
*ppv = CoTaskMemAlloc (cb);
if (!*ppv)
{
hr = E_OUTOFMEMORY;
}
TraceError ("HrCoTaskMemAlloc", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrCoTaskMemAllocAndDupSzLen
//
// Purpose: Allocate memory using CoTaskMemAlloc and copy a string
// into it. This is used by the implementation of COM interfaces
// that return strings.
//
// Arguments:
// pszSrc [in] Pointer to source string.
// cchSrc [in] Number of characters to copy from source string.
// ppszDst [out] Address of pointer to destination string.
//
// Returns: S_OK or E_OUTOFMEMORY
//
// Author: shaunco 14 Jan 1999
//
// Notes: NULL input pointers are allocated as empty strings
// deliberately.
// The returned string is guaranteed to be NULL terminated.
//
HRESULT
HrCoTaskMemAllocAndDupSzLen (
IN PCWSTR pszSrc,
IN ULONG cchSrc,
OUT PWSTR* ppszDst)
{
Assert (ppszDst);
HRESULT hr;
DWORD cb = cchSrc * sizeof(WCHAR);
hr = E_OUTOFMEMORY;
*ppszDst = (PWSTR)CoTaskMemAlloc (cb + sizeof(WCHAR));
if (*ppszDst)
{
hr = S_OK;
wcsncpy (*ppszDst, pszSrc, cchSrc);
(*ppszDst)[cchSrc] = 0;
}
TraceError ("HrCoTaskMemAllocAndDupSz", hr);
return hr;
}
HRESULT
HrCoTaskMemAllocAndDupSz (
IN PCWSTR pszSrc,
OUT PWSTR* ppszDst)
{
return HrCoTaskMemAllocAndDupSzLen (
pszSrc,
CchOfSzSafe(pszSrc),
ppszDst);
}
//+---------------------------------------------------------------------------
//
// Function: HrFromLastWin32Error
//
// Purpose: Converts the GetLastError() Win32 call into a proper HRESULT.
//
// Arguments:
// (none)
//
// Returns: Converted HRESULT value.
//
// Author: danielwe 24 Mar 1997
//
// Notes: This is not inline as it actually generates quite a bit of
// code.
// If GetLastError returns an error that looks like a SetupApi
// error, this function will convert the error to an HRESULT
// with FACILITY_SETUP instead of FACILITY_WIN32
//
NOTHROW
HRESULT
HrFromLastWin32Error ()
{
DWORD dwError = GetLastError();
HRESULT hr;
// This test is testing SetupApi errors only (this is
// temporary because the new HRESULT_FROM_SETUPAPI macro will
// do the entire conversion)
if (dwError & (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR))
{
hr = HRESULT_FROM_SETUPAPI(dwError);
}
else
{
hr = HRESULT_FROM_WIN32(dwError);
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrGetProcAddress
//
// Purpose: Loads a libray and returns the address of a procedure within
// the library
//
// Arguments:
// hModule [in] The handle to the library module instance
// pszaFunction [in] Function to retrieve
// ppfn [out] Address of szFunction
//
// Returns: S_OK if successful, Win32 converted error if failure.
//
// Author: billbe 10 June 1997
//
// Notes:
//
HRESULT
HrGetProcAddress (
HMODULE hModule,
PCSTR pszaFunction,
FARPROC* ppfn)
{
Assert(hModule);
Assert(pszaFunction);
Assert(ppfn);
HRESULT hr = S_OK;
*ppfn = GetProcAddress(hModule, pszaFunction);
if (!*ppfn)
{
hr = HrFromLastWin32Error();
TraceTag(ttidError, "HrGetProcAddress failed: szFunction: %s",
pszaFunction);
}
TraceError("HrGetProcAddress", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrLoadLibAndGetProcs
//
// Purpose: Load a dynamic link library and the addresses of one or
// more procedures within that library.
//
// Arguments:
// pszLibPath [in] Path to the DLL to load.
// cFunctions [in] Number of procedures to load.
// apszaFunctionNames [in] Array of function names. (Must be 'cFunctions'
// of them.)
// phmod [out] Returned handle to the loaded module.
// apfn [out] Array of returned pointers to the procedures
// loaded. (Must be 'cFunctions' of them.)
//
// Returns: S_OK if all procedures were loaded, S_FALSE if only
// some of them were, or a Win32 error code. If only
// one procedure is to be loaded and it is not, S_FALSE will
// not be returned, rather, the reason for why the single
// procedure could not be loaded will be returned. This allows
// HrLoadLibAndGetProc to be implemented using this function.
//
// Author: shaunco 19 Jan 1998
//
// Notes: phmod should be freed by the caller using FreeLibrary if
// the return value is S_OK.
//
HRESULT
HrLoadLibAndGetProcs (
PCWSTR pszLibPath,
UINT cFunctions,
const PCSTR* apszaFunctionNames,
HMODULE* phmod,
FARPROC* apfn)
{
Assert (pszLibPath);
Assert (cFunctions);
Assert (apszaFunctionNames);
Assert (phmod);
Assert (apfn);
HRESULT hr = S_OK;
// Load the module and initialize the output parameters.
//
HMODULE hmod = LoadLibrary (pszLibPath);
*phmod = hmod;
ZeroMemory (apfn, cFunctions * sizeof(FARPROC));
if (hmod)
{
// Get the proc address of each function.
//
for (UINT i = 0; i < cFunctions; i++)
{
apfn[i] = GetProcAddress (hmod, apszaFunctionNames[i]);
if (!apfn[i])
{
// Couldn't load all functions. We'll be returning S_FALSE
// (if their are more than one function.)
//
hr = S_FALSE;
TraceTag (ttidError, "HrLoadLibAndGetProcs: GetProcAddress "
"for '%s' failed.",
apszaFunctionNames[i]);
}
}
// If we're only loading one function, and it failed,
// return the failure.
//
if ((1 == cFunctions) && !apfn[0])
{
hr = HrFromLastWin32Error ();
FreeLibrary (hmod);
}
}
else
{
hr = HrFromLastWin32Error ();
TraceTag (ttidError, "HrLoadLibAndGetProcs: LoadLibrary (%S) failed.",
pszLibPath);
}
TraceError ("HrLoadLibAndGetProcs", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrGetProcAddressesVa
//
// Purpose: Get proc-address of each function-name passed
//
// Arguments:
// hModule [in] handle of DLL
// arglist [in] list of var-args. the expected format is
// "func-name", FARPROC*, ..., NULL
//
// Returns: S_OK on success, otherwise an error code
//
// Author: kumarp 29-December-97
//
// Notes:
//
HRESULT
HrGetProcAddressesVa (
HMODULE hModule,
va_list arglist)
{
PCSTR szFunctionName;
FARPROC* ppfn;
HRESULT hr = S_OK;
typedef FARPROC* PFARPROC;
while (NULL != (szFunctionName = va_arg(arglist, CHAR*)))
{
ppfn = va_arg(arglist, PFARPROC);
*ppfn = GetProcAddress(hModule, szFunctionName);
if (!*ppfn)
{
hr = HrFromLastWin32Error();
TraceTag(ttidError, "HrGetProcAddressesVa failed: szFunction: %s",
szFunctionName);
break;
}
}
TraceError("HrGetProcAddressesVa", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrGetProcAddressesV
//
// Purpose: Get proc-address of each function-name passed
//
// Arguments:
// hModule [in] handle of DLL
// ... [in] list of var-args. the expected format is
// "func-name", FARPROC*, ..., NULL
//
// Returns: S_OK on success, otherwise an error code
//
// Author: kumarp 29-December-97
//
// Notes:
//
HRESULT
HrGetProcAddressesV (
HMODULE hModule,
...)
{
HRESULT hr=S_OK;
va_list arglist;
va_start(arglist, hModule);
hr = HrGetProcAddressesVa(hModule, arglist);
va_end(arglist);
TraceError("HrGetProcAddressesV", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrLoadLibAndGetProcsV
//
// Purpose: Get proc-address of each function-name passed
//
// Arguments:
// pszLibPath [in] DLL to load
// phModule [out] pointer to handle of DLL loaded
// ... [in] list of var-args. the expected format is
// "func-name", FARPROC*, ..., NULL
//
// Returns: S_OK on success, otherwise an error code
//
// Author: kumarp 29-December-97
//
// Notes:
//
HRESULT
HrLoadLibAndGetProcsV (
PCWSTR pszLibPath,
HMODULE* phModule,
...)
{
Assert(pszLibPath);
Assert(phModule);
HRESULT hr = S_OK;
// Attempt to load the library
*phModule = LoadLibrary(pszLibPath);
if (*phModule)
{
va_list arglist;
va_start(arglist, phModule);
hr = HrGetProcAddressesVa(*phModule, arglist);
va_end(arglist);
if (FAILED(hr))
{
// Free the library
FreeLibrary(*phModule);
}
}
else
{
hr = HrFromLastWin32Error();
TraceTag(ttidError, "HrLoadLibAndGetProcsV failed: szLibPath: %S",
pszLibPath);
}
// if we failed then we should set *phModule to NULL since we might
// have successfully loaded it and failed getting the proc
if (FAILED(hr))
{
*phModule = NULL;
}
TraceError("HrLoadLibAndGetProcsV", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrCreateEventWithWorldAccess
//
// Purpose: Creates a event with permissions to allow access to
// everyone.
//
// Arguments:
// pszName [in] Name for the event.
// fManualReset [in] See Win32 docs.
// fInitialState [in] See Win32 docs.
// pfAlreadyExists [out] TRUE if the event already existed.
// FALSE otherwise.
// phEvent [out] The created event.
//
// Returns: S_OK on success. An error code otherwise.
//
// Author: BillBe 16 Nov 1998
//
// Notes:
//
HRESULT
HrCreateEventWithWorldAccess(PCWSTR pszName, BOOL fManualReset,
BOOL fInitialState, BOOL* pfAlreadyExists, HANDLE* phEvent)
{
Assert(pszName);
Assert(phEvent);
if (pfAlreadyExists)
{
*pfAlreadyExists = FALSE;
}
*phEvent = NULL;
// Create the correct descriptor.
PSECURITY_DESCRIPTOR pSd;
HRESULT hr = HrAllocateSecurityDescriptorAllowAccessToWorld(&pSd);
if (SUCCEEDED(hr))
{
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSd;
sa.bInheritHandle = FALSE;
// Create Event
//
*phEvent = CreateEvent(&sa, fManualReset, fInitialState, pszName);
hr = HrFromLastWin32Error();
if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hr)
{
if (pfAlreadyExists)
{
*pfAlreadyExists = TRUE;
}
hr = S_OK;
}
MemFree(pSd);
}
TraceError("HrCreateEventWithWorldAccess", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrCreateMutexWithWorldAccess
//
// Purpose: Creates a mutex with permissions to allow access to
// everyone.
//
// Arguments:
// pszName [in] Name for the mutex.
// fInitialOwner [in] See Win32 docs.
// pfAlreadyExists [out] TRUE if the mutex already existed,
// FALSE otherwise.
// phMutex [out] The created mutex.
//
// Returns: S_OK on success. An error code otherwise.
//
// Author: BillBe 16 Nov 1998
//
// Notes:
//
HRESULT
HrCreateMutexWithWorldAccess (
PCWSTR pszName,
BOOL fInitialOwner,
BOOL* pfAlreadyExists,
HANDLE* phMutex)
{
Assert(pszName);
Assert(phMutex);
if (pfAlreadyExists)
{
*pfAlreadyExists = FALSE;
}
*phMutex = NULL;
// Create the correct descriptor.
PSECURITY_DESCRIPTOR pSd;
HRESULT hr = HrAllocateSecurityDescriptorAllowAccessToWorld(&pSd);
if (S_OK == hr)
{
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSd;
sa.bInheritHandle = FALSE;
// Create Mutex
//
*phMutex = CreateMutex(&sa, fInitialOwner, pszName);
hr = HrFromLastWin32Error();
if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hr)
{
if (pfAlreadyExists)
{
*pfAlreadyExists = TRUE;
}
hr = S_OK;
}
MemFree(pSd);
}
TraceError("HrCreateMutexWithWorldAccess", hr);
return hr;
}
//+---------------------------------------------------------------------------
// The standard parameterization of CoSetProxyBlanket. Call this instead
// of CoSetProxyBlanket so you get the same security and authentication
// settings as everyone else. This version saves code space at the call-site
// because it pushes only one parameter instead of eight.
// This does not return an error because it does not invalidate the use of
// pUnk after it's called.
//
VOID
NcSetProxyBlanket (
IN IUnknown* pUnk)
{
HRESULT hr;
hr = CoSetProxyBlanket (
pUnk,
RPC_C_AUTHN_WINNT, // use NT default security
RPC_C_AUTHZ_NONE, // use NT default authentication
NULL, // must be null if default
RPC_C_AUTHN_LEVEL_CALL, // call
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, // use process token
EOAC_NONE);
if(SUCCEEDED(hr))
{
IUnknown * pUnkSet = NULL;
hr = pUnk->QueryInterface(&pUnkSet);
if(SUCCEEDED(hr))
{
hr = CoSetProxyBlanket (
pUnkSet,
RPC_C_AUTHN_WINNT, // use NT default security
RPC_C_AUTHZ_NONE, // use NT default authentication
NULL, // must be null if default
RPC_C_AUTHN_LEVEL_CALL, // call
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, // use process token
EOAC_NONE);
ReleaseObj(pUnkSet);
}
}
TraceHr(ttidError, FAL, hr, (E_NOINTERFACE == hr), "NcSetProxyBlanket");
}
//+---------------------------------------------------------------------------
//
// Function: HrCreateInstanceBase
//
// Purpose: Creates a COM object and sets default proxy settings.
//
// Arguments:
// rclsid [in] See documentation for CoCreateInstance.
// dwClsContext [in] ""
// riid [in] ""
// ppv [out] ""
//
// Returns: S_OK on success. An error code otherwise.
//
// Author: mbend 1 Mar 2000
//
// Notes: Call type safe version HrCreateInstance
//
HRESULT
HrCreateInstanceBase (
REFCLSID rclsid,
DWORD dwClsContext,
REFIID riid,
LPVOID * ppv)
{
HRESULT hr = S_OK;
hr = ::CoCreateInstance(rclsid, NULL, dwClsContext, riid, ppv);
if(SUCCEEDED(hr) && (dwClsContext & CLSCTX_LOCAL_SERVER))
{
NcSetProxyBlanket(reinterpret_cast<IUnknown*>(*ppv));
}
TraceError("HrCreateInstanceBase", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrQIAndSetProxyBlanketBase
//
// Purpose: Performs QueryInterface and sets default proxy settings.
//
// Arguments:
// pUnk [in] Interface pointer to perform QueryInterface on.
// riid [in] See documentation of QueryInterface
// ppv [out] ""
//
// Returns: S_OK on success. An error code otherwise.
//
// Author: mbend 1 Mar 2000
//
// Notes: Call type safe version HrQIAndSetProxyBlanket
//
HRESULT
HrQIAndSetProxyBlanketBase(IUnknown * pUnk, REFIID riid, void ** ppv)
{
HRESULT hr = pUnk->QueryInterface(riid, ppv);
if(SUCCEEDED(hr))
{
NcSetProxyBlanket(reinterpret_cast<IUnknown*>(*ppv));
}
TraceError("HrQIAndSetProxyBlanketBase", hr);
return hr;
}