1052 lines
31 KiB
C++
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;
|
|
}
|
|
|