Implemented support for arrays and safe arrays in VARIANT data

structures. Also moved the SAFEARRAY definition (yet again) to the
obj_oleaut.h file.
oldstable
Francis Beaudet 1999-02-28 10:07:12 +00:00 committed by Alexandre Julliard
parent 11db496578
commit bc5477f7d2
4 changed files with 270 additions and 209 deletions

View File

@ -7,38 +7,6 @@
/* the following depend only on obj_base.h */
#include "wine/obj_oleaut.h"
/*****************************************************************
* SafeArray defines and structs
*/
#define FADF_AUTO ( 0x1 )
#define FADF_STATIC ( 0x2 )
#define FADF_EMBEDDED ( 0x4 )
#define FADF_FIXEDSIZE ( 0x10 )
#define FADF_BSTR ( 0x100 )
#define FADF_UNKNOWN ( 0x200 )
#define FADF_DISPATCH ( 0x400 )
#define FADF_VARIANT ( 0x800 )
#define FADF_RESERVED ( 0xf0e8 )
typedef struct tagSAFEARRAYBOUND
{
ULONG cElements; /* Number of elements in dimension */
LONG lLbound; /* Lower bound of dimension */
} SAFEARRAYBOUND;
typedef struct tagSAFEARRAY
{
USHORT cDims; /* Count of array dimension */
USHORT fFeatures; /* Flags describing the array */
ULONG cbElements; /* Size of each element */
ULONG cLocks; /* Number of lock on array */
PVOID pvData; /* Pointer to data valid when cLocks > 0 */
SAFEARRAYBOUND rgsabound[ 1 ]; /* One bound for each dimension */
} SAFEARRAY, *LPSAFEARRAY;
typedef enum tagCALLCONV {
CC_CDECL = 1,
CC_MSCPASCAL = CC_CDECL + 1,

View File

@ -65,6 +65,37 @@ typedef struct ISupportErrorInfo ISupportErrorInfo,*LPSUPPORTERRORINFO;
* Automation data types
*/
/*****************************************************************
* SafeArray defines and structs
*/
#define FADF_AUTO ( 0x1 )
#define FADF_STATIC ( 0x2 )
#define FADF_EMBEDDED ( 0x4 )
#define FADF_FIXEDSIZE ( 0x10 )
#define FADF_BSTR ( 0x100 )
#define FADF_UNKNOWN ( 0x200 )
#define FADF_DISPATCH ( 0x400 )
#define FADF_VARIANT ( 0x800 )
#define FADF_RESERVED ( 0xf0e8 )
typedef struct tagSAFEARRAYBOUND
{
ULONG cElements; /* Number of elements in dimension */
LONG lLbound; /* Lower bound of dimension */
} SAFEARRAYBOUND;
typedef struct tagSAFEARRAY
{
USHORT cDims; /* Count of array dimension */
USHORT fFeatures; /* Flags describing the array */
ULONG cbElements; /* Size of each element */
ULONG cLocks; /* Number of lock on array */
PVOID pvData; /* Pointer to data valid when cLocks > 0 */
SAFEARRAYBOUND rgsabound[ 1 ]; /* One bound for each dimension */
} SAFEARRAY, *LPSAFEARRAY;
/*
* Data types for Variants.
*/
@ -175,8 +206,8 @@ struct tagVARIANT {
DECIMAL decVal;
IUnknown* punkVal;
IDispatch* pdispVal;
SAFEARRAY* parray;
*/
SAFEARRAY* parray;
/* By reference
*/
@ -201,8 +232,8 @@ struct tagVARIANT {
DECIMAL* pdecVal;
IUnknown** ppunkVal;
IDispatch** ppdispVal;
SAFEARRAY** pparray;
*/
SAFEARRAY** pparray;
} _wine_tagVARIANT_UNION_NAME;
};

View File

@ -387,6 +387,13 @@ HRESULT WINAPI SafeArrayGetLBound(
UINT WINAPI SafeArrayGetDim(
SAFEARRAY * psa)
{
/*
* A quick test in Windows shows that the behavior here for an invalid
* pointer is to return 0.
*/
if(! validArg(psa))
return 0;
return psa->cDims;
}
@ -396,6 +403,13 @@ UINT WINAPI SafeArrayGetDim(
UINT WINAPI SafeArrayGetElemsize(
SAFEARRAY * psa)
{
/*
* A quick test in Windows shows that the behavior here for an invalid
* pointer is to return 0.
*/
if(! validArg(psa))
return 0;
return psa->cbElements;
}
@ -728,6 +742,12 @@ static BOOL validArg(
LONG descSize = 0;
LONG fullSize = 0;
/*
* Let's check for the null pointer just in case.
*/
if (psa == NULL)
return FALSE;
/* Check whether the size of the chunk make sens... That's the only thing
I can think of now... */

View File

@ -1644,14 +1644,12 @@ static HRESULT WINAPI ValidateVt( VARTYPE vt )
*/
void WINAPI VariantInit(VARIANTARG* pvarg)
{
TRACE(ole,"(%p),stub\n",pvarg);
TRACE(ole,"(%p),stub\n",pvarg);
pvarg->vt = VT_EMPTY;
pvarg->wReserved1 = 0;
pvarg->wReserved2= 0;
pvarg->wReserved3= 0;
memset(pvarg, 0, sizeof (VARIANTARG));
pvarg->vt = VT_EMPTY;
return;
return;
}
/******************************************************************************
@ -1664,41 +1662,51 @@ void WINAPI VariantInit(VARIANTARG* pvarg)
*/
HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
{
HRESULT res = S_OK;
TRACE(ole,"(%p),stub\n",pvarg);
HRESULT res = S_OK;
TRACE(ole,"(%p)\n",pvarg);
res = ValidateVariantType( pvarg->vt );
if( res == S_OK )
res = ValidateVariantType( pvarg->vt );
if( res == S_OK )
{
if( !( pvarg->vt & VT_BYREF ) )
{
/*
* The VT_ARRAY flag is a special case of a safe array.
*/
if ( (pvarg->vt & VT_ARRAY) != 0)
{
SafeArrayDestroy(pvarg->u.parray);
}
else
{
switch( pvarg->vt & VT_TYPEMASK )
{
if( !( pvarg->vt & VT_BYREF ) )
{
switch( pvarg->vt & VT_TYPEMASK )
{
case( VT_BSTR ):
SysFreeString( pvarg->u.bstrVal );
break;
case( VT_DISPATCH ):
break;
case( VT_VARIANT ):
break;
case( VT_UNKNOWN ):
break;
case( VT_SAFEARRAY ):
break;
default:
break;
}
}
/* Set the fields to empty.
*/
pvarg->wReserved1 = 0;
pvarg->wReserved2 = 0;
pvarg->wReserved3 = 0;
pvarg->vt = VT_EMPTY;
case( VT_BSTR ):
SysFreeString( pvarg->u.bstrVal );
break;
case( VT_DISPATCH ):
break;
case( VT_VARIANT ):
break;
case( VT_UNKNOWN ):
break;
case( VT_SAFEARRAY ):
SafeArrayDestroy(pvarg->u.parray);
break;
default:
break;
}
}
}
/*
* Empty all the fields and mark the type as empty.
*/
memset(pvarg, 0, sizeof (VARIANTARG));
pvarg->vt = VT_EMPTY;
}
return res;
return res;
}
/******************************************************************************
@ -1708,59 +1716,72 @@ HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
*/
HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
{
HRESULT res = S_OK;
TRACE(ole,"(%p, %p),stub\n", pvargDest, pvargSrc);
HRESULT res = S_OK;
res = ValidateVariantType( pvargSrc->vt );
/* If the pointer are to the same variant we don't need
* to do anything.
TRACE(ole,"(%p, %p)\n", pvargDest, pvargSrc);
res = ValidateVariantType( pvargSrc->vt );
/* If the pointer are to the same variant we don't need
* to do anything.
*/
if( pvargDest != pvargSrc && res == S_OK )
{
res = VariantClear( pvargDest );
if( res == S_OK )
{
if( pvargSrc->vt & VT_BYREF )
{
/* In the case of byreference we only need
* to copy the pointer.
*/
if( pvargDest != pvargSrc && res == S_OK )
pvargDest->u = pvargSrc->u;
pvargDest->vt = pvargSrc->vt;
}
else
{
/*
* The VT_ARRAY flag is another way to designate a safe array.
*/
if (pvargSrc->vt & VT_ARRAY)
{
res = VariantClear( pvargDest );
if( res == S_OK )
{
if( pvargSrc->vt & VT_BYREF )
{
/* In the case of byreference we only need
* to copy the pointer.
*/
pvargDest->u = pvargSrc->u;
pvargDest->vt = pvargSrc->vt;
}
else
{
/* In the case of by value we need to
* copy the actuall value. In the case of
* VT_BSTR a copy of the string is made,
* if VT_ARRAY the entire array is copied
* if VT_DISPATCH or VT_IUNKNOWN AddReff is
* called to increment the object's reference count.
*/
switch( pvargSrc->vt & VT_TYPEMASK )
{
case( VT_BSTR ):
pvargDest->u.bstrVal = SysAllocString( pvargSrc->u.bstrVal );
break;
case( VT_DISPATCH ):
break;
case( VT_VARIANT ):
break;
case( VT_UNKNOWN ):
break;
case( VT_SAFEARRAY ):
break;
default:
pvargDest->u = pvargSrc->u;
break;
}
pvargDest->vt = pvargSrc->vt;
}
}
SafeArrayCopy(pvargSrc->u.parray, &pvargDest->u.parray);
}
return res;
else
{
/* In the case of by value we need to
* copy the actuall value. In the case of
* VT_BSTR a copy of the string is made,
* if VT_DISPATCH or VT_IUNKNOWN AddReff is
* called to increment the object's reference count.
*/
switch( pvargSrc->vt & VT_TYPEMASK )
{
case( VT_BSTR ):
pvargDest->u.bstrVal = SysAllocString( pvargSrc->u.bstrVal );
break;
case( VT_DISPATCH ):
break;
case( VT_VARIANT ):
break;
case( VT_UNKNOWN ):
break;
case( VT_SAFEARRAY ):
SafeArrayCopy(pvargSrc->u.parray, &pvargDest->u.parray);
break;
default:
pvargDest->u = pvargSrc->u;
break;
}
}
pvargDest->vt = pvargSrc->vt;
}
}
}
return res;
}
@ -1772,101 +1793,122 @@ HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
*/
HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
{
HRESULT res = S_OK;
TRACE(ole,"(%p, %p),stub\n", pvargDest, pvargSrc);
HRESULT res = S_OK;
res = ValidateVariantType( pvargSrc->vt );
if( res != S_OK )
return res;
if( pvargSrc->vt & VT_BYREF )
TRACE(ole,"(%p, %p)\n", pvargDest, pvargSrc);
res = ValidateVariantType( pvargSrc->vt );
if( res != S_OK )
return res;
if( pvargSrc->vt & VT_BYREF )
{
VARIANTARG varg;
VariantInit( &varg );
/* handle the in place copy.
*/
if( pvargDest == pvargSrc )
{
/* we will use a copy of the source instead.
*/
res = VariantCopy( &varg, pvargSrc );
pvargSrc = &varg;
}
if( res == S_OK )
{
res = VariantClear( pvargDest );
if( res == S_OK )
{
/*
* The VT_ARRAY flag is another way to designate a safearray variant.
*/
if ( pvargSrc->vt & VT_ARRAY)
{
VARIANTARG varg;
VariantInit( &varg );
/* handle the in place copy.
*/
if( pvargDest == pvargSrc )
{
/* we will use a copy of the source instead.
*/
res = VariantCopy( &varg, pvargSrc );
pvargSrc = &varg;
}
if( res == S_OK )
{
res = VariantClear( pvargDest );
if( res == S_OK )
{
/* In the case of by reference we need
* to copy the date pointed to by the variant.
*/
/* Get the variant type.
*/
switch( pvargSrc->vt & VT_TYPEMASK )
{
case( VT_BSTR ):
pvargDest->u.bstrVal = SysAllocString( *(pvargSrc->u.pbstrVal) );
break;
case( VT_DISPATCH ):
break;
case( VT_VARIANT ):
{
/* Prevent from cycling. According to tests on
* VariantCopyInd in Windows and the documentation
* this API dereferences the inner Variants to only one depth.
* If the inner Variant itself contains an
* other inner variant the E_INVALIDARG error is
* returned.
*/
if( pvargSrc->wReserved1 & PROCESSING_INNER_VARIANT )
{
/* If we get here we are attempting to deference
* an inner variant that that is itself contained
* in an inner variant so report E_INVALIDARG error.
*/
res = E_INVALIDARG;
}
else
{
/* Set the processing inner variant flag.
* We will set this flag in the inner variant
* that will be passed to the VariantCopyInd function.
*/
(pvargSrc->u.pvarVal)->wReserved1 |= PROCESSING_INNER_VARIANT;
/* Dereference the inner variant.
*/
res = VariantCopyInd( pvargDest, pvargSrc->u.pvarVal );
}
}
break;
case( VT_UNKNOWN ):
break;
case( VT_SAFEARRAY ):
break;
default:
/* This is a by reference Variant which means that the union
* part of the Variant contains a pointer to some data of
* type "pvargSrc->vt & VT_TYPEMASK".
* We will deference this data in a generic fashion using
* the void pointer "Variant.u.byref".
* We will copy this data into the union of the destination
* Variant.
*/
memcpy( &pvargDest->u, pvargSrc->u.byref, SizeOfVariantData( pvargSrc ) );
break;
}
pvargDest->vt = pvargSrc->vt & VT_TYPEMASK;
}
}
/* this should not fail.
*/
VariantClear( &varg );
SafeArrayCopy(*pvargSrc->u.pparray, &pvargDest->u.parray);
}
else
{
res = VariantCopy( pvargDest, pvargSrc );
/* In the case of by reference we need
* to copy the date pointed to by the variant.
*/
/* Get the variant type.
*/
switch( pvargSrc->vt & VT_TYPEMASK )
{
case( VT_BSTR ):
pvargDest->u.bstrVal = SysAllocString( *(pvargSrc->u.pbstrVal) );
break;
case( VT_DISPATCH ):
break;
case( VT_VARIANT ):
{
/* Prevent from cycling. According to tests on
* VariantCopyInd in Windows and the documentation
* this API dereferences the inner Variants to only one depth.
* If the inner Variant itself contains an
* other inner variant the E_INVALIDARG error is
* returned.
*/
if( pvargSrc->wReserved1 & PROCESSING_INNER_VARIANT )
{
/* If we get here we are attempting to deference
* an inner variant that that is itself contained
* in an inner variant so report E_INVALIDARG error.
*/
res = E_INVALIDARG;
}
else
{
/* Set the processing inner variant flag.
* We will set this flag in the inner variant
* that will be passed to the VariantCopyInd function.
*/
(pvargSrc->u.pvarVal)->wReserved1 |= PROCESSING_INNER_VARIANT;
/* Dereference the inner variant.
*/
res = VariantCopyInd( pvargDest, pvargSrc->u.pvarVal );
}
}
break;
case( VT_UNKNOWN ):
break;
case( VT_SAFEARRAY ):
SafeArrayCopy(*pvargSrc->u.pparray, &pvargDest->u.parray);
break;
default:
/* This is a by reference Variant which means that the union
* part of the Variant contains a pointer to some data of
* type "pvargSrc->vt & VT_TYPEMASK".
* We will deference this data in a generic fashion using
* the void pointer "Variant.u.byref".
* We will copy this data into the union of the destination
* Variant.
*/
memcpy( &pvargDest->u, pvargSrc->u.byref, SizeOfVariantData( pvargSrc ) );
break;
}
}
return res;
pvargDest->vt = pvargSrc->vt & VT_TYPEMASK;
}
}
/* this should not fail.
*/
VariantClear( &varg );
}
else
{
res = VariantCopy( pvargDest, pvargSrc );
}
return res;
}
/******************************************************************************