|
|
/*++
Copyright (C) 1995-2001 Microsoft Corporation
Module Name:
PROVREG.CPP
Abstract:
Defines the acutal "Put" and "Get" functions for the registry provider. The mapping string format is; machine|regpath[|datafield] Examples:
local|hkey_current_user\dave local|hkey_current_user\dave|stringdata local|hkey_local_machine\hardware\resourcemap\hardware abstraction layer\ pc compatible eisa/isa HAL|.raw("internal")(0)(2)("interrupt.vector") LMPGM|hkey_local_machine\clone\clone\control|CurrentUser
History:
a-davj 9-27-95 Created.
--*/
#include "precomp.h"
#include <initguid.h>
#include "perfprov.h"
#include "cvariant.h"
#include "provreg.h"
#include <genutils.h>
#include <cominit.h>
#include <userenv.h>
#define NUM_FOR_LIST 4
#define NUM_FOR_PARTIAL 2
#define TYPE_OFFSET 0
#define BUS_OFFSET 1
#define PARTIAL_OFFSET 0
#define DATA_OFFSET 1
#define NUM_LIST_ONLY 2
#define MIN_REG_TOKENS 2
#define BOGUS 0
// for certain "resource" registry item it is necessary to specify which bus
// and what part of the data union is to be returned. These strings allow
// the mapping string to specify both using text
TCHAR * cpIntTypes[] = { TEXT("Internal"),TEXT("Isa"),TEXT("Eisa"),TEXT("MicroChannel"),TEXT("TurboChannel"), TEXT("PCIBus"),TEXT("VMEBus"),TEXT("NuBus"),TEXT("PCMCIABus"),TEXT("CBus"), TEXT("MPIBus"),TEXT("MPSABus"),TEXT("MaximumInterfaceType")};
struct UnionOffset { TCHAR * tpName; int iOffset; int iType; int iSize; } Offsets[] = { {TEXT("Port.Start"),0,CmResourceTypePort,8}, {TEXT("Port.PhysicalAddress"),0,CmResourceTypePort,8}, {TEXT("Port.Physical Address"),0,CmResourceTypePort,8}, {TEXT("Port.Length"),8,CmResourceTypePort,4}, {TEXT("Interrupt.Level"),0,CmResourceTypeInterrupt,4}, {TEXT("Interrupt.Vector"),4,CmResourceTypeInterrupt,4}, {TEXT("Interrupt.Affinity"),8,CmResourceTypeInterrupt,4}, {TEXT("Memory.Start"),0,CmResourceTypeMemory,8}, {TEXT("Memory.PhysicalAddress"),0,CmResourceTypeMemory,8}, {TEXT("Memory.Physical Address"),0,CmResourceTypeMemory,8}, {TEXT("Memory.Length"),8,CmResourceTypeMemory,4}, {TEXT("Dma.Channel"),0,CmResourceTypeDma,4}, {TEXT("Dma.Port"),4,CmResourceTypeDma,4}, {TEXT("Dma.Reserved1"),8,CmResourceTypeDma,4}, {TEXT("DeviceSpecificData.DataSize"),0,CmResourceTypeDeviceSpecific,4}, {TEXT("DeviceSpecificData.Data Size"),0,CmResourceTypeDeviceSpecific,4}, {TEXT("DeviceSpecificData.Reserved1"),4,CmResourceTypeDeviceSpecific,4}, {TEXT("DeviceSpecificData.Reserved2"),8,CmResourceTypeDeviceSpecific,4} };
// Define the names of the basic registry handles
struct BaseTypes { LPTSTR lpName; HKEY hKey; } Bases[] = { {TEXT("HKEY_CLASSES_ROOT") , HKEY_CLASSES_ROOT}, {TEXT("HKEY_CURRENT_USER") , HKEY_CURRENT_USER}, {TEXT("HKEY_LOCAL_MACHINE") , HKEY_LOCAL_MACHINE}, {TEXT("HKEY_USERS") , HKEY_USERS}, {TEXT("HKEY_PERFORMANCE_DATA") , HKEY_PERFORMANCE_DATA}, {TEXT("HKEY_CURRENT_CONFIG") , HKEY_CURRENT_CONFIG}, {TEXT("HKEY_DYN_DATA") , HKEY_DYN_DATA}};
//***************************************************************************
//
// BOOL CImpReg::bGetOffsetData
//
// DESCRIPTION:
//
// Getting data from a resource list requires four offsets while getting
// it from a single descriptor requires the last two offsets.
//
// PARAMETERS:
//
// dwReg Indicates if we are looking for a full or partial
// resource descriptor.
// ProvObj Object containing the property context string.
// iIntType interface type - could be a string such as "eisa"
// iBus bus number
// iPartial partial descriptor number - each full descriptor
// has several partial desc.
// iDataOffset Data Offset - each partial descriptor has data in
// a union and this is the byte offset. Could be a
// sting such as "Dma.Channel"
// iDataType Data type
// iSourceSize Size of data
// dwArray no longer used, should always be 0
//
// RETURN VALUE:
//
// TRUE if data is found
//
//***************************************************************************
BOOL CImpReg::bGetOffsetData( IN DWORD dwReg, IN CProvObj & ProvObj, OUT IN int & iIntType, OUT IN int & iBus, OUT IN int & iPartial, OUT IN int & iDataOffset, OUT IN int & iDataType, OUT IN int & iSourceSize, DWORD dwArray) { int iNumRequired, iListOffset; int iLastToken = ProvObj.iGetNumTokens()-1;
// determine the number needed for the type of data being requested
if(dwReg == REG_RESOURCE_LIST) iNumRequired = NUM_FOR_LIST; else iNumRequired = NUM_FOR_PARTIAL;
if(ProvObj.iGetNumExp(iLastToken) < iNumRequired) return FALSE; // Get the first two descriptors that are only needed in the list case.
if(dwReg == REG_RESOURCE_LIST) {
// the first offset can either be a string such as "EISA" or a
// numeric offset.
if(ProvObj.IsExpString(iLastToken,TYPE_OFFSET)) iIntType = iLookUpInt(ProvObj.sGetStringExp(iLastToken,TYPE_OFFSET)); else iIntType = ProvObj.iGetIntExp(iLastToken,TYPE_OFFSET,dwArray); iBus = ProvObj.iGetIntExp(iLastToken,BUS_OFFSET,dwArray); if(iBus == -1 || iIntType == -1) return FALSE; iListOffset = NUM_LIST_ONLY; } else iListOffset = 0;
// Get the last two offsets which are for identenfying which partial
// descriptor and the last is for specifying the offset inside the
// union.
iPartial = ProvObj.iGetIntExp(iLastToken,PARTIAL_OFFSET+iListOffset,dwArray); // The data offset can be a string such as "Dma.Port".
iDataType = -1; // not necessarily an error, see the function
// GetResourceDescriptorData for more info.
iSourceSize = 0; if(ProvObj.IsExpString(iLastToken,DATA_OFFSET+iListOffset)) iDataOffset = iLookUpOffset(ProvObj.sGetStringExp(iLastToken, DATA_OFFSET+iListOffset), iDataType,iSourceSize); else iDataOffset = ProvObj.iGetIntExp(iLastToken,DATA_OFFSET+iListOffset,dwArray);
if(iPartial == -1 || iDataOffset == -1) return FALSE; return TRUE; }
//***************************************************************************
//
// CImpReg::CImpReg
//
// DESCRIPTION:
//
// Constructor.
//
// PARAMETERS:
//
//***************************************************************************
CImpReg::CImpReg() { StringCchCopyW(wcCLSID, sizeof(wcCLSID)/sizeof(WCHAR), L"{FE9AF5C0-D3B6-11CE-A5B6-00AA00680C3F}");
// To disable dmreg, uncomment hDMRegLib = NULL;
// To disable dmreg, uncomment return;
hDMRegLib = NULL; //LoadLibrary("DMREG.DLL");
m_hRoot = NULL; m_bLoadedProfile = false; if(IsNT()) { SCODE sc = WbemCoImpersonateClient(); if(sc == S_OK) { sc = m_ap.LoadProfile(m_hRoot); if(sc == S_OK) m_bLoadedProfile = true;
WbemCoRevertToSelf(); } } return; }
//***************************************************************************
//
// CImpReg::~CImpReg
//
// DESCRIPTION:
//
// Destructor.
//
//***************************************************************************
CImpReg::~CImpReg() { if(hDMRegLib) FreeLibrary(hDMRegLib); }
//***************************************************************************
//
// CImpReg::ConvertGetDataFromDesc
//
// DESCRIPTION:
//
// Extracts the data when it is in either the REG_RESOURCE_LIST or
// REG_FULL_RESOURCE_DESCRIPTOR format. The REG_RESOURCE_LIST has a list
// of "full resource" blocks and so in that case it is necessary to first
// determine which block to extract from and after that the code is common.
//
// PARAMETERS:
//
// cVar reference to CVariant that get set with the result
// pData raw data
// dwRegType Indicates if we are looking for a full or partial
// resource descriptor.
// dwBufferSize not used
// ProvObj Object containing the property context string.
//
// RETURN VALUE:
//
// S_OK all is well
// WBEM_E_INVALID_PARAMETER couldnt find the data. Probably a bad context
// string
// otherwise, error converting the data in SetData()
//***************************************************************************
SCODE CImpReg::ConvertGetDataFromDesc( OUT CVariant & cVar, IN void * pData, IN DWORD dwRegType, IN DWORD dwBufferSize, IN CProvObj & ProvObj) { int iIntType, iBus, iPartial, iDataOffset,iDataType,iSourceSize; ULONG uCnt;
PCM_FULL_RESOURCE_DESCRIPTOR pFull; PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartial;
// Get the various operator values. A typical provider string would
// be "..|.raw("internal")(0)(2)("interrupt.vector")
if(!bGetOffsetData(dwRegType,ProvObj,iIntType,iBus,iPartial, iDataOffset,iDataType, iSourceSize, BOGUS)) return WBEM_E_INVALID_PARAMETER;
// if list, get the right full resource block.
if(dwRegType == REG_RESOURCE_LIST) { PCM_RESOURCE_LIST pList = (PCM_RESOURCE_LIST)pData; pFull = &pList->List[0]; for(uCnt=0; uCnt < pList->Count; uCnt++) if(pFull->InterfaceType == iIntType && pFull->BusNumber == (unsigned)iBus) break; // found it!
else pFull = GetNextFull(pFull); if(uCnt == pList->Count) return WBEM_E_INVALID_PARAMETER; // specified invalid type or bus number
} else pFull = (PCM_FULL_RESOURCE_DESCRIPTOR)pData; // Get the partial resource descriptor. Each full
// descriptor is a list of partial descriptors. If the
// last expression was of the form ("interrupt.vector"),
// then all the partial blocks that arn't interrupt data
// will be ignored. If the last expression just has a
// number, then the type of block is ignored.
unsigned uSoFar = 0; pPartial = pFull->PartialResourceList.PartialDescriptors; unsigned uLimit = pFull->PartialResourceList.Count; for(uCnt = 0; uCnt < (unsigned)uLimit; uCnt++) { if(iDataType == -1 || iDataType == pPartial->Type) { if(uSoFar == (unsigned)iPartial) break; // got it!
uSoFar++; } pPartial = GetNextPartial(pPartial); } if(uCnt == uLimit) return WBEM_E_INVALID_PARAMETER; // specified invalid block
// Copy the data into a variant
char * cpTemp = (char *)&pPartial->u.Dma.Channel + iDataOffset; if(iSourceSize == 1) return cVar.SetData(cpTemp,VT_UI1); else if(iSourceSize == 2) return cVar.SetData(cpTemp,VT_I2); else if(iSourceSize == 4) return cVar.SetData(cpTemp,VT_I4); else return cVar.SetData(cpTemp,VT_I8); //todo fix this VT_I8 dont work!!!
}
//***************************************************************************
//
// SCODE CImpReg::ConvertGetDataFromSimple
//
// DESCRIPTION:
//
// Converts that data returned by the registry into the closest VARIANT
// type.
//
// PARAMETERS:
//
// cVar Reference to CVariant where result is to be put
// pData pointer to data
// dwRegType registry type, ex, REG_MUTISZ
// dwBufferSize size of data
// pClassInt Pointer to class object
// PropName Property name.
//
// RETURN VALUE:
//
// S_OK all is well
// else could fail if the "Get" on the property fails,
// or if the data conversion fails in SetData.
//***************************************************************************
SCODE CImpReg::ConvertGetDataFromSimple( OUT CVariant & cVar, IN void * pData, IN DWORD dwRegType, IN DWORD dwBufferSize, IN IWbemClassObject FAR * pClassInt, IN BSTR PropName) { TCHAR tTemp[1]; TCHAR * pTemp; SCODE sc = S_OK; int nSize; char * cpTo, * cpFrom; long vtProp;
// Note that the current winnt.h file defines the constants
// REG_DWORD_LITTLE_ENDIAN and REG_DWORD as being the same.
// The compiler considers this an error in a switch statement and so
// there is this "if" to ensure that they are handled the same even
// if someday the constants become different
if(dwRegType == REG_DWORD_LITTLE_ENDIAN) dwRegType = REG_DWORD;
switch(dwRegType) { case REG_SZ: sc = cVar.SetData(pData, VT_BSTR,dwBufferSize); break; case REG_EXPAND_SZ: nSize = ExpandEnvironmentStrings((TCHAR *)pData,tTemp,1) + 1; pTemp = new TCHAR[nSize+1]; if(pTemp == NULL) return WBEM_E_OUT_OF_MEMORY; ExpandEnvironmentStrings((TCHAR *)pData,pTemp,nSize+1); sc = cVar.SetData(pTemp, VT_BSTR, nSize+1); delete pTemp; break;
case REG_BINARY: if(pClassInt) { sc = pClassInt->Get(PropName,0,NULL,&vtProp,NULL); if(sc != S_OK) return sc; } else vtProp = VT_UI1 | VT_ARRAY; if((vtProp & VT_ARRAY) == 0) sc = WBEM_E_FAILED; // Incompatible types
else sc = cVar.SetData(pData,vtProp, dwBufferSize); break;
case REG_DWORD: sc = cVar.SetData(pData,VT_I4); break;
case REG_DWORD_BIG_ENDIAN: sc = cVar.SetData(pData,VT_I4); cpTo = (char *)cVar.GetDataPtr(); cpFrom = (char *)pData; cpTo[0] = cpFrom[3]; cpTo[1] = cpFrom[2]; cpTo[2] = cpFrom[1]; cpTo[3] = cpFrom[0]; break;
case REG_MULTI_SZ: sc = cVar.SetData(pData, VT_BSTR | VT_ARRAY, dwBufferSize); break;
default: sc = WBEM_E_TYPE_MISMATCH; } return sc; } //***************************************************************************
//
// SCODE CImpReg::ConvertSetData
//
// DESCRIPTION:
//
// Takes WBEM type data and converts it into the proper
// form for storage in the registry. There are two distinct
// case: Binary array data and normal data.
//
// PARAMETERS:
//
// cVar Contains the source
// **ppData pointer which will be set to point to some allocate
// data. Note that the data allocated should be freed
// using CoTaskMemFree
// pdwRegType desired registry type
// pdwBufferSize size of allocated data
//
// RETURN VALUE:
//
// S_OK all is well
// WBEM_E_TYPE_MISMATCH invalied type
// else error is set by GetData()
//
//***************************************************************************
SCODE CImpReg::ConvertSetData( IN CVariant & cVar, OUT void **ppData, IN DWORD * pdwRegType, OUT DWORD * pdwBufferSize) { void * pRet = NULL; SCODE sc;
switch (cVar.GetType() & ~VT_ARRAY) { case VT_I1: case VT_UI1: case VT_I2: case VT_UI2: case VT_I4: case VT_UI4: case VT_BOOL: case VT_INT: case VT_UINT:
// convert data into DWORD format which is equivalent to
// the REG_DWORD.
*pdwRegType = (cVar.IsArray()) ? REG_BINARY : REG_DWORD; sc = cVar.GetData(ppData,*pdwRegType,pdwBufferSize); break; case VT_I8: case VT_UI8: case VT_LPSTR: case VT_LPWSTR: case VT_R4: case VT_R8: case VT_CY: case VT_DATE: case VT_BSTR: *pdwRegType = (cVar.IsArray()) ? REG_MULTI_SZ : REG_SZ; sc = cVar.GetData(ppData,*pdwRegType,pdwBufferSize); break; default: sc = WBEM_E_TYPE_MISMATCH; } return sc; }
//***************************************************************************
//
// void CImpReg::EndBatch
//
// DESCRIPTION:
//
// Called at the end of a batch of Refrest/Update Property calls. Free up
// any cached handles and then delete the handle cache.
//
// PARAMETERS:
//
// lFlags flags, not used
// pClassInt class object, not used
// *pObj pointer to our cache, free it
// bGet indicates if a Refresh or Put was being done
//
//***************************************************************************
void CImpReg::EndBatch( long lFlags, IWbemClassObject FAR * pClassInt, CObject *pObj, BOOL bGet) { if(pObj != NULL) { Free(0,(CHandleCache *)pObj); delete pObj; } }
//***************************************************************************
//
// void CImpReg::Free
//
// DESCRIPTION:
//
// Frees up cached registry handles starting with position
// iStart till the end. After freeing handles, the cache object
// member function is used to delete the cache entries.
//
// PARAMETERS:
//
// iStart Where to start freeing. 0 indicates that whole
// cache should be emptied
// pCache Cache to be freed
//
//***************************************************************************
void CImpReg::Free( IN int iStart, IN CHandleCache * pCache) { HKEY hClose; int iCurr; long lRet; for(iCurr = pCache->lGetNumEntries()-1; iCurr >= iStart; iCurr--) { hClose = (HKEY)pCache->hGetHandle(iCurr); if(hClose != NULL) if(hDMRegLib && !pCache->IsRemote()) lRet = pClose(hClose); else lRet = RegCloseKey(hClose); } pCache->Delete(iStart); // get cache to delete the entries
}
//***************************************************************************
//
// PCM_FULL_RESOURCE_DESCRIPTOR CImpReg::GetNextFull
//
// DESCRIPTION:
//
// Returns a pointer to the next full resource descritor block. Used
// when stepping through resource data.
//
// PARAMETERS:
//
// pCurr points to current location.
//
// RETURN VALUE:
//
// see description.
//***************************************************************************
PCM_FULL_RESOURCE_DESCRIPTOR CImpReg::GetNextFull( IN PCM_FULL_RESOURCE_DESCRIPTOR pCurr) { unsigned uCount; PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartial;
// Get a pointer to the first partial descriptor and then step
// through each of the partial descriptor blocks.
pPartial = &pCurr->PartialResourceList.PartialDescriptors[0];
for(uCount = 0; uCount < pCurr->PartialResourceList.Count; uCount++) pPartial = GetNextPartial(pPartial); return (PCM_FULL_RESOURCE_DESCRIPTOR)pPartial; }
//***************************************************************************
//
// PCM_PARTIAL_RESOURCE_DESCRIPTOR CImpReg::GetNextPartial
//
// DESCRIPTION:
//
// Returns a pointer to the next partial resource descritor block. Used
// when stepping through resource data.
//
// PARAMETERS:
//
// pCurr Current location.
//
// RETURN VALUE:
//
// see description.
//***************************************************************************
PCM_PARTIAL_RESOURCE_DESCRIPTOR CImpReg::GetNextPartial( IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pCurr) { char * cpTemp = (char *)pCurr; cpTemp += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); if(pCurr->Type == CmResourceTypeDeviceSpecific) cpTemp += pCurr->u.DeviceSpecificData.DataSize; return (PCM_PARTIAL_RESOURCE_DESCRIPTOR)cpTemp; }
//***************************************************************************
//
// int CImpReg::GetRoot
//
// DESCRIPTION:
//
// Gets the starting registry key. The key can be on either the local
// machine or a remote one. If there are handles in the cache, then
// the starting key can be retrieved from it in so far as the paths match.
//
// PARAMETERS:
//
// pKey Set to point to the root key
// Path registry path
// pNewMachine Machine name
// pCache Handle cache object
// iNumSkip Set to the number of tokens that matched
//
// RETURN VALUE:
//
//
//***************************************************************************
int CImpReg::GetRoot( OUT HKEY * pKey, IN CProvObj & Path, IN const TCHAR * pNewMachine, OUT IN CHandleCache * pCache, OUT int & iNumSkip) { int iCnt; *pKey = NULL; iNumSkip = 0; int iRet; HKEY hRoot = NULL; const TCHAR * pNewRoot = Path.sGetFullToken(0); if(pNewRoot == NULL || pNewMachine == NULL) return ERROR_UNKNOWN; // bad mapping string
// If there are handles in the cache, then they may be used if and
// only if the machines names and root keys match.
if(pCache->lGetNumEntries() > 0) { const TCHAR * pOldMachine = pCache->sGetString(0); const TCHAR * pOldRoot = pCache->sGetString(1); if(pOldMachine == NULL || pOldRoot == NULL) return ERROR_UNKNOWN; if(lstrcmpi(pOldMachine,pNewMachine) || lstrcmpi(pOldRoot,pNewRoot)) // Either machine or root key has changed, in either
// case, free all the cached handles and get a new root.
Free(0,pCache); else { // Machine and root are in common. Determine how much
// else is in common, free what isnt in common, and return
// the subkey share a common path.
iNumSkip = pCache->lGetNumMatch(2,1,Path); Free(2+iNumSkip,pCache); *pKey = (HKEY)pCache->hGetHandle(1+iNumSkip); return ERROR_SUCCESS; } }
// Got to get the root key. First, use the second token to determine
// which predefined key to use. That would be something like;
// HKEY_CURRENT_USER.
int iSize= sizeof(Bases) / sizeof(struct BaseTypes); for(iCnt = 0; iCnt < iSize; iCnt++) if(!lstrcmpi(pNewRoot,Bases[iCnt].lpName)) { hRoot = Bases[iCnt].hKey; break; } if(hRoot == HKEY_CURRENT_USER && m_bLoadedProfile) hRoot = m_hRoot;
if(hRoot == NULL) return ERROR_UNKNOWN;
// Now use the first key to determine if it is the local machine or
// another.
if(lstrcmpi(pNewMachine,TEXT("LOCAL"))) { // Connect to a remote machine.
int iRet; pCache->SetRemote(TRUE); // Note that RegConnectRegistry requires a NON constant name
// pointer (ARG!) and thus a temp string must be created!!
TString sTemp; sTemp = pNewMachine; iRet = RegConnectRegistry(sTemp, hRoot,pKey);
sTemp.Empty(); if(iRet == 0) iRet = pCache->lAddToList(pNewMachine,NULL); // dont need to free this
if(iRet == 0) iRet = pCache->lAddToList(pNewRoot,*pKey); // do free this.
return iRet; } else {
// Local registry. Save tokens and handles. By adding NULL to the
// cache, the handle will not be freed.
pCache->SetRemote(FALSE); iRet = pCache->lAddToList(pNewMachine,NULL); if(iRet == 0) iRet = pCache->lAddToList(pNewRoot,NULL); // standard handles dont need to be freed
*pKey = hRoot; } return iRet; }
//***************************************************************************
//
// int CImpReg::iLookUpInt
//
// DESCRIPTION:
//
// Searches (case insensitive) the list of interface types and
// returns the index of the match or -1 if no match.
//
// PARAMETERS:
//
// tpTest name to search for
//
// RETURN VALUE:
//
// see description.
//***************************************************************************
int CImpReg::iLookUpInt( const TCHAR * tpTest) { int iCnt,iSize; iSize = sizeof(cpIntTypes) / sizeof(TCHAR *); for(iCnt = 0; iCnt < iSize; iCnt++) if(tpTest != NULL && !lstrcmpi(tpTest,cpIntTypes[iCnt])) return iCnt; return -1; }
//***************************************************************************
//
// int CImpReg::iLookUpOffset
//
// DESCRIPTION:
//
// Searches (case insensitive) the list data types held in
// resource descripters.
//
// PARAMETERS:
//
// tpTest String to look for
// iType Set to the type
// iTypeSize Set to the type's size
//
// RETURN VALUE:
//
// Returns index if match is found (-1 for failure) and also
// sets the referneces that specifiy which type and the type's
// size.
//
//
//***************************************************************************
int CImpReg::iLookUpOffset( IN const TCHAR * tpTest, OUT int & iType, OUT int & iTypeSize) { int iCnt, iSize; iSize = sizeof(Offsets) / sizeof(struct UnionOffset); for(iCnt = 0; iCnt < iSize; iCnt++) if(tpTest != NULL && !lstrcmpi(tpTest,Offsets[iCnt].tpName)) { iType = Offsets[iCnt].iType; iTypeSize = Offsets[iCnt].iSize; return Offsets[iCnt].iOffset; } return -1; }
//***************************************************************************
//
// int CImpReg::OpenKeyForWritting
//
// DESCRIPTION:
//
// Opens a registry for updates. Since updates are writes, it is
// possible that the key may need to be created. Since DM reg
// does not support RegCreateKey, then it must be called and the
// resulting key closed for the new key case.
//
// PARAMETERS:
//
// hCurr Parent key
// pName sub key to be opened/created
// pNew pointer to opened/created key
// pCache handle cache.
//
// RETURN VALUE:
//
// 0 if OK,
// else set by RegOpenKey or RegCreateKey
//
//***************************************************************************
int CImpReg::OpenKeyForWritting( HKEY hCurr, LPTSTR pName, HKEY * pNew, CHandleCache * pCache) { int iRet; iRet = RegOpenKeyEx(hCurr,pName,0,KEY_WRITE,pNew); if(iRet == 0) // all done should be normal case.
return 0;
iRet = RegOpenKeyEx(hCurr,pName,0,KEY_SET_VALUE,pNew); if(iRet == 0) // all done should be normal case.
return 0; // Try creating the key. If not using DM reg, just use the key from
// here
iRet = RegCreateKey(hCurr,pName,pNew); if(hDMRegLib!=NULL && !pCache->IsRemote() && iRet == 0) { // Close the key and reopen
RegCloseKey(*pNew); iRet = pOpen(hCurr,pName,0,0,KEY_QUERY_VALUE,pNew); } return iRet; }
//***************************************************************************
//
// SCODE CImpReg::ReadRegData
//
// DESCRIPTION:
//
// Allocates a buffer and reads the registry. If the buffer is not large
// enough, then it is reallocated and reread.
//
// PARAMETERS:
//
// hKey Registry Key
// pName Value Name
// dwRegType Set to the type
// dwSize set to the size
// pData set to the allocated data. This must be freed via
// CoTaskmemFree()
// pCache Handle Cache.
//
// RETURN VALUE:
//
// Return: Registry value. Also sets the size and type of the registry data
//
//***************************************************************************
SCODE CImpReg::ReadRegData( IN HKEY hKey, IN const TCHAR * pName, OUT DWORD & dwRegType, OUT DWORD & dwSize, OUT void ** pData, IN CHandleCache * pCache) { void * pRet; int iRet; // Initially the buffer is set to hold INIT_SIZE
// bytes. If that isnt enough, the query will be
// repeated a second time
dwSize = INIT_SIZE; pRet = (unsigned char *)CoTaskMemAlloc(dwSize); if(pRet == NULL) { return WBEM_E_OUT_OF_MEMORY; }
if(hDMRegLib && !pCache->IsRemote()) iRet = pQueryValue(hKey, (TCHAR *) pName, 0l, &dwRegType, (LPBYTE)pRet,&dwSize); else iRet = RegQueryValueEx(hKey, pName, 0l, &dwRegType, (LPBYTE)pRet,&dwSize);
// If we failed for lack of space, retry once.
if(iRet == ERROR_MORE_DATA) { void * pSave = pRet; pRet= (char *)CoTaskMemRealloc(pRet, dwSize); if(pRet == NULL) { CoTaskMemFree(pSave); return WBEM_E_OUT_OF_MEMORY; } if(hDMRegLib && !pCache->IsRemote()) iRet = pQueryValue(hKey, (TCHAR *) pName, 0l, &dwRegType, (LPBYTE)pRet,&dwSize); else iRet = RegQueryValueEx(hKey, pName, 0l, &dwRegType, (LPBYTE)pRet, &dwSize); } *pData = pRet; return iRet; }
//***************************************************************************
//
// SCODE CImpReg::RefreshProperty
//
// DESCRIPTION:
//
// Gets the value of a single property from the registry.
//
// PARAMETERS:
//
// lFlags flags. Not currently used
// pClassInt Instance object
// PropName Property name
// ProvObj Object containing the property context string.
// pPackage Caching object
// pVar Points to value to set
// bTesterDetails Provide extra info for testers
//
// RETURN VALUE:
//
// S_OK
// WBEM_E_INVALID_PARAMETER
// or others??
//***************************************************************************
SCODE CImpReg::RefreshProperty( long lFlags, IWbemClassObject FAR * pClassInt, BSTR PropName, CProvObj & ProvObj, CObject * pPackage, CVariant * pVar, BOOL bTesterDetails) { int iCnt; int iNumSkip; // number of handles already provided by cache.
CHandleCache * pCache = (CHandleCache *)pPackage; DWORD dwRegType,dwBufferSize; void * pData = NULL; const TCHAR * pName; HKEY hCurr,hNew; SCODE sc;
// Do a second parse on the provider string. The initial parse
// is done by the calling routine and it's first token is
// the path. The path token is then parsed
// into RegPath and it will have a token for each part of the
// registry path.
CProvObj RegPath(ProvObj.sGetFullToken(1),SUB_DELIM,true); sc = RegPath.dwGetStatus(1); if(sc != S_OK) return WBEM_E_INVALID_PARAMETER; // Get a handle to a place in the reg path. Note that it might be just
// a root key (such as HKEY_LOCAL_MACHINE) or it might be a subkey
// if the cache contains some open handles that can be used.
sc = GetRoot(&hCurr,RegPath,ProvObj.sGetFullToken(0), pCache,iNumSkip); if(sc != ERROR_SUCCESS) return sc;
// Go down the registry path till we get to the key
for(iCnt = 1+iNumSkip; iCnt < RegPath.iGetNumTokens(); iCnt ++) { int iRet; if(hDMRegLib && !pCache->IsRemote()) iRet = pOpen(hCurr,RegPath.sGetToken(iCnt),0,0,KEY_QUERY_VALUE,&hNew); else iRet = RegOpenKeyEx(hCurr,RegPath.sGetToken(iCnt),0,KEY_READ,&hNew); if(iRet != ERROR_SUCCESS) { sc = iRet; // bad path!
return sc; } hCurr = hNew; sc = pCache->lAddToList(RegPath.sGetToken(iCnt),hNew); if(sc != ERROR_SUCCESS) return sc; }
// If it is a named value, get a pointer to the name
if(ProvObj.iGetNumTokens() > MIN_REG_TOKENS) pName = ProvObj.sGetToken(MIN_REG_TOKENS); else pName = NULL;
// Time to get the data.
sc = ReadRegData(hCurr, pName,dwRegType, dwBufferSize, &pData,pCache); if(sc == S_OK && dwBufferSize == 0) sc = 2; if(sc == S_OK) { CVariant cVar; if(dwRegType == REG_RESOURCE_LIST || dwRegType == REG_FULL_RESOURCE_DESCRIPTOR) sc = ConvertGetDataFromDesc(cVar,pData,dwRegType,dwBufferSize,ProvObj); else sc = ConvertGetDataFromSimple(cVar,pData,dwRegType,dwBufferSize,pClassInt,PropName); if(sc == S_OK) sc = cVar.DoPut(lFlags,pClassInt,PropName,pVar); } if(pData != NULL) CoTaskMemFree(pData); return sc; }
//***************************************************************************
//
// SCODE CImpReg::StartBatch
//
// DESCRIPTION:
//
// Called at the start of a batch of Refrest/Update Property calls. Initialize
// the handle cache.
//
// PARAMETERS:
//
// lFlags flags
// pClassInt Points to an instance object
// pObj Misc object pointer
// bGet TRUE if we will be getting data.
//
// RETURN VALUE:
//
// S_OK all is well
// WBEM_E_OUT_OF_MEMORY
//***************************************************************************
SCODE CImpReg::StartBatch( long lFlags, IWbemClassObject FAR * pClassInt, CObject **pObj, BOOL bGet) { *pObj = new CHandleCache; return (*pObj) ? S_OK : WBEM_E_OUT_OF_MEMORY; }
//***************************************************************************
//
// SCODE CImpReg::UpdateProperty
//
// DESCRIPTION:
//
// Sets the value of a single property into the registry.
//
// PARAMETERS:
//
// lFlags not used
// pClassInt pointer to instance object
// PropName property name
// ProvObj Object containing the property context string.
// pPackage pointer to the handle cache
// pVar value to be set
//
// RETURN VALUE:
//
// S_OK if ok,
// otherwise misc errors.
//***************************************************************************
SCODE CImpReg::UpdateProperty( IN long lFlags, IN IWbemClassObject FAR * pClassInt, IN BSTR PropName, IN CProvObj & ProvObj, IN CObject * pPackage, IN CVariant * pVar) { int iCnt; SCODE sc; void * pData; TString sProv; CHandleCache * pCache = (CHandleCache *)pPackage; const TCHAR * pName; int iNumSkip; HKEY hCurr,hNew; DWORD dwRegType, dwBufferSize;
// Do a second parse on the provider string. The initial parse
// is done by the calling routine and it's first token is
// the path. The path token is then parsed
// into RegPath and it will have a token for each part of the
// registry path.
CProvObj RegPath(ProvObj.sGetFullToken(1),SUB_DELIM,true); sc = RegPath.dwGetStatus(1); if(sc != WBEM_NO_ERROR) return sc;
// Get a handle to a place in the reg path. Note that it might be just
// a root key (such as HKEY_LOCAL_MACHINE) or it might be a subkey
// if the cache contains some open handles that can be used.
sc = GetRoot(&hCurr,RegPath,ProvObj.sGetFullToken(0), pCache,iNumSkip); if(sc != ERROR_SUCCESS) return sc;
// Go down the registry path, creating keys if necessary
for(iCnt = 1+iNumSkip; iCnt < RegPath.iGetNumTokens(); iCnt ++) { int iRet; iRet = OpenKeyForWritting(hCurr,(LPTSTR)RegPath.sGetToken(iCnt), &hNew, pCache); if(iRet != ERROR_SUCCESS) { sc = iRet; return sc; } hCurr = hNew; sc = pCache->lAddToList(RegPath.sGetToken(iCnt),hNew); if(sc != ERROR_SUCCESS) return sc; }
// If it is a named value, get a pointer to the name
if(ProvObj.iGetNumTokens() > MIN_REG_TOKENS) pName = ProvObj.sGetToken(MIN_REG_TOKENS); else pName = NULL;
// Get the data and set it
CVariant cVar;
if(pClassInt) { sc = pClassInt->Get(PropName,0,cVar.GetVarPtr(),NULL,NULL); } else if(pVar) { sc = OMSVariantChangeType(cVar.GetVarPtr(), pVar->GetVarPtr(),0, pVar->GetType()); } else sc = WBEM_E_FAILED; if(sc != S_OK) return sc;
sc = ConvertSetData(cVar, &pData, &dwRegType, &dwBufferSize); if(sc == S_OK) {
if(hDMRegLib && !pCache->IsRemote()) sc = pSetValue(hCurr, pName, 0l, dwRegType, (LPBYTE)pData, dwBufferSize); else sc = RegSetValueEx(hCurr, pName, 0l, dwRegType, (LPBYTE)pData, dwBufferSize); CoTaskMemFree(pData); } return sc; }
//***************************************************************************
//
// SCODE CImpReg::MakeEnum
//
// DESCRIPTION:
//
// Creates a CEnumRegInfo object which can be used for enumeration
//
// PARAMETERS:
//
// pClass Pointer to the class object.
// ProvObj Object containing the property context string.
// ppInfo Set to point to an collection object which has
// the keynames of the instances.
//
// RETURN VALUE:
//
// S_OK all is well,
// WBEM_E_INVALID_PARAMETER bad context string
// WBEM_E_OUT_OF_MEMORY
// WBEM_E_FAILED couldnt open the root key
// or RegConnectRegistry failure,
// or RegOpenKeyEx failure
//
//***************************************************************************
SCODE CImpReg::MakeEnum( IWbemClassObject * pClass, CProvObj & ProvObj, CEnumInfo ** ppInfo) { HKEY hRoot = NULL; HKEY hKey = NULL; HKEY hRemoteKey = NULL; DWORD dwLen; // Parse the class context
if(ProvObj.iGetNumTokens() < 2) return WBEM_E_INVALID_PARAMETER; dwLen = lstrlen(ProvObj.sGetToken(1))+1; TCHAR * pTemp = new TCHAR[dwLen]; if(pTemp == NULL) return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(pTemp, dwLen, ProvObj.sGetToken(1));
// Point to the root name and path. These initially in a single string
// and separated by a '\'. find the backslash and replace with a null
LPTSTR pRoot = pTemp; LPTSTR pPath; for(pPath = pRoot; *pPath; pPath++) if(*pPath == TEXT('\\')) break; if(*pPath == NULL || pPath[1] == NULL) { pPath = NULL; } else { *pPath = NULL; pPath ++; }
// Got to get the root key. First, use the second token to determine
// which predefined key to use. That would be something like;
// HKEY_CURRENT_USER.
int iSize= sizeof(Bases) / sizeof(struct BaseTypes), iCnt; for(iCnt = 0; iCnt < iSize; iCnt++) if(!lstrcmpi(pRoot,Bases[iCnt].lpName)) { hRoot = Bases[iCnt].hKey; break; } if(hRoot == NULL) { delete pTemp; return WBEM_E_FAILED; } if(hRoot == HKEY_CURRENT_USER && m_bLoadedProfile && !lstrcmpi(ProvObj.sGetToken(0),TEXT("local"))) hRoot = m_hRoot;
// If the machine is remote, hook up to it. Note that RegConnectRegistry
// requires a non constant arg for the machine name and so a temp string
// must be created.
if(lstrcmpi(ProvObj.sGetToken(0),TEXT("local"))) { dwLen = lstrlen(ProvObj.sGetToken(0))+1; TCHAR * pMachine = new TCHAR[dwLen]; if(pMachine == NULL) { delete pTemp; return WBEM_E_FAILED; } StringCchCopyW(pMachine, dwLen, ProvObj.sGetToken(0)); int iRet = RegConnectRegistry(pMachine,hRoot,&hRemoteKey); delete pMachine; if(iRet != 0) { delete pTemp; return iRet; } hRoot = hRemoteKey; }
// Open the key down to be used for enumeration!
int iRet; if(hDMRegLib && hRemoteKey == NULL) iRet = pOpen(hRoot,pPath,0,0,KEY_ALL_ACCESS,&hKey); else iRet = RegOpenKeyEx(hRoot,pPath,0,KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS ,&hKey);
delete pTemp; // all done
if(iRet == ERROR_BAD_IMPERSONATION_LEVEL) return WBEM_E_ACCESS_DENIED; if(iRet != 0) return WBEM_E_FAILED; if(hDMRegLib && hRemoteKey == NULL) *ppInfo = new CEnumRegInfo(hKey,hRemoteKey,pClose); else *ppInfo = new CEnumRegInfo(hKey,hRemoteKey,NULL);
return (*ppInfo) ? S_OK : WBEM_E_OUT_OF_MEMORY;
} //***************************************************************************
//
// SCODE CImpReg::GetKey
//
// DESCRIPTION:
//
// Gets the key name of an entry in the enumeration list.
//
// PARAMETERS:
//
// pInfo Collection list
// iIndex Index in the collection
// ppKey Set to the string. MUST BE FREED with "delete"
//
// RETURN VALUE:
//
// S_OK if all is well
// WBEM_E_FAILED end of data
// WBEM_E_OUT_OF_MEMORY
//***************************************************************************
SCODE CImpReg::GetKey( CEnumInfo * pInfo, int iIndex, LPWSTR * ppKey) { CEnumRegInfo * pRegInfo = (CEnumRegInfo *)pInfo; BOOL bUseDM = (hDMRegLib && pRegInfo->GetRemoteKey() == NULL); int iSize = 100; LPTSTR pData = NULL; *ppKey = NULL; long lRet = ERROR_MORE_DATA; while(lRet == ERROR_MORE_DATA && iSize < 1000) { FILETIME ft; iSize *= 2; if(pData) delete pData; pData = new TCHAR[iSize]; if(pData == NULL) return WBEM_E_OUT_OF_MEMORY; DWORD dwSize = iSize; if(bUseDM) lRet = pEnumKey(pRegInfo->GetKey(),iIndex,pData,&dwSize,NULL,NULL,NULL,&ft); else lRet = RegEnumKeyEx(pRegInfo->GetKey(),iIndex,pData,&dwSize,NULL,NULL,NULL,&ft); } if(lRet == 0) {
// got data. if we are in unicode, just use the current buffer, otherwise
// we have to convert
#ifdef UNICODE
*ppKey = pData; return S_OK; #else
*ppKey = new WCHAR[lstrlen(pData)+1]; if(*ppKey == NULL) { delete pData; return WBEM_E_OUT_OF_MEMORY; } mbstowcs(*ppKey,pData,lstrlen(pData)+1); delete pData; return S_OK; #endif
} delete pData; return WBEM_E_FAILED; }
//***************************************************************************
//
// CEnumRegInfo::CEnumRegInfo
//
// DESCRIPTION:
//
// Constructor.
//
// PARAMETERS:
//
// hKey Registry Key
// hRemoteKey Remote registry key
// pClose pointer to function used to close the handle
//
//***************************************************************************
CEnumRegInfo::CEnumRegInfo( HKEY hKey, HKEY hRemoteKey, PCLOSE pClose) { m_pClose = pClose; m_hKey = hKey; m_hRemoteKey = hRemoteKey; }
//***************************************************************************
//
// CEnumRegInfo::~CEnumRegInfo
//
// DESCRIPTION:
//
// Destructor.
//
//***************************************************************************
CEnumRegInfo::~CEnumRegInfo() { long lRet; if(m_pClose != NULL && m_hRemoteKey == NULL) lRet = m_pClose(m_hKey); else lRet = RegCloseKey(m_hKey); if(m_hRemoteKey) lRet = RegCloseKey(m_hRemoteKey); }
//***************************************************************************
//
// CImpRegProp::CImpRegProp
//
// DESCRIPTION:
//
// Constructor.
//
//***************************************************************************
CImpRegProp::CImpRegProp() { m_pImpDynProv = new CImpReg(); }
//***************************************************************************
//
// CImpRegProp::~CImpRegProp
//
// DESCRIPTION:
//
// Destructor.
//
//***************************************************************************
CImpRegProp::~CImpRegProp() { if(m_pImpDynProv) delete m_pImpDynProv; }
|