user32: Move unpack_message call to User32CallWindowProc.
[wine.git] / dlls / oleaut32 / tests / safearray.c
blobdbbe86994f51a05e682f197e772512be4bb4e5fc
1 /*
2 * SafeArray test program
4 * Copyright 2002 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include <float.h>
27 #define COBJMACROS
28 #define CONST_VTABLE
29 #include "wine/test.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "wingdi.h"
34 #include "winnls.h"
35 #include "winsock2.h"
36 #include "winerror.h"
37 #include "winnt.h"
39 #include "wtypes.h"
40 #include "oleauto.h"
42 #ifndef FADF_CREATEVECTOR
43 const USHORT FADF_CREATEVECTOR = 0x2000;
44 #endif
46 static HMODULE hOleaut32;
48 static HRESULT (WINAPI *pSafeArrayAllocDescriptorEx)(VARTYPE,UINT,SAFEARRAY**);
49 static HRESULT (WINAPI *pSafeArrayGetVartype)(SAFEARRAY*,VARTYPE*);
50 static HRESULT (WINAPI *pSafeArrayGetRecordInfo)(SAFEARRAY*,IRecordInfo**);
51 static SAFEARRAY* (WINAPI *pSafeArrayCreateEx)(VARTYPE,UINT,SAFEARRAYBOUND*,LPVOID);
53 #define GETPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func)
55 /* Has I8/UI8 data type? */
56 static BOOL has_i8;
57 /* Has INT_PTR/UINT_PTR type? */
58 static BOOL has_int_ptr;
60 static const USHORT ignored_copy_features[] =
62 FADF_AUTO,
63 FADF_STATIC,
64 FADF_EMBEDDED,
65 FADF_FIXEDSIZE
68 #define START_REF_COUNT 1
69 #define RECORD_SIZE 64
70 #define RECORD_SIZE_FAIL 17
71 /************************************************************************
72 * Dummy IRecordInfo Implementation
74 typedef struct IRecordInfoImpl
76 IRecordInfo IRecordInfo_iface;
77 LONG ref;
78 unsigned int sizeCalled;
79 unsigned int clearCalled;
80 unsigned int recordcopy;
81 } IRecordInfoImpl;
83 static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface)
85 return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface);
88 static HRESULT WINAPI RecordInfo_QueryInterface(IRecordInfo *iface, REFIID riid, void **obj)
90 *obj = NULL;
92 if (IsEqualIID(riid, &IID_IUnknown) ||
93 IsEqualIID(riid, &IID_IRecordInfo))
95 *obj = iface;
96 IRecordInfo_AddRef(iface);
97 return S_OK;
100 return E_NOINTERFACE;
103 static ULONG WINAPI RecordInfo_AddRef(IRecordInfo *iface)
105 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
106 return InterlockedIncrement(&This->ref);
109 static ULONG WINAPI RecordInfo_Release(IRecordInfo *iface)
111 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
112 ULONG ref = InterlockedDecrement(&This->ref);
114 if (!ref)
115 HeapFree(GetProcessHeap(), 0, This);
117 return ref;
120 static HRESULT WINAPI RecordInfo_RecordInit(IRecordInfo *iface, PVOID pvNew)
122 ok(0, "unexpected call\n");
123 return E_NOTIMPL;
126 static BOOL fail_GetSize; /* Whether to fail the GetSize call */
128 static HRESULT WINAPI RecordInfo_RecordClear(IRecordInfo *iface, PVOID pvExisting)
130 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
131 This->clearCalled++;
132 return S_OK;
135 static HRESULT WINAPI RecordInfo_RecordCopy(IRecordInfo *iface, PVOID pvExisting, PVOID pvNew)
137 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
138 This->recordcopy++;
139 return S_OK;
142 static HRESULT WINAPI RecordInfo_GetGuid(IRecordInfo *iface, GUID *pguid)
144 ok(0, "unexpected call\n");
145 return E_NOTIMPL;
148 static HRESULT WINAPI RecordInfo_GetName(IRecordInfo *iface, BSTR *pbstrName)
150 ok(0, "unexpected call\n");
151 return E_NOTIMPL;
154 static HRESULT WINAPI RecordInfo_GetSize(IRecordInfo *iface, ULONG* size)
156 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
157 This->sizeCalled++;
158 if (fail_GetSize)
160 *size = RECORD_SIZE_FAIL;
161 return E_UNEXPECTED;
163 *size = RECORD_SIZE;
164 return S_OK;
167 static HRESULT WINAPI RecordInfo_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo)
169 ok(0, "unexpected call\n");
170 return E_NOTIMPL;
173 static HRESULT WINAPI RecordInfo_GetField(IRecordInfo *iface, PVOID pvData,
174 LPCOLESTR szFieldName, VARIANT *pvarField)
176 ok(0, "unexpected call\n");
177 return E_NOTIMPL;
180 static HRESULT WINAPI RecordInfo_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData,
181 LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray)
183 ok(0, "unexpected call\n");
184 return E_NOTIMPL;
187 static HRESULT WINAPI RecordInfo_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData,
188 LPCOLESTR szFieldName, VARIANT *pvarField)
190 ok(0, "unexpected call\n");
191 return E_NOTIMPL;
194 static HRESULT WINAPI RecordInfo_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags,
195 PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField)
197 ok(0, "unexpected call\n");
198 return E_NOTIMPL;
201 static HRESULT WINAPI RecordInfo_GetFieldNames(IRecordInfo *iface, ULONG *pcNames,
202 BSTR *rgBstrNames)
204 ok(0, "unexpected call\n");
205 return E_NOTIMPL;
208 static BOOL WINAPI RecordInfo_IsMatchingType(IRecordInfo *iface, IRecordInfo *info2)
210 ok(0, "unexpected call\n");
211 return FALSE;
214 static PVOID WINAPI RecordInfo_RecordCreate(IRecordInfo *iface)
216 ok(0, "unexpected call\n");
217 return NULL;
220 static HRESULT WINAPI RecordInfo_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource,
221 PVOID *ppvDest)
223 ok(0, "unexpected call\n");
224 return E_NOTIMPL;
227 static HRESULT WINAPI RecordInfo_RecordDestroy(IRecordInfo *iface, PVOID pvRecord)
229 ok(0, "unexpected call\n");
230 return E_NOTIMPL;
233 static const IRecordInfoVtbl RecordInfoVtbl =
235 RecordInfo_QueryInterface,
236 RecordInfo_AddRef,
237 RecordInfo_Release,
238 RecordInfo_RecordInit,
239 RecordInfo_RecordClear,
240 RecordInfo_RecordCopy,
241 RecordInfo_GetGuid,
242 RecordInfo_GetName,
243 RecordInfo_GetSize,
244 RecordInfo_GetTypeInfo,
245 RecordInfo_GetField,
246 RecordInfo_GetFieldNoCopy,
247 RecordInfo_PutField,
248 RecordInfo_PutFieldNoCopy,
249 RecordInfo_GetFieldNames,
250 RecordInfo_IsMatchingType,
251 RecordInfo_RecordCreate,
252 RecordInfo_RecordCreateCopy,
253 RecordInfo_RecordDestroy
256 static IRecordInfoImpl *IRecordInfoImpl_Construct(void)
258 IRecordInfoImpl *rec;
260 rec = HeapAlloc(GetProcessHeap(), 0, sizeof(IRecordInfoImpl));
261 rec->IRecordInfo_iface.lpVtbl = &RecordInfoVtbl;
262 rec->ref = START_REF_COUNT;
263 rec->clearCalled = 0;
264 rec->sizeCalled = 0;
265 return rec;
268 static DWORD SAFEARRAY_GetVTSize(VARTYPE vt)
270 switch (vt)
272 case VT_I1:
273 case VT_UI1: return sizeof(BYTE);
274 case VT_BOOL:
275 case VT_I2:
276 case VT_UI2: return sizeof(SHORT);
277 case VT_I4:
278 case VT_UI4:
279 case VT_R4:
280 case VT_ERROR: return sizeof(LONG);
281 case VT_R8: return sizeof(LONG64);
282 case VT_I8:
283 case VT_UI8:
284 if (has_i8)
285 return sizeof(LONG64);
286 break;
287 case VT_INT:
288 case VT_UINT: return sizeof(INT);
289 case VT_INT_PTR:
290 case VT_UINT_PTR:
291 if (has_int_ptr)
292 return sizeof(UINT_PTR);
293 break;
294 case VT_CY: return sizeof(CY);
295 case VT_DATE: return sizeof(DATE);
296 case VT_BSTR: return sizeof(BSTR);
297 case VT_DISPATCH: return sizeof(LPDISPATCH);
298 case VT_VARIANT: return sizeof(VARIANT);
299 case VT_UNKNOWN: return sizeof(LPUNKNOWN);
300 case VT_DECIMAL: return sizeof(DECIMAL);
302 return 0;
305 static void check_for_VT_INT_PTR(void)
307 /* Set a global flag if VT_INT_PTR is supported */
309 SAFEARRAY* a;
310 SAFEARRAYBOUND bound;
311 bound.cElements = 0;
312 bound.lLbound = 0;
313 a = SafeArrayCreate(VT_INT_PTR, 1, &bound);
314 if (a) {
315 HRESULT hres;
316 trace("VT_INT_PTR is supported\n");
317 has_int_ptr = TRUE;
318 hres = SafeArrayDestroy(a);
319 ok(hres == S_OK, "got 0x%08lx\n", hres);
321 else {
322 trace("VT_INT_PTR is not supported\n");
323 has_int_ptr = FALSE;
327 #define VARTYPE_NOT_SUPPORTED 0
328 static struct {
329 VARTYPE vt; /* VT */
330 UINT elemsize; /* elementsize by VT */
331 UINT expflags; /* fFeatures from SafeArrayAllocDescriptorEx */
332 UINT addflags; /* additional fFeatures from SafeArrayCreate */
333 } vttypes[] = {
334 {VT_EMPTY, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
335 {VT_NULL, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
336 {VT_I2, 2, FADF_HAVEVARTYPE,0},
337 {VT_I4, 4, FADF_HAVEVARTYPE,0},
338 {VT_R4, 4, FADF_HAVEVARTYPE,0},
339 {VT_R8, 8, FADF_HAVEVARTYPE,0},
340 {VT_CY, 8, FADF_HAVEVARTYPE,0},
341 {VT_DATE, 8, FADF_HAVEVARTYPE,0},
342 {VT_BSTR, sizeof(BSTR), FADF_HAVEVARTYPE,FADF_BSTR},
343 {VT_DISPATCH, sizeof(LPDISPATCH), FADF_HAVEIID, FADF_DISPATCH},
344 {VT_ERROR, 4, FADF_HAVEVARTYPE,0},
345 {VT_BOOL, 2, FADF_HAVEVARTYPE,0},
346 {VT_VARIANT, sizeof(VARIANT), FADF_HAVEVARTYPE,FADF_VARIANT},
347 {VT_UNKNOWN, sizeof(LPUNKNOWN), FADF_HAVEIID, FADF_UNKNOWN},
348 {VT_DECIMAL, sizeof(DECIMAL), FADF_HAVEVARTYPE,0},
349 {15, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0}, /* no VT_xxx */
350 {VT_I1, 1, FADF_HAVEVARTYPE,0},
351 {VT_UI1, 1, FADF_HAVEVARTYPE,0},
352 {VT_UI2, 2, FADF_HAVEVARTYPE,0},
353 {VT_UI4, 4, FADF_HAVEVARTYPE,0},
354 {VT_I8, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
355 {VT_UI8, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
356 {VT_INT, sizeof(INT), FADF_HAVEVARTYPE,0},
357 {VT_UINT, sizeof(UINT), FADF_HAVEVARTYPE,0},
358 {VT_VOID, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
359 {VT_HRESULT, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
360 {VT_PTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
361 {VT_SAFEARRAY,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
362 {VT_CARRAY, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
363 {VT_USERDEFINED,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
364 {VT_LPSTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
365 {VT_LPWSTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
366 {VT_FILETIME, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
367 {VT_RECORD, VARTYPE_NOT_SUPPORTED,FADF_RECORD,0},
368 {VT_BLOB, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
369 {VT_STREAM, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
370 {VT_STORAGE, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
371 {VT_STREAMED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
372 {VT_STORED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
373 {VT_BLOB_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
374 {VT_CF, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
375 {VT_CLSID, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
378 static void test_safearray(void)
380 SAFEARRAY *a, b, *c;
381 unsigned int i, diff;
382 LONG indices[2];
383 HRESULT hres;
384 SAFEARRAYBOUND bound, bounds[2];
385 VARIANT v,d;
386 LPVOID data;
387 IID iid;
388 VARTYPE vt;
389 LONG l;
390 unsigned char *ptr1, *ptr2;
392 hres = SafeArrayDestroy( NULL);
393 ok( hres == S_OK, "SafeArrayDestroy( NULL) returned 0x%lx\n", hres);
395 bound.cElements = 1;
396 bound.lLbound = 0;
397 a = SafeArrayCreate(-1, 1, &bound);
398 ok(NULL == a,"SAC(-1,1,[1,0]) not failed?\n");
400 bound.cElements = 0;
401 bound.lLbound = 42;
402 a = SafeArrayCreate(VT_I4, 1, &bound);
403 ok(NULL != a,"SAC(VT_I4,1,[0,0]) failed.\n");
405 hres = SafeArrayGetLBound(a, 1, &l);
406 ok(hres == S_OK, "SAGLB of 0 size dimensioned array failed with %lx\n",hres);
407 ok(l == 42, "SAGLB of 0 size dimensioned array failed to return 42, but returned %ld\n",l);
408 hres = SafeArrayGetUBound(a, 1, &l);
409 ok(hres == S_OK, "SAGUB of 0 size dimensioned array failed with %lx\n",hres);
410 ok(l == 41, "SAGUB of 0 size dimensioned array failed to return 41, but returned %ld\n",l);
412 hres = SafeArrayAccessData(a, &data);
413 ok(hres == S_OK, "SafeArrayAccessData of 0 size dimensioned array failed with %lx\n", hres);
414 SafeArrayUnaccessData(a);
416 bound.cElements = 2;
417 hres = SafeArrayRedim(a, &bound);
418 ok(hres == S_OK,"SAR of a 0 elements dimension failed with hres %lx\n", hres);
419 bound.cElements = 0;
420 hres = SafeArrayRedim(a, &bound);
421 ok(hres == S_OK || hres == E_OUTOFMEMORY,
422 "SAR to a 0 elements dimension failed with hres %lx\n", hres);
423 hres = SafeArrayDestroy(a);
424 ok(hres == S_OK,"SAD of 0 dim array failed with hres %lx\n", hres);
426 SafeArrayAllocDescriptor(2, &a);
427 a->rgsabound[0].cElements = 2;
428 a->rgsabound[0].lLbound = 1;
429 a->rgsabound[1].cElements = 4;
430 a->rgsabound[1].lLbound = 1;
431 a->cbElements = 2;
432 hres = SafeArrayAllocData(a);
433 ok(hres == S_OK, "SafeArrayAllocData failed with hres %lx\n", hres);
435 indices[0] = 4;
436 indices[1] = 2;
437 hres = SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
438 ok(hres == S_OK, "SAPOI failed with hres %lx\n", hres);
439 SafeArrayAccessData(a, (void **)&ptr2);
440 ok(ptr1 - ptr2 == 14, "SAPOI got wrong ptr\n");
441 *(WORD *)ptr1 = 0x55aa;
442 SafeArrayUnaccessData(a);
444 bound.cElements = 10;
445 bound.lLbound = 1;
446 SafeArrayRedim(a, &bound);
447 ptr1 = NULL;
448 SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
449 ok(*(WORD *)ptr1 == 0x55aa, "Data not preserved when resizing array\n");
451 bound.cElements = 10;
452 bound.lLbound = 0;
453 SafeArrayRedim(a, &bound);
454 SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
455 ok(*(WORD *)ptr1 == 0 ||
456 broken(*(WORD *)ptr1 != 0), /* Win 2003 */
457 "Expanded area not zero-initialized\n");
459 indices[1] = 1;
460 SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
461 ok(*(WORD *)ptr1 == 0x55aa ||
462 broken(*(WORD *)ptr1 != 0x55aa), /* Win 2003 */
463 "Data not preserved when resizing array\n");
465 hres = SafeArrayDestroy(a);
466 ok(hres == S_OK,"SAD failed with hres %lx\n", hres);
468 bounds[0].cElements = 0; bounds[0].lLbound = 1;
469 bounds[1].cElements = 2; bounds[1].lLbound = 23;
470 a = SafeArrayCreate(VT_I4,2,bounds);
471 ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
473 hres = SafeArrayDestroy(a);
474 ok(hres == S_OK,"SAD failed with hres %lx\n", hres);
475 bounds[0].cElements = 1; bounds[0].lLbound = 1;
476 bounds[1].cElements = 0; bounds[1].lLbound = 23;
477 a = SafeArrayCreate(VT_I4,2,bounds);
478 ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
480 hres = SafeArrayDestroy(a);
481 ok(hres == S_OK,"SAD failed with hres %lx\n", hres);
483 bounds[0].cElements = 42; bounds[0].lLbound = 1;
484 bounds[1].cElements = 2; bounds[1].lLbound = 23;
485 a = SafeArrayCreate(VT_I4,2,bounds);
486 ok(a != NULL,"SAC(VT_INT32,2,...) failed.\n");
488 hres = SafeArrayGetLBound (a, 0, &l);
489 ok (hres == DISP_E_BADINDEX, "SAGLB 0 failed with %lx\n", hres);
490 hres = SafeArrayGetLBound (a, 1, &l);
491 ok (hres == S_OK, "SAGLB 1 failed with %lx\n", hres);
492 ok (l == 1, "SAGLB 1 returned %ld instead of 1\n", l);
493 hres = SafeArrayGetLBound (a, 2, &l);
494 ok (hres == S_OK, "SAGLB 2 failed with %lx\n", hres);
495 ok (l == 23, "SAGLB 2 returned %ld instead of 23\n", l);
496 hres = SafeArrayGetLBound (a, 3, &l);
497 ok (hres == DISP_E_BADINDEX, "SAGLB 3 failed with %lx\n", hres);
499 hres = SafeArrayGetUBound (a, 0, &l);
500 ok (hres == DISP_E_BADINDEX, "SAGUB 0 failed with %lx\n", hres);
501 hres = SafeArrayGetUBound (a, 1, &l);
502 ok (hres == S_OK, "SAGUB 1 failed with %lx\n", hres);
503 ok (l == 42, "SAGUB 1 returned %ld instead of 42\n", l);
504 hres = SafeArrayGetUBound (a, 2, &l);
505 ok (hres == S_OK, "SAGUB 2 failed with %lx\n", hres);
506 ok (l == 24, "SAGUB 2 returned %ld instead of 24\n", l);
507 hres = SafeArrayGetUBound (a, 3, &l);
508 ok (hres == DISP_E_BADINDEX, "SAGUB 3 failed with %lx\n", hres);
510 i = SafeArrayGetDim(a);
511 ok(i == 2, "getdims of 2 din array returned %d\n",i);
513 indices[0] = 0;
514 indices[1] = 23;
515 hres = SafeArrayGetElement(a, indices, &i);
516 ok(DISP_E_BADINDEX == hres,"SAGE failed [0,23], hres 0x%lx\n",hres);
518 indices[0] = 1;
519 indices[1] = 22;
520 hres = SafeArrayGetElement(a, indices, &i);
521 ok(DISP_E_BADINDEX == hres,"SAGE failed [1,22], hres 0x%lx\n",hres);
523 indices[0] = 1;
524 indices[1] = 23;
525 hres = SafeArrayGetElement(a, indices, &i);
526 ok(S_OK == hres,"SAGE failed [1,23], hres 0x%lx\n",hres);
528 indices[0] = 1;
529 indices[1] = 25;
530 hres = SafeArrayGetElement(a, indices, &i);
531 ok(DISP_E_BADINDEX == hres,"SAGE failed [1,24], hres 0x%lx\n",hres);
533 indices[0] = 3;
534 indices[1] = 23;
535 hres = SafeArrayGetElement(a, indices, &i);
536 ok(S_OK == hres,"SAGE failed [42,23], hres 0x%lx\n",hres);
538 hres = SafeArrayAccessData(a, (void**)&ptr1);
539 ok(S_OK == hres, "SAAD failed with 0x%lx\n", hres);
541 indices[0] = 3;
542 indices[1] = 23;
543 hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2);
544 ok(S_OK == hres,"SAPOI failed [1,23], hres 0x%lx\n",hres);
545 diff = ptr2 - ptr1;
546 ok(diff == 8,"ptr difference is not 8, but %d (%p vs %p)\n", diff, ptr2, ptr1);
548 indices[0] = 3;
549 indices[1] = 24;
550 hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2);
551 ok(S_OK == hres,"SAPOI failed [5,24], hres 0x%lx\n",hres);
552 diff = ptr2 - ptr1;
553 ok(diff == 176,"ptr difference is not 176, but %d (%p vs %p)\n", diff, ptr2, ptr1);
555 indices[0] = 20;
556 indices[1] = 23;
557 hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2);
558 ok(S_OK == hres,"SAPOI failed [20,23], hres 0x%lx\n",hres);
559 diff = ptr2 - ptr1;
560 ok(diff == 76,"ptr difference is not 76, but %d (%p vs %p)\n", diff, ptr2, ptr1);
562 hres = SafeArrayUnaccessData(a);
563 ok(S_OK == hres, "SAUAD failed with 0x%lx\n", hres);
565 hres = SafeArrayDestroy(a);
566 ok(hres == S_OK,"SAD failed with hres %lx\n", hres);
568 for (i = 0; i < ARRAY_SIZE(vttypes); i++) {
569 if ((i == VT_I8 || i == VT_UI8) && has_i8)
571 vttypes[i].elemsize = sizeof(LONG64);
574 a = SafeArrayCreate(vttypes[i].vt, 1, &bound);
576 ok((!a && !vttypes[i].elemsize) ||
577 (a && vttypes[i].elemsize == a->cbElements),
578 "SAC(%d,1,[1,0]), %p result %ld, expected %d\n",
579 vttypes[i].vt,a,(a?a->cbElements:0),vttypes[i].elemsize);
581 if (a)
583 ok(a->fFeatures == (vttypes[i].expflags | vttypes[i].addflags),
584 "SAC of %d returned feature flags %x, expected %x\n",
585 vttypes[i].vt, a->fFeatures,
586 vttypes[i].expflags|vttypes[i].addflags);
587 ok(SafeArrayGetElemsize(a) == vttypes[i].elemsize,
588 "SAGE for vt %d returned elemsize %d instead of expected %d\n",
589 vttypes[i].vt, SafeArrayGetElemsize(a),vttypes[i].elemsize);
592 if (!a) continue;
594 if (pSafeArrayGetVartype)
596 hres = pSafeArrayGetVartype(a, &vt);
597 ok(hres == S_OK, "SAGVT of arra y with vt %d failed with %lx\n", vttypes[i].vt, hres);
598 /* Windows prior to Vista returns VT_UNKNOWN instead of VT_DISPATCH */
599 ok(broken(vt == VT_UNKNOWN) || vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d\n", vttypes[i].vt, vt);
602 hres = SafeArrayCopy(a, &c);
603 ok(hres == S_OK, "failed to copy safearray of vt %d with hres %lx\n", vttypes[i].vt, hres);
605 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
607 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);
608 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);
610 if (pSafeArrayGetVartype) {
611 hres = pSafeArrayGetVartype(c, &vt);
612 ok(hres == S_OK, "SAGVT of array with vt %d failed with %lx\n", vttypes[i].vt, hres);
613 /* Windows prior to Vista returns VT_UNKNOWN instead of VT_DISPATCH */
614 ok(broken(vt == VT_UNKNOWN) || vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d\n", vttypes[i].vt, vt);
617 hres = SafeArrayCopyData(a, c);
618 ok(hres == S_OK, "failed to copy safearray data of vt %d with hres %lx\n", vttypes[i].vt, hres);
620 hres = SafeArrayDestroyData(c);
621 ok(hres == S_OK,"SADD of copy of array with vt %d failed with hres %lx\n", vttypes[i].vt, hres);
623 hres = SafeArrayDestroy(c);
624 ok(hres == S_OK,"SAD failed with hres %lx\n", hres);
626 hres = SafeArrayDestroy(a);
627 ok(hres == S_OK,"SAD of array with vt %d failed with hres %lx\n", vttypes[i].vt, hres);
630 /* Test conversion of type|VT_ARRAY <-> VT_BSTR */
631 bound.lLbound = 0;
632 bound.cElements = 10;
633 a = SafeArrayCreate(VT_UI1, 1, &bound);
634 ok(a != NULL, "SAC failed.\n");
635 ok(S_OK == SafeArrayAccessData(a, &data),"SACD failed\n");
636 memcpy(data,"Hello World\n",10);
637 ok(S_OK == SafeArrayUnaccessData(a),"SAUD failed\n");
638 V_VT(&v) = VT_ARRAY|VT_UI1;
639 V_ARRAY(&v) = a;
640 hres = VariantChangeTypeEx(&v, &v, 0, 0, VT_BSTR);
641 ok(hres==S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx\n",hres);
642 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));
643 ok(V_BSTR(&v)[0] == 0x6548,"First letter are not 'He', but %x\n", V_BSTR(&v)[0]);
644 VariantClear(&v);
646 VariantInit(&d);
647 V_VT(&v) = VT_BSTR;
648 V_BSTR(&v) = SysAllocStringLen(NULL, 0);
649 hres = VariantChangeTypeEx(&d, &v, 0, 0, VT_UI1|VT_ARRAY);
650 ok(hres==S_OK, "CTE VT_BSTR -> VT_UI1|VT_ARRAY failed with %lx\n",hres);
651 ok(V_VT(&d) == (VT_UI1|VT_ARRAY),"CTE BSTR -> VT_UI1|VT_ARRAY did not return VT_UI1|VT_ARRAY, but %d.v\n",V_VT(&v));
652 VariantClear(&v);
653 VariantClear(&d);
655 /* check locking functions */
656 a = SafeArrayCreate(VT_I4, 1, &bound);
657 ok(a!=NULL,"SAC should not fail\n");
659 hres = SafeArrayAccessData(a, &data);
660 ok(hres == S_OK,"SAAD failed with hres %lx\n",hres);
662 hres = SafeArrayDestroy(a);
663 ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy not failed with DISP_E_ARRAYISLOCKED, but with hres %lx\n", hres);
665 hres = SafeArrayDestroyData(a);
666 ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy data not failed with DISP_E_ARRAYISLOCKED, but with hres %lx\n", hres);
668 hres = SafeArrayDestroyDescriptor(a);
669 ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy descriptor not failed with DISP_E_ARRAYISLOCKED, but with hres %lx\n", hres);
671 hres = SafeArrayUnaccessData(a);
672 ok(hres == S_OK,"SAUD failed after lock/destroy test\n");
674 hres = SafeArrayDestroy(a);
675 ok(hres == S_OK,"SAD failed after lock/destroy test\n");
677 /* Test if we need to destroy data before descriptor */
678 a = SafeArrayCreate(VT_I4, 1, &bound);
679 ok(a!=NULL,"SAC should not fail\n");
680 hres = SafeArrayDestroyDescriptor(a);
681 ok(hres == S_OK,"SADD with data in array failed with hres %lx\n",hres);
683 /* IID functions */
684 /* init a small stack safearray */
685 memset(&b, 0, sizeof(b));
686 b.cDims = 1;
687 memset(&iid, 0x42, sizeof(IID));
688 hres = SafeArraySetIID(&b, &iid);
689 ok(hres == E_INVALIDARG, "Unexpected ret value %#lx.\n", hres);
691 hres = SafeArrayAllocDescriptor(1, &a);
692 ok(hres == S_OK, "Failed to allocate array descriptor, hr %#lx.\n", hres);
693 ok((a->fFeatures & FADF_HAVEIID) == 0, "Unexpected features mask %#x.\n", a->fFeatures);
694 hres = SafeArraySetIID(a, &iid);
695 ok(hres == E_INVALIDARG, "Unexpected ret value %#lx.\n", hres);
697 hres = SafeArrayDestroyDescriptor(a);
698 ok(hres == S_OK,"SADD failed with hres %lx\n",hres);
700 if (!pSafeArrayAllocDescriptorEx)
701 return;
703 for (i = 0; i < ARRAY_SIZE(vttypes); i++) {
704 a = NULL;
705 hres = pSafeArrayAllocDescriptorEx(vttypes[i].vt,1,&a);
706 ok(hres == S_OK, "SafeArrayAllocDescriptorEx gave hres 0x%lx\n", hres);
707 ok(a->fFeatures == vttypes[i].expflags,"SAADE(%d) resulted with flags %x, expected %x\n", vttypes[i].vt, a->fFeatures, vttypes[i].expflags);
708 if (a->fFeatures & FADF_HAVEIID) {
709 hres = SafeArrayGetIID(a, &iid);
710 ok(hres == S_OK,"SAGIID failed for vt %d with hres %lx\n", vttypes[i].vt,hres);
711 switch (vttypes[i].vt) {
712 case VT_UNKNOWN:
713 ok(IsEqualGUID(((GUID*)a)-1,&IID_IUnknown),"guid for VT_UNKNOWN is not IID_IUnknown\n");
714 ok(IsEqualGUID(&iid, &IID_IUnknown),"SAGIID returned wrong GUID for IUnknown\n");
715 break;
716 case VT_DISPATCH:
717 ok(IsEqualGUID(((GUID*)a)-1,&IID_IDispatch),"guid for VT_UNKNOWN is not IID_IDispatch\n");
718 ok(IsEqualGUID(&iid, &IID_IDispatch),"SAGIID returned wrong GUID for IDispatch\n");
719 break;
720 default:
721 ok(FALSE,"unknown vt %d with FADF_HAVEIID\n",vttypes[i].vt);
722 break;
724 } else {
725 hres = SafeArrayGetIID(a, &iid);
726 ok(hres == E_INVALIDARG,"SAGIID did not fail for vt %d with hres %lx\n", vttypes[i].vt,hres);
728 if (a->fFeatures & FADF_RECORD) {
729 ok(vttypes[i].vt == VT_RECORD,"FADF_RECORD for non record %d\n",vttypes[i].vt);
731 if (a->fFeatures & FADF_HAVEVARTYPE) {
732 ok(vttypes[i].vt == ((DWORD*)a)[-1], "FADF_HAVEVARTYPE set, but vt %d mismatch stored %ld\n",vttypes[i].vt,((DWORD*)a)[-1]);
735 hres = pSafeArrayGetVartype(a, &vt);
736 ok(hres == S_OK, "SAGVT of array with vt %d failed with %lx\n", vttypes[i].vt, hres);
738 if (vttypes[i].vt == VT_DISPATCH) {
739 /* Special case. Checked against Windows. */
740 ok(vt == VT_UNKNOWN, "SAGVT of array with VT_DISPATCH returned not VT_UNKNOWN, but %d\n", vt);
741 } else {
742 ok(vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d\n", vttypes[i].vt, vt);
745 if (a->fFeatures & FADF_HAVEIID) {
746 hres = SafeArraySetIID(a, &IID_IStorage); /* random IID */
747 ok(hres == S_OK,"SASIID failed with FADF_HAVEIID set for vt %d with %lx\n", vttypes[i].vt, hres);
748 hres = SafeArrayGetIID(a, &iid);
749 ok(hres == S_OK,"SAGIID failed with FADF_HAVEIID set for vt %d with %lx\n", vttypes[i].vt, hres);
750 ok(IsEqualGUID(&iid, &IID_IStorage),"returned iid is not IID_IStorage\n");
751 } else {
752 hres = SafeArraySetIID(a, &IID_IStorage); /* random IID */
753 ok(hres == E_INVALIDARG,"SASIID did not failed with !FADF_HAVEIID set for vt %d with %lx\n", vttypes[i].vt, hres);
755 hres = SafeArrayDestroyDescriptor(a);
756 ok(hres == S_OK,"SADD failed with hres %lx\n",hres);
760 static void test_SafeArrayAllocDestroyDescriptor(void)
762 SAFEARRAY *sa;
763 HRESULT hres;
764 UINT i;
766 /* Failure cases */
767 hres = SafeArrayAllocDescriptor(0, &sa);
768 ok(hres == E_INVALIDARG, "0 dimensions gave hres 0x%lx\n", hres);
770 hres = SafeArrayAllocDescriptor(65536, &sa);
771 ok(hres == E_INVALIDARG, "65536 dimensions gave hres 0x%lx\n", hres);
773 if (0)
775 /* Crashes on 95: XP & Wine return E_POINTER */
776 hres=SafeArrayAllocDescriptor(1, NULL);
777 ok(hres == E_POINTER,"NULL parm gave hres 0x%lx\n", hres);
780 /* Test up to the dimension boundary case */
781 for (i = 5; i <= 65535; i += 30)
783 hres = SafeArrayAllocDescriptor(i, &sa);
784 ok(hres == S_OK, "%d dimensions failed; hres 0x%lx\n", i, hres);
786 if (hres == S_OK)
788 ok(SafeArrayGetDim(sa) == i, "Dimension is %d; should be %d\n",
789 SafeArrayGetDim(sa), i);
791 hres = SafeArrayDestroyDescriptor(sa);
792 ok(hres == S_OK, "destroy failed; hres 0x%lx\n", hres);
796 if (!pSafeArrayAllocDescriptorEx)
797 return;
799 hres = pSafeArrayAllocDescriptorEx(VT_UI1, 0, &sa);
800 ok(hres == E_INVALIDARG, "0 dimensions gave hres 0x%lx\n", hres);
802 hres = pSafeArrayAllocDescriptorEx(VT_UI1, 65536, &sa);
803 ok(hres == E_INVALIDARG, "65536 dimensions gave hres 0x%lx\n", hres);
805 hres = pSafeArrayAllocDescriptorEx(VT_UI1, 1, NULL);
806 ok(hres == E_POINTER,"NULL parm gave hres 0x%lx\n", hres);
808 hres = pSafeArrayAllocDescriptorEx(-1, 1, &sa);
809 ok(hres == S_OK, "VT = -1 gave hres 0x%lx\n", hres);
811 sa->rgsabound[0].cElements = 0;
812 sa->rgsabound[0].lLbound = 1;
814 hres = SafeArrayAllocData(sa);
815 ok(hres == S_OK, "SafeArrayAllocData gave hres 0x%lx\n", hres);
817 hres = SafeArrayDestroy(sa);
818 ok(hres == S_OK,"SafeArrayDestroy failed with hres %lx\n",hres);
821 static void test_SafeArrayCreateLockDestroy(void)
823 SAFEARRAYBOUND sab[4];
824 SAFEARRAY *sa;
825 HRESULT hres;
826 VARTYPE vt;
827 UINT dimension;
829 for (dimension = 0; dimension < ARRAY_SIZE(sab); dimension++)
831 sab[dimension].lLbound = 0;
832 sab[dimension].cElements = 8;
835 /* Failure cases */
836 /* This test crashes very early versions with no error checking...
837 sa = SafeArrayCreate(VT_UI1, 1, NULL);
838 ok(sa == NULL, "NULL bounds didn't fail\n");
840 sa = SafeArrayCreate(VT_UI1, 65536, sab);
841 ok(!sa, "Max bounds didn't fail\n");
843 memset(sab, 0, sizeof(sab));
845 /* Don't test 0 sized dimensions, as Windows has a bug which allows this */
847 for (dimension = 0; dimension < ARRAY_SIZE(sab); dimension++)
848 sab[dimension].cElements = 8;
850 /* Test all VARTYPES in 1-4 dimensions */
851 for (dimension = 1; dimension < 4; dimension++)
853 for (vt = VT_EMPTY; vt < VT_CLSID; vt++)
855 DWORD dwLen = SAFEARRAY_GetVTSize(vt);
857 sa = SafeArrayCreate(vt, dimension, sab);
859 if (dwLen)
860 ok(sa != NULL, "VARTYPE %d (@%d dimensions) failed\n", vt, dimension);
861 else
862 ok(sa == NULL || vt == VT_R8,
863 "VARTYPE %d (@%d dimensions) succeeded!\n", vt, dimension);
865 if (sa)
867 ok(SafeArrayGetDim(sa) == dimension,
868 "VARTYPE %d (@%d dimensions) cDims is %d, expected %d\n",
869 vt, dimension, SafeArrayGetDim(sa), dimension);
870 ok(SafeArrayGetElemsize(sa) == dwLen || vt == VT_R8,
871 "VARTYPE %d (@%d dimensions) cbElements is %d, expected %ld\n",
872 vt, dimension, SafeArrayGetElemsize(sa), dwLen);
874 if (vt != VT_UNKNOWN && vt != VT_DISPATCH)
876 ok((sa->fFeatures & FADF_HAVEIID) == 0,
877 "Non interface type should not have FADF_HAVEIID\n");
878 hres = SafeArraySetIID(sa, &IID_IUnknown);
879 ok(hres == E_INVALIDARG, "Unexpected ret value %#lx.\n", hres);
880 if (vt != VT_RECORD)
882 VARTYPE aVt;
884 ok(sa->fFeatures & FADF_HAVEVARTYPE,
885 "Non interface type should have FADF_HAVEVARTYPE\n");
886 if (pSafeArrayGetVartype)
888 hres = pSafeArrayGetVartype(sa, &aVt);
889 ok(hres == S_OK && aVt == vt,
890 "Non interface type %d: bad type %d, hres %lx\n", vt, aVt, hres);
894 else
896 ok(sa->fFeatures & FADF_HAVEIID, "Interface type should have FADF_HAVEIID\n");
897 hres = SafeArraySetIID(sa, &IID_IUnknown);
898 ok(hres == S_OK, "Failed to set array IID, hres %#lx.\n", hres);
899 ok((sa->fFeatures & FADF_HAVEVARTYPE) == 0,
900 "Interface type %d should not have FADF_HAVEVARTYPE\n", vt);
903 hres = SafeArrayLock(sa);
904 ok(hres == S_OK, "Lock VARTYPE %d (@%d dimensions) failed; hres 0x%lx\n",
905 vt, dimension, hres);
907 if (hres == S_OK)
909 hres = SafeArrayDestroy(sa);
910 ok(hres == DISP_E_ARRAYISLOCKED,"Destroy() got hres %lx\n", hres);
912 hres = SafeArrayDestroyData(sa);
913 ok(hres == DISP_E_ARRAYISLOCKED,"DestroyData() got hres %lx\n", hres);
915 hres = SafeArrayDestroyDescriptor(sa);
916 ok(hres == DISP_E_ARRAYISLOCKED,"DestroyDescriptor() got hres %lx\n", hres);
918 hres = SafeArrayUnlock(sa);
919 ok(hres == S_OK, "Unlock VARTYPE %d (@%d dims) hres 0x%lx\n",
920 vt, dimension, hres);
922 hres = SafeArrayDestroy(sa);
923 ok(hres == S_OK, "destroy VARTYPE %d (@%d dims) hres 0x%lx\n",
924 vt, dimension, hres);
931 static void test_VectorCreateLockDestroy(void)
933 SAFEARRAY *sa;
934 HRESULT hres;
935 VARTYPE vt;
936 int element;
938 sa = SafeArrayCreateVector(VT_UI1, 0, 0);
939 ok(sa != NULL, "SACV with 0 elements failed.\n");
941 hres = SafeArrayDestroy(sa);
942 ok(hres == S_OK, "SafeArrayDestroy failed with hres %lx\n",hres);
944 /* Test all VARTYPES in different lengths */
945 for (element = 1; element <= 101; element += 10)
947 for (vt = VT_EMPTY; vt < VT_CLSID; vt++)
949 DWORD dwLen = SAFEARRAY_GetVTSize(vt);
951 sa = SafeArrayCreateVector(vt, 0, element);
953 if (dwLen)
954 ok(sa != NULL, "VARTYPE %d (@%d elements) failed\n", vt, element);
955 else
956 ok(sa == NULL, "VARTYPE %d (@%d elements) succeeded!\n", vt, element);
958 if (sa)
960 ok(SafeArrayGetDim(sa) == 1, "VARTYPE %d (@%d elements) cDims %d, not 1\n",
961 vt, element, SafeArrayGetDim(sa));
962 ok(SafeArrayGetElemsize(sa) == dwLen,
963 "VARTYPE %d (@%d elements) cbElements is %d, expected %ld\n",
964 vt, element, SafeArrayGetElemsize(sa), dwLen);
966 hres = SafeArrayLock(sa);
967 ok(hres == S_OK, "Lock VARTYPE %d (@%d elements) failed; hres 0x%lx\n",
968 vt, element, hres);
970 if (hres == S_OK)
972 hres = SafeArrayUnlock(sa);
973 ok(hres == S_OK, "Unlock VARTYPE %d (@%d elements) failed; hres 0x%lx\n",
974 vt, element, hres);
976 hres = SafeArrayDestroy(sa);
977 ok(hres == S_OK, "destroy VARTYPE %d (@%d elements) failed; hres 0x%lx\n",
978 vt, element, hres);
985 static void test_LockUnlock(void)
987 SAFEARRAYBOUND sab[4];
988 SAFEARRAY *sa;
989 HRESULT hres;
990 BOOL bVector = FALSE;
991 int dimension;
993 /* Failure cases */
994 hres = SafeArrayLock(NULL);
995 ok(hres == E_INVALIDARG, "Lock NULL array hres 0x%lx\n", hres);
996 hres = SafeArrayUnlock(NULL);
997 ok(hres == E_INVALIDARG, "Lock NULL array hres 0x%lx\n", hres);
999 for (dimension = 0; dimension < ARRAY_SIZE(sab); dimension++)
1001 sab[dimension].lLbound = 0;
1002 sab[dimension].cElements = 8;
1005 sa = SafeArrayCreate(VT_UI1, ARRAY_SIZE(sab), sab);
1007 /* Test maximum locks */
1008 test_LockUnlock_Vector:
1009 if (sa)
1011 int count = 0;
1013 hres = SafeArrayUnlock(sa);
1014 ok (hres == E_UNEXPECTED, "Bad %sUnlock gave hres 0x%lx\n",
1015 bVector ? "vector " : "\n", hres);
1017 while ((hres = SafeArrayLock(sa)) == S_OK)
1018 count++;
1019 ok (count == 65535 && hres == E_UNEXPECTED, "Lock %sfailed at %d; hres 0x%lx\n",
1020 bVector ? "vector " : "\n", count, hres);
1022 if (count == 65535 && hres == E_UNEXPECTED)
1024 while ((hres = SafeArrayUnlock(sa)) == S_OK)
1025 count--;
1026 ok (count == 0 && hres == E_UNEXPECTED, "Unlock %sfailed at %d; hres 0x%lx\n",
1027 bVector ? "vector " : "\n", count, hres);
1030 hres = SafeArrayDestroy(sa);
1031 ok(hres == S_OK, "got 0x%08lx\n", hres);
1034 if (bVector == FALSE)
1036 /* Test again with a vector */
1037 sa = SafeArrayCreateVector(VT_UI1, 0, 100);
1038 bVector = TRUE;
1039 goto test_LockUnlock_Vector;
1043 static void test_SafeArrayGetPutElement(void)
1045 SAFEARRAYBOUND sab[4];
1046 LONG indices[ARRAY_SIZE(sab)], index;
1047 SAFEARRAY *sa;
1048 HRESULT hres;
1049 int value = 0, gotvalue, dimension;
1050 IRecordInfoImpl *irec;
1051 unsigned int x,y,z,a;
1053 for (dimension = 0; dimension < ARRAY_SIZE(sab); dimension++)
1055 sab[dimension].lLbound = dimension * 2 + 1;
1056 sab[dimension].cElements = dimension * 3 + 1;
1059 sa = SafeArrayCreate(VT_INT, ARRAY_SIZE(sab), sab);
1060 if (!sa)
1061 return; /* Some early versions can't handle > 3 dims */
1063 ok(sa->cbElements == sizeof(value), "int size mismatch\n");
1065 /* Failure cases */
1066 for (x = 0; x < ARRAY_SIZE(sab); x++)
1068 indices[0] = sab[0].lLbound;
1069 indices[1] = sab[1].lLbound;
1070 indices[2] = sab[2].lLbound;
1071 indices[3] = sab[3].lLbound;
1073 indices[x] = indices[x] - 1;
1074 hres = SafeArrayPutElement(sa, indices, &value);
1075 ok(hres == DISP_E_BADINDEX, "Put allowed too small index in dimension %d\n", x);
1076 hres = SafeArrayGetElement(sa, indices, &value);
1077 ok(hres == DISP_E_BADINDEX, "Get allowed too small index in dimension %d\n", x);
1079 indices[x] = sab[x].lLbound + sab[x].cElements;
1080 hres = SafeArrayPutElement(sa, indices, &value);
1081 ok(hres == DISP_E_BADINDEX, "Put allowed too big index in dimension %d\n", x);
1082 hres = SafeArrayGetElement(sa, indices, &value);
1083 ok(hres == DISP_E_BADINDEX, "Get allowed too big index in dimension %d\n", x);
1086 indices[0] = sab[0].lLbound;
1087 indices[1] = sab[1].lLbound;
1088 indices[2] = sab[2].lLbound;
1089 indices[3] = sab[3].lLbound;
1091 hres = SafeArrayPutElement(NULL, indices, &value);
1092 ok(hres == E_INVALIDARG, "Put NULL array hres 0x%lx\n", hres);
1093 hres = SafeArrayGetElement(NULL, indices, &value);
1094 ok(hres == E_INVALIDARG, "Get NULL array hres 0x%lx\n", hres);
1096 hres = SafeArrayPutElement(sa, NULL, &value);
1097 ok(hres == E_INVALIDARG, "Put NULL indices hres 0x%lx\n", hres);
1098 hres = SafeArrayGetElement(sa, NULL, &value);
1099 ok(hres == E_INVALIDARG, "Get NULL indices hres 0x%lx\n", hres);
1101 if (0)
1103 /* This is retarded. Windows checks every case of invalid parameters
1104 * except the following, which crashes. We ERR this in Wine.
1106 hres = SafeArrayPutElement(sa, indices, NULL);
1107 ok(hres == E_INVALIDARG, "Put NULL value hres 0x%lx\n", hres);
1110 hres = SafeArrayGetElement(sa, indices, NULL);
1111 ok(hres == E_INVALIDARG, "Get NULL value hres 0x%lx\n", hres);
1113 value = 0;
1115 /* Make sure we can read and get back the correct values in 4 dimensions,
1116 * Each with a different size and lower bound.
1118 for (x = 0; x < sab[0].cElements; x++)
1120 indices[0] = sab[0].lLbound + x;
1121 for (y = 0; y < sab[1].cElements; y++)
1123 indices[1] = sab[1].lLbound + y;
1124 for (z = 0; z < sab[2].cElements; z++)
1126 indices[2] = sab[2].lLbound + z;
1127 for (a = 0; a < sab[3].cElements; a++)
1129 indices[3] = sab[3].lLbound + a;
1130 hres = SafeArrayPutElement(sa, indices, &value);
1131 ok(hres == S_OK, "Failed to put element at (%d,%d,%d,%d) hres 0x%lx\n",
1132 x, y, z, a, hres);
1133 value++;
1139 value = 0;
1141 for (x = 0; x < sab[0].cElements; x++)
1143 indices[0] = sab[0].lLbound + x;
1144 for (y = 0; y < sab[1].cElements; y++)
1146 indices[1] = sab[1].lLbound + y;
1147 for (z = 0; z < sab[2].cElements; z++)
1149 indices[2] = sab[2].lLbound + z;
1150 for (a = 0; a < sab[3].cElements; a++)
1152 indices[3] = sab[3].lLbound + a;
1153 gotvalue = value / 3;
1154 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1155 ok(hres == S_OK, "Failed to get element at (%d,%d,%d,%d) hres 0x%lx\n",
1156 x, y, z, a, hres);
1157 if (hres == S_OK)
1158 ok(value == gotvalue, "Got value %d instead of %d at (%d,%d,%d,%d)\n",
1159 gotvalue, value, x, y, z, a);
1160 value++;
1165 hres = SafeArrayDestroy(sa);
1166 ok(hres == S_OK, "got 0x%08lx\n", hres);
1168 /* VT_RECORD array */
1169 irec = IRecordInfoImpl_Construct();
1170 irec->ref = 1;
1172 sab[0].lLbound = 0;
1173 sab[0].cElements = 8;
1175 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &irec->IRecordInfo_iface);
1176 ok(sa != NULL, "failed to create array\n");
1177 ok(irec->ref == 2, "got %ld\n", irec->ref);
1179 index = 0;
1180 irec->recordcopy = 0;
1181 hres = SafeArrayPutElement(sa, &index, (void*)0xdeadbeef);
1182 ok(hres == S_OK, "got 0x%08lx\n", hres);
1183 ok(irec->recordcopy == 1, "got %d\n", irec->recordcopy);
1185 index = 0;
1186 irec->recordcopy = 0;
1187 hres = SafeArrayGetElement(sa, &index, (void*)0xdeadbeef);
1188 ok(hres == S_OK, "got 0x%08lx\n", hres);
1189 ok(irec->recordcopy == 1, "got %d\n", irec->recordcopy);
1191 hres = SafeArrayDestroy(sa);
1192 ok(hres == S_OK, "got 0x%08lx\n", hres);
1193 ok(irec->ref == 1, "got %ld\n", irec->ref);
1194 IRecordInfo_Release(&irec->IRecordInfo_iface);
1197 static void test_SafeArrayGetPutElement_BSTR(void)
1199 SAFEARRAYBOUND sab;
1200 LONG indices[1];
1201 SAFEARRAY *sa;
1202 HRESULT hres;
1203 BSTR value = 0, gotvalue;
1204 const OLECHAR szTest[5] = { 'T','e','s','t','\0' };
1206 sab.lLbound = 1;
1207 sab.cElements = 1;
1209 sa = SafeArrayCreate(VT_BSTR, 1, &sab);
1210 ok(sa != NULL, "BSTR test couldn't create array\n");
1211 if (!sa)
1212 return;
1214 ok(sa->cbElements == sizeof(BSTR), "BSTR size mismatch\n");
1216 indices[0] = sab.lLbound;
1217 value = SysAllocString(szTest);
1218 ok (value != NULL, "Expected non-NULL\n");
1219 hres = SafeArrayPutElement(sa, indices, value);
1220 ok(hres == S_OK, "Failed to put bstr element hres 0x%lx\n", hres);
1221 gotvalue = NULL;
1222 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1223 ok(hres == S_OK, "Failed to get bstr element at hres 0x%lx\n", hres);
1224 if (hres == S_OK)
1225 ok(SysStringLen(value) == SysStringLen(gotvalue), "Got len %d instead of %d\n", SysStringLen(gotvalue), SysStringLen(value));
1226 hres = SafeArrayDestroy(sa);
1227 ok(hres == S_OK, "got 0x%08lx\n", hres);
1228 SysFreeString(value);
1229 SysFreeString(gotvalue);
1232 struct xtunk_impl {
1233 IUnknown IUnknown_iface;
1234 LONG ref;
1236 static const IUnknownVtbl xtunk_vtbl;
1238 static struct xtunk_impl xtunk = {{&xtunk_vtbl}, 0};
1240 static HRESULT WINAPI tunk_QueryInterface(IUnknown *punk, REFIID riid, void **x)
1242 return E_FAIL;
1245 static ULONG WINAPI tunk_AddRef(IUnknown *punk)
1247 return ++xtunk.ref;
1250 static ULONG WINAPI tunk_Release(IUnknown *punk)
1252 return --xtunk.ref;
1255 static const IUnknownVtbl xtunk_vtbl = {
1256 tunk_QueryInterface,
1257 tunk_AddRef,
1258 tunk_Release
1261 static void test_SafeArrayGetPutElement_IUnknown(void)
1263 SAFEARRAYBOUND sab;
1264 LONG indices[1];
1265 SAFEARRAY *sa;
1266 HRESULT hres;
1267 IUnknown *gotvalue;
1269 sab.lLbound = 1;
1270 sab.cElements = 1;
1271 sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab);
1272 ok(sa != NULL, "UNKNOWN test couldn't create array\n");
1273 if (!sa)
1274 return;
1276 ok(sa->cbElements == sizeof(LPUNKNOWN), "LPUNKNOWN size mismatch\n");
1278 indices[0] = sab.lLbound;
1279 xtunk.ref = 1;
1280 hres = SafeArrayPutElement(sa, indices, &xtunk.IUnknown_iface);
1281 ok(hres == S_OK, "Failed to put bstr element hres 0x%lx\n", hres);
1282 ok(xtunk.ref == 2,"Failed to increment refcount of iface.\n");
1283 gotvalue = NULL;
1284 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1285 ok(xtunk.ref == 3,"Failed to increment refcount of iface.\n");
1286 ok(hres == S_OK, "Failed to get bstr element at hres 0x%lx\n", hres);
1287 if (hres == S_OK)
1288 ok(gotvalue == &xtunk.IUnknown_iface, "Got %p instead of %p\n", gotvalue, &xtunk.IUnknown_iface);
1289 hres = SafeArrayDestroy(sa);
1290 ok(hres == S_OK, "got 0x%08lx\n", hres);
1291 ok(xtunk.ref == 2,"Failed to decrement refcount of iface.\n");
1294 static void test_SafeArrayRedim_IUnknown(void)
1296 SAFEARRAYBOUND sab;
1297 LONG indices[1];
1298 SAFEARRAY *sa;
1299 HRESULT hres;
1301 sab.lLbound = 1;
1302 sab.cElements = 2;
1303 sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab);
1304 ok(sa != NULL, "UNKNOWN test couldn't create array\n");
1305 if (!sa)
1306 return;
1308 ok(sa->cbElements == sizeof(LPUNKNOWN), "LPUNKNOWN size mismatch\n");
1310 indices[0] = 2;
1311 xtunk.ref = 1;
1312 hres = SafeArrayPutElement(sa, indices, &xtunk.IUnknown_iface);
1313 ok(hres == S_OK, "Failed to put IUnknown element hres 0x%lx\n", hres);
1314 ok(xtunk.ref == 2,"Failed to increment refcount of iface.\n");
1315 sab.cElements = 1;
1316 hres = SafeArrayRedim(sa, &sab);
1317 ok(hres == S_OK, "Failed to shrink array hres 0x%lx\n", hres);
1318 ok(xtunk.ref == 1, "Failed to decrement refcount\n");
1319 hres = SafeArrayDestroy(sa);
1320 ok(hres == S_OK, "got 0x%08lx\n", hres);
1323 static void test_SafeArrayGetPutElement_VARIANT(void)
1325 SAFEARRAYBOUND sab;
1326 LONG indices[1];
1327 SAFEARRAY *sa;
1328 HRESULT hres;
1329 VARIANT value, gotvalue;
1331 sab.lLbound = 1;
1332 sab.cElements = 1;
1333 sa = SafeArrayCreate(VT_VARIANT, 1, &sab);
1334 ok(sa != NULL, "VARIANT test couldn't create array\n");
1335 if (!sa)
1336 return;
1338 ok(sa->cbElements == sizeof(VARIANT), "VARIANT size mismatch\n");
1340 indices[0] = sab.lLbound;
1341 V_VT(&value) = VT_I4;
1342 V_I4(&value) = 0x42424242;
1343 hres = SafeArrayPutElement(sa, indices, &value);
1344 ok(hres == S_OK, "Failed to put Variant I4 element hres 0x%lx\n", hres);
1346 V_VT(&gotvalue) = 0xdead;
1347 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1348 ok(hres == S_OK, "Failed to get variant element at hres 0x%lx\n", hres);
1350 V_VT(&gotvalue) = VT_EMPTY;
1351 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1352 ok(hres == S_OK, "Failed to get variant element at hres 0x%lx\n", hres);
1353 if (hres == S_OK) {
1354 ok(V_VT(&value) == V_VT(&gotvalue), "Got type 0x%x instead of 0x%x\n", V_VT(&value), V_VT(&gotvalue));
1355 if (V_VT(&value) == V_VT(&gotvalue))
1356 ok(V_I4(&value) == V_I4(&gotvalue), "Got %ld instead of %d\n", V_I4(&value), V_VT(&gotvalue));
1358 hres = SafeArrayDestroy(sa);
1359 ok(hres == S_OK, "got 0x%08lx\n", hres);
1362 static void test_SafeArrayCopyData(void)
1364 SAFEARRAYBOUND sab[4];
1365 SAFEARRAY *sa;
1366 SAFEARRAY *sacopy;
1367 HRESULT hres;
1368 int dimension, size = 1, i;
1370 for (dimension = 0; dimension < ARRAY_SIZE(sab); dimension++)
1372 sab[dimension].lLbound = dimension * 2 + 2;
1373 sab[dimension].cElements = dimension * 3 + 1;
1374 size *= sab[dimension].cElements;
1377 sa = SafeArrayCreate(VT_INT, ARRAY_SIZE(sab), sab);
1378 ok(sa != NULL, "Copy test couldn't create array\n");
1379 sacopy = SafeArrayCreate(VT_INT, ARRAY_SIZE(sab), sab);
1380 ok(sacopy != NULL, "Copy test couldn't create copy array\n");
1382 if (!sa || !sacopy)
1383 return;
1385 ok(sa->cbElements == sizeof(int), "int size mismatch\n");
1387 /* Fill the source array with some data; it doesn't matter what */
1388 for (dimension = 0; dimension < size; dimension++)
1390 int* data = sa->pvData;
1391 data[dimension] = dimension;
1394 hres = SafeArrayCopyData(sa, sacopy);
1395 ok(hres == S_OK, "copy data failed hres 0x%lx\n", hres);
1396 if (hres == S_OK)
1398 ok(!memcmp(sa->pvData, sacopy->pvData, size * sizeof(int)), "compared different\n");
1401 /* Failure cases */
1402 hres = SafeArrayCopyData(NULL, sacopy);
1403 ok(hres == E_INVALIDARG, "Null copy source hres 0x%lx\n", hres);
1404 hres = SafeArrayCopyData(sa, NULL);
1405 ok(hres == E_INVALIDARG, "Null copy hres 0x%lx\n", hres);
1407 sacopy->rgsabound[0].cElements += 1;
1408 hres = SafeArrayCopyData(sa, sacopy);
1409 ok(hres == E_INVALIDARG, "Bigger copy first dimension hres 0x%lx\n", hres);
1411 sacopy->rgsabound[0].cElements -= 2;
1412 hres = SafeArrayCopyData(sa, sacopy);
1413 ok(hres == E_INVALIDARG, "Smaller copy first dimension hres 0x%lx\n", hres);
1414 sacopy->rgsabound[0].cElements += 1;
1416 sacopy->rgsabound[3].cElements += 1;
1417 hres = SafeArrayCopyData(sa, sacopy);
1418 ok(hres == E_INVALIDARG, "Bigger copy last dimension hres 0x%lx\n", hres);
1420 sacopy->rgsabound[3].cElements -= 2;
1421 hres = SafeArrayCopyData(sa, sacopy);
1422 ok(hres == E_INVALIDARG, "Smaller copy last dimension hres 0x%lx\n", hres);
1423 sacopy->rgsabound[3].cElements += 1;
1425 hres = SafeArrayDestroy(sacopy);
1426 ok(hres == S_OK, "got 0x%08lx\n", hres);
1427 sacopy = NULL;
1428 hres = SafeArrayCopyData(sa, sacopy);
1429 ok(hres == E_INVALIDARG, "->Null copy hres 0x%lx\n", hres);
1431 hres = SafeArrayCopy(sa, &sacopy);
1432 ok(hres == S_OK, "copy failed hres 0x%lx\n", hres);
1433 ok(SafeArrayGetElemsize(sa) == SafeArrayGetElemsize(sacopy),"elemsize wrong\n");
1434 ok(SafeArrayGetDim(sa) == SafeArrayGetDim(sacopy),"dimensions wrong\n");
1435 ok(!memcmp(sa->pvData, sacopy->pvData, size * sizeof(int)), "compared different\n");
1436 hres = SafeArrayDestroy(sacopy);
1437 ok(hres == S_OK, "got 0x%08lx\n", hres);
1439 sacopy = SafeArrayCreate(VT_INT, ARRAY_SIZE(sab), sab);
1440 ok(sacopy != NULL, "Copy test couldn't create copy array\n");
1441 ok(sacopy->fFeatures == FADF_HAVEVARTYPE, "0x%04x\n", sacopy->fFeatures);
1443 for (i = 0; i < ARRAY_SIZE(ignored_copy_features); i++)
1445 USHORT feature = ignored_copy_features[i];
1446 USHORT orig = sacopy->fFeatures;
1448 sa->fFeatures |= feature;
1449 hres = SafeArrayCopyData(sa, sacopy);
1450 ok(hres == S_OK, "got 0x%08lx\n", hres);
1451 ok(sacopy->fFeatures == orig && orig == FADF_HAVEVARTYPE, "got features 0x%04x\n", sacopy->fFeatures);
1452 sa->fFeatures &= ~feature;
1455 hres = SafeArrayDestroy(sacopy);
1456 ok(hres == S_OK, "got 0x%08lx\n", hres);
1457 hres = SafeArrayDestroy(sa);
1458 ok(hres == S_OK, "got 0x%08lx\n", hres);
1460 /* copy data from a vector */
1461 sa = SafeArrayCreateVector(VT_UI1, 0, 2);
1463 sacopy = SafeArrayCreateVector(VT_UI1, 0, 2);
1464 ok(sa->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1465 broken(sa->fFeatures == FADF_CREATEVECTOR /* W2k */),
1466 "got 0x%08x\n", sa->fFeatures);
1467 ok(sacopy->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1468 broken(sacopy->fFeatures == FADF_CREATEVECTOR /* W2k */),
1469 "got 0x%08x\n", sacopy->fFeatures);
1470 hres = SafeArrayCopyData(sa, sacopy);
1471 ok(hres == S_OK, "got 0x%08lx\n", hres);
1472 ok(sacopy->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1473 broken(sacopy->fFeatures == FADF_CREATEVECTOR /* W2k */),
1474 "got 0x%04x\n", sacopy->fFeatures);
1475 SafeArrayDestroy(sacopy);
1477 sacopy = SafeArrayCreate(VT_UI1, ARRAY_SIZE(sab), sab);
1478 ok(sacopy != NULL, "Copy test couldn't create copy array\n");
1479 ok(sacopy->fFeatures == FADF_HAVEVARTYPE, "0x%04x\n", sacopy->fFeatures);
1480 hres = SafeArrayCopyData(sa, sacopy);
1481 ok(hres == E_INVALIDARG, "got 0x%08lx\n", hres);
1482 SafeArrayDestroy(sacopy);
1484 SafeArrayDestroy(sa);
1487 static void test_SafeArrayCreateEx(void)
1489 IRecordInfoImpl* iRec;
1490 SAFEARRAYBOUND sab[4];
1491 SAFEARRAY *sa;
1492 HRESULT hres;
1493 UINT dimension;
1495 if (!pSafeArrayCreateEx)
1497 win_skip("SafeArrayCreateEx not supported\n");
1498 return;
1501 for (dimension = 0; dimension < ARRAY_SIZE(sab); dimension++)
1503 sab[dimension].lLbound = 0;
1504 sab[dimension].cElements = 8;
1507 /* Failure cases */
1508 sa = pSafeArrayCreateEx(VT_UI1, 1, NULL, NULL);
1509 ok(sa == NULL, "CreateEx NULL bounds didn't fail\n");
1511 /* test IID storage & defaulting */
1512 sa = pSafeArrayCreateEx(VT_DISPATCH, 1, sab, (PVOID)&IID_ITypeInfo);
1513 ok(sa != NULL, "CreateEx (ITypeInfo) failed\n");
1515 if (sa)
1517 GUID guid;
1519 hres = SafeArrayGetIID(sa, &guid);
1520 ok(hres == S_OK, "Failed to get array IID, hres %#lx.\n", hres);
1521 ok(IsEqualGUID(&guid, &IID_ITypeInfo), "CreateEx (ITypeInfo) bad IID\n");
1522 hres = SafeArraySetIID(sa, &IID_IUnknown);
1523 ok(hres == S_OK, "Failed to set IID, hres = %8lx\n", hres);
1524 hres = SafeArrayGetIID(sa, &guid);
1525 ok(hres == S_OK && IsEqualGUID(&guid, &IID_IUnknown), "Set bad IID\n");
1526 hres = SafeArrayDestroy(sa);
1527 ok(hres == S_OK, "got 0x%08lx\n", hres);
1530 sa = pSafeArrayCreateEx(VT_DISPATCH, 1, sab, NULL);
1531 ok(sa != NULL, "CreateEx (NULL) failed\n");
1533 if (sa)
1535 GUID guid;
1537 hres = SafeArrayGetIID(sa, &guid);
1538 ok(hres == S_OK, "Failed to get array IID, hres %#lx.\n", hres);
1539 ok(IsEqualGUID(&guid, &IID_IDispatch), "CreateEx (NULL) bad IID\n");
1540 hres = SafeArrayDestroy(sa);
1541 ok(hres == S_OK, "got 0x%08lx\n", hres);
1544 sa = pSafeArrayCreateEx(VT_UNKNOWN, 1, sab, NULL);
1545 ok(sa != NULL, "CreateEx (NULL-Unk) failed\n");
1547 if (sa)
1549 GUID guid;
1551 hres = SafeArrayGetIID(sa, &guid);
1552 ok(hres == S_OK, "Failed to get array IID, hres %#lx.\n", hres);
1553 ok(IsEqualGUID(&guid, &IID_IUnknown), "CreateEx (NULL-Unk) bad IID\n");
1554 hres = SafeArrayDestroy(sa);
1555 ok(hres == S_OK, "got 0x%08lx\n", hres);
1558 /* VT_RECORD failure case */
1559 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, NULL);
1560 ok(sa == NULL, "CreateEx (NULL-Rec) succeeded\n");
1562 iRec = IRecordInfoImpl_Construct();
1564 /* Win32 doesn't care if GetSize fails */
1565 fail_GetSize = TRUE;
1566 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface);
1567 ok(sa != NULL, "CreateEx (Fail Size) failed\n");
1568 ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %ld\n", iRec->ref);
1569 ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled);
1570 ok(iRec->clearCalled == 0, "Clear called %d times\n", iRec->clearCalled);
1571 if (sa)
1573 ok(sa->cbElements == RECORD_SIZE_FAIL, "Altered size to %ld\n", sa->cbElements);
1574 hres = SafeArrayDestroy(sa);
1575 ok(hres == S_OK, "got 0x%08lx\n", hres);
1576 ok(iRec->clearCalled == sab[0].cElements, "Destroy->Clear called %d times\n", iRec->clearCalled);
1577 ok(iRec->ref == START_REF_COUNT, "got %ld, expected %d\n", iRec->ref, START_REF_COUNT);
1580 /* Test VT_RECORD array */
1581 fail_GetSize = FALSE;
1582 iRec->ref = START_REF_COUNT;
1583 iRec->sizeCalled = 0;
1584 iRec->clearCalled = 0;
1585 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface);
1586 ok(sa != NULL, "CreateEx (Rec) failed\n");
1587 ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %ld\n", iRec->ref);
1588 ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled);
1589 ok(iRec->clearCalled == 0, "Clear called %d times\n", iRec->clearCalled);
1590 if (sa && pSafeArrayGetRecordInfo)
1592 IRecordInfo* saRec = NULL;
1593 SAFEARRAY *sacopy;
1595 hres = pSafeArrayGetRecordInfo(sa, &saRec);
1596 ok(hres == S_OK,"GRI failed\n");
1597 ok(saRec == &iRec->IRecordInfo_iface, "Different saRec\n");
1598 ok(iRec->ref == START_REF_COUNT + 2, "Didn't AddRef %ld\n", iRec->ref);
1599 IRecordInfo_Release(saRec);
1601 ok(sa->cbElements == RECORD_SIZE,"Elemsize is %ld\n", sa->cbElements);
1603 /* try to copy record based arrays */
1604 sacopy = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface);
1605 iRec->recordcopy = 0;
1606 iRec->clearCalled = 0;
1607 /* array copy code doesn't explicitly clear a record */
1608 hres = SafeArrayCopyData(sa, sacopy);
1609 ok(hres == S_OK, "got 0x%08lx\n", hres);
1610 ok(iRec->recordcopy == sab[0].cElements, "got %d\n", iRec->recordcopy);
1611 ok(iRec->clearCalled == 0, "got %d\n", iRec->clearCalled);
1613 hres = SafeArrayDestroy(sacopy);
1614 ok(hres == S_OK, "got 0x%08lx\n", hres);
1616 iRec->clearCalled = 0;
1617 iRec->sizeCalled = 0;
1618 hres = SafeArrayDestroy(sa);
1619 ok(hres == S_OK, "got 0x%08lx\n", hres);
1620 ok(iRec->sizeCalled == 0, "Destroy->GetSize called %d times\n", iRec->sizeCalled);
1621 ok(iRec->clearCalled == sab[0].cElements, "Destroy->Clear called %d times\n", iRec->clearCalled);
1622 ok(iRec->ref == START_REF_COUNT, "Wrong iRec refcount %ld\n", iRec->ref);
1624 else
1626 hres = SafeArrayDestroy(sa);
1627 ok(hres == S_OK, "got 0x%08lx\n", hres);
1630 IRecordInfo_Release(&iRec->IRecordInfo_iface);
1633 static void test_SafeArrayClear(void)
1635 SAFEARRAYBOUND sab;
1636 SAFEARRAY *sa;
1637 VARIANTARG v;
1638 HRESULT hres;
1640 sab.lLbound = 0;
1641 sab.cElements = 10;
1642 sa = SafeArrayCreate(VT_UI1, 1, &sab);
1643 ok(sa != NULL, "Create() failed.\n");
1644 if (!sa)
1645 return;
1647 /* Test clearing non-NULL variants containing arrays */
1648 V_VT(&v) = VT_ARRAY|VT_UI1;
1649 V_ARRAY(&v) = sa;
1650 hres = VariantClear(&v);
1651 ok(hres == S_OK && V_VT(&v) == VT_EMPTY, "VariantClear: hres 0x%lx, Type %d\n", hres, V_VT(&v));
1652 ok(V_ARRAY(&v) == sa, "VariantClear: Overwrote value\n");
1654 sa = SafeArrayCreate(VT_UI1, 1, &sab);
1655 ok(sa != NULL, "Create() failed.\n");
1656 if (!sa)
1657 return;
1659 V_VT(&v) = VT_SAFEARRAY;
1660 V_ARRAY(&v) = sa;
1661 hres = VariantClear(&v);
1662 ok(hres == DISP_E_BADVARTYPE, "VariantClear: hres 0x%lx\n", hres);
1664 V_VT(&v) = VT_SAFEARRAY|VT_BYREF;
1665 V_ARRAYREF(&v) = &sa;
1666 hres = VariantClear(&v);
1667 ok(hres == DISP_E_BADVARTYPE, "VariantClear: hres 0x%lx\n", hres);
1669 hres = SafeArrayDestroy(sa);
1670 ok(hres == S_OK, "got 0x%08lx\n", hres);
1673 static void test_SafeArrayCopy(void)
1675 SAFEARRAYBOUND sab;
1676 SAFEARRAY *sa, *sa2;
1677 VARIANTARG vSrc, vDst;
1678 HRESULT hres;
1679 int i;
1681 sab.lLbound = 0;
1682 sab.cElements = 10;
1683 sa = SafeArrayCreate(VT_UI1, 1, &sab);
1684 ok(sa != NULL, "Create() failed.\n");
1685 if (!sa)
1686 return;
1688 /* Test copying non-NULL variants containing arrays */
1689 V_VT(&vSrc) = (VT_ARRAY|VT_BYREF|VT_UI1);
1690 V_ARRAYREF(&vSrc) = &sa;
1691 V_VT(&vDst) = VT_EMPTY;
1693 hres = VariantCopy(&vDst, &vSrc);
1694 ok(hres == S_OK && V_VT(&vDst) == (VT_ARRAY|VT_BYREF|VT_UI1),
1695 "VariantCopy: hres 0x%lx, Type %d\n", hres, V_VT(&vDst));
1696 ok(V_ARRAYREF(&vDst) == &sa, "VariantClear: Performed deep copy\n");
1698 V_VT(&vSrc) = (VT_ARRAY|VT_UI1);
1699 V_ARRAY(&vSrc) = sa;
1700 V_VT(&vDst) = VT_EMPTY;
1702 hres = VariantCopy(&vDst, &vSrc);
1703 ok(hres == S_OK && V_VT(&vDst) == (VT_ARRAY|VT_UI1),
1704 "VariantCopy: hres 0x%lx, Type %d\n", hres, V_VT(&vDst));
1705 ok(V_ARRAY(&vDst) != sa, "VariantClear: Performed shallow copy\n");
1707 hres = SafeArrayDestroy(V_ARRAY(&vSrc));
1708 ok(hres == S_OK, "got 0x%08lx\n", hres);
1709 hres = SafeArrayDestroy(V_ARRAY(&vDst));
1710 ok(hres == S_OK, "got 0x%08lx\n", hres);
1712 hres = SafeArrayAllocDescriptor(1, &sa);
1713 ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08lx\n", hres);
1715 sa->cbElements = 16;
1716 hres = SafeArrayCopy(sa, &sa2);
1717 ok(hres == S_OK, "SafeArrayCopy failed with error 0x%08lx\n", hres);
1718 ok(sa != sa2, "SafeArrayCopy performed shallow copy\n");
1720 hres = SafeArrayDestroy(sa2);
1721 ok(hres == S_OK, "got 0x%08lx\n", hres);
1722 hres = SafeArrayDestroy(sa);
1723 ok(hres == S_OK, "got 0x%08lx\n", hres);
1725 sa2 = (void*)0xdeadbeef;
1726 hres = SafeArrayCopy(NULL, &sa2);
1727 ok(hres == S_OK, "SafeArrayCopy failed with error 0x%08lx\n", hres);
1728 ok(!sa2, "SafeArrayCopy didn't return NULL for output array\n");
1730 hres = SafeArrayAllocDescriptor(1, &sa);
1731 ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08lx\n", hres);
1733 sa2 = (void*)0xdeadbeef;
1734 hres = SafeArrayCopy(sa, &sa2);
1735 ok(hres == E_INVALIDARG,
1736 "SafeArrayCopy with empty array should have failed with error E_INVALIDARG instead of 0x%08lx\n",
1737 hres);
1738 ok(!sa2, "SafeArrayCopy didn't return NULL for output array\n");
1740 hres = SafeArrayDestroy(sa2);
1741 ok(hres == S_OK, "got 0x%08lx\n", hres);
1742 hres = SafeArrayDestroy(sa);
1743 ok(hres == S_OK, "got 0x%08lx\n", hres);
1745 /* test feature copy */
1746 hres = SafeArrayAllocDescriptor(1, &sa);
1747 ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08lx\n", hres);
1748 ok(sa->fFeatures == 0, "got src features 0x%04x\n", sa->fFeatures);
1749 sa->cbElements = 16;
1751 for (i = 0; i < ARRAY_SIZE(ignored_copy_features); i++)
1753 USHORT feature = ignored_copy_features[i];
1755 sa->fFeatures |= feature;
1756 hres = SafeArrayCopy(sa, &sa2);
1757 ok(hres == S_OK, "got 0x%08lx\n", hres);
1758 ok(sa2->fFeatures == 0, "got features 0x%04x\n", sa2->fFeatures);
1759 hres = SafeArrayDestroy(sa2);
1760 ok(hres == S_OK, "got 0x%08lx\n", hres);
1761 sa->fFeatures &= ~feature;
1764 SafeArrayDestroy(sa);
1766 /* copy from a vector */
1767 sa = SafeArrayCreateVector(VT_UI1, 0, 2);
1768 ok(sa->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1769 broken(sa->fFeatures == FADF_CREATEVECTOR /* W2k */),
1770 "got 0x%08x\n", sa->fFeatures);
1771 hres = SafeArrayCopy(sa, &sa2);
1772 ok(hres == S_OK, "got 0x%08lx\n", hres);
1773 ok(sa2->fFeatures == FADF_HAVEVARTYPE ||
1774 broken(!sa2->fFeatures /* W2k */), "got 0x%04x\n",
1775 sa2->fFeatures);
1777 SafeArrayDestroy(sa2);
1778 SafeArrayDestroy(sa);
1781 #define MKARRAY(low,num,typ) sab.lLbound = low; sab.cElements = num; \
1782 sa = SafeArrayCreate(typ, 1, &sab); ok(sa != NULL, "Create() failed.\n"); \
1783 if (!sa) return; \
1784 V_VT(&v) = VT_ARRAY|typ; V_ARRAY(&v) = sa; VariantInit(&v2)
1786 #define MKARRAYCONT(low,num,typ) sab.lLbound = low; sab.cElements = num; \
1787 sa = SafeArrayCreate(typ, 1, &sab); if (!sa) continue; \
1788 V_VT(&v) = VT_ARRAY|typ; V_ARRAY(&v) = sa; VariantInit(&v2)
1790 static void test_SafeArrayChangeTypeEx(void)
1792 static const char *szHello = "Hello World";
1793 SAFEARRAYBOUND sab;
1794 SAFEARRAY *sa;
1795 VARIANTARG v,v2;
1796 VARTYPE vt;
1797 HRESULT hres;
1799 /* VT_ARRAY|VT_UI1 -> VT_BSTR */
1800 MKARRAY(0,strlen(szHello)+1,VT_UI1);
1801 memcpy(sa->pvData, szHello, strlen(szHello)+1);
1803 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR);
1804 ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx\n", hres);
1805 if (hres == S_OK)
1807 ok(V_VT(&v2) == VT_BSTR, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.\n",V_VT(&v2));
1808 ok(strcmp((char*)V_BSTR(&v2),szHello) == 0,"Expected string '%s', got '%s'\n", szHello,
1809 (char*)V_BSTR(&v2));
1810 VariantClear(&v2);
1813 /* VT_VECTOR|VT_UI1 -> VT_BSTR */
1814 hres = SafeArrayDestroy(sa);
1815 ok(hres == S_OK, "got 0x%08lx\n", hres);
1817 sa = SafeArrayCreateVector(VT_UI1, 0, strlen(szHello)+1);
1818 ok(sa != NULL, "CreateVector() failed.\n");
1819 if (!sa)
1820 return;
1822 memcpy(sa->pvData, szHello, strlen(szHello)+1);
1823 V_VT(&v) = VT_VECTOR|VT_UI1;
1824 V_ARRAY(&v) = sa;
1825 VariantInit(&v2);
1827 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR);
1828 ok(hres == DISP_E_BADVARTYPE, "CTE VT_VECTOR|VT_UI1 returned %lx\n", hres);
1830 /* (vector)VT_ARRAY|VT_UI1 -> VT_BSTR (In place) */
1831 V_VT(&v) = VT_ARRAY|VT_UI1;
1832 hres = VariantChangeTypeEx(&v, &v, 0, 0, VT_BSTR);
1833 ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx\n", hres);
1834 if (hres == S_OK)
1836 ok(V_VT(&v) == VT_BSTR, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.\n",V_VT(&v));
1837 ok(strcmp((char*)V_BSTR(&v),szHello) == 0,"Expected string '%s', got '%s'\n", szHello,
1838 (char*)V_BSTR(&v));
1839 VariantClear(&v);
1842 /* To/from BSTR only works with arrays of VT_UI1 */
1843 for (vt = VT_EMPTY; vt <= VT_CLSID; vt++)
1845 if (vt == VT_UI1)
1846 continue;
1848 sab.lLbound = 0;
1849 sab.cElements = 1;
1850 sa = SafeArrayCreate(vt, 1, &sab);
1851 if (!sa) continue;
1853 V_VT(&v) = VT_ARRAY|vt;
1854 V_ARRAY(&v) = sa;
1855 VariantInit(&v2);
1857 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR);
1858 if (vt == VT_INT_PTR || vt == VT_UINT_PTR)
1860 ok(hres == DISP_E_BADVARTYPE, "expected DISP_E_BADVARTYPE, got 0x%08lx\n", hres);
1861 SafeArrayDestroy(sa);
1863 else
1865 ok(hres == DISP_E_TYPEMISMATCH, "got 0x%08lx for vt=%d, instead of DISP_E_TYPEMISMATCH\n", hres, vt);
1866 hres = VariantClear(&v);
1867 ok(hres == S_OK, "expected S_OK, got 0x%08lx\n", hres);
1869 VariantClear(&v2);
1872 /* Can't change an array of one type into array of another type , even
1873 * if the other type is the same size
1875 sa = SafeArrayCreateVector(VT_UI1, 0, 1);
1876 ok(sa != NULL, "CreateVector() failed.\n");
1877 if (!sa)
1878 return;
1880 V_VT(&v) = VT_ARRAY|VT_UI1;
1881 V_ARRAY(&v) = sa;
1882 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_ARRAY|VT_I1);
1883 ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_I1 returned %lx\n", hres);
1885 /* But can change to the same array type */
1886 hres = SafeArrayDestroy(sa);
1887 ok(hres == S_OK, "got 0x%08lx\n", hres);
1888 sa = SafeArrayCreateVector(VT_UI1, 0, 1);
1889 ok(sa != NULL, "CreateVector() failed.\n");
1890 if (!sa)
1891 return;
1892 V_VT(&v) = VT_ARRAY|VT_UI1;
1893 V_ARRAY(&v) = sa;
1894 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_ARRAY|VT_UI1);
1895 ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_UI1 returned %lx\n", hres);
1896 hres = SafeArrayDestroy(sa);
1897 ok(hres == S_OK, "got 0x%08lx\n", hres);
1898 VariantClear(&v2);
1900 /* NULL/EMPTY */
1901 MKARRAY(0,1,VT_UI1);
1902 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_NULL);
1903 ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1 returned %lx\n", hres);
1904 VariantClear(&v);
1905 MKARRAY(0,1,VT_UI1);
1906 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_EMPTY);
1907 ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1 returned %lx\n", hres);
1908 VariantClear(&v);
1911 static void test_SafeArrayDestroyData (void)
1913 SAFEARRAYBOUND sab[2];
1914 SAFEARRAY *sa;
1915 HRESULT hres;
1916 int value = 0xdeadbeef;
1917 LONG index[1];
1918 void *temp_pvData;
1919 USHORT features;
1921 sab[0].lLbound = 0;
1922 sab[0].cElements = 10;
1923 sa = SafeArrayCreate(VT_INT, 1, sab);
1924 ok(sa != NULL, "Create() failed.\n");
1925 ok(sa->fFeatures == FADF_HAVEVARTYPE, "got 0x%x\n", sa->fFeatures);
1927 index[0] = 1;
1928 SafeArrayPutElement (sa, index, &value);
1930 /* SafeArrayDestroyData shouldn't free pvData if FADF_STATIC is set. */
1931 features = (sa->fFeatures |= FADF_STATIC);
1932 temp_pvData = sa->pvData;
1933 hres = SafeArrayDestroyData(sa);
1934 ok(hres == S_OK, "SADData FADF_STATIC failed, error code %lx.\n",hres);
1935 ok(features == sa->fFeatures, "got 0x%x\n", sa->fFeatures);
1936 ok(sa->pvData == temp_pvData, "SADData FADF_STATIC: pvData=%p, expected %p (fFeatures = %d).\n",
1937 sa->pvData, temp_pvData, sa->fFeatures);
1938 SafeArrayGetElement (sa, index, &value);
1939 ok(value == 0, "Data not cleared after SADData\n");
1941 /* Clear FADF_STATIC, now really destroy the data. */
1942 features = (sa->fFeatures ^= FADF_STATIC);
1943 hres = SafeArrayDestroyData(sa);
1944 ok(hres == S_OK, "SADData !FADF_STATIC failed, error code %lx.\n",hres);
1945 ok(features == sa->fFeatures, "got 0x%x\n", sa->fFeatures);
1946 ok(sa->pvData == NULL, "SADData !FADF_STATIC: pvData=%p, expected NULL.\n", sa->pvData);
1948 hres = SafeArrayDestroy(sa);
1949 ok(hres == S_OK, "SAD failed, error code %lx.\n", hres);
1951 /* two dimensions */
1952 sab[0].lLbound = 0;
1953 sab[0].cElements = 10;
1954 sab[1].lLbound = 0;
1955 sab[1].cElements = 10;
1957 sa = SafeArrayCreate(VT_INT, 2, sab);
1958 ok(sa != NULL, "Create() failed.\n");
1959 ok(sa->fFeatures == FADF_HAVEVARTYPE, "got 0x%x\n", sa->fFeatures);
1961 features = sa->fFeatures;
1962 hres = SafeArrayDestroyData(sa);
1963 ok(hres == S_OK, "got 0x%08lx\n",hres);
1964 ok(features == sa->fFeatures, "got 0x%x\n", sa->fFeatures);
1966 SafeArrayDestroy(sa);
1968 /* try to destroy data from descriptor */
1969 hres = SafeArrayAllocDescriptor(1, &sa);
1970 ok(hres == S_OK, "got 0x%08lx\n", hres);
1971 ok(sa->fFeatures == 0, "got 0x%x\n", sa->fFeatures);
1973 hres = SafeArrayDestroyData(sa);
1974 ok(hres == S_OK, "got 0x%08lx\n", hres);
1975 ok(sa->fFeatures == 0, "got 0x%x\n", sa->fFeatures);
1977 hres = SafeArrayDestroyDescriptor(sa);
1978 ok(hres == S_OK, "got 0x%08lx\n", hres);
1980 hres = SafeArrayAllocDescriptor(2, &sa);
1981 ok(hres == S_OK, "got 0x%08lx\n", hres);
1982 ok(sa->fFeatures == 0, "got 0x%x\n", sa->fFeatures);
1984 hres = SafeArrayDestroyData(sa);
1985 ok(hres == S_OK, "got 0x%08lx\n", hres);
1986 ok(sa->fFeatures == 0, "got 0x%x\n", sa->fFeatures);
1988 hres = SafeArrayDestroyDescriptor(sa);
1989 ok(hres == S_OK, "got 0x%08lx\n", hres);
1991 /* vector case */
1992 sa = SafeArrayCreateVector(VT_I4, 0, 10);
1993 ok(sa != NULL, "got %p\n", sa);
1994 ok(sa->fFeatures == (FADF_CREATEVECTOR|FADF_HAVEVARTYPE), "got 0x%x\n", sa->fFeatures);
1996 ok(sa->pvData != NULL, "got %p\n", sa->pvData);
1997 hres = SafeArrayDestroyData(sa);
1998 ok(hres == S_OK, "got 0x%08lx\n", hres);
1999 todo_wine
2000 ok(sa->fFeatures == FADF_HAVEVARTYPE, "got 0x%x\n", sa->fFeatures);
2001 todo_wine
2002 ok(sa->pvData == NULL || broken(sa->pvData != NULL), "got %p\n", sa->pvData);
2003 /* There was a bug on windows, especially visible on 64bit systems,
2004 probably double-free or similar issue. */
2005 sa->pvData = NULL;
2006 SafeArrayDestroy(sa);
2009 static void test_safearray_layout(void)
2011 IRecordInfoImpl *irec;
2012 IRecordInfo *record;
2013 GUID guid, *guidptr;
2014 SAFEARRAYBOUND sab;
2015 SAFEARRAY *sa;
2016 DWORD *dwptr;
2017 HRESULT hr;
2019 sab.lLbound = 0;
2020 sab.cElements = 10;
2022 /* GUID field */
2023 sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab);
2024 ok(sa != NULL, "got %p\n", sa);
2026 guidptr = (GUID*)sa - 1;
2027 ok(IsEqualIID(guidptr, &IID_IUnknown), "got %s\n", wine_dbgstr_guid(guidptr));
2029 hr = SafeArraySetIID(sa, &IID_IDispatch);
2030 ok(hr == S_OK, "got 0x%08lx\n", hr);
2031 ok(IsEqualIID(guidptr, &IID_IDispatch), "got %s\n", wine_dbgstr_guid(guidptr));
2033 memcpy(guidptr, &IID_IUnknown, sizeof(GUID));
2034 hr = SafeArrayGetIID(sa, &guid);
2035 ok(hr == S_OK, "got 0x%08lx\n", hr);
2036 ok(IsEqualIID(&guid, &IID_IUnknown), "got %s\n", wine_dbgstr_guid(&guid));
2038 hr = SafeArrayDestroy(sa);
2039 ok(hr == S_OK, "got 0x%08lx\n", hr);
2041 /* VARTYPE field */
2042 sa = SafeArrayCreate(VT_UI1, 1, &sab);
2043 ok(sa != NULL, "got %p\n", sa);
2045 dwptr = (DWORD*)sa - 1;
2046 ok(*dwptr == VT_UI1, "got %ld\n", *dwptr);
2048 hr = SafeArrayDestroy(sa);
2049 ok(hr == S_OK, "got 0x%08lx\n", hr);
2051 /* IRecordInfo pointer */
2052 irec = IRecordInfoImpl_Construct();
2053 irec->ref = 1;
2055 sa = pSafeArrayCreateEx(VT_RECORD, 1, &sab, &irec->IRecordInfo_iface);
2056 ok(sa != NULL, "failed to create array\n");
2058 record = *((IRecordInfo**)sa - 1);
2059 ok(record == &irec->IRecordInfo_iface, "got %p\n", record);
2061 hr = SafeArrayDestroy(sa);
2062 ok(hr == S_OK, "got 0x%08lx\n", hr);
2063 IRecordInfo_Release(&irec->IRecordInfo_iface);
2066 START_TEST(safearray)
2068 hOleaut32 = GetModuleHandleA("oleaut32.dll");
2070 has_i8 = GetProcAddress(hOleaut32, "VarI8FromI1") != NULL;
2072 GETPTR(SafeArrayAllocDescriptorEx);
2073 GETPTR(SafeArrayGetVartype);
2074 GETPTR(SafeArrayCreateEx);
2075 GETPTR(SafeArrayGetRecordInfo);
2077 check_for_VT_INT_PTR();
2078 test_safearray();
2079 test_SafeArrayAllocDestroyDescriptor();
2080 test_SafeArrayCreateLockDestroy();
2081 test_VectorCreateLockDestroy();
2082 test_LockUnlock();
2083 test_SafeArrayChangeTypeEx();
2084 test_SafeArrayCopy();
2085 test_SafeArrayClear();
2086 test_SafeArrayCreateEx();
2087 test_SafeArrayCopyData();
2088 test_SafeArrayDestroyData();
2089 test_SafeArrayGetPutElement();
2090 test_SafeArrayGetPutElement_BSTR();
2091 test_SafeArrayGetPutElement_IUnknown();
2092 test_SafeArrayRedim_IUnknown();
2093 test_SafeArrayGetPutElement_VARIANT();
2094 test_safearray_layout();