//+--------------------------------------------------------------------------- // // 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 #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, IN ULONG cchMaxDest) { Assert (ppszDst); HRESULT hr; DWORD cbCopy = min(cchSrc, cchMaxDest); DWORD cb = cbCopy * sizeof(WCHAR); hr = E_OUTOFMEMORY; *ppszDst = (PWSTR)CoTaskMemAlloc (cb + sizeof(WCHAR)); if (*ppszDst) { hr = S_OK; wcsncpy (*ppszDst, pszSrc, cbCopy); (*ppszDst)[cbCopy] = 0; } TraceError ("HrCoTaskMemAllocAndDupSz", hr); return hr; } HRESULT HrCoTaskMemAllocAndDupSz ( IN PCWSTR pszSrc, OUT PWSTR* ppszDst, IN ULONG cchMaxDest) { return HrCoTaskMemAllocAndDupSzLen ( pszSrc, CchOfSzSafe(pszSrc), ppszDst, cchMaxDest); } //+--------------------------------------------------------------------------- // // 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(*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(*ppv)); } TraceError("HrQIAndSetProxyBlanketBase", hr); return hr; }