Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1585 lines
44 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1998.
//
// File: StgVarA.cxx
//
// Contents: C++ wrapper for PROPVARIANT.
//
// History: 01-Aug-94 KyleP Created
// 14-May-97 mohamedn allocate/deallocate SafeArrays (VT_ARRAY)
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#ifndef _NTDLLBUILD_
#include <propset.h>
#include <propvar.h>
#include <pmalloc.hxx>
CAllocStorageVariant::CAllocStorageVariant(
BYTE *pb,
ULONG cb,
PMemoryAllocator &ma)
{
vt = VT_BLOB;
if ( 0 == pb )
{
blob.cbSize = 0;
blob.pBlobData = 0;
}
else
{
blob.cbSize = cb;
blob.pBlobData = (BYTE *) ma.Allocate(cb);
if (blob.pBlobData != NULL)
{
memcpy(blob.pBlobData, pb, cb);
}
}
}
CAllocStorageVariant::CAllocStorageVariant(
char const *psz,
PMemoryAllocator &ma)
{
vt = VT_LPSTR;
if ( 0 == psz )
{
pszVal = 0;
}
else
{
int cb = strlen(psz) + 1;
pszVal = (char *) ma.Allocate(cb);
if (pszVal != NULL)
{
memcpy(pszVal, psz, cb);
}
}
}
CAllocStorageVariant::CAllocStorageVariant(
WCHAR const *pwsz,
PMemoryAllocator &ma)
{
vt = VT_LPWSTR;
if ( 0 == pwsz )
{
pwszVal = 0;
}
else
{
int cb = (wcslen(pwsz) + 1) * sizeof(WCHAR);
pwszVal = (WCHAR *) ma.Allocate(cb);
if (pszVal != NULL)
{
memcpy(pwszVal, pwsz, cb);
}
}
}
CAllocStorageVariant::CAllocStorageVariant(
CLSID const *pcid,
PMemoryAllocator &ma)
{
vt = VT_CLSID;
puuid = (CLSID *) ma.Allocate(sizeof(CLSID));
if (puuid != NULL)
{
memcpy(puuid, pcid, sizeof(CLSID));
}
}
CAllocStorageVariant::CAllocStorageVariant(
VARENUM v,
ULONG cElements,
PMemoryAllocator &ma)
{
ULONG cbElement;
BOOLEAN fZero = FALSE;
// Ignore vector flag. This constructor is always for vectors only.
vt = v | VT_VECTOR;
switch (vt)
{
case VT_VECTOR | VT_I1:
case VT_VECTOR | VT_UI1:
AssertByteVector(cac); // VT_I1
AssertByteVector(caub); // VT_UI1
cbElement = sizeof(caub.pElems[0]);
break;
case VT_VECTOR | VT_I2:
case VT_VECTOR | VT_UI2:
case VT_VECTOR | VT_BOOL:
AssertShortVector(cai); // VT_I2
AssertShortVector(caui); // VT_UI2
AssertShortVector(cabool); // VT_BOOL
cbElement = sizeof(cai.pElems[0]);
break;
case VT_VECTOR | VT_I4:
case VT_VECTOR | VT_UI4:
case VT_VECTOR | VT_R4:
case VT_VECTOR | VT_ERROR:
AssertLongVector(cal); // VT_I4
AssertLongVector(caul); // VT_UI4
AssertLongVector(caflt); // VT_R4
AssertLongVector(cascode); // VT_ERROR
cbElement = sizeof(cal.pElems[0]);
break;
case VT_VECTOR | VT_I8:
case VT_VECTOR | VT_UI8:
case VT_VECTOR | VT_R8:
case VT_VECTOR | VT_CY:
case VT_VECTOR | VT_DATE:
case VT_VECTOR | VT_FILETIME:
AssertLongLongVector(cah); // VT_I8
AssertLongLongVector(cauh); // VT_UI8
AssertLongLongVector(cadbl); // VT_R8
AssertLongLongVector(cacy); // VT_CY
AssertLongLongVector(cadate); // VT_DATE
AssertLongLongVector(cafiletime); // VT_FILETIME
cbElement = sizeof(cah.pElems[0]);
break;
case VT_VECTOR | VT_CLSID:
AssertVarVector(cauuid, sizeof(GUID));
cbElement = sizeof(GUID);
fZero = TRUE;
break;
case VT_VECTOR | VT_CF:
AssertVarVector(caclipdata, sizeof(CLIPDATA)); // VT_CF
cbElement = sizeof(CLIPDATA);
fZero = TRUE;
break;
case VT_VECTOR | VT_BSTR:
case VT_VECTOR | VT_LPSTR:
case VT_VECTOR | VT_LPWSTR:
AssertStringVector(calpwstr); // VT_LPWSTR
AssertStringVector(cabstr); // VT_BSTR
AssertStringVector(calpstr); // VT_LPSTR
cbElement = sizeof(VOID *);
fZero = TRUE;
break;
case VT_VECTOR | VT_VARIANT:
AssertVarVector(capropvar, sizeof(PROPVARIANT)); // VT_VARIANT
cbElement = sizeof(PROPVARIANT);
ASSERT(VT_EMPTY == 0);
fZero = TRUE;
break;
default:
ASSERT(!"CAllocStorageVariant -- Invalid vector type");
vt = VT_EMPTY;
break;
}
if (vt != VT_EMPTY)
{
caub.cElems = 0;
caub.pElems = (BYTE *) ma.Allocate(cElements * cbElement);
if (caub.pElems != NULL)
{
if (fZero)
{
memset(caub.pElems, 0, cElements * cbElement);
}
caub.cElems = cElements;
}
}
}
#define POINTER_FIXUP(type, field) \
field.pElems = (type *) ma.Allocate(field.cElems * sizeof(field.pElems[0]));\
if (field.pElems != NULL) \
{ \
memcpy( \
field.pElems, \
var.field.pElems, \
field.cElems * sizeof(field.pElems[0])); \
}
CAllocStorageVariant::CAllocStorageVariant(
PROPVARIANT& var,
PMemoryAllocator &ma): CBaseStorageVariant(var)
{
BOOLEAN fNoMemory = FALSE;
ULONG i;
//
// Fixup any pointers
//
switch (vt)
{
case VT_EMPTY:
case VT_NULL:
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_BOOL:
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_ERROR:
case VT_I8:
case VT_UI8:
case VT_R8:
case VT_INT:
case VT_UINT:
case VT_DECIMAL:
case VT_CY:
case VT_DATE:
case VT_FILETIME:
break;
case VT_CLSID:
vt = VT_EMPTY;
SetCLSID(var.puuid, ma);
break;
case VT_BLOB:
case VT_BLOB_OBJECT:
blob.pBlobData = (BYTE *) ma.Allocate(blob.cbSize);
if (blob.pBlobData == NULL)
{
fNoMemory = TRUE;
break;
}
memcpy(blob.pBlobData, var.blob.pBlobData, blob.cbSize);
break;
case VT_CF:
pclipdata = (CLIPDATA *) ma.Allocate(sizeof(*pclipdata));
if (pclipdata == NULL)
{
fNoMemory = TRUE;
break;
}
*pclipdata = *var.pclipdata;
pclipdata->pClipData = (BYTE *) ma.Allocate(CBPCLIPDATA(*pclipdata));
if (pclipdata->pClipData == NULL)
{
fNoMemory = TRUE;
break;
}
memcpy(pclipdata->pClipData, var.pclipdata->pClipData, CBPCLIPDATA(*pclipdata));
break;
case VT_STREAM:
case VT_VERSIONED_STREAM:
case VT_STREAMED_OBJECT:
pStream->AddRef();
break;
case VT_STORAGE:
case VT_STORED_OBJECT:
pStorage->AddRef();
break;
case VT_BSTR:
vt = VT_EMPTY;
SetBSTR(var.bstrVal, ma);
break;
case VT_LPSTR:
vt = VT_EMPTY;
SetLPSTR(var.pszVal, ma);
break;
case VT_LPWSTR:
vt = VT_EMPTY;
SetLPWSTR(var.pwszVal, ma);
break;
case VT_VECTOR | VT_I1:
case VT_VECTOR | VT_UI1:
POINTER_FIXUP(BYTE, caub);
break;
case VT_VECTOR | VT_I2:
case VT_VECTOR | VT_UI2:
case VT_VECTOR | VT_BOOL:
AssertShortVector(cai); // VT_I2
AssertShortVector(caui); // VT_UI2
AssertShortVector(cabool); // VT_BOOL
POINTER_FIXUP(short, cai);
break;
case VT_VECTOR | VT_I4:
case VT_VECTOR | VT_UI4:
case VT_VECTOR | VT_R4:
case VT_VECTOR | VT_ERROR:
AssertLongVector(cal); // VT_I4
AssertLongVector(caul); // VT_UI4
AssertLongVector(caflt); // VT_R4
AssertLongVector(cascode); // VT_ERROR
POINTER_FIXUP(long, cal);
break;
case VT_VECTOR | VT_I8:
case VT_VECTOR | VT_UI8:
case VT_VECTOR | VT_R8:
case VT_VECTOR | VT_CY:
case VT_VECTOR | VT_DATE:
case VT_VECTOR | VT_FILETIME:
AssertLongLongVector(cah); // VT_I8
AssertLongLongVector(cauh); // VT_UI8
AssertLongLongVector(cadbl); // VT_R8
AssertLongLongVector(cacy); // VT_CY
AssertLongLongVector(cadate); // VT_DATE
AssertLongLongVector(cafiletime); // VT_FILETIME
POINTER_FIXUP(LARGE_INTEGER, cah);
break;
case VT_VECTOR | VT_CLSID:
POINTER_FIXUP(CLSID, cauuid);
break;
case VT_VECTOR | VT_CF:
{
caclipdata.pElems = (CLIPDATA *)
ma.Allocate(caclipdata.cElems * sizeof(caclipdata.pElems[0]));
if (caclipdata.pElems == NULL)
{
fNoMemory = TRUE;
break;
}
memset(
caclipdata.pElems,
0,
caclipdata.cElems * sizeof(caclipdata.pElems[0]));
for (i = 0; i < caclipdata.cElems; i++)
{
caclipdata.pElems[i] = var.caclipdata.pElems[i];
caclipdata.pElems[i].pClipData = (BYTE *)
ma.Allocate(CBPCLIPDATA(caclipdata.pElems[i]));
if (caclipdata.pElems[i].pClipData == NULL)
{
fNoMemory = TRUE;
break;
}
memcpy(
caclipdata.pElems[i].pClipData,
var.caclipdata.pElems[i].pClipData,
CBPCLIPDATA(caclipdata.pElems[i]));
}
break;
}
case VT_VECTOR | VT_BSTR:
{
cabstr.pElems = (BSTR *)
ma.Allocate(cabstr.cElems * sizeof(cabstr.pElems[0]));
if (cabstr.pElems == NULL)
{
fNoMemory = TRUE;
break;
}
memset(cabstr.pElems, 0, cabstr.cElems * sizeof(cabstr.pElems[0]));
for (i = 0; i < cabstr.cElems; i++)
{
cabstr.pElems[i] = SysAllocString(var.cabstr.pElems[i]);
if (cabstr.pElems[i] == NULL)
{
fNoMemory = TRUE;
break;
}
}
break;
}
case VT_VECTOR | VT_LPSTR:
{
calpstr.pElems = (LPSTR *)
ma.Allocate(calpstr.cElems * sizeof(calpstr.pElems[0]));
if (calpstr.pElems == NULL)
{
fNoMemory = TRUE;
break;
}
memset(calpstr.pElems, 0, calpstr.cElems * sizeof(calpstr.pElems[0]));
for (i = 0; i < calpstr.cElems; i++)
{
unsigned cb = strlen(var.calpstr.pElems[i]) + 1;
calpstr.pElems[i] = (char *) ma.Allocate(cb);
if (calpstr.pElems[i] == NULL)
{
fNoMemory = TRUE;
break;
}
memcpy(calpstr.pElems[i], var.calpstr.pElems[i], cb);
}
break;
}
case VT_VECTOR | VT_LPWSTR:
{
calpwstr.pElems = (LPWSTR *)
ma.Allocate(calpwstr.cElems * sizeof(calpwstr.pElems[0]));
if (calpwstr.pElems == NULL)
{
fNoMemory = TRUE;
break;
}
memset(calpwstr.pElems, 0, calpwstr.cElems * sizeof(calpwstr.pElems[0]));
for (i = 0; i < calpwstr.cElems; i++)
{
unsigned cb = (wcslen(var.calpwstr.pElems[i]) + 1) * sizeof(WCHAR);
calpwstr.pElems[i] = (WCHAR *) ma.Allocate(cb);
if (calpwstr.pElems[i] == NULL)
{
fNoMemory = TRUE;
break;
}
memcpy(calpwstr.pElems[i], var.calpwstr.pElems[i], cb);
}
break;
}
case VT_VECTOR | VT_VARIANT:
capropvar.pElems = (PROPVARIANT *)
ma.Allocate(capropvar.cElems * sizeof(capropvar.pElems[0]));
if (capropvar.pElems == NULL)
{
fNoMemory = TRUE;
break;
}
ASSERT(VT_EMPTY == 0);
memset(
capropvar.pElems,
0,
capropvar.cElems * sizeof(capropvar.pElems[0]));
for (i = 0; i < capropvar.cElems; i++)
{
new (&capropvar.pElems[i]) CAllocStorageVariant(
var.capropvar.pElems[i],
ma);
if (!((CAllocStorageVariant *) &capropvar.pElems[i])->IsValid())
{
fNoMemory = TRUE;
break;
}
}
break;
case VT_ARRAY | VT_I4:
case VT_ARRAY | VT_UI1:
case VT_ARRAY | VT_I2:
case VT_ARRAY | VT_R4:
case VT_ARRAY | VT_R8:
case VT_ARRAY | VT_BOOL:
case VT_ARRAY | VT_ERROR:
case VT_ARRAY | VT_CY:
case VT_ARRAY | VT_DATE:
case VT_ARRAY | VT_I1:
case VT_ARRAY | VT_UI2:
case VT_ARRAY | VT_UI4:
case VT_ARRAY | VT_INT:
case VT_ARRAY | VT_UINT:
case VT_ARRAY | VT_DECIMAL:
case VT_ARRAY | VT_BSTR:
case VT_ARRAY | VT_VARIANT:
{
//
// avoid double delete of the source variant
//
parray = 0;
SAFEARRAY * pSaDst = 0;
if ( FAILED( SafeArrayCopy( var.parray, &pSaDst ) ) )
{
fNoMemory = TRUE;
break;
}
parray = pSaDst;
}
break;
default:
{
Win4Assert( !"Unexpected vt type" );
return;
}
}
if (fNoMemory || !IsValid())
{
ResetType(ma);
// We cannot raise in a non-unwindable constructor.
// Just return a PROPVARIANT guaranteed to look invalid.
vt = VT_LPSTR;
pszVal = NULL;
}
}
//+---------------------------------------------------------------------------
//
// Function: SaCreateAndCopy
//
// Synopsis: Creates a safearray & initializes it with source safearray.
//
// Arguments: [ma] - memory allocator to use
// [psaSrc] - source safearry
// [ppsaDst] - safearray to be created.
//
// Returns: TRUE - upon success
// FALSE - upon failure
//
// History: 5-10-97 mohamedn created
//
//----------------------------------------------------------------------------
BOOL SaCreateAndCopy( PMemoryAllocator &ma,
SAFEARRAY * psaSrc,
SAFEARRAY **ppsaDst )
{
ULONG cb = sizeof SAFEARRAY + ( ( 0 != psaSrc->cDims ?
(psaSrc->cDims-1) : 0) * sizeof SAFEARRAYBOUND );
Win4Assert( psaSrc->cDims > 0);
SAFEARRAY * psaDst = (SAFEARRAY *) ma.Allocate( cb );
if ( 0 == psaDst )
{
*ppsaDst = 0;
return FALSE;
}
RtlCopyMemory(psaDst, psaSrc, cb);
// reset fields and values
psaDst->fFeatures &= ~( FADF_AUTO | FADF_STATIC );
psaDst->cLocks = 1; // new safearray has lockcount of 1
psaDst->pvData = 0;
*ppsaDst = psaDst;
return TRUE;
} //SaCreateAndCopy
//+---------------------------------------------------------------------------
//
// Function: SaCreateData
//
// Synopsis: Creates/initializes SafeArray's data area
//
// Arguments: [ma] - memory allocator to use
// [vt] - variant type (VT_ARRAY assumed)
// [saSrc] - source safearry
// [saDst] - destination safearray.
// [fUseAllocatorOnly] - if TRUE, BSTRs are allocated using [ma]
//
// Returns: TRUE - upon success
// FALSE - upon failure
//
// History: 5-10-97 mohamedn created
//
//----------------------------------------------------------------------------
BOOL SaCreateData(
PVarAllocator & ma,
VARTYPE vt,
SAFEARRAY & saSrc,
SAFEARRAY & saDst,
BOOL fUseAllocatorOnly )
{
//
// Find out how much memory is needed for the array and allocate it.
//
unsigned cDataElements = SaCountElements(saSrc);
ULONG cb = cDataElements * saSrc.cbElements;
void * pv = ma.Allocate( cb );
if ( !pv )
return FALSE;
RtlZeroMemory( pv, cb );
switch (vt)
{
case VT_I4:
case VT_UI1:
case VT_I2:
case VT_R4:
case VT_R8:
case VT_BOOL:
case VT_ERROR:
case VT_CY:
case VT_DATE:
case VT_I1:
case VT_UI2:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_DECIMAL:
{
RtlCopyMemory( pv, saSrc.pvData, cb);
saDst.pvData = pv;
}
break;
case VT_BSTR:
{
BSTR *pBstrSrc = (BSTR *) saSrc.pvData;
BSTR *pBstrDst = (BSTR *) pv;
for ( unsigned i = 0; i < cDataElements; i++ )
{
Win4Assert( pBstrSrc[i] != 0 );
Win4Assert( pBstrDst[i] == 0 );
if ( fUseAllocatorOnly )
{
ULONG cbBstr = SysStringByteLen(pBstrSrc[i]) +
sizeof (ULONG) +
sizeof (WCHAR);
void * pv = ma.Allocate( cbBstr );
if ( 0 != pv )
{
BYTE * pbSrc = (BYTE *) pBstrSrc[i];
pbSrc -= sizeof ULONG;
RtlCopyMemory( pv, pbSrc, cbBstr);
pBstrDst[i] = (BSTR) ( (BYTE *) pv + sizeof ULONG );
pBstrDst[i] = (BSTR) ma.PointerToOffset( pBstrDst[i] );
}
}
else
{
pBstrDst[i] = SysAllocString(pBstrSrc[i]);
}
if ( 0 == pBstrDst[i] )
return FALSE;
}
saDst.pvData = pv;
}
break;
case VT_VARIANT:
{
CAllocStorageVariant *pVarntSrc = (CAllocStorageVariant *)saSrc.pvData;
CAllocStorageVariant *pVarntDst = (CAllocStorageVariant *)pv;
for ( unsigned i = 0; i < cDataElements; i++ )
{
Win4Assert( pVarntDst[i].vt == 0 );
if ( VT_BSTR == pVarntSrc[i].vt )
{
if ( fUseAllocatorOnly )
{
ULONG cbBstr = SysStringByteLen(pVarntSrc[i].bstrVal) +
sizeof (ULONG) +
sizeof (WCHAR);
void * pv = ma.Allocate( cbBstr );
if ( 0 != pv )
{
BYTE * pbSrc = (BYTE *) pVarntSrc[i].bstrVal;
pbSrc -= sizeof ULONG;
RtlCopyMemory( pv, pbSrc, cbBstr);
pVarntDst[i].bstrVal = (BSTR) ((BYTE *) pv + sizeof ULONG);
pVarntDst[i].bstrVal = (BSTR) ma.PointerToOffset( pVarntDst[i].bstrVal );
}
}
else
{
pVarntDst[i].bstrVal = SysAllocString(pVarntSrc[i].bstrVal);
}
if ( 0 == pVarntDst[i].bstrVal )
return FALSE;
pVarntDst[i].vt = VT_BSTR;
}
else if ( 0 != (pVarntSrc[i].vt & VT_ARRAY) )
{
SAFEARRAY * pSaSrc = pVarntSrc[i].parray;
SAFEARRAY * pSaDst = 0;
if ( !SaCreateAndCopy( ma, pSaSrc, &pSaDst ) )
return FALSE;
if ( !SaCreateData( ma,
pVarntSrc[i].vt & ~VT_ARRAY,
*pSaSrc,
*pSaDst,
fUseAllocatorOnly ) )
return FALSE;
pVarntDst[i].parray = (SAFEARRAY *) ma.PointerToOffset( pSaDst );
pVarntDst[i].vt = pVarntSrc[i].vt;
}
else
{
Win4Assert( pVarntSrc[i].vt != VT_VARIANT );
Win4Assert( pVarntSrc[i].vt != VT_LPWSTR );
Win4Assert( pVarntSrc[i].vt != VT_LPSTR );
Win4Assert( pVarntSrc[i].vt != VT_CLSID );
pVarntDst[i] = pVarntSrc[i];
}
}
saDst.pvData = pv;
}
break;
default:
ciDebugOut(( DEB_ERROR, "Unexpected SafeArray type: vt=%x\n", vt ) );
Win4Assert( !"Unexpected SafeArray Type" );
return FALSE;
}
saDst.pvData = (void *) ma.PointerToOffset( saDst.pvData );
return TRUE;
} //SaCreateData
//+---------------------------------------------------------------------------
//
// Function: SaComputeSize
//
// Synopsis: Computes the size of a safearray.
//
// Arguments: [vt] - variant type (VT_ARRAY assumed)
// [saSrc] - source safearry
//
// Returns: ULONG - number of bytes of memory needed to store safearray
//
// History: 5-01-98 AlanW Created
//
//----------------------------------------------------------------------------
ULONG SaComputeSize( VARTYPE vt,
SAFEARRAY & saSrc )
{
//
// get number of data elements in array and size of the header.
//
unsigned cDataElements = SaCountElements(saSrc);
Win4Assert( 0 != saSrc.cDims );
ULONG cb = sizeof (SAFEARRAY) +
(saSrc.cDims-1) * sizeof (SAFEARRAYBOUND) +
cDataElements * saSrc.cbElements;
cb = AlignBlock( cb, sizeof LONGLONG );
switch (vt)
{
case VT_I4:
case VT_UI1:
case VT_I2:
case VT_R4:
case VT_R8:
case VT_BOOL:
case VT_ERROR:
case VT_CY:
case VT_DATE:
case VT_I1:
case VT_UI2:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_DECIMAL:
break;
case VT_BSTR:
{
BSTR *pBstrSrc = (BSTR *) saSrc.pvData;
for ( unsigned i = 0; i < cDataElements; i++ )
{
Win4Assert( pBstrSrc[i] != 0 );
cb += AlignBlock( SysStringByteLen(pBstrSrc[i]) +
sizeof ULONG + sizeof WCHAR,
sizeof LONGLONG );
}
}
break;
case VT_VARIANT:
{
CAllocStorageVariant *pVarnt = (CAllocStorageVariant *)saSrc.pvData;
for ( unsigned i = 0; i < cDataElements; i++ )
{
if ( VT_BSTR == pVarnt[i].vt )
{
cb += AlignBlock( SysStringByteLen(pVarnt[i].bstrVal) +
sizeof ULONG + sizeof WCHAR,
sizeof LONGLONG );
}
else if ( 0 != (pVarnt[i].vt & VT_ARRAY) )
{
cb += AlignBlock( SaComputeSize( (pVarnt[i].vt & ~VT_ARRAY),
*pVarnt[i].parray),
sizeof LONGLONG );
}
else
{
Win4Assert( pVarnt[i].vt != VT_VARIANT );
}
}
}
break;
default:
ciDebugOut(( DEB_ERROR, "Unexpected SafeArray type: vt=%x\n", vt ) );
Win4Assert( !"Unexpected SafeArray Type" );
return 1;
}
return cb;
}
CAllocStorageVariant::~CAllocStorageVariant()
{
switch (vt)
{
case VT_EMPTY:
case VT_NULL:
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_BOOL:
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_ERROR:
case VT_I8:
case VT_UI8:
case VT_R8:
case VT_INT:
case VT_UINT:
case VT_DECIMAL:
case VT_CY:
case VT_DATE:
case VT_FILETIME:
break;
default:
ciDebugOut(( DEB_ERROR, "~CAllocStorageVariant -- Memory Leak: vt=%x\n", vt ) );
}
}
void
CAllocStorageVariant::ResetType(PMemoryAllocator &ma)
{
// The most typical case
if ( VT_EMPTY == vt )
return;
ULONG i;
if ((vt & VT_BYREF) == 0)
{
switch (vt)
{
case VT_EMPTY:
case VT_NULL:
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_BOOL:
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_ERROR:
case VT_I8:
case VT_UI8:
case VT_R8:
case VT_INT:
case VT_UINT:
case VT_DECIMAL:
case VT_CY:
case VT_DATE:
case VT_FILETIME:
break;
case VT_CLSID:
ma.Free(puuid);
break;
case VT_BLOB:
case VT_BLOB_OBJECT:
ma.Free(blob.pBlobData);
break;
case VT_CF:
if (pclipdata != NULL)
{
ma.Free(pclipdata->pClipData);
ma.Free(pclipdata);
}
break;
case VT_STREAM:
case VT_VERSIONED_STREAM:
case VT_STREAMED_OBJECT:
pStream->Release();
break;
case VT_STORAGE:
case VT_STORED_OBJECT:
pStorage->Release();
break;
case VT_BSTR:
SysFreeString(bstrVal);
break;
case VT_LPSTR:
case VT_LPWSTR:
AssertStringField(pszVal); // VT_LPSTR
AssertStringField(pwszVal); // VT_LPWSTR
ma.Free(pwszVal);
break;
case VT_VECTOR | VT_I1:
case VT_VECTOR | VT_UI1:
case VT_VECTOR | VT_I2:
case VT_VECTOR | VT_UI2:
case VT_VECTOR | VT_BOOL:
case VT_VECTOR | VT_I4:
case VT_VECTOR | VT_UI4:
case VT_VECTOR | VT_R4:
case VT_VECTOR | VT_ERROR:
case VT_VECTOR | VT_I8:
case VT_VECTOR | VT_UI8:
case VT_VECTOR | VT_R8:
case VT_VECTOR | VT_CY:
case VT_VECTOR | VT_DATE:
case VT_VECTOR | VT_FILETIME:
case VT_VECTOR | VT_CLSID:
AssertByteVector(cac); // VT_I1
AssertByteVector(caub); // VT_UI1
AssertShortVector(cai); // VT_I2
AssertShortVector(caui); // VT_UI2
AssertShortVector(cabool); // VT_BOOL
AssertLongVector(cal); // VT_I4
AssertLongVector(caul); // VT_UI4
AssertLongVector(caflt); // VT_R4
AssertLongVector(cascode); // VT_ERROR
AssertLongLongVector(cah); // VT_I8
AssertLongLongVector(cauh); // VT_UI8
AssertLongLongVector(cadbl); // VT_R8
AssertLongLongVector(cacy); // VT_CY
AssertLongLongVector(cadate); // VT_DATE
AssertLongLongVector(cafiletime); // VT_FILETIME
AssertVarVector(cauuid, sizeof(GUID)); // VT_CLSID
ma.Free(cal.pElems);
break;
case VT_VECTOR | VT_CF:
if (caclipdata.pElems != NULL)
{
for (i = 0; i < caclipdata.cElems; i++)
{
ma.Free(caclipdata.pElems[i].pClipData);
}
ma.Free(caclipdata.pElems);
}
break;
case VT_VECTOR | VT_LPSTR:
case VT_VECTOR | VT_LPWSTR:
AssertStringVector(calpwstr); // VT_LPWSTR
AssertStringVector(calpstr); // VT_LPSTR
if (calpwstr.pElems != NULL)
{
for (i = 0; i < calpwstr.cElems; i++)
{
if (calpstr.pElems[i] != NULL) // don't free (NULL - cbbstr)
{
ma.Free((BYTE *) calpstr.pElems[i] );
}
}
ma.Free(calpwstr.pElems);
}
break;
case VT_VECTOR | VT_BSTR:
AssertStringVector(cabstr); // VT_BSTR
if (cabstr.pElems != NULL )
{
for (i = 0; i < cabstr.cElems; i++)
{
SysFreeString(cabstr.pElems[i]);
}
ma.Free(cabstr.pElems);
}
break;
case VT_VECTOR | VT_VARIANT:
if (capropvar.pElems != NULL)
{
for (i = 0; i < calpstr.cElems; i++)
{
((CAllocStorageVariant *) &capropvar.pElems[i])->ResetType(ma);
}
ma.Free(capropvar.pElems);
}
break;
case VT_ARRAY | VT_I4:
case VT_ARRAY | VT_UI1:
case VT_ARRAY | VT_I2:
case VT_ARRAY | VT_R4:
case VT_ARRAY | VT_R8:
case VT_ARRAY | VT_BOOL:
case VT_ARRAY | VT_ERROR:
case VT_ARRAY | VT_CY:
case VT_ARRAY | VT_DATE:
case VT_ARRAY | VT_I1:
case VT_ARRAY | VT_UI2:
case VT_ARRAY | VT_UI4:
case VT_ARRAY | VT_INT:
case VT_ARRAY | VT_UINT:
case VT_ARRAY | VT_DECIMAL:
case VT_ARRAY | VT_BSTR:
case VT_ARRAY | VT_VARIANT:
{
//
// What should we do if the array is locked?
// Perhaps just set cLocks to 0 so it can be freed.
// Note that we never hit the assert below because
// we deal with SafeArrays under our control so we
// know they won't be locked.
//
if ( 0 != parray )
{
Win4Assert( 0 == parray->cLocks );
HRESULT hr = SafeArrayDestroy( parray );
Win4Assert( S_OK == hr );
}
break;
}
default:
Win4Assert( !" Unexpected VT type" );
}
}
vt = VT_EMPTY;
}
// Invalid variants have a pointer type but a NULL pointer.
// Some are valid in this form in general, but not for many uses.
BOOL
CAllocStorageVariant::IsValid() const
{
ULONG i;
if ((VT_VECTOR & vt) && cal.cElems != 0 && cal.pElems == NULL)
{
return(FALSE);
}
switch (vt)
{
case VT_EMPTY:
case VT_NULL:
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_BOOL:
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_ERROR:
case VT_I8:
case VT_UI8:
case VT_INT:
case VT_UINT:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_FILETIME:
break;
case VT_DECIMAL:
return ( 0 == decVal.sign || DECIMAL_NEG == decVal.sign );
case VT_CLSID:
return(puuid != NULL);
case VT_BLOB:
case VT_BLOB_OBJECT:
return(blob.cbSize == 0 || blob.pBlobData != NULL);
case VT_CF:
return(pclipdata != NULL && pclipdata->pClipData != NULL);
case VT_STREAM:
case VT_VERSIONED_STREAM:
case VT_STREAMED_OBJECT:
return(pStream != NULL);
case VT_STORAGE:
case VT_STORED_OBJECT:
return(pStorage != NULL);
case VT_BSTR:
case VT_LPSTR:
case VT_LPWSTR:
AssertStringField(bstrVal); // VT_BSTR
AssertStringField(pszVal); // VT_LPSTR
AssertStringField(pwszVal); // VT_LPWSTR
return(pszVal != NULL);
case VT_VECTOR | VT_I1:
case VT_VECTOR | VT_UI1:
case VT_VECTOR | VT_I2:
case VT_VECTOR | VT_UI2:
case VT_VECTOR | VT_BOOL:
case VT_VECTOR | VT_I4:
case VT_VECTOR | VT_UI4:
case VT_VECTOR | VT_R4:
case VT_VECTOR | VT_ERROR:
case VT_VECTOR | VT_I8:
case VT_VECTOR | VT_UI8:
case VT_VECTOR | VT_R8:
case VT_VECTOR | VT_CY:
case VT_VECTOR | VT_DATE:
case VT_VECTOR | VT_FILETIME:
case VT_VECTOR | VT_CLSID:
AssertByteVector(cac); // VT_I1
AssertByteVector(caub); // VT_UI1
AssertShortVector(cai); // VT_I2
AssertShortVector(caui); // VT_UI2
AssertShortVector(cabool); // VT_BOOL
AssertLongVector(cal); // VT_I4
AssertLongVector(caul); // VT_UI4
AssertLongVector(caflt); // VT_R4
AssertLongVector(cascode); // VT_ERROR
AssertLongLongVector(cah); // VT_I8
AssertLongLongVector(cauh); // VT_UI8
AssertLongLongVector(cadbl); // VT_R8
AssertLongLongVector(cacy); // VT_CY
AssertLongLongVector(cadate); // VT_DATE
AssertLongLongVector(cafiletime); // VT_FILETIME
AssertVarVector(cauuid, sizeof(GUID)); // VT_CLSID
break;
case VT_VECTOR | VT_CF:
for (i = 0; i < caclipdata.cElems; i++)
{
if (caclipdata.pElems[i].pClipData == NULL)
{
return(FALSE);
}
}
case VT_VECTOR | VT_BSTR:
case VT_VECTOR | VT_LPSTR:
case VT_VECTOR | VT_LPWSTR:
AssertStringVector(calpwstr); // VT_LPWSTR
AssertStringVector(cabstr); // VT_BSTR
AssertStringVector(calpstr); // VT_LPSTR
for (i = 0; i < calpstr.cElems; i++)
{
if (calpstr.pElems[i] == NULL)
{
return(FALSE);
}
}
break;
case VT_VECTOR | VT_VARIANT:
for (i = 0; i < capropvar.cElems; i++)
{
if (!((CAllocStorageVariant *) &capropvar.pElems[i])->IsValid())
{
return(FALSE);
}
}
break;
case VT_ARRAY | VT_I4:
case VT_ARRAY | VT_UI1:
case VT_ARRAY | VT_I2:
case VT_ARRAY | VT_R4:
case VT_ARRAY | VT_R8:
case VT_ARRAY | VT_BOOL:
case VT_ARRAY | VT_ERROR:
case VT_ARRAY | VT_CY:
case VT_ARRAY | VT_DATE:
case VT_ARRAY | VT_I1:
case VT_ARRAY | VT_UI2:
case VT_ARRAY | VT_UI4:
case VT_ARRAY | VT_INT:
case VT_ARRAY | VT_UINT:
case VT_ARRAY | VT_BSTR:
case VT_ARRAY | VT_DECIMAL:
case VT_ARRAY | VT_VARIANT:
{
SAFEARRAY *pSa = parray;
if ( 0 == pSa )
return FALSE;
if ( !(pSa->cDims && pSa->pvData) )
return FALSE;
// validate all the bstrs are allocated
if ( ( VT_BSTR | VT_ARRAY ) == vt )
{
unsigned cDataElements = SaCountElements(*pSa);
BSTR *pBstr = (BSTR *)pSa->pvData;
for ( i = 0; i < cDataElements; i++ )
if ( 0 == pBstr[i] )
return FALSE;
}
if ( ( VT_VARIANT | VT_ARRAY ) == vt )
{
unsigned cDataElements = SaCountElements(*pSa);
CAllocStorageVariant *pVarnt = (CAllocStorageVariant *)pSa->pvData;
for ( i = 0; i < cDataElements; i++ )
if ( ! pVarnt[i].IsValid() )
return FALSE;
}
}
break;
case VT_BYREF | VT_I2:
case VT_BYREF | VT_I4:
case VT_BYREF | VT_R4:
case VT_BYREF | VT_R8:
case VT_BYREF | VT_CY:
case VT_BYREF | VT_DATE:
case VT_BYREF | VT_ERROR:
case VT_BYREF | VT_BOOL:
case VT_BYREF | VT_I1:
case VT_BYREF | VT_UI1:
case VT_BYREF | VT_UI2:
case VT_BYREF | VT_UI4:
case VT_BYREF | VT_INT:
case VT_BYREF | VT_UINT:
return (piVal != 0);
case VT_BYREF | VT_BSTR:
return ( pbstrVal != 0 && *pbstrVal != 0 );
case VT_BYREF | VT_DECIMAL:
return ( pdecVal != 0 &&
( 0 == pdecVal->sign || DECIMAL_NEG == pdecVal->sign ) );
case VT_BYREF | VT_VARIANT:
return ( pvarVal != 0 && pvarVal->vt != (VT_BYREF|VT_VARIANT) &&
((CAllocStorageVariant*)pvarVal)->IsValid() );
default:
ASSERT(!"CAllocStorageVariant::IsValid -- Invalid variant type");
return FALSE;
}
return TRUE;
}
CAllocStorageVariant::CAllocStorageVariant(
PDeSerStream& stm,
PMemoryAllocator &ma)
{
Unmarshall(stm, *((PROPVARIANT *)this), ma);
}
#define VECTOR_SET_BODY(type, vtype, val, aval) \
\
void CAllocStorageVariant::Set##vtype( \
type val, \
unsigned pos, \
PMemoryAllocator &ma) \
{ \
if (vt != ( VT_##vtype | VT_VECTOR ) ) \
{ \
ResetType(ma); \
new (this) CAllocStorageVariant(VT_##vtype, pos, ma); \
} \
\
if (pos >= cai.cElems) \
{ \
type *pTemp = aval.pElems; \
aval.pElems = (type *) ma.Allocate( (pos+1) * sizeof(aval.pElems[0]));\
if (aval.pElems != NULL) \
{ \
memcpy(aval.pElems, pTemp, aval.cElems * sizeof(aval.pElems[0])); \
memset( \
&aval.pElems[aval.cElems], \
0, \
(( pos+1 ) - aval.cElems) * sizeof(aval.pElems[0])); \
aval.pElems[pos] = val; \
aval.cElems = pos+1; \
ma.Free(pTemp); \
} \
} \
else \
{ \
aval.pElems[pos] = val; \
} \
}
#define VECTOR_GET_BODY(type, vtype, aval, nullval) \
\
type CAllocStorageVariant::Get##vtype(unsigned pos) const \
{ \
if (vt == (VT_##vtype | VT_VECTOR) && pos < aval.cElems) \
{ \
return(aval.pElems[pos]); \
} \
return(nullval); \
}
VECTOR_SET_BODY(CHAR, I1, i, cac)
VECTOR_GET_BODY(CHAR, I1, cac, 0)
VECTOR_SET_BODY(BYTE, UI1, ui, caub)
VECTOR_GET_BODY(BYTE, UI1, caub, 0)
VECTOR_SET_BODY(short, I2, i, cai)
VECTOR_GET_BODY(short, I2, cai, 0)
VECTOR_SET_BODY(USHORT, UI2, ui, caui)
VECTOR_GET_BODY(USHORT, UI2, caui, 0)
VECTOR_SET_BODY(long, I4, l, cal)
VECTOR_GET_BODY(long, I4, cal, 0)
VECTOR_SET_BODY(ULONG, UI4, ul, caul)
VECTOR_GET_BODY(ULONG, UI4, caul, 0)
VECTOR_SET_BODY(SCODE, ERROR, scode, cascode)
VECTOR_GET_BODY(SCODE, ERROR, cascode, 0)
static LARGE_INTEGER const liZero = { 0, 0 };
VECTOR_SET_BODY(LARGE_INTEGER, I8, li, cah)
VECTOR_GET_BODY(LARGE_INTEGER, I8, cah, liZero)
static ULARGE_INTEGER const uliZero = { 0, 0 };
VECTOR_SET_BODY(ULARGE_INTEGER, UI8, uli, cauh)
VECTOR_GET_BODY(ULARGE_INTEGER, UI8, cauh, uliZero)
VECTOR_SET_BODY(float, R4, f, caflt)
VECTOR_GET_BODY(float, R4, caflt, (float)0.0)
VECTOR_SET_BODY(double, R8, d, cadbl)
VECTOR_GET_BODY(double, R8, cadbl, 0.0)
VECTOR_SET_BODY(VARIANT_BOOL, BOOL, b, cabool)
VECTOR_GET_BODY(VARIANT_BOOL, BOOL, cabool, FALSE)
static CY const cyZero = { 0, 0 };
VECTOR_SET_BODY(CY, CY, cy, cacy)
VECTOR_GET_BODY(CY, CY, cacy, cyZero)
VECTOR_SET_BODY(DATE, DATE, d, cadate)
VECTOR_GET_BODY(DATE, DATE, cadate, 0.0)
BOOLEAN
CAllocStorageVariant::_AddStringToVector(
unsigned pos,
VOID *pv,
ULONG cb,
PMemoryAllocator &ma)
{
ASSERT(vt == (VT_VECTOR | VT_BSTR) ||
vt == (VT_VECTOR | VT_LPSTR) ||
vt == (VT_VECTOR | VT_LPWSTR));
ASSERT(calpstr.pElems != NULL);
if (pos >= calpstr.cElems)
{
char **ppsz = calpstr.pElems;
calpstr.pElems =
(char **) ma.Allocate((pos + 1) * sizeof(calpstr.pElems[0]));
if (calpstr.pElems == NULL)
{
calpstr.pElems = ppsz;
return(FALSE);
}
memcpy(calpstr.pElems, ppsz, calpstr.cElems * sizeof(calpstr.pElems[0]));
memset(
&calpstr.pElems[calpstr.cElems],
0,
((pos + 1) - calpstr.cElems) * sizeof(calpstr.pElems[0]));
calpstr.cElems = pos + 1;
ma.Free(ppsz);
}
if ( vt == (VT_VECTOR|VT_BSTR) )
{
BSTR bstrVal = SysAllocString( (OLECHAR *)pv );
if (bstrVal == NULL)
{
return (FALSE);
}
if ( cabstr.pElems[pos] != NULL )
{
SysFreeString(cabstr.pElems[pos]);
}
cabstr.pElems[pos] = bstrVal;
}
else
{
char *psz = (char *) ma.Allocate(cb);
if (psz == NULL)
{
return(FALSE);
}
memcpy(psz, pv, cb);
if (calpstr.pElems[pos] != NULL)
{
ma.Free(calpstr.pElems[pos]);
}
calpstr.pElems[pos] = psz;
}
return(TRUE);
}
void
CAllocStorageVariant::SetBSTR(BSTR b, PMemoryAllocator &ma)
{
ResetType(ma);
vt = VT_BSTR;
bstrVal = SysAllocString(b);
}
void
CAllocStorageVariant::SetBSTR(
BSTR b,
unsigned pos,
PMemoryAllocator &ma)
{
if (vt != (VT_VECTOR | VT_BSTR))
{
ResetType(ma);
new (this) CAllocStorageVariant(VT_BSTR, pos, ma);
}
_AddStringToVector(
pos,
b,
-1, // not used, pass an invalid value to detect failure.
ma);
}
void
CAllocStorageVariant::SetLPSTR(
char const *psz,
unsigned pos,
PMemoryAllocator &ma)
{
if (vt != (VT_VECTOR | VT_LPSTR))
{
ResetType(ma);
new (this) CAllocStorageVariant(VT_LPSTR, pos, ma);
}
_AddStringToVector(pos, (VOID *) psz, strlen(psz) + 1, ma);
}
void
CAllocStorageVariant::SetLPWSTR(
WCHAR const *pwsz,
unsigned pos,
PMemoryAllocator &ma)
{
if (vt != (VT_VECTOR | VT_LPWSTR))
{
ResetType(ma);
new (this) CAllocStorageVariant(VT_LPWSTR, pos, ma);
}
_AddStringToVector(
pos,
(VOID *) pwsz,
(wcslen(pwsz) + 1) * sizeof(WCHAR),
ma);
}
VECTOR_GET_BODY(char *, LPSTR, calpstr, 0);
VECTOR_GET_BODY(WCHAR *, LPWSTR, calpwstr, 0);
static FILETIME const fiZero = { 0, 0 };
VECTOR_SET_BODY(FILETIME, FILETIME, ft, cafiletime)
VECTOR_GET_BODY(FILETIME, FILETIME, cafiletime, fiZero)
static CLSID const guidZero =
{
0x00000000,
0x0000,
0x0000,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
VECTOR_SET_BODY(CLSID, CLSID, c, cauuid)
VECTOR_GET_BODY(CLSID, CLSID, cauuid, guidZero)
#endif //ifndef _NTDLLBUILD_