Skip to content
Snippets Groups Projects
Commit bc5477f7 authored by Francis Beaudet's avatar Francis Beaudet Committed by Alexandre Julliard
Browse files

Implemented support for arrays and safe arrays in VARIANT data

structures. Also moved the SAFEARRAY definition (yet again) to the
obj_oleaut.h file.
parent 11db4965
No related branches found
No related tags found
No related merge requests found
......@@ -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,
......
......@@ -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;
};
......
......@@ -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... */
......
......@@ -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.
*/
pvargDest->u = pvargSrc->u;
pvargDest->vt = pvargSrc->vt;
}
else
{
/*
* The VT_ARRAY flag is another way to designate a safe array.
*/
if( pvargDest != pvargSrc && res == S_OK )
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.
SafeArrayCopy(*pvargSrc->u.pparray, &pvargDest->u.parray);
}
else
{
/* 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( pvargDest == pvargSrc )
if( pvargSrc->wReserved1 & PROCESSING_INNER_VARIANT )
{
/* we will use a copy of the source instead.
*/
res = VariantCopy( &varg, pvargSrc );
pvargSrc = &varg;
/* 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;
}
if( res == S_OK )
else
{
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;
}
/* 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 );
}
/* this should not fail.
*/
VariantClear( &varg );
}
else
{
res = VariantCopy( pvargDest, pvargSrc );
}
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;
}
/******************************************************************************
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment