1532 lines
45 KiB
C++
1532 lines
45 KiB
C++
/*++
|
|
|
|
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()
|
|
{
|
|
wcscpy(wcCLSID,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_hToken = NULL;
|
|
m_bLoadedProfile = false;
|
|
if(IsNT())
|
|
{
|
|
SCODE sc = WbemCoImpersonateClient();
|
|
if(sc == S_OK)
|
|
{
|
|
sc = LoadProfile(m_hToken, m_hRoot);
|
|
if(sc == S_OK)
|
|
m_bLoadedProfile = true;
|
|
|
|
WbemCoRevertToSelf();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CImpReg::~CImpReg
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CImpReg::~CImpReg()
|
|
{
|
|
if(hDMRegLib)
|
|
FreeLibrary(hDMRegLib);
|
|
if(m_bLoadedProfile)
|
|
UnloadUserProfile(m_hToken, m_hRoot);
|
|
if(m_hToken)
|
|
CloseHandle(m_hToken);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// 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)
|
|
{
|
|
pRet= (char *)CoTaskMemRealloc(pRet, 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);
|
|
}
|
|
*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;
|
|
// Parse the class context
|
|
|
|
if(ProvObj.iGetNumTokens() < 2)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
TCHAR * pTemp = new TCHAR[lstrlen(ProvObj.sGetToken(1))+1];
|
|
if(pTemp == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
lstrcpy(pTemp,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")))
|
|
{
|
|
TCHAR * pMachine = new TCHAR[lstrlen(ProvObj.sGetToken(0))+1];
|
|
if(pMachine == NULL)
|
|
{
|
|
delete pTemp;
|
|
return WBEM_E_FAILED;
|
|
}
|
|
lstrcpy(pMachine,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;
|
|
}
|
|
|