windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/stdprov/provcomp.cpp
2020-09-26 16:20:57 +08:00

1052 lines
31 KiB
C++

/*++
Copyright (C) 1995-2001 Microsoft Corporation
Module Name:
PROVCOMP.CPP
Abstract:
Purpose: Defines the acutal "Put" and "Get" functions for the
Ole compound file provider.
History:
a-davj 10-10-95 v0.01
--*/
#include "precomp.h"
#include "stdafx.h"
#include <wbemidl.h>
#include "impdyn.h"
#define GET_FLAGS STGM_READ|STGM_SHARE_DENY_WRITE
#define PUT_FLAGS STGM_READWRITE|STGM_SHARE_EXCLUSIVE
enum {NORMAL, STRING, WSTRING, DBLOB, DCLSID, UNKNOWN};
void CImpComp::AddBlankData(CBuff * pBuff,DWORD dwType)
{
VARIANTARG vTemp;
DWORD dwDataSize;
BOOL bStringType;
// If we have an variant array, then add an empty entry and be done
if(dwType == VT_VARIANT) {
DWORD dwEmpty = VT_EMPTY; //TODO, is the right? maybe VT_NULL??
pBuff->Add((void *)&dwEmpty,sizeof(DWORD));
return;
}
// Create an empty variantarg, get its statistics
VariantInit(&vTemp);
vTemp.cyVal.int64 = 0;
vTemp.vt = (VARTYPE)dwType;
if(!bGetVariantStats(&vTemp, NULL, &dwDataSize, &bStringType))
return;
if(!bStringType) {
pBuff->Add((void *)&vTemp.cyVal.int64,dwDataSize);
}
else if (dwType == VT_BLOB){
DWORD dwSize = 0;
pBuff->Add((void *)&dwSize,sizeof(DWORD));
}
else {
DWORD dwSize = 1;
pBuff->Add((void *)&dwSize,sizeof(DWORD));
pBuff->Add((void *)&vTemp.cyVal.int64,2); // add a null,
pBuff->RoundOff();
}
}
//***************************************************************************
//
// CImpComp::AddVariantData
//
// Adds the property value to a buffer that is to be output. For normal
// data, this acutally sets the buffer. However, for the case of array
// data, it is probably adding to the buffer (unless its the first element)
//
//***************************************************************************
void CImpComp::AddVariantData(VARIANTARG * pIn,CBuff * pBuff)
{
void * pCopy;
BOOL bSizeNeeded;
DWORD dwDataSize;
bGetVariantStats(pIn, NULL, &dwDataSize, &bSizeNeeded);
// If strings, blobs etc, copy size in first
if(bSizeNeeded) {
if(pIn->vt == VT_LPWSTR){
DWORD dwTemp = dwDataSize /2 ;
pBuff->Add((void*)&dwTemp,sizeof(DWORD));
}
else
pBuff->Add((void*)&dwDataSize,sizeof(DWORD));
pCopy = (void *)pIn->bstrVal;
}
else
pCopy = (void *)&pIn->iVal;
// copy the data
pBuff->Add((void *)pCopy,dwDataSize);
// round the data to a 4 byte boundry
if(bSizeNeeded)
pBuff->RoundOff();
return;
}
//***************************************************************************
//
// CImpComp::bCreateWriteArray
//
// Create a buffer with an array of values. This is used when writting
// out properties that are members of arrays. To do this, an array must
// be constructed.
//
//***************************************************************************
BOOL CImpComp::bCreateWriteArray(VARIANTARG * pIn, CBuff * pBuff,
MODYNPROP *pMo, int iIndex, DWORD & dwType, BOOL bExisting, CProp * pProp)
{
DWORD * dwp;
DWORD dwExisting; // number of existing entries
DWORD dwNumElem; // number of elements to be written
DWORD dwTempType;
SCODE sc;
// If the property alread exists, get the current type and number
// of existing elements.
if(bExisting) {
dwType = pProp->GetType();
dwType &= ~VT_VECTOR;
dwp = (DWORD *)pProp->Get();
dwExisting = *dwp;
}
else {
if(!bGetVariantStats(pIn, &dwType, NULL, NULL)){
pMo->dwResult = ERROR_UNKNOWN; // BAD INPUT DATA
return FALSE;
}
dwExisting = 0;
}
// Determine the number of elements to write. It may be more that the
// number of existing elements when writting a new vector or adding to
// an existing one
if((unsigned)iIndex >= dwExisting)
dwNumElem = iIndex + 1; // iIndex has 0 as the first element
else
dwNumElem = dwExisting;
// Copy in the number of elements
pBuff->Add((void *)&dwNumElem,sizeof(DWORD));
// Now build the output array one element at the time
// todo, more error checking in here???
DWORD dwCnt;
for(dwCnt = 0; dwCnt < dwNumElem; dwCnt++) {
if(dwCnt == (unsigned)iIndex) {
// This element is being supplied by the caller
if(!bExisting) {
// no converstion necessary since this is a new array
AddVariantData(pIn,pBuff);
}
else if(dwType == VT_VARIANT) {
// write type first
DWORD dwTemp = 0;
dwTemp = pIn->vt;
pBuff->Add((void *)&dwTemp,sizeof(DWORD));
// write the data;
AddVariantData(pIn,pBuff);
}
else {
// existing array that isnt VARIANT type. Convert the input
// data into the same format and then add
VARIANTARG vTemp;
VariantInit(&vTemp);
vTemp.cyVal.int64 = 0;
sc = OMSVariantChangeType(&vTemp,pIn,0,(VARTYPE)dwType);
if(sc != S_OK) {
pMo->dwResult = sc;
return FALSE;
}
// write the data;
AddVariantData(&vTemp,pBuff);
OMSVariantClear(&vTemp); // all done, free it
}
}
else if (dwCnt < dwExisting) {
// Add from the read data
int iIgnore;
void * pTemp = ExtractData(pProp,dwTempType,dwCnt,TRUE);
DWORD dwSkip = dwSkipSize((char *)pTemp,dwTempType,iIgnore);
pBuff->Add(pTemp,dwSkip);
}
else
// create a blank entry
AddBlankData(pBuff,dwType);
}
dwType |= VT_VECTOR;
return TRUE;
}
//***************************************************************************
//
// CImpComp::bGetVariantStats
//
// Determines various characteristics of a VARIANTARG.
//
// Returns TRUE if the variant type is valid.
//
//***************************************************************************
BOOL CImpComp::bGetVariantStats(VARIANTARG * pIn, DWORD * pType, DWORD * pDataSize, BOOL * pSizeNeeded)
{
BOOL bSizeNeeded = FALSE; // set to true for strings and blobs etc.
DWORD dwDataSize = 0, dwType;
void * pData = (void *)pIn->bstrVal;
// normall the type is whatever is in the VARIANTARG. However,
// certain new types, such as VT_UI4 are not in the ole spec and
// might cause problems to older programs. Therefore, the new
// types have an equivalent older type returned.
dwType = pIn->vt;
// just in case we are running in a 16 bit environment
if((sizeof(INT) == 2) && (pIn->vt == VT_INT || pIn->vt == VT_UINT))
pIn->vt = VT_I2;
// determine how big the data is, where to copy it from and determine
// if the size needs to also be written.
switch (pIn->vt) {
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_BOOL:
case VT_UI2: // all get handled as I2
if(pIn->vt != VT_BOOL)
dwType = VT_I2;
dwDataSize = 2;
break;
case VT_R4:
case VT_I4:
case VT_INT:
case VT_UINT:
case VT_UI4:
if(pIn->vt != VT_R4)
dwType = VT_I4;
dwDataSize = 4;
break;
case VT_I8:
case VT_UI8:
case VT_R8:
case VT_CY:
case VT_DATE:
if(pIn->vt == VT_UI8)
dwType = VT_I8;
dwDataSize = 8;
break;
case VT_LPSTR:
dwDataSize = lstrlenA((char *)pData)+1;
bSizeNeeded = TRUE;
break;
case VT_LPWSTR:
dwDataSize = 2*(lstrlenW((WCHAR *)pData)+1);
bSizeNeeded = TRUE;
break;
case VT_BSTR:
if(sizeof(OLECHAR) == 2)
dwDataSize = 2*(lstrlenW((WCHAR *)pData)+1);
else
dwDataSize = lstrlenA((char *)pData)+1;
bSizeNeeded = TRUE;
break;
default:
return FALSE;
}
// Set the desired values
if(pType)
*pType = dwType;
if(pDataSize)
*pDataSize = dwDataSize;
if(pSizeNeeded)
*pSizeNeeded = bSizeNeeded;
return TRUE;
}
//***************************************************************************
//
// CImpComp::CImpComp
//
// Constructor. Doesnt do much except call base class constructor.
//
//***************************************************************************
CImpComp::CImpComp(LPUNKNOWN pUnkOuter) : CImpDyn(pUnkOuter)
{
return;
}
//***************************************************************************
//
// CImpComp::ConvertGetData
//
// Converts the data from the property set into the format desired by
// the caller.
//
//***************************************************************************
void CImpComp::ConvertGetData(MODYNPROP *pMo,char * pData,DWORD dwType)
{
HRESULT sc;
OLECHAR * poTemp = NULL;
GUID * piid;
int iCat;
DWORD dwLen = dwSkipSize(pData,dwType,iCat);
// TODO, remove this temporary stuff!!!
DWORD dwSave = pMo->dwType;
if(pMo->dwType == M_TYPE_LPSTR)
pMo->dwType = VT_LPSTR;
else if(pMo->dwType == M_TYPE_DWORD)
pMo->dwType = VT_UINT;
else if(pMo->dwType == M_TYPE_INT64)
pMo->dwType = VT_I8;
else {
pMo->dwResult = M_INVALID_TYPE;
return;
}
// bail out if bad data
if(iCat == UNKNOWN || pData == NULL) {
pMo->dwResult = ERROR_UNKNOWN;
return;
}
// convert the data into standard form
VARIANTARG vTemp,* pvConvert;
pvConvert = (VARIANTARG *)CoTaskMemAlloc(sizeof(VARIANTARG));
if(pvConvert == NULL) {
pMo->dwResult = WBEM_E_OUT_OF_MEMORY;
return;
}
VariantInit(&vTemp);
VariantInit(pvConvert);
vTemp.cyVal.int64 = 0;
pvConvert->cyVal.int64 = 0;
switch(iCat) {
case NORMAL:
memcpy((void *)&vTemp.iVal,pData,dwLen);
vTemp.vt = (VARTYPE)dwType;
break;
case STRING:
vTemp.bstrVal = (BSTR)(pData + sizeof(DWORD));
vTemp.vt = VT_LPSTR;
break;
case WSTRING:
vTemp.bstrVal = (BSTR)(pData + sizeof(DWORD));
vTemp.vt = VT_LPWSTR;
break;
case DBLOB:
vTemp.bstrVal = (BSTR)pData; // TODO, check on this!
vTemp.vt = VT_BLOB;
break;
case DCLSID:
piid = (GUID * )pData;
sc = StringFromIID(*piid,&poTemp); //todo, error checking!
vTemp.bstrVal = (BSTR)poTemp;
if(sizeof(OLECHAR) == 1)
vTemp.vt = VT_LPSTR;
else
vTemp.vt = VT_LPWSTR;
break;
}
sc = OMSVariantChangeType(pvConvert,&vTemp,0,(VARTYPE)pMo->dwType);
if(poTemp)
CoTaskMemFree(poTemp);
// note, that the variant memory is not freeded here since it is
// actually "owned" by the CProp object which will free it.
if(sc != S_OK) {
pMo->dwResult = sc;
return;
}
//todo, in the future, the size should just be s
// sizeof VARIANTARG! AND WE SHOULD RETURN THE VARIANT
// POINTER AND NOT THE DATA!!!!!
int iSize = sizeof(VARIANTARG);
if(pMo->dwType == VT_LPSTR)
iSize = lstrlen((LPTSTR)pvConvert->pbstrVal) + 1;
if(pMo->dwType == VT_LPWSTR)
iSize = 2*wcslen((WCHAR *)pvConvert->pbstrVal) + 2;
if(pMo->dwType == VT_BSTR)
iSize = 2*wcslen((WCHAR *)pvConvert->pbstrVal) + 6;
pMo->pPropertyValue = CoTaskMemAlloc(iSize);
// check for errors
if(pMo->pPropertyValue == NULL){
pMo->dwResult = WBEM_E_OUT_OF_MEMORY;
}
else {
if(pMo->dwType != VT_LPSTR)
memcpy(pMo->pPropertyValue,(void *)&pvConvert->iVal,iSize);
else
memcpy(pMo->pPropertyValue,(void *)pvConvert->pbstrVal,iSize);
pMo->dwResult = ERROR_SUCCESS;
}
pMo->dwType = dwSave ;
}
//***************************************************************************
//
// CImpComp::DoSetData
//
// Conversts the property data into propset format and writes it out.
//
//***************************************************************************
void CImpComp::DoSetData(MODYNPROP *pMo,int iIndex,CProp * pProp,
CPropSet * pSet,GUID fmtid,int iPid,LPSTREAM pIStream)
{
BOOL bExisting = TRUE;
CBuff OutBuff;
DWORD dwType;
// If the property doesnt exist, I.e, its new, then create it
if(pProp == NULL) {
bExisting = FALSE;
pProp = new CProp;
if(pProp == NULL) {
pMo->dwResult = WBEM_E_OUT_OF_MEMORY;
return;
}
pSet->AddProperty(fmtid,pProp);
}
// TODO REMOVE, TEMP CODE, create variant
VARIANTARG vIn;
VariantInit(&vIn);
vIn.cyVal.int64 = 0;
if(pMo->dwType == M_TYPE_DWORD){
vIn.vt = VT_I4;
vIn.lVal = *(DWORD *)pMo->pPropertyValue;
}
else if(pMo->dwType == M_TYPE_LPSTR){
vIn.vt = VT_LPSTR;
vIn.bstrVal = (BSTR)pMo->pPropertyValue;
}
else {
pMo->dwResult = M_TYPE_NOT_SUPPORTED;
return;
}
// TODO REMOVE, TEMP CODE,
if(iIndex >= 0) {
// Get the data for an array
if(!bCreateWriteArray(&vIn,&OutBuff,pMo,iIndex,dwType,
bExisting,pProp)) {
return;
}
}
else {
if(!bGetVariantStats(&vIn, &dwType, NULL, NULL)) {
pMo->dwResult = ERROR_UNKNOWN; // bad input data
return;
}
AddVariantData(&vIn,&OutBuff);
/* temp stuff to generate a sample vector
dwType = VT_VARIANT | VT_VECTOR;
DWORD dwCnt = 3;
OutBuff.Add((void *)&dwCnt, 4);
DWORD dwT = VT_I4;
OutBuff.Add((void *)&dwT, 4);
DWORD dwData = 0x1234;
OutBuff.Add((void *)&dwData, 4);
dwT = VT_I2;
dwData = 1;
OutBuff.Add((void *)&dwT, 4);
OutBuff.Add((void *)&dwData, 2);
dwData = 2;
OutBuff.Add((void *)&dwT, 4);
OutBuff.Add((void *)&dwData, 2);
end of temp stuff */
}
if(!OutBuff.bOK())
pMo->dwResult = WBEM_E_OUT_OF_MEMORY; // bad input data
else {
pProp->Set(iPid, OutBuff.Get(),dwType,OutBuff.GetSize());
pSet->WriteToStream(pIStream);
}
//xxx pIStream->Commit(STGC_OVERWRITE);
return;
}
//***************************************************************************
//
// CImpComp::dwSkip
//
// Returns the size of a data element. Also sets the iCat reference to
// indicate the category of the data type.
//
//***************************************************************************
DWORD CImpComp::dwSkipSize(char *pData,DWORD dwType, int & iCat)
{
DWORD cbItem, cbVariant = 0;
DWORD * dwp;
iCat = NORMAL;
dwType &= ~VT_VECTOR;
if(dwType == VT_VARIANT) {
dwp = (DWORD *)pData;
dwType = *dwp;
pData += sizeof(DWORD);
cbVariant = sizeof(DWORD);
}
switch (dwType)
{
case VT_EMPTY: // nothing
cbItem = 0;
break;
case VT_I2: // 2 byte signed int
case VT_BOOL: // True=-1, False=0
cbItem = 2;
break;
case VT_I4: // 4 byte signed int
case VT_R4: // 4 byte real
cbItem = 4;
break;
case VT_R8: // 8 byte real
case VT_CY: // currency
case VT_DATE: // date
case VT_I8: // signed 64-bit int
case VT_FILETIME: // FILETIME
cbItem = 8;
break;
case VT_LPSTR: // null terminated string
case VT_BSTR: // binary string
case VT_BLOB: // Length prefixed bytes
case VT_BLOB_OBJECT: // Blob contains an object
case VT_BLOB_PROPSET: // Blob contains a propset
// Read the DWORD that gives us the size, making
// sure we increment cbValue.
dwp = (DWORD *)pData;
cbItem = sizeof(DWORD)+ *dwp;
if(dwType != VT_BLOB && dwType != VT_BLOB_OBJECT &&
dwType != VT_BLOB_PROPSET)
iCat = STRING;
else
iCat = DBLOB;
for(;cbItem % 4; cbItem++); // round up to 4 byte boundry
break;
case VT_LPWSTR: // UNICODE string
dwp = (DWORD *)pData;
cbItem = sizeof(DWORD)+ (*dwp) * sizeof(WCHAR);
iCat = WSTRING;
for(;cbItem % 4; cbItem++); // round up to 4 byte boundry
break;
case VT_CLSID: // A Class ID
cbItem = sizeof(CLSID);
iCat = DCLSID;
break;
default:
iCat = UNKNOWN;
cbItem = 0;
}
return cbItem + cbVariant;
}
//***************************************************************************
//
// CImpComp::EndBatch
//
// Called at the end of a batch of Refrest/Update Property calls. Free up
// any cached handles and then delete the handle cache.
//
//***************************************************************************
void CImpComp::EndBatch(MODYNPROP * pMo,CObject *pObj,DWORD dwListSize,BOOL bGet)
{
if(pObj != NULL) {
Free(0,(CHandleCache *)pObj);
delete pObj;
}
}
//***************************************************************************
//
// CImpComp::ExtractData
//
// Gets the property objects data and returns a pointer to it. This is
// complicated since the data may be a vector (array) or the data might
// be a variant, or even a vectory of variants.
//
// Returns a pointer to the data and also sets the dwType reference to
// indicate the type. Note that the type refernce indicates the acutal
// data and does not include the vector bit or the fact that the data
// may be a variant.
//
//***************************************************************************
void * CImpComp::ExtractData( CProp * pProp,DWORD & dwType,int iIndex, BOOL bRaw)
{
// Get the type and data
char * pRet;
int iIgnore;
pRet = (char *)pProp->Get();
dwType = pProp->GetType();
// if the type is a vector, then step into the data. Ie if there are
// 10 elements and we want the 5th, step over the first four
if(dwType & VT_VECTOR) {
DWORD dwCnt;
DWORD * dwpNumVec = (DWORD *)pRet; // first dword is num elements
pRet += sizeof(DWORD);
if(iIndex == -1 || (unsigned)iIndex >= *dwpNumVec)
return NULL;
for(dwCnt = 0; dwCnt < (unsigned)iIndex; dwCnt++)
pRet += dwSkipSize(pRet,dwType, iIgnore);
}
dwType &= ~VT_VECTOR;
// If the data type is VARIANT, then get the actual type out of
// the variant structure and increment the pointer past it.
if(dwType == VT_VARIANT && !bRaw) {
DWORD *dwp = (DWORD *)pRet;
dwType = *dwp;
pRet += sizeof(DWORD);
}
return pRet;
}
//***************************************************************************
//
// CImpComp::Free
//
// 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.
//
//***************************************************************************
void CImpComp::Free(int iStart, CHandleCache * pCache)
{
int iCurr,iLast;
iLast = pCache->lGetNumEntries()-1;
for(iCurr = iLast; iCurr >= iStart; iCurr--) {
LPSTORAGE pIStorage = (LPSTORAGE)pCache->hGetHandle(iCurr);
// if(iCurr == 0)
// pIStorage->Commit(STGC_OVERWRITE);
if(pIStorage != NULL)
pIStorage->Release();
}
pCache->Delete(iStart); // get cache to delete the entries
}
//***************************************************************************
//
// CImpComp::GetData
//
// Gets a pointer to a property object and then calls the conversion
// routines to convert the properties data. Note that some properties
// are stream or storage names and so this routine may be called
// recursively to get the acutual data.
//
//***************************************************************************
void CImpComp::GetData(MODYNPROP * pMo, CProvObj & ProvObj, int iToken,
LPSTORAGE pIStore, LPSTREAM pIStream, BOOL bGet, BOOL bNewStream)
{
SCODE hr;
COleString sTemp;
DWORD dwType;
void * pData;
// create a property set object
CPropSet Set;
GUID fmtid;
if(!bNewStream) {
BOOL bRet = Set.ReadFromStream(pIStream);
if(bRet == 0) {
pMo->dwResult = ERROR_UNKNOWN; //bad stream, probably bad mapping
return;
}
}
// Get the property.
sTemp = ProvObj.sGetToken(iToken++);
hr = IIDFromString(sTemp,&fmtid);
if(hr != S_OK) {
pMo->dwResult = ERROR_UNKNOWN;
return;
}
int iPid = ProvObj.iGetIntExp(iToken,0,pMo->dwOptArrayIndex);
if(iPid == -1) {
pMo->dwResult = ERROR_UNKNOWN; // bad mapping string!
return;
}
CProp * pProp = Set.GetProperty(fmtid,iPid);
int iIndex = ProvObj.iGetIntExp(iToken,1,pMo->dwOptArrayIndex);
if(bGet) {
// Get the data, it might be complicated if the property is an array
// etc.
if(pProp == NULL) {
pMo->dwResult = ERROR_UNKNOWN; // bad mapping string!
return;
}
pData = ExtractData(pProp, dwType,iIndex,FALSE);
if(pData == NULL)
pMo->dwResult = ERROR_UNKNOWN; // bad mapping string!
else
ConvertGetData(pMo, (char *)pData, dwType);
}
else
DoSetData(pMo, iIndex, pProp, &Set,fmtid, iPid, pIStream);
return;
}
//***************************************************************************
//
// CImpComp::GetProp
//
// Gets the value of a single property from an Ole Compound file
//
//***************************************************************************
void CImpComp::GetProp(MODYNPROP * pMo, CProvObj & ProvObj,CObject * pPackage)
{
int iCnt;
int iNumSkip; // number of handles already provided by cache.
SCODE hr;
int iLast;
CHandleCache * pCache = (CHandleCache *)pPackage;
CString sRoot,sRet;
COleString soTemp;
LPSTORAGE pCurr,pNew;
LPSTREAM pIStream;
// 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 StorePath and it will have a token for each part of the
// storage path.
CProvObj StorePath(ProvObj.sGetFullToken(1),SUB_DELIM);
pMo->dwResult = StorePath.dwGetStatus();
if(pMo->dwResult != WBEM_NO_ERROR)
return;
// Get the root storage (ie, the file) and possibly other substorages
// if available in the cache.
pMo->dwResult = GetRoot(&pCurr,StorePath,ProvObj.sGetFullToken(0),
pCache,iNumSkip,TRUE);
if(pMo->dwResult != ERROR_SUCCESS)
return;
pIStream = (LPSTREAM)pCurr; // just in case cache matched all the way.
// Go down the storage path till we get to the stream
iLast = StorePath.iGetNumTokens() -1;
for(iCnt = iNumSkip; iCnt <= iLast; iCnt ++) {
soTemp = StorePath.sGetToken(iCnt);
if(iCnt == iLast) {
// the last entry in the path specifies the stream
hr = pCurr->OpenStream(soTemp,NULL,
STGM_READ|STGM_SHARE_EXCLUSIVE,
0,&pIStream);
if(hr != S_OK) {
pMo->dwResult = hr; // bad storage name!
return;
}
pMo->dwResult = pCache->lAddToList(soTemp,pIStream);
if(pMo->dwResult != WBEM_NO_ERROR)
return;
}
else {
hr = pCurr->OpenStorage(soTemp,NULL,
STGM_READ|STGM_SHARE_EXCLUSIVE,
NULL,0,&pNew);
if(hr != S_OK) {
pMo->dwResult = hr; // bad storage name!
return;
}
pMo->dwResult = pCache->lAddToList(soTemp,pNew);
if(pMo->dwResult != WBEM_NO_ERROR)
return;
pCurr = pNew;
}
}
// Finish up getting the data.
GetData(pMo,ProvObj,2, pNew, pIStream, TRUE);
return;
}
//***************************************************************************
//
// CImpComp::GetRoot
//
// Sets the pointer to an open storage. Typically this is the root storage,
// but it might be a substorage if the path matches the storages in the
// cachee.
// Returns 0 if OK, otherwise return is error code. Also the storage
// pointer is set as well as the number of substorages to skip in
// cases where the cache is being used.
//
//***************************************************************************
int CImpComp::GetRoot(LPSTORAGE * pRet,CProvObj & Path,const TCHAR * pNewFilePath,CHandleCache * pCache,int & iNumSkip,BOOL bGet)
{
*pRet = NULL;
int iRet;
iNumSkip = 0;
LPSTORAGE pIStorage;
SCODE hr;
if(pCache->lGetNumEntries() > 0){ //I.e. in use
const TCHAR * pOldFilePath = pCache->sGetString(0);
if(lstrcmpi(pOldFilePath,pNewFilePath)) //todo, handle nulls here!
// If the file path has changed, free all
// the cached handles and get a new root
Free(0,pCache);
else {
// FilePath is in common.
// determine how much else is in
// common, free what isnt in common,
// return handle of best match.
iNumSkip = pCache->lGetNumMatch(1,0,Path);
Free(1+iNumSkip,pCache);
*pRet = (LPSTORAGE)pCache->hGetHandle(1+iNumSkip);
return ERROR_SUCCESS;
}
}
// If the is a Set, and the file doesnt exist, create it
COleString sNew;
sNew = pNewFilePath;
if(!bGet)
if(NOERROR != StgIsStorageFile(sNew)) {
hr = StgCreateDocfile(sNew,
STGM_READWRITE|STGM_SHARE_DENY_WRITE|STGM_CREATE,
0L, &pIStorage);
if(hr == S_OK) {
iRet = pCache->lAddToList(pNewFilePath,pIStorage);
if(iRet)
return iRet;
*pRet = pIStorage;
}
return hr;
}
// open an existing file
hr = StgOpenStorage(sNew,NULL,
(bGet) ? GET_FLAGS : PUT_FLAGS,
NULL,0L, &pIStorage);
if(hr == S_OK){
hr = pCache->lAddToList(pNewFilePath,pIStorage);
*pRet = pIStorage;
}
return hr;
}
//***************************************************************************
//
// CImpComp::SetProp
//
// Writes the value of a single property into an Ole Compound file
//
//***************************************************************************
void CImpComp::SetProp(MODYNPROP * pMo, CProvObj & ProvObj,CObject * pPackage)
{
int iCnt;
int iNumSkip; // number of handles already provided by cache.
SCODE hr;
int iLast;
CHandleCache * pCache = (CHandleCache *)pPackage;
CString sRoot,sRet;
COleString soTemp;
LPSTORAGE pCurr,pNew;
LPSTREAM pIStream;
BOOL bStreamCreated = FALSE;
// 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 StorePath and it will have a token for each part of the
// storage path.
CProvObj StorePath(ProvObj.sGetFullToken(1),SUB_DELIM);
pMo->dwResult = StorePath.dwGetStatus();
if(pMo->dwResult != WBEM_NO_ERROR)
return;
// Get the root storage (ie, the file) and possibly other substorages
// if available in the cache.
pMo->dwResult = GetRoot(&pCurr,StorePath,ProvObj.sGetFullToken(0),
pCache,iNumSkip,FALSE);
if(pMo->dwResult != ERROR_SUCCESS)
return;
pIStream = (LPSTREAM)pCurr; // just in case cache matched all the way.
// Go down the storage path till we get to the stream
iLast = StorePath.iGetNumTokens() -1;
for(iCnt = iNumSkip; iCnt <= iLast; iCnt ++) {
soTemp = StorePath.sGetToken(iCnt);
if(iCnt == iLast) {
// the last entry in the path specifies the stream
hr = pCurr->OpenStream(soTemp,NULL,
STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
0,&pIStream);
if(hr == STG_E_FILENOTFOUND) {
bStreamCreated = TRUE;
hr = pCurr->CreateStream(soTemp,
STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_FAILIFTHERE,
0,0,&pIStream);
}
if(hr != S_OK) {
pMo->dwResult = hr; // bad storage name!
return;
}
pMo->dwResult = pCache->lAddToList(soTemp,pIStream);
if(pMo->dwResult != WBEM_NO_ERROR)
return;
}
else {
hr = pCurr->OpenStorage(soTemp,NULL,
STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
NULL,0,&pNew);
if(hr == STG_E_FILENOTFOUND)
hr = pCurr->CreateStorage(soTemp,
STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_FAILIFTHERE,
0,0,&pNew);
if(hr != S_OK) {
pMo->dwResult = hr; // bad storage name!
return;
}
pMo->dwResult = pCache->lAddToList(soTemp,pNew);
if(pMo->dwResult != WBEM_NO_ERROR)
return;
pCurr = pNew;
}
}
// Finish up getting the data.
GetData(pMo,ProvObj,2, pNew, pIStream, FALSE, bStreamCreated);
return;
}
//***************************************************************************
//
// CImpComp::StartBatch
//
// Called at the start of a batch of Refrest/Update Property calls. Initialize
// the handle cache.
//
//***************************************************************************
void CImpComp::StartBatch(MODYNPROP * pMo,CObject **pObj,DWORD dwListSize,BOOL bGet)
{
*pObj = new CHandleCache;
}