|
|
/*++
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; }
|