2002-12-23 03:02:49 +01:00
/*
* SafeArray test program
*
* Copyright 2002 Marcus Meissner
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
2003-09-06 01:08:26 +02:00
# include <stdarg.h>
2002-12-23 03:02:49 +01:00
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <float.h>
# include <time.h>
# include "wine/test.h"
2003-09-06 01:08:26 +02:00
# include "windef.h"
2002-12-23 03:02:49 +01:00
# include "winbase.h"
# include "winuser.h"
# include "wingdi.h"
# include "winnls.h"
2003-09-06 01:08:26 +02:00
# include "winsock.h"
2002-12-23 03:02:49 +01:00
# include "winerror.h"
# include "winnt.h"
# include "wtypes.h"
# include "oleauto.h"
2003-12-15 22:11:25 +01:00
static HMODULE hOleaut32 ;
static HRESULT ( WINAPI * pSafeArrayAllocDescriptorEx ) ( VARTYPE , UINT , SAFEARRAY * * ) ;
static HRESULT ( WINAPI * pSafeArrayCopyData ) ( SAFEARRAY * , SAFEARRAY * ) ;
static HRESULT ( WINAPI * pSafeArrayGetIID ) ( SAFEARRAY * , GUID * ) ;
static HRESULT ( WINAPI * pSafeArraySetIID ) ( SAFEARRAY * , REFGUID ) ;
static HRESULT ( WINAPI * pSafeArrayGetVartype ) ( SAFEARRAY * , VARTYPE * ) ;
static SAFEARRAY * ( WINAPI * pSafeArrayCreateEx ) ( VARTYPE , UINT , SAFEARRAYBOUND * , LPVOID ) ;
# define GETPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func)
/* Is a given function exported from oleaut32? */
# define HAVE_FUNC(func) ((void*)GetProcAddress(hOleaut32, #func) != NULL)
/* Have IRecordInfo data type? */
# define HAVE_OLEAUT32_RECORD HAVE_FUNC(SafeArraySetRecordInfo)
/* Have I8/UI8 data type? */
# define HAVE_OLEAUT32_I8 HAVE_FUNC(VarI8FromI1)
# define START_REF_COUNT 1
# define RECORD_SIZE 64
# define RECORD_SIZE_FAIL 17
/************************************************************************
* Dummy IRecordInfo Implementation
*/
typedef struct IRecordInfoImpl
{
ICOM_VTABLE ( IRecordInfo ) * lpvtbl ;
DWORD ref ;
DWORD sizeCalled ;
DWORD clearCalled ;
} IRecordInfoImpl ;
static ICOM_VTABLE ( IRecordInfo ) IRecordInfoImpl_VTable ;
static IRecordInfoImpl * IRecordInfoImpl_Construct ( )
{
IRecordInfoImpl * rec ;
rec = HeapAlloc ( GetProcessHeap ( ) , 0 , sizeof ( IRecordInfoImpl ) ) ;
rec - > lpvtbl = & IRecordInfoImpl_VTable ;
rec - > ref = START_REF_COUNT ;
rec - > clearCalled = 0 ;
rec - > sizeCalled = 0 ;
return rec ;
}
static ULONG CALLBACK IRecordInfoImpl_AddRef ( IRecordInfo * iface )
{
ICOM_THIS ( IRecordInfoImpl , iface ) ;
return + + This - > ref ;
}
static ULONG CALLBACK IRecordInfoImpl_Release ( IRecordInfo * iface )
{
ICOM_THIS ( IRecordInfoImpl , iface ) ;
return - - This - > ref ;
}
static BOOL fail_GetSize ; /* Whether to fail the GetSize call */
static HRESULT CALLBACK IRecordInfoImpl_RecordClear ( IRecordInfo * iface , PVOID pvExisting WINE_UNUSED )
{
ICOM_THIS ( IRecordInfoImpl , iface ) ;
This - > clearCalled + + ;
return S_OK ;
}
static HRESULT CALLBACK IRecordInfoImpl_GetSize ( IRecordInfo * iface , ULONG * size )
{
ICOM_THIS ( IRecordInfoImpl , iface ) ;
This - > sizeCalled + + ;
* size = 17 ;
if ( fail_GetSize )
return E_UNEXPECTED ;
* size = RECORD_SIZE ;
return S_OK ;
}
static HRESULT CALLBACK IRecordInfoImpl_Dummy ( IRecordInfo * iface WINE_UNUSED )
{
trace ( " Called an unexpected IRecordInfo method - please report! \n " ) ;
/* Quit because we'll just crash anyway */
fflush ( NULL ) ;
exit ( 255 ) ;
}
static ICOM_VTABLE ( IRecordInfo ) IRecordInfoImpl_VTable =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
( PVOID ) IRecordInfoImpl_Dummy ,
IRecordInfoImpl_AddRef ,
IRecordInfoImpl_Release ,
( PVOID ) IRecordInfoImpl_Dummy ,
IRecordInfoImpl_RecordClear ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_GetSize ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy ,
( PVOID ) IRecordInfoImpl_Dummy
} ;
static DWORD SAFEARRAY_GetVTSize ( VARTYPE vt )
{
switch ( vt )
{
case VT_I1 :
case VT_UI1 : return sizeof ( BYTE ) ;
case VT_BOOL :
case VT_I2 :
case VT_UI2 : return sizeof ( SHORT ) ;
case VT_I4 :
case VT_UI4 :
case VT_R4 :
case VT_ERROR : return sizeof ( LONG ) ;
case VT_R8 :
case VT_I8 :
case VT_UI8 : return sizeof ( LONG64 ) ;
case VT_INT :
case VT_UINT : return sizeof ( INT ) ;
case VT_INT_PTR :
case VT_UINT_PTR : return sizeof ( UINT_PTR ) ;
case VT_CY : return sizeof ( CY ) ;
case VT_DATE : return sizeof ( DATE ) ;
case VT_BSTR : return sizeof ( BSTR ) ;
case VT_DISPATCH : return sizeof ( LPDISPATCH ) ;
case VT_VARIANT : return sizeof ( VARIANT ) ;
case VT_UNKNOWN : return sizeof ( LPUNKNOWN ) ;
case VT_DECIMAL : return sizeof ( DECIMAL ) ;
}
return 0 ;
}
2003-01-07 20:40:40 +01:00
2002-12-23 03:02:49 +01:00
# define VARTYPE_NOT_SUPPORTED 0
2003-01-03 00:13:56 +01:00
static struct {
2003-01-05 02:03:12 +01:00
VARTYPE vt ; /* VT */
2003-01-03 00:13:56 +01:00
UINT elemsize ; /* elementsize by VT */
UINT expflags ; /* fFeatures from SafeArrayAllocDescriptorEx */
UINT addflags ; /* additional fFeatures from SafeArrayCreate */
} vttypes [ ] = {
{ VT_EMPTY , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_NULL , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_I2 , 2 , FADF_HAVEVARTYPE , 0 } ,
{ VT_I4 , 4 , FADF_HAVEVARTYPE , 0 } ,
{ VT_R4 , 4 , FADF_HAVEVARTYPE , 0 } ,
{ VT_R8 , 8 , FADF_HAVEVARTYPE , 0 } ,
{ VT_CY , 8 , FADF_HAVEVARTYPE , 0 } ,
{ VT_DATE , 8 , FADF_HAVEVARTYPE , 0 } ,
{ VT_BSTR , sizeof ( BSTR ) , FADF_HAVEVARTYPE , FADF_BSTR } ,
{ VT_DISPATCH , sizeof ( LPDISPATCH ) , FADF_HAVEIID , FADF_DISPATCH } ,
{ VT_ERROR , 4 , FADF_HAVEVARTYPE , 0 } ,
{ VT_BOOL , 2 , FADF_HAVEVARTYPE , 0 } ,
{ VT_VARIANT , sizeof ( VARIANT ) , FADF_HAVEVARTYPE , FADF_VARIANT } ,
{ VT_UNKNOWN , sizeof ( LPUNKNOWN ) , FADF_HAVEIID , FADF_UNKNOWN } ,
{ VT_DECIMAL , sizeof ( DECIMAL ) , FADF_HAVEVARTYPE , 0 } ,
{ 15 , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } , /* no VT_xxx */
{ VT_I1 , 1 , FADF_HAVEVARTYPE , 0 } ,
{ VT_UI1 , 1 , FADF_HAVEVARTYPE , 0 } ,
{ VT_UI2 , 2 , FADF_HAVEVARTYPE , 0 } ,
{ VT_UI4 , 4 , FADF_HAVEVARTYPE , 0 } ,
{ VT_I8 , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_UI8 , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_INT , sizeof ( INT ) , FADF_HAVEVARTYPE , 0 } ,
{ VT_UINT , sizeof ( UINT ) , FADF_HAVEVARTYPE , 0 } ,
{ VT_VOID , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_HRESULT , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_PTR , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_SAFEARRAY , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_CARRAY , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_USERDEFINED , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_LPSTR , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_LPWSTR , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_FILETIME , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_RECORD , VARTYPE_NOT_SUPPORTED , FADF_RECORD , 0 } ,
{ VT_BLOB , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_STREAM , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_STORAGE , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_STREAMED_OBJECT , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_STORED_OBJECT , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_BLOB_OBJECT , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_CF , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
{ VT_CLSID , VARTYPE_NOT_SUPPORTED , FADF_HAVEVARTYPE , 0 } ,
2002-12-23 03:02:49 +01:00
} ;
2003-12-15 22:11:25 +01:00
static void test_safearray ( void )
2002-12-23 03:02:49 +01:00
{
2003-01-03 00:13:56 +01:00
SAFEARRAY * a , b , * c ;
unsigned int i ;
2003-06-13 18:35:07 +02:00
long indices [ 2 ] ;
2002-12-23 03:02:49 +01:00
HRESULT hres ;
2003-06-13 18:35:07 +02:00
SAFEARRAYBOUND bound , bounds [ 2 ] ;
2003-01-03 00:13:56 +01:00
VARIANT v ;
LPVOID data ;
IID iid ;
VARTYPE vt ;
2003-06-13 18:35:07 +02:00
LONG l ;
unsigned char * ptr1 , * ptr2 ;
2002-12-23 03:02:49 +01:00
bound . cElements = 1 ;
bound . lLbound = 0 ;
a = SafeArrayCreate ( - 1 , 1 , & bound ) ;
2003-12-15 22:11:25 +01:00
ok ( NULL = = a , " SAC(-1,1,[1,0]) not failed? \n " ) ;
2003-06-13 18:35:07 +02:00
bounds [ 0 ] . cElements = 42 ; bounds [ 0 ] . lLbound = 1 ;
bounds [ 1 ] . cElements = 2 ; bounds [ 1 ] . lLbound = 23 ;
a = SafeArrayCreate ( VT_I4 , 2 , bounds ) ;
2003-12-15 22:11:25 +01:00
ok ( a ! = NULL , " SAC(VT_INT32,2,...) failed. \n " ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetLBound ( a , 0 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = DISP_E_BADINDEX , " SAGLB 0 failed with %lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetLBound ( a , 1 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGLB 1 failed with %lx \n " , hres ) ;
ok ( l = = 1 , " SAGLB 1 returned %ld instead of 1 \n " , l ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetLBound ( a , 2 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGLB 2 failed with %lx \n " , hres ) ;
ok ( l = = 23 , " SAGLB 2 returned %ld instead of 23 \n " , l ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetLBound ( a , 3 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = DISP_E_BADINDEX , " SAGLB 3 failed with %lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetUBound ( a , 0 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = DISP_E_BADINDEX , " SAGUB 0 failed with %lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetUBound ( a , 1 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGUB 1 failed with %lx \n " , hres ) ;
ok ( l = = 42 , " SAGUB 1 returned %ld instead of 42 \n " , l ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetUBound ( a , 2 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGUB 2 failed with %lx \n " , hres ) ;
ok ( l = = 24 , " SAGUB 2 returned %ld instead of 24 \n " , l ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayGetUBound ( a , 3 , & l ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = DISP_E_BADINDEX , " SAGUB 3 failed with %lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
i = SafeArrayGetDim ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( i = = 2 , " getdims of 2 din array returned %d \n " , i ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 0 ;
indices [ 1 ] = 23 ;
hres = SafeArrayGetElement ( a , indices , & i ) ;
2003-12-15 22:11:25 +01:00
ok ( DISP_E_BADINDEX = = hres , " SAGE failed [0,23], hres 0x%lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 1 ;
indices [ 1 ] = 22 ;
hres = SafeArrayGetElement ( a , indices , & i ) ;
2003-12-15 22:11:25 +01:00
ok ( DISP_E_BADINDEX = = hres , " SAGE failed [1,22], hres 0x%lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 1 ;
indices [ 1 ] = 23 ;
hres = SafeArrayGetElement ( a , indices , & i ) ;
2003-12-15 22:11:25 +01:00
ok ( S_OK = = hres , " SAGE failed [1,23], hres 0x%lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 1 ;
indices [ 1 ] = 25 ;
hres = SafeArrayGetElement ( a , indices , & i ) ;
2003-12-15 22:11:25 +01:00
ok ( DISP_E_BADINDEX = = hres , " SAGE failed [1,24], hres 0x%lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 3 ;
indices [ 1 ] = 23 ;
hres = SafeArrayGetElement ( a , indices , & i ) ;
2003-12-15 22:11:25 +01:00
ok ( S_OK = = hres , " SAGE failed [42,23], hres 0x%lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayAccessData ( a , ( void * * ) & ptr1 ) ;
2003-12-15 22:11:25 +01:00
ok ( S_OK = = hres , " SAAD failed with 0x%lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 3 ;
indices [ 1 ] = 23 ;
hres = SafeArrayPtrOfIndex ( a , indices , ( void * * ) & ptr2 ) ;
2003-12-15 22:11:25 +01:00
ok ( S_OK = = hres , " SAPOI failed [1,23], hres 0x%lx \n " , hres ) ;
ok ( ptr2 - ptr1 = = 8 , " ptr difference is not 8, but %d (%p vs %p) \n " , ptr2 - ptr1 , ptr2 , ptr1 ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 3 ;
indices [ 1 ] = 24 ;
hres = SafeArrayPtrOfIndex ( a , indices , ( void * * ) & ptr2 ) ;
2003-12-15 22:11:25 +01:00
ok ( S_OK = = hres , " SAPOI failed [5,24], hres 0x%lx \n " , hres ) ;
ok ( ptr2 - ptr1 = = 176 , " ptr difference is not 176, but %d (%p vs %p) \n " , ptr2 - ptr1 , ptr2 , ptr1 ) ;
2003-06-13 18:35:07 +02:00
indices [ 0 ] = 20 ;
indices [ 1 ] = 23 ;
hres = SafeArrayPtrOfIndex ( a , indices , ( void * * ) & ptr2 ) ;
2003-12-15 22:11:25 +01:00
ok ( S_OK = = hres , " SAPOI failed [20,23], hres 0x%lx \n " , hres ) ;
ok ( ptr2 - ptr1 = = 76 , " ptr difference is not 176, but %d (%p vs %p) \n " , ptr2 - ptr1 , ptr2 , ptr1 ) ;
2003-06-13 18:35:07 +02:00
hres = SafeArrayUnaccessData ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( S_OK = = hres , " SAUAD failed with 0x%lx \n " , hres ) ;
2003-06-13 18:35:07 +02:00
2002-12-23 03:02:49 +01:00
for ( i = 0 ; i < sizeof ( vttypes ) / sizeof ( vttypes [ 0 ] ) ; i + + ) {
2003-12-15 22:11:25 +01:00
if ( ( i = = VT_I8 | | i = = VT_UI8 ) & & HAVE_OLEAUT32_I8 )
{
vttypes [ i ] . elemsize = sizeof ( LONG64 ) ;
}
2003-01-03 00:13:56 +01:00
a = SafeArrayCreate ( vttypes [ i ] . vt , 1 , & bound ) ;
ok ( ( ( a = = NULL ) & & ( vttypes [ i ] . elemsize = = 0 ) ) | |
( ( a ! = NULL ) & & ( vttypes [ i ] . elemsize = = a - > cbElements ) ) ,
2003-12-15 22:11:25 +01:00
" SAC(%d,1,[1,0]), result %ld, expected %d \n " ,
vttypes [ i ] . vt , ( a ? a - > cbElements : 0 ) , vttypes [ i ] . elemsize
2002-12-23 03:02:49 +01:00
) ;
2003-01-07 20:40:40 +01:00
if ( a ! = NULL ) {
ok ( a - > fFeatures = = ( vttypes [ i ] . expflags | vttypes [ i ] . addflags ) ,
2003-12-15 22:11:25 +01:00
" SAC of %d returned feature flags %x, expected %x \n " ,
2003-01-07 20:40:40 +01:00
vttypes [ i ] . vt , a - > fFeatures ,
vttypes [ i ] . expflags | vttypes [ i ] . addflags ) ;
ok ( SafeArrayGetElemsize ( a ) = = vttypes [ i ] . elemsize ,
2003-12-15 22:11:25 +01:00
" SAGE for vt %d returned elemsize %d instead of expected %d \n " ,
2003-01-07 20:40:40 +01:00
vttypes [ i ] . vt , SafeArrayGetElemsize ( a ) , vttypes [ i ] . elemsize ) ;
}
2003-01-03 00:13:56 +01:00
if ( ! a ) continue ;
2003-01-07 20:40:40 +01:00
if ( pSafeArrayGetVartype ) {
hres = pSafeArrayGetVartype ( a , & vt ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGVT of arra y with vt %d failed with %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-07 20:40:40 +01:00
if ( vttypes [ i ] . vt = = VT_DISPATCH ) {
/* Special case. Checked against Windows. */
2003-12-15 22:11:25 +01:00
ok ( vt = = VT_UNKNOWN , " SAGVT of a rray with VT_DISPATCH returned not VT_UNKNOWN, but %d \n " , vt ) ;
2003-01-07 20:40:40 +01:00
} else {
2003-12-15 22:11:25 +01:00
ok ( vt = = vttypes [ i ] . vt , " SAGVT of array with vt %d returned %d \n " , vttypes [ i ] . vt , vt ) ;
2003-01-07 20:40:40 +01:00
}
}
2003-01-03 00:13:56 +01:00
hres = SafeArrayCopy ( a , & c ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " failed to copy safearray of vt %d with hres %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-03 00:13:56 +01:00
2003-12-15 22:11:25 +01:00
ok ( vttypes [ i ] . elemsize = = c - > cbElements , " copy of SAC(%d,1,[1,0]), result %ld, expected %d \n " , vttypes [ i ] . vt , ( c ? c - > cbElements : 0 ) , vttypes [ i ] . elemsize
2003-01-03 00:13:56 +01:00
) ;
2003-12-15 22:11:25 +01:00
ok ( c - > fFeatures = = ( vttypes [ i ] . expflags | vttypes [ i ] . addflags ) , " SAC of %d returned feature flags %x, expected %x \n " , vttypes [ i ] . vt , c - > fFeatures , vttypes [ i ] . expflags | vttypes [ i ] . addflags ) ;
ok ( SafeArrayGetElemsize ( c ) = = vttypes [ i ] . elemsize , " SAGE for vt %d returned elemsize %d instead of expected %d \n " , vttypes [ i ] . vt , SafeArrayGetElemsize ( c ) , vttypes [ i ] . elemsize ) ;
2003-01-03 00:13:56 +01:00
2003-01-07 20:40:40 +01:00
if ( pSafeArrayGetVartype ) {
hres = pSafeArrayGetVartype ( c , & vt ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGVT of array with vt %d failed with %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-07 20:40:40 +01:00
if ( vttypes [ i ] . vt = = VT_DISPATCH ) {
/* Special case. Checked against Windows. */
2003-12-15 22:11:25 +01:00
ok ( vt = = VT_UNKNOWN , " SAGVT of array with VT_DISPATCH returned not VT_UNKNOWN, but %d \n " , vt ) ;
2003-01-07 20:40:40 +01:00
} else {
2003-12-15 22:11:25 +01:00
ok ( vt = = vttypes [ i ] . vt , " SAGVT of array with vt %d returned %d \n " , vttypes [ i ] . vt , vt ) ;
2003-01-07 20:40:40 +01:00
}
}
if ( pSafeArrayCopyData ) {
hres = pSafeArrayCopyData ( a , c ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " failed to copy safearray data of vt %d with hres %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-07 20:40:40 +01:00
hres = SafeArrayDestroyData ( c ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SADD of copy of array with vt %d failed with hres %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-07 20:40:40 +01:00
}
2003-01-03 00:13:56 +01:00
hres = SafeArrayDestroy ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAD of array with vt %d failed with hres %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-03 00:13:56 +01:00
}
/* Test conversion of type|VT_ARRAY <-> VT_BSTR */
bound . lLbound = 0 ;
bound . cElements = 10 ;
a = SafeArrayCreate ( VT_UI1 , 1 , & bound ) ;
2003-12-15 22:11:25 +01:00
ok ( a ! = NULL , " SAC failed. \n " ) ;
ok ( S_OK = = SafeArrayAccessData ( a , & data ) , " SACD failed \n " ) ;
memcpy ( data , " Hello World \n " , 10 ) ;
ok ( S_OK = = SafeArrayUnaccessData ( a ) , " SAUD failed \n " ) ;
2003-01-03 00:13:56 +01:00
V_VT ( & v ) = VT_ARRAY | VT_UI1 ;
V_ARRAY ( & v ) = a ;
hres = VariantChangeTypeEx ( & v , & v , 0 , 0 , VT_BSTR ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx \n " , hres ) ;
ok ( V_VT ( & v ) = = VT_BSTR , " CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.v \n " , V_VT ( & v ) ) ;
ok ( V_BSTR ( & v ) [ 0 ] = = 0x6548 , " First letter are not 'He', but %x \n " , V_BSTR ( & v ) [ 0 ] ) ;
2003-01-03 00:13:56 +01:00
/* check locking functions */
a = SafeArrayCreate ( VT_I4 , 1 , & bound ) ;
2003-12-15 22:11:25 +01:00
ok ( a ! = NULL , " SAC should not fail \n " ) ;
2003-01-03 00:13:56 +01:00
hres = SafeArrayAccessData ( a , & data ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAAD failed with hres %lx \n " , hres ) ;
2003-01-03 00:13:56 +01:00
hres = SafeArrayDestroy ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = DISP_E_ARRAYISLOCKED , " locked safe array destroy not failed with DISP_E_ARRAYISLOCKED, but with hres %lx \n " , hres ) ;
2003-01-03 00:13:56 +01:00
hres = SafeArrayDestroyData ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = DISP_E_ARRAYISLOCKED , " locked safe array destroy data not failed with DISP_E_ARRAYISLOCKED, but with hres %lx \n " , hres ) ;
2003-01-03 00:13:56 +01:00
hres = SafeArrayDestroyDescriptor ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = DISP_E_ARRAYISLOCKED , " locked safe array destroy descriptor not failed with DISP_E_ARRAYISLOCKED, but with hres %lx \n " , hres ) ;
2003-01-03 00:13:56 +01:00
hres = SafeArrayUnaccessData ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAUD failed after lock/destroy test \n " ) ;
2003-01-03 00:13:56 +01:00
hres = SafeArrayDestroy ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAD failed after lock/destroy test \n " ) ;
2003-01-03 00:13:56 +01:00
/* Test if we need to destroy data before descriptor */
a = SafeArrayCreate ( VT_I4 , 1 , & bound ) ;
2003-12-15 22:11:25 +01:00
ok ( a ! = NULL , " SAC should not fail \n " ) ;
2003-01-03 00:13:56 +01:00
hres = SafeArrayDestroyDescriptor ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SADD with data in array failed with hres %lx \n " , hres ) ;
2003-01-03 00:13:56 +01:00
/* IID functions */
/* init a small stack safearray */
2003-01-07 20:40:40 +01:00
if ( pSafeArraySetIID ) {
memset ( & b , 0 , sizeof ( b ) ) ;
b . cDims = 1 ;
memset ( & iid , 0x42 , sizeof ( IID ) ) ;
hres = pSafeArraySetIID ( & b , & iid ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = E_INVALIDARG , " SafeArraySetIID of non IID capable safearray did not return E_INVALIDARG, but %lx \n " , hres ) ;
2003-01-07 20:40:40 +01:00
hres = SafeArrayAllocDescriptor ( 1 , & a ) ;
2003-12-15 22:11:25 +01:00
ok ( ( a - > fFeatures & FADF_HAVEIID ) = = 0 , " newly allocated descriptor with SAAD should not have FADF_HAVEIID \n " ) ;
2003-01-07 20:40:40 +01:00
hres = pSafeArraySetIID ( a , & iid ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = E_INVALIDARG , " SafeArraySetIID of newly allocated descriptor with SAAD should return E_INVALIDARG, but %lx \n " , hres ) ;
2003-01-07 20:40:40 +01:00
}
if ( ! pSafeArrayAllocDescriptorEx )
return ;
2003-01-03 00:13:56 +01:00
for ( i = 0 ; i < sizeof ( vttypes ) / sizeof ( vttypes [ 0 ] ) ; i + + ) {
2003-12-15 22:11:25 +01:00
a = NULL ;
2003-01-07 20:40:40 +01:00
hres = pSafeArrayAllocDescriptorEx ( vttypes [ i ] . vt , 1 , & a ) ;
2003-01-03 00:13:56 +01:00
ok ( a - > fFeatures = = vttypes [ i ] . expflags , " SAADE(%d) resulted with flags %x, expected %x \n " , vttypes [ i ] . vt , a - > fFeatures , vttypes [ i ] . expflags ) ;
if ( a - > fFeatures & FADF_HAVEIID ) {
2003-01-07 20:40:40 +01:00
hres = pSafeArrayGetIID ( a , & iid ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGIID failed for vt %d with hres %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-03 00:13:56 +01:00
switch ( vttypes [ i ] . vt ) {
case VT_UNKNOWN :
2003-12-15 22:11:25 +01:00
ok ( IsEqualGUID ( ( ( GUID * ) a ) - 1 , & IID_IUnknown ) , " guid for VT_UNKNOWN is not IID_IUnknown \n " ) ;
ok ( IsEqualGUID ( & iid , & IID_IUnknown ) , " SAGIID returned wrong GUID for IUnknown \n " ) ;
2003-01-03 00:13:56 +01:00
break ;
case VT_DISPATCH :
2003-12-15 22:11:25 +01:00
ok ( IsEqualGUID ( ( ( GUID * ) a ) - 1 , & IID_IDispatch ) , " guid for VT_UNKNOWN is not IID_IDispatch \n " ) ;
ok ( IsEqualGUID ( & iid , & IID_IDispatch ) , " SAGIID returned wrong GUID for IDispatch \n " ) ;
2003-01-03 00:13:56 +01:00
break ;
default :
2003-12-15 22:11:25 +01:00
ok ( FALSE , " unknown vt %d with FADF_HAVEIID \n " , vttypes [ i ] . vt ) ;
2003-01-03 00:13:56 +01:00
break ;
}
} else {
2003-01-07 20:40:40 +01:00
hres = pSafeArrayGetIID ( a , & iid ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = E_INVALIDARG , " SAGIID did not fail for vt %d with hres %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-03 00:13:56 +01:00
}
if ( a - > fFeatures & FADF_RECORD ) {
2003-12-15 22:11:25 +01:00
ok ( vttypes [ i ] . vt = = VT_RECORD , " FADF_RECORD for non record %d \n " , vttypes [ i ] . vt ) ;
2003-01-03 00:13:56 +01:00
}
if ( a - > fFeatures & FADF_HAVEVARTYPE ) {
2003-12-15 22:11:25 +01:00
ok ( vttypes [ i ] . vt = = ( ( DWORD * ) a ) [ - 1 ] , " FADF_HAVEVARTYPE set, but vt %d mismatch stored %ld \n " , vttypes [ i ] . vt , ( ( DWORD * ) a ) [ - 1 ] ) ;
2003-01-03 00:13:56 +01:00
}
2003-01-07 20:40:40 +01:00
hres = pSafeArrayGetVartype ( a , & vt ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGVT of array with vt %d failed with %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-03 00:13:56 +01:00
if ( vttypes [ i ] . vt = = VT_DISPATCH ) {
/* Special case. Checked against Windows. */
2003-12-15 22:11:25 +01:00
ok ( vt = = VT_UNKNOWN , " SAGVT of array with VT_DISPATCH returned not VT_UNKNOWN, but %d \n " , vt ) ;
2003-01-03 00:13:56 +01:00
} else {
2003-12-15 22:11:25 +01:00
ok ( vt = = vttypes [ i ] . vt , " SAGVT of array with vt %d returned %d \n " , vttypes [ i ] . vt , vt ) ;
2003-01-03 00:13:56 +01:00
}
if ( a - > fFeatures & FADF_HAVEIID ) {
2003-01-07 20:40:40 +01:00
hres = pSafeArraySetIID ( a , & IID_IStorage ) ; /* random IID */
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SASIID failed with FADF_HAVEIID set for vt %d with %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-07 20:40:40 +01:00
hres = pSafeArrayGetIID ( a , & iid ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SAGIID failed with FADF_HAVEIID set for vt %d with %lx \n " , vttypes [ i ] . vt , hres ) ;
ok ( IsEqualGUID ( & iid , & IID_IStorage ) , " returned iid is not IID_IStorage \n " ) ;
2003-01-03 00:13:56 +01:00
} else {
2003-01-07 20:40:40 +01:00
hres = pSafeArraySetIID ( a , & IID_IStorage ) ; /* random IID */
2003-12-15 22:11:25 +01:00
ok ( hres = = E_INVALIDARG , " SASIID did not failed with !FADF_HAVEIID set for vt %d with %lx \n " , vttypes [ i ] . vt , hres ) ;
2003-01-03 00:13:56 +01:00
}
hres = SafeArrayDestroyDescriptor ( a ) ;
2003-12-15 22:11:25 +01:00
ok ( hres = = S_OK , " SADD failed with hres %lx \n " , hres ) ;
2002-12-23 03:02:49 +01:00
}
}
2003-12-15 22:11:25 +01:00
static void test_SafeArrayAllocDestroyDescriptor ( void )
{
SAFEARRAY * sa ;
HRESULT hres ;
int i ;
/* Failure cases */
hres = SafeArrayAllocDescriptor ( 0 , & sa ) ;
ok ( hres = = E_INVALIDARG , " 0 dimensions gave hres 0x%lx \n " , hres ) ;
hres = SafeArrayAllocDescriptor ( 65536 , & sa ) ;
ok ( hres = = E_INVALIDARG , " 65536 dimensions gave hres 0x%lx \n " , hres ) ;
#if 0
/* Crashes on 95: XP & Wine return E_POINTER */
hres = SafeArrayAllocDescriptor ( 1 , NULL ) ;
ok ( hres = = E_POINTER , " NULL parm gave hres 0x%lx \n " , hres ) ;
# endif
/* Test up to the dimension boundary case */
for ( i = 5 ; i < = 65535 ; i + = 30 )
{
hres = SafeArrayAllocDescriptor ( i , & sa ) ;
ok ( hres = = S_OK , " %d dimensions failed; hres 0x%lx \n " , i , hres ) ;
if ( hres = = S_OK )
{
ok ( SafeArrayGetDim ( sa ) = = ( UINT ) i , " Dimension is %d; should be %d \n " ,
SafeArrayGetDim ( sa ) , i ) ;
hres = SafeArrayDestroyDescriptor ( sa ) ;
ok ( hres = = S_OK , " destroy failed; hres 0x%lx \n " , hres ) ;
}
}
if ( ! pSafeArrayAllocDescriptorEx )
return ;
hres = pSafeArrayAllocDescriptorEx ( VT_UI1 , 0 , & sa ) ;
ok ( hres = = E_INVALIDARG , " 0 dimensions gave hres 0x%lx \n " , hres ) ;
hres = pSafeArrayAllocDescriptorEx ( VT_UI1 , 65536 , & sa ) ;
ok ( hres = = E_INVALIDARG , " 65536 dimensions gave hres 0x%lx \n " , hres ) ;
hres = pSafeArrayAllocDescriptorEx ( VT_UI1 , 1 , NULL ) ;
ok ( hres = = E_POINTER , " NULL parm gave hres 0x%lx \n " , hres ) ;
}
static void test_SafeArrayCreateLockDestroy ( void )
{
SAFEARRAYBOUND sab [ 4 ] ;
SAFEARRAY * sa ;
HRESULT hres ;
VARTYPE vt ;
int dimension ;
# define NUM_DIMENSIONS (int)(sizeof(sab) / sizeof(sab[0]))
for ( dimension = 0 ; dimension < NUM_DIMENSIONS ; dimension + + )
{
sab [ dimension ] . lLbound = 0 ;
sab [ dimension ] . cElements = 8 ;
}
/* Failure cases */
sa = SafeArrayCreate ( VT_UI1 , 1 , NULL ) ;
ok ( sa = = NULL , " NULL bounds didn't fail \n " ) ;
sa = SafeArrayCreate ( VT_UI1 , 65536 , sab ) ;
ok ( sa = = NULL , " Max bounds didn't fail \n " ) ;
memset ( sab , 0 , sizeof ( sab ) ) ;
/* Don't test 0 sized dimensions, as Windows has a bug which allows this */
for ( dimension = 0 ; dimension < NUM_DIMENSIONS ; dimension + + )
sab [ dimension ] . cElements = 8 ;
/* Test all VARTYPES in 1-4 dimensions */
for ( dimension = 1 ; dimension < 4 ; dimension + + )
{
for ( vt = VT_EMPTY ; vt < VT_CLSID ; vt + + )
{
DWORD dwLen = SAFEARRAY_GetVTSize ( vt ) ;
sa = SafeArrayCreate ( vt , dimension , sab ) ;
if ( dwLen )
ok ( sa ! = NULL , " VARTYPE %d (@%d dimensions) failed \n " , vt , dimension ) ;
else
ok ( sa = = NULL , " VARTYPE %d (@%d dimensions) succeeded! \n " , vt , dimension ) ;
if ( sa )
{
ok ( SafeArrayGetDim ( sa ) = = ( UINT ) dimension ,
" VARTYPE %d (@%d dimensions) cDims is %d, expected %d \n " ,
vt , dimension , SafeArrayGetDim ( sa ) , dimension ) ;
ok ( SafeArrayGetElemsize ( sa ) = = dwLen ,
" VARTYPE %d (@%d dimensions) cbElements is %d, expected %ld \n " ,
vt , dimension , SafeArrayGetElemsize ( sa ) , dwLen ) ;
if ( vt ! = VT_UNKNOWN & & vt ! = VT_DISPATCH )
{
ok ( ( sa - > fFeatures & FADF_HAVEIID ) = = 0 ,
" Non interface type should not have FADF_HAVEIID \n " ) ;
if ( pSafeArraySetIID )
{
hres = pSafeArraySetIID ( sa , & IID_IUnknown ) ;
ok ( hres = = E_INVALIDARG ,
" Non interface type allowed SetIID(), hres %lx \n " , hres ) ;
}
if ( vt ! = VT_RECORD )
{
VARTYPE aVt ;
ok ( ( sa - > fFeatures & FADF_HAVEVARTYPE ) ! = 0 ,
" Non interface type should have FADF_HAVEVARTYPE \n " ) ;
if ( pSafeArrayGetVartype )
{
hres = pSafeArrayGetVartype ( sa , & aVt ) ;
ok ( hres = = S_OK & & aVt = = vt ,
" Non interface type %d: bad type %d, hres %lx \n " , vt , aVt , hres ) ;
}
}
}
else
{
ok ( ( sa - > fFeatures & FADF_HAVEIID ) ! = 0 ,
" Interface type should have FADF_HAVEIID \n " ) ;
if ( pSafeArraySetIID )
{
hres = pSafeArraySetIID ( sa , & IID_IUnknown ) ;
ok ( hres = = S_OK ,
" Non interface type disallowed SetIID(), hres %lx \n " , hres ) ;
}
ok ( ( sa - > fFeatures & FADF_HAVEVARTYPE ) = = 0 ,
" Interface type %d should not have FADF_HAVEVARTYPE \n " , vt ) ;
}
hres = SafeArrayLock ( sa ) ;
ok ( hres = = S_OK , " Lock VARTYPE %d (@%d dimensions) failed; hres 0x%lx \n " ,
vt , dimension , hres ) ;
if ( hres = = S_OK )
{
hres = SafeArrayDestroy ( sa ) ;
ok ( hres = = DISP_E_ARRAYISLOCKED , " Destroy() got hres %lx \n " , hres ) ;
hres = SafeArrayDestroyData ( sa ) ;
ok ( hres = = DISP_E_ARRAYISLOCKED , " DestroyData() got hres %lx \n " , hres ) ;
hres = SafeArrayDestroyDescriptor ( sa ) ;
ok ( hres = = DISP_E_ARRAYISLOCKED , " DestroyDescriptor() got hres %lx \n " , hres ) ;
hres = SafeArrayUnlock ( sa ) ;
ok ( hres = = S_OK , " Unlock VARTYPE %d (@%d dims) hres 0x%lx \n " ,
vt , dimension , hres ) ;
hres = SafeArrayDestroyDescriptor ( sa ) ;
ok ( hres = = S_OK , " destroy VARTYPE %d (@%d dims) hres 0x%lx \n " ,
vt , dimension , hres ) ;
}
}
}
}
}
static void test_VectorCreateLockDestroy ( void )
{
SAFEARRAY * sa ;
HRESULT hres ;
VARTYPE vt ;
int element ;
#if 0
/* Native allows you to to create 0 sized vectors. Its an ERR in Wine, lets
* see if anyone reports it before supporting this brain damage . Actually
* using the returned array just crashes in native anyway .
*/
sa = SafeArrayCreateVector ( VT_UI1 , 0 , 0 ) ;
ok ( sa = = NULL , " 0 elements didn't fail \n " ) ;
# endif
/* Test all VARTYPES in different lengths */
for ( element = 1 ; element < = 101 ; element + = 10 )
{
for ( vt = VT_EMPTY ; vt < VT_CLSID ; vt + + )
{
DWORD dwLen = SAFEARRAY_GetVTSize ( vt ) ;
sa = SafeArrayCreateVector ( vt , 0 , element ) ;
if ( dwLen )
ok ( sa ! = NULL , " VARTYPE %d (@%d elements) failed \n " , vt , element ) ;
else
ok ( sa = = NULL , " VARTYPE %d (@%d elements) succeeded! \n " , vt , element ) ;
if ( sa )
{
ok ( SafeArrayGetDim ( sa ) = = 1 , " VARTYPE %d (@%d elements) cDims %d, not 1 \n " ,
vt , element , SafeArrayGetDim ( sa ) ) ;
ok ( SafeArrayGetElemsize ( sa ) = = dwLen ,
" VARTYPE %d (@%d elements) cbElements is %d, expected %ld \n " ,
vt , element , SafeArrayGetElemsize ( sa ) , dwLen ) ;
hres = SafeArrayLock ( sa ) ;
ok ( hres = = S_OK , " Lock VARTYPE %d (@%d elements) failed; hres 0x%lx \n " ,
vt , element , hres ) ;
if ( hres = = S_OK )
{
hres = SafeArrayUnlock ( sa ) ;
ok ( hres = = S_OK , " Unlock VARTYPE %d (@%d elements) failed; hres 0x%lx \n " ,
vt , element , hres ) ;
hres = SafeArrayDestroyDescriptor ( sa ) ;
ok ( hres = = S_OK , " destroy VARTYPE %d (@%d elements) failed; hres 0x%lx \n " ,
vt , element , hres ) ;
}
}
}
}
}
static void test_LockUnlock ( void )
{
SAFEARRAYBOUND sab [ 4 ] ;
SAFEARRAY * sa ;
HRESULT hres ;
BOOL bVector = FALSE ;
int dimension ;
/* Failure cases */
hres = SafeArrayLock ( NULL ) ;
ok ( hres = = E_INVALIDARG , " Lock NULL array hres 0x%lx \n " , hres ) ;
hres = SafeArrayUnlock ( NULL ) ;
ok ( hres = = E_INVALIDARG , " Lock NULL array hres 0x%lx \n " , hres ) ;
for ( dimension = 0 ; dimension < NUM_DIMENSIONS ; dimension + + )
{
sab [ dimension ] . lLbound = 0 ;
sab [ dimension ] . cElements = 8 ;
}
sa = SafeArrayCreate ( VT_UI1 , NUM_DIMENSIONS , sab ) ;
/* Test maximum locks */
test_LockUnlock_Vector :
if ( sa )
{
int count = 0 ;
hres = SafeArrayUnlock ( sa ) ;
ok ( hres = = E_UNEXPECTED , " Bad %sUnlock gave hres 0x%lx \n " ,
bVector ? " vector " : " \n " , hres ) ;
while ( ( hres = SafeArrayLock ( sa ) ) = = S_OK )
count + + ;
ok ( count = = 65535 & & hres = = E_UNEXPECTED , " Lock %sfailed at %d; hres 0x%lx \n " ,
bVector ? " vector " : " \n " , count , hres ) ;
if ( count = = 65535 & & hres = = E_UNEXPECTED )
{
while ( ( hres = SafeArrayUnlock ( sa ) ) = = S_OK )
count - - ;
ok ( count = = 0 & & hres = = E_UNEXPECTED , " Unlock %sfailed at %d; hres 0x%lx \n " ,
bVector ? " vector " : " \n " , count , hres ) ;
}
SafeArrayDestroy ( sa ) ;
}
if ( bVector = = FALSE )
{
/* Test again with a vector */
sa = SafeArrayCreateVector ( VT_UI1 , 0 , 100 ) ;
bVector = TRUE ;
goto test_LockUnlock_Vector ;
}
}
static void test_SafeArrayGetPutElement ( void )
{
SAFEARRAYBOUND sab [ 4 ] ;
LONG indices [ NUM_DIMENSIONS ] ;
SAFEARRAY * sa ;
HRESULT hres ;
int value = 0 , gotvalue , dimension ;
unsigned int x , y , z , a ;
for ( dimension = 0 ; dimension < NUM_DIMENSIONS ; dimension + + )
{
sab [ dimension ] . lLbound = dimension * 2 + 1 ;
sab [ dimension ] . cElements = dimension * 3 + 1 ;
}
sa = SafeArrayCreate ( VT_INT , NUM_DIMENSIONS , sab ) ;
ok ( sa ! = NULL , " 4d test couldn't create array \n " ) ;
if ( ! sa )
return ;
ok ( sa - > cbElements = = sizeof ( value ) , " int size mismatch \n " ) ;
if ( sa - > cbElements ! = sizeof ( value ) )
return ;
/* Failure cases */
for ( x = 0 ; x < NUM_DIMENSIONS ; x + + )
{
indices [ 0 ] = sab [ 0 ] . lLbound ;
indices [ 1 ] = sab [ 1 ] . lLbound ;
indices [ 2 ] = sab [ 2 ] . lLbound ;
indices [ 3 ] = sab [ 3 ] . lLbound ;
indices [ x ] = indices [ x ] - 1 ;
hres = SafeArrayPutElement ( sa , indices , & value ) ;
ok ( hres = = DISP_E_BADINDEX , " Put allowed too small index in dimension %d \n " , x ) ;
hres = SafeArrayGetElement ( sa , indices , & value ) ;
ok ( hres = = DISP_E_BADINDEX , " Get allowed too small index in dimension %d \n " , x ) ;
indices [ x ] = sab [ x ] . lLbound + sab [ x ] . cElements ;
hres = SafeArrayPutElement ( sa , indices , & value ) ;
ok ( hres = = DISP_E_BADINDEX , " Put allowed too big index in dimension %d \n " , x ) ;
hres = SafeArrayGetElement ( sa , indices , & value ) ;
ok ( hres = = DISP_E_BADINDEX , " Get allowed too big index in dimension %d \n " , x ) ;
}
indices [ 0 ] = sab [ 0 ] . lLbound ;
indices [ 1 ] = sab [ 1 ] . lLbound ;
indices [ 2 ] = sab [ 2 ] . lLbound ;
indices [ 3 ] = sab [ 3 ] . lLbound ;
hres = SafeArrayPutElement ( NULL , indices , & value ) ;
ok ( hres = = E_INVALIDARG , " Put NULL array hres 0x%lx \n " , hres ) ;
hres = SafeArrayGetElement ( NULL , indices , & value ) ;
ok ( hres = = E_INVALIDARG , " Get NULL array hres 0x%lx \n " , hres ) ;
hres = SafeArrayPutElement ( sa , NULL , & value ) ;
ok ( hres = = E_INVALIDARG , " Put NULL indices hres 0x%lx \n " , hres ) ;
hres = SafeArrayGetElement ( sa , NULL , & value ) ;
ok ( hres = = E_INVALIDARG , " Get NULL indices hres 0x%lx \n " , hres ) ;
#if 0
/* This is retarded. Windows checks every case of invalid parameters
* except the following , which crashes . We ERR this in Wine .
*/
hres = SafeArrayPutElement ( sa , indices , NULL ) ;
ok ( hres = = E_INVALIDARG , " Put NULL value hres 0x%lx \n " , hres ) ;
# endif
hres = SafeArrayGetElement ( sa , indices , NULL ) ;
ok ( hres = = E_INVALIDARG , " Get NULL value hres 0x%lx \n " , hres ) ;
value = 0 ;
/* Make sure we can read and get back the correct values in 4 dimensions,
* Each with a different size and lower bound .
*/
for ( x = 0 ; x < sab [ 0 ] . cElements ; x + + )
{
indices [ 0 ] = sab [ 0 ] . lLbound + x ;
for ( y = 0 ; y < sab [ 1 ] . cElements ; y + + )
{
indices [ 1 ] = sab [ 1 ] . lLbound + y ;
for ( z = 0 ; z < sab [ 2 ] . cElements ; z + + )
{
indices [ 2 ] = sab [ 2 ] . lLbound + z ;
for ( a = 0 ; a < sab [ 3 ] . cElements ; a + + )
{
indices [ 3 ] = sab [ 3 ] . lLbound + a ;
hres = SafeArrayPutElement ( sa , indices , & value ) ;
ok ( hres = = S_OK , " Failed to put element at (%d,%d,%d,%d) hres 0x%lx \n " ,
x , y , z , a , hres ) ;
value + + ;
}
}
}
}
value = 0 ;
for ( x = 0 ; x < sab [ 0 ] . cElements ; x + + )
{
indices [ 0 ] = sab [ 0 ] . lLbound + x ;
for ( y = 0 ; y < sab [ 1 ] . cElements ; y + + )
{
indices [ 1 ] = sab [ 1 ] . lLbound + y ;
for ( z = 0 ; z < sab [ 2 ] . cElements ; z + + )
{
indices [ 2 ] = sab [ 2 ] . lLbound + z ;
for ( a = 0 ; a < sab [ 3 ] . cElements ; a + + )
{
indices [ 3 ] = sab [ 3 ] . lLbound + a ;
gotvalue = value / 3 ;
hres = SafeArrayGetElement ( sa , indices , & gotvalue ) ;
ok ( hres = = S_OK , " Failed to get element at (%d,%d,%d,%d) hres 0x%lx \n " ,
x , y , z , a , hres ) ;
if ( hres = = S_OK )
ok ( value = = gotvalue , " Got value %d instead of %d at (%d,%d,%d,%d) \n " ,
gotvalue , value , x , y , z , a ) ;
value + + ;
}
}
}
}
SafeArrayDestroy ( sa ) ;
}
static void test_SafeArrayCopyData ( void )
{
SAFEARRAYBOUND sab [ 4 ] ;
SAFEARRAY * sa ;
SAFEARRAY * sacopy ;
HRESULT hres ;
int dimension , size = 1 ;
if ( ! pSafeArrayCopyData )
return ;
for ( dimension = 0 ; dimension < NUM_DIMENSIONS ; dimension + + )
{
sab [ dimension ] . lLbound = dimension * 2 + 2 ;
sab [ dimension ] . cElements = dimension * 3 + 1 ;
size * = sab [ dimension ] . cElements ;
}
sa = SafeArrayCreate ( VT_INT , NUM_DIMENSIONS , sab ) ;
ok ( sa ! = NULL , " Copy test couldn't create array \n " ) ;
sacopy = SafeArrayCreate ( VT_INT , NUM_DIMENSIONS , sab ) ;
ok ( sacopy ! = NULL , " Copy test couldn't create copy array \n " ) ;
if ( ! sa | | ! sacopy )
return ;
ok ( sa - > cbElements = = sizeof ( int ) , " int size mismatch \n " ) ;
if ( sa - > cbElements ! = sizeof ( int ) )
return ;
/* Fill the source array with some data; it doesn't matter what */
for ( dimension = 0 ; dimension < size ; dimension + + )
{
int * data = ( int * ) sa - > pvData ;
data [ dimension ] = dimension ;
}
hres = pSafeArrayCopyData ( sa , sacopy ) ;
ok ( hres = = S_OK , " copy data failed hres 0x%lx \n " , hres ) ;
if ( hres = = S_OK )
{
ok ( ! memcmp ( sa - > pvData , sacopy - > pvData , size * sizeof ( int ) ) , " compared different \n " ) ;
}
/* Failure cases */
hres = pSafeArrayCopyData ( NULL , sacopy ) ;
ok ( hres = = E_INVALIDARG , " Null copy source hres 0x%lx \n " , hres ) ;
hres = pSafeArrayCopyData ( sa , NULL ) ;
ok ( hres = = E_INVALIDARG , " Null copy hres 0x%lx \n " , hres ) ;
sacopy - > rgsabound [ 0 ] . cElements + = 1 ;
hres = pSafeArrayCopyData ( sa , sacopy ) ;
ok ( hres = = E_INVALIDARG , " Bigger copy first dimension hres 0x%lx \n " , hres ) ;
sacopy - > rgsabound [ 0 ] . cElements - = 2 ;
hres = pSafeArrayCopyData ( sa , sacopy ) ;
ok ( hres = = E_INVALIDARG , " Smaller copy first dimension hres 0x%lx \n " , hres ) ;
sacopy - > rgsabound [ 0 ] . cElements + = 1 ;
sacopy - > rgsabound [ 3 ] . cElements + = 1 ;
hres = pSafeArrayCopyData ( sa , sacopy ) ;
ok ( hres = = E_INVALIDARG , " Bigger copy last dimension hres 0x%lx \n " , hres ) ;
sacopy - > rgsabound [ 3 ] . cElements - = 2 ;
hres = pSafeArrayCopyData ( sa , sacopy ) ;
ok ( hres = = E_INVALIDARG , " Smaller copy last dimension hres 0x%lx \n " , hres ) ;
sacopy - > rgsabound [ 3 ] . cElements + = 1 ;
SafeArrayDestroy ( sacopy ) ;
sacopy = NULL ;
hres = pSafeArrayCopyData ( sa , sacopy ) ;
ok ( hres = = E_INVALIDARG , " ->Null copy hres 0x%lx \n " , hres ) ;
hres = SafeArrayCopy ( sa , & sacopy ) ;
ok ( hres = = S_OK , " copy failed hres 0x%lx \n " , hres ) ;
if ( hres = = S_OK )
{
ok ( SafeArrayGetElemsize ( sa ) = = SafeArrayGetElemsize ( sacopy ) , " elemsize wrong \n " ) ;
ok ( SafeArrayGetDim ( sa ) = = SafeArrayGetDim ( sacopy ) , " dimensions wrong \n " ) ;
ok ( ! memcmp ( sa - > pvData , sacopy - > pvData , size * sizeof ( int ) ) , " compared different \n " ) ;
}
SafeArrayDestroy ( sa ) ;
}
static void test_SafeArrayCreateEx ( void )
{
IRecordInfoImpl * iRec ;
SAFEARRAYBOUND sab [ 4 ] ;
SAFEARRAY * sa ;
HRESULT hres ;
int dimension ;
if ( ! pSafeArrayCreateEx )
return ;
for ( dimension = 0 ; dimension < NUM_DIMENSIONS ; dimension + + )
{
sab [ dimension ] . lLbound = 0 ;
sab [ dimension ] . cElements = 8 ;
}
/* Failure cases */
sa = pSafeArrayCreateEx ( VT_UI1 , 1 , NULL , NULL ) ;
ok ( sa = = NULL , " CreateEx NULL bounds didn't fail \n " ) ;
/* test IID storage & defaulting */
sa = pSafeArrayCreateEx ( VT_DISPATCH , 1 , sab , ( PVOID ) & IID_ITypeInfo ) ;
ok ( sa ! = NULL , " CreateEx (ITypeInfo) failed \n " ) ;
if ( sa )
{
GUID guid ;
if ( pSafeArrayGetIID )
{
hres = pSafeArrayGetIID ( sa , & guid ) ;
ok ( hres = = S_OK , " CreateEx (ITypeInfo) no IID hres 0x%lx \n " , hres ) ;
if ( hres = = S_OK )
{
ok ( IsEqualGUID ( & guid , & IID_ITypeInfo ) , " CreateEx (ITypeInfo) bad IID \n " ) ;
}
}
if ( pSafeArraySetIID )
{
hres = pSafeArraySetIID ( sa , & IID_IUnknown ) ;
ok ( hres = = S_OK , " Failed to set IID, hres = %8lx \n " , hres ) ;
if ( hres = = S_OK & & pSafeArrayGetIID )
{
hres = pSafeArrayGetIID ( sa , & guid ) ;
ok ( hres = = S_OK & & IsEqualGUID ( & guid , & IID_IUnknown ) , " Set bad IID \n " ) ;
}
}
SafeArrayDestroy ( sa ) ;
}
sa = pSafeArrayCreateEx ( VT_DISPATCH , 1 , sab , NULL ) ;
ok ( sa ! = NULL , " CreateEx (NULL) failed \n " ) ;
if ( sa )
{
GUID guid ;
if ( pSafeArrayGetIID )
{
hres = SafeArrayGetIID ( sa , & guid ) ;
ok ( hres = = S_OK , " CreateEx (NULL) no IID hres 0x%lx \n " , hres ) ;
if ( hres = = S_OK )
{
ok ( IsEqualGUID ( & guid , & IID_IDispatch ) , " CreateEx (NULL) bad IID \n " ) ;
}
}
SafeArrayDestroy ( sa ) ;
}
sa = pSafeArrayCreateEx ( VT_UNKNOWN , 1 , sab , NULL ) ;
ok ( sa ! = NULL , " CreateEx (NULL-Unk) failed \n " ) ;
if ( sa )
{
GUID guid ;
if ( pSafeArrayGetIID )
{
hres = SafeArrayGetIID ( sa , & guid ) ;
ok ( hres = = S_OK , " CreateEx (NULL-Unk) no IID hres 0x%lx \n " , hres ) ;
if ( hres = = S_OK )
{
ok ( IsEqualGUID ( & guid , & IID_IUnknown ) , " CreateEx (NULL-Unk) bad IID \n " ) ;
}
}
SafeArrayDestroy ( sa ) ;
}
/* VT_RECORD failure case */
sa = pSafeArrayCreateEx ( VT_RECORD , 1 , sab , NULL ) ;
ok ( sa = = NULL , " CreateEx (NULL-Rec) succeded \n " ) ;
iRec = IRecordInfoImpl_Construct ( ) ;
/* Win32 doesn't care if GetSize fails */
fail_GetSize = TRUE ;
sa = pSafeArrayCreateEx ( VT_RECORD , 1 , sab , ( LPVOID ) iRec ) ;
ok ( sa ! = NULL , " CreateEx (Fail Size) failed \n " ) ;
ok ( iRec - > ref = = START_REF_COUNT + 1 , " Wrong iRec refcount %ld \n " , iRec - > ref ) ;
ok ( iRec - > sizeCalled = = 1 , " GetSize called %ld times \n " , iRec - > sizeCalled ) ;
ok ( iRec - > clearCalled = = 0 , " Clear called %ld times \n " , iRec - > clearCalled ) ;
if ( sa )
{
ok ( sa - > cbElements = = RECORD_SIZE_FAIL , " Altered size to %ld \n " , sa - > cbElements ) ;
SafeArrayDestroy ( sa ) ;
ok ( iRec - > clearCalled = = sab [ 0 ] . cElements , " Destroy->Clear called %ld times \n " , iRec - > clearCalled ) ;
}
/* Test VT_RECORD array */
fail_GetSize = FALSE ;
iRec - > ref = START_REF_COUNT ;
iRec - > sizeCalled = 0 ;
iRec - > clearCalled = 0 ;
sa = pSafeArrayCreateEx ( VT_RECORD , 1 , sab , ( LPVOID ) iRec ) ;
ok ( sa ! = NULL , " CreateEx (Rec) failed \n " ) ;
ok ( iRec - > ref = = START_REF_COUNT + 1 , " Wrong iRec refcount %ld \n " , iRec - > ref ) ;
ok ( iRec - > sizeCalled = = 1 , " GetSize called %ld times \n " , iRec - > sizeCalled ) ;
ok ( iRec - > clearCalled = = 0 , " Clear called %ld times \n " , iRec - > clearCalled ) ;
if ( sa )
{
IRecordInfo * saRec = NULL ;
hres = SafeArrayGetRecordInfo ( sa , & saRec ) ;
ok ( hres = = S_OK , " GRI failed \n " ) ;
ok ( saRec = = ( IRecordInfo * ) iRec , " Different saRec \n " ) ;
ok ( iRec - > ref = = START_REF_COUNT + 2 , " Didn't AddRef %ld \n " , iRec - > ref ) ;
if ( iRec - > ref = = START_REF_COUNT + 2 )
IRecordInfo_Release ( saRec ) ;
ok ( sa - > cbElements = = RECORD_SIZE , " Elemsize is %ld \n " , sa - > cbElements ) ;
SafeArrayDestroy ( sa ) ;
ok ( iRec - > sizeCalled = = 1 , " Destroy->GetSize called %ld times \n " , iRec - > sizeCalled ) ;
ok ( iRec - > clearCalled = = sab [ 0 ] . cElements , " Destroy->Clear called %ld times \n " , iRec - > clearCalled ) ;
ok ( iRec - > ref = = START_REF_COUNT , " Wrong iRec refcount %ld \n " , iRec - > ref ) ;
}
}
static void test_SafeArrayClear ( void )
{
SAFEARRAYBOUND sab ;
SAFEARRAY * sa ;
VARIANTARG v ;
HRESULT hres ;
sab . lLbound = 0 ;
sab . cElements = 10 ;
sa = SafeArrayCreate ( VT_UI1 , 1 , & sab ) ;
ok ( sa ! = NULL , " Create() failed. \n " ) ;
if ( ! sa )
return ;
/* Test clearing non-NULL variants containing arrays */
V_VT ( & v ) = VT_ARRAY | VT_UI1 ;
V_ARRAY ( & v ) = sa ;
hres = VariantClear ( & v ) ;
ok ( hres = = S_OK & & V_VT ( & v ) = = VT_EMPTY , " VariantClear: hres 0x%lx, Type %d \n " , hres , V_VT ( & v ) ) ;
ok ( V_ARRAY ( & v ) = = sa , " VariantClear: Overwrote value \n " ) ;
sa = SafeArrayCreate ( VT_UI1 , 1 , & sab ) ;
ok ( sa ! = NULL , " Create() failed. \n " ) ;
if ( ! sa )
return ;
V_VT ( & v ) = VT_SAFEARRAY ;
V_ARRAY ( & v ) = sa ;
hres = VariantClear ( & v ) ;
ok ( hres = = DISP_E_BADVARTYPE , " VariantClear: hres 0x%lx \n " , hres ) ;
V_VT ( & v ) = VT_SAFEARRAY | VT_BYREF ;
V_ARRAYREF ( & v ) = & sa ;
hres = VariantClear ( & v ) ;
ok ( hres = = DISP_E_BADVARTYPE , " VariantClear: hres 0x%lx \n " , hres ) ;
SafeArrayDestroy ( sa ) ;
}
static void test_SafeArrayCopy ( void )
{
SAFEARRAYBOUND sab ;
SAFEARRAY * sa ;
VARIANTARG vSrc , vDst ;
HRESULT hres ;
sab . lLbound = 0 ;
sab . cElements = 10 ;
sa = SafeArrayCreate ( VT_UI1 , 1 , & sab ) ;
ok ( sa ! = NULL , " Create() failed. \n " ) ;
if ( ! sa )
return ;
/* Test copying non-NULL variants containing arrays */
V_VT ( & vSrc ) = ( VT_ARRAY | VT_BYREF | VT_UI1 ) ;
V_ARRAYREF ( & vSrc ) = & sa ;
V_VT ( & vDst ) = VT_EMPTY ;
hres = VariantCopy ( & vDst , & vSrc ) ;
ok ( hres = = S_OK & & V_VT ( & vDst ) = = ( VT_ARRAY | VT_BYREF | VT_UI1 ) ,
" VariantCopy: hres 0x%lx, Type %d \n " , hres , V_VT ( & vDst ) ) ;
ok ( V_ARRAYREF ( & vDst ) = = & sa , " VariantClear: Performed deep copy \n " ) ;
V_VT ( & vSrc ) = ( VT_ARRAY | VT_UI1 ) ;
V_ARRAY ( & vSrc ) = sa ;
V_VT ( & vDst ) = VT_EMPTY ;
hres = VariantCopy ( & vDst , & vSrc ) ;
ok ( hres = = S_OK & & V_VT ( & vDst ) = = ( VT_ARRAY | VT_UI1 ) ,
" VariantCopy: hres 0x%lx, Type %d \n " , hres , V_VT ( & vDst ) ) ;
ok ( V_ARRAY ( & vDst ) ! = sa , " VariantClear: Performed shallow copy \n " ) ;
SafeArrayDestroy ( V_ARRAY ( & vSrc ) ) ;
SafeArrayDestroy ( V_ARRAY ( & vDst ) ) ;
}
# define MKARRAY(low,num,typ) sab.lLbound = low; sab.cElements = num; \
sa = SafeArrayCreate ( typ , 1 , & sab ) ; ok ( sa ! = NULL , " Create() failed. \n " ) ; \
if ( ! sa ) return ; \
V_VT ( & v ) = VT_ARRAY | typ ; V_ARRAY ( & v ) = sa ; VariantInit ( & v2 )
# define MKARRAYCONT(low,num,typ) sab.lLbound = low; sab.cElements = num; \
sa = SafeArrayCreate ( typ , 1 , & sab ) ; if ( ! sa ) continue ; \
V_VT ( & v ) = VT_ARRAY | typ ; V_ARRAY ( & v ) = sa ; VariantInit ( & v2 )
static void test_SafeArrayChangeTypeEx ( void )
{
static const char * szHello = " Hello World " ;
SAFEARRAYBOUND sab ;
SAFEARRAY * sa ;
VARIANTARG v , v2 ;
VARTYPE vt ;
HRESULT hres ;
/* VT_ARRAY|VT_UI1 -> VT_BSTR */
MKARRAY ( 0 , strlen ( szHello ) + 1 , VT_UI1 ) ;
memcpy ( sa - > pvData , szHello , strlen ( szHello ) + 1 ) ;
hres = VariantChangeTypeEx ( & v2 , & v , 0 , 0 , VT_BSTR ) ;
ok ( hres = = S_OK , " CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx \n " , hres ) ;
if ( hres = = S_OK )
{
ok ( V_VT ( & v2 ) = = VT_BSTR , " CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d. \n " , V_VT ( & v2 ) ) ;
ok ( strcmp ( ( char * ) V_BSTR ( & v2 ) , szHello ) = = 0 , " Expected string '%s', got '%s' \n " , szHello ,
( char * ) V_BSTR ( & v2 ) ) ;
VariantClear ( & v2 ) ;
}
/* VT_VECTOR|VT_UI1 -> VT_BSTR */
SafeArrayDestroy ( sa ) ;
sa = SafeArrayCreateVector ( VT_UI1 , 0 , strlen ( szHello ) + 1 ) ;
ok ( sa ! = NULL , " CreateVector() failed. \n " ) ;
if ( ! sa )
return ;
memcpy ( sa - > pvData , szHello , strlen ( szHello ) + 1 ) ;
V_VT ( & v ) = VT_VECTOR | VT_UI1 ;
V_ARRAY ( & v ) = sa ;
VariantInit ( & v2 ) ;
hres = VariantChangeTypeEx ( & v2 , & v , 0 , 0 , VT_BSTR ) ;
ok ( hres = = DISP_E_BADVARTYPE , " CTE VT_VECTOR|VT_UI1 returned %lx \n " , hres ) ;
/* (vector)VT_ARRAY|VT_UI1 -> VT_BSTR (In place) */
V_VT ( & v ) = VT_ARRAY | VT_UI1 ;
hres = VariantChangeTypeEx ( & v , & v , 0 , 0 , VT_BSTR ) ;
ok ( hres = = S_OK , " CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx \n " , hres ) ;
if ( hres = = S_OK )
{
ok ( V_VT ( & v ) = = VT_BSTR , " CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d. \n " , V_VT ( & v ) ) ;
ok ( strcmp ( ( char * ) V_BSTR ( & v ) , szHello ) = = 0 , " Expected string '%s', got '%s' \n " , szHello ,
( char * ) V_BSTR ( & v ) ) ;
VariantClear ( & v ) ;
}
/* To/from BSTR only works with arrays of VT_UI1 */
for ( vt = 0 ; vt < = VT_CLSID ; vt + + )
{
if ( vt = = VT_UI1 )
continue ;
MKARRAYCONT ( 0 , 1 , vt ) ;
hres = VariantChangeTypeEx ( & v2 , & v , 0 , 0 , VT_BSTR ) ;
ok ( hres ! = S_OK , " CTE VT_ARRAY|VT %d->BSTR succeeded \n " , vt ) ;
VariantClear ( & v2 ) ;
}
/* Can't change an array of one type into array of another type , even
* if the other type is the same size
*/
sa = SafeArrayCreateVector ( VT_UI1 , 0 , 1 ) ;
ok ( sa ! = NULL , " CreateVector() failed. \n " ) ;
if ( ! sa )
return ;
V_VT ( & v ) = VT_ARRAY | VT_UI1 ;
V_ARRAY ( & v ) = sa ;
hres = VariantChangeTypeEx ( & v2 , & v , 0 , 0 , VT_ARRAY | VT_I1 ) ;
ok ( hres = = DISP_E_TYPEMISMATCH , " CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_I1 returned %lx \n " , hres ) ;
/* But can change to the same array type */
SafeArrayDestroy ( sa ) ;
sa = SafeArrayCreateVector ( VT_UI1 , 0 , 1 ) ;
ok ( sa ! = NULL , " CreateVector() failed. \n " ) ;
if ( ! sa )
return ;
V_VT ( & v ) = VT_ARRAY | VT_UI1 ;
V_ARRAY ( & v ) = sa ;
hres = VariantChangeTypeEx ( & v2 , & v , 0 , 0 , VT_ARRAY | VT_UI1 ) ;
ok ( hres = = S_OK , " CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_UI1 returned %lx \n " , hres ) ;
/* NULL/EMPTY */
MKARRAY ( 0 , 1 , VT_UI1 ) ;
hres = VariantChangeTypeEx ( & v2 , & v , 0 , 0 , VT_NULL ) ;
ok ( hres = = DISP_E_TYPEMISMATCH , " CTE VT_ARRAY|VT_UI1 returned %lx \n " , hres ) ;
MKARRAY ( 0 , 1 , VT_UI1 ) ;
hres = VariantChangeTypeEx ( & v2 , & v , 0 , 0 , VT_EMPTY ) ;
ok ( hres = = DISP_E_TYPEMISMATCH , " CTE VT_ARRAY|VT_UI1 returned %lx \n " , hres ) ;
}
START_TEST ( safearray )
{
hOleaut32 = LoadLibraryA ( " oleaut32.dll " ) ;
GETPTR ( SafeArrayAllocDescriptorEx ) ;
GETPTR ( SafeArrayCopyData ) ;
GETPTR ( SafeArrayGetIID ) ;
GETPTR ( SafeArraySetIID ) ;
GETPTR ( SafeArrayGetVartype ) ;
GETPTR ( SafeArrayCreateEx ) ;
test_safearray ( ) ;
test_SafeArrayAllocDestroyDescriptor ( ) ;
test_SafeArrayCreateLockDestroy ( ) ;
test_VectorCreateLockDestroy ( ) ;
test_LockUnlock ( ) ;
test_SafeArrayChangeTypeEx ( ) ;
test_SafeArrayCopy ( ) ;
test_SafeArrayClear ( ) ;
test_SafeArrayCreateEx ( ) ;
test_SafeArrayCopyData ( ) ;
test_SafeArrayGetPutElement ( ) ;
}