[OLEAUT32_WINETEST] Sync with Wine Staging 1.7.47. CORE-9924
[reactos.git] / rostests / winetests / oleaut32 / safearray.c
1 /*
2 * SafeArray test program
3 *
4 * Copyright 2002 Marcus Meissner
5 *
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.
10 *
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.
15 *
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
19 *
20 */
21
22 #define WIN32_NO_STATUS
23 #define _INC_WINDOWS
24 #define COM_NO_WINDOWS_H
25
26 //#include <stdarg.h>
27 #include <stdio.h>
28 //#include <math.h>
29 //#include <float.h>
30
31 #define COBJMACROS
32 #define CONST_VTABLE
33 #include <wine/test.h>
34 //#include "windef.h"
35 //#include "winbase.h"
36 //#include "winuser.h"
37 //#include "wingdi.h"
38 //#include "winnls.h"
39 //#include "winsock.h"
40 //#include "winerror.h"
41 //#include "winnt.h"
42 #include <objbase.h>
43 //#include "wtypes.h"
44 #include <oleauto.h>
45
46 #ifndef FADF_CREATEVECTOR
47 const USHORT FADF_CREATEVECTOR = 0x2000;
48 #endif
49
50 static HMODULE hOleaut32;
51
52 static HRESULT (WINAPI *pSafeArrayAllocDescriptorEx)(VARTYPE,UINT,SAFEARRAY**);
53 static HRESULT (WINAPI *pSafeArrayCopyData)(SAFEARRAY*,SAFEARRAY*);
54 static HRESULT (WINAPI *pSafeArrayGetIID)(SAFEARRAY*,GUID*);
55 static HRESULT (WINAPI *pSafeArraySetIID)(SAFEARRAY*,REFGUID);
56 static HRESULT (WINAPI *pSafeArrayGetVartype)(SAFEARRAY*,VARTYPE*);
57 static HRESULT (WINAPI *pSafeArrayGetRecordInfo)(SAFEARRAY*,IRecordInfo**);
58 static SAFEARRAY* (WINAPI *pSafeArrayCreateEx)(VARTYPE,UINT,SAFEARRAYBOUND*,LPVOID);
59 static SAFEARRAY* (WINAPI *pSafeArrayCreateVector)(VARTYPE,LONG,ULONG);
60
61 #define GETPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func)
62
63 /* Has I8/UI8 data type? */
64 static BOOL has_i8;
65 /* Has INT_PTR/UINT_PTR type? */
66 static BOOL has_int_ptr;
67
68 static const USHORT ignored_copy_features[] =
69 {
70 FADF_AUTO,
71 FADF_STATIC,
72 FADF_EMBEDDED,
73 FADF_FIXEDSIZE
74 };
75
76 #define START_REF_COUNT 1
77 #define RECORD_SIZE 64
78 #define RECORD_SIZE_FAIL 17
79 /************************************************************************
80 * Dummy IRecordInfo Implementation
81 */
82 typedef struct IRecordInfoImpl
83 {
84 IRecordInfo IRecordInfo_iface;
85 LONG ref;
86 unsigned int sizeCalled;
87 unsigned int clearCalled;
88 unsigned int recordcopy;
89 } IRecordInfoImpl;
90
91 static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface)
92 {
93 return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface);
94 }
95
96 static HRESULT WINAPI RecordInfo_QueryInterface(IRecordInfo *iface, REFIID riid, void **obj)
97 {
98 *obj = NULL;
99
100 if (IsEqualIID(riid, &IID_IUnknown) ||
101 IsEqualIID(riid, &IID_IRecordInfo))
102 {
103 *obj = iface;
104 IRecordInfo_AddRef(iface);
105 return S_OK;
106 }
107
108 return E_NOINTERFACE;
109 }
110
111 static ULONG WINAPI RecordInfo_AddRef(IRecordInfo *iface)
112 {
113 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
114 return InterlockedIncrement(&This->ref);
115 }
116
117 static ULONG WINAPI RecordInfo_Release(IRecordInfo *iface)
118 {
119 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
120 ULONG ref = InterlockedDecrement(&This->ref);
121
122 if (!ref)
123 HeapFree(GetProcessHeap(), 0, This);
124
125 return ref;
126 }
127
128 static HRESULT WINAPI RecordInfo_RecordInit(IRecordInfo *iface, PVOID pvNew)
129 {
130 ok(0, "unexpected call\n");
131 return E_NOTIMPL;
132 }
133
134 static BOOL fail_GetSize; /* Whether to fail the GetSize call */
135
136 static HRESULT WINAPI RecordInfo_RecordClear(IRecordInfo *iface, PVOID pvExisting)
137 {
138 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
139 This->clearCalled++;
140 return S_OK;
141 }
142
143 static HRESULT WINAPI RecordInfo_RecordCopy(IRecordInfo *iface, PVOID pvExisting, PVOID pvNew)
144 {
145 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
146 This->recordcopy++;
147 return S_OK;
148 }
149
150 static HRESULT WINAPI RecordInfo_GetGuid(IRecordInfo *iface, GUID *pguid)
151 {
152 ok(0, "unexpected call\n");
153 return E_NOTIMPL;
154 }
155
156 static HRESULT WINAPI RecordInfo_GetName(IRecordInfo *iface, BSTR *pbstrName)
157 {
158 ok(0, "unexpected call\n");
159 return E_NOTIMPL;
160 }
161
162 static HRESULT WINAPI RecordInfo_GetSize(IRecordInfo *iface, ULONG* size)
163 {
164 IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
165 This->sizeCalled++;
166 if (fail_GetSize)
167 {
168 *size = RECORD_SIZE_FAIL;
169 return E_UNEXPECTED;
170 }
171 *size = RECORD_SIZE;
172 return S_OK;
173 }
174
175 static HRESULT WINAPI RecordInfo_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo)
176 {
177 ok(0, "unexpected call\n");
178 return E_NOTIMPL;
179 }
180
181 static HRESULT WINAPI RecordInfo_GetField(IRecordInfo *iface, PVOID pvData,
182 LPCOLESTR szFieldName, VARIANT *pvarField)
183 {
184 ok(0, "unexpected call\n");
185 return E_NOTIMPL;
186 }
187
188 static HRESULT WINAPI RecordInfo_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData,
189 LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray)
190 {
191 ok(0, "unexpected call\n");
192 return E_NOTIMPL;
193 }
194
195 static HRESULT WINAPI RecordInfo_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData,
196 LPCOLESTR szFieldName, VARIANT *pvarField)
197 {
198 ok(0, "unexpected call\n");
199 return E_NOTIMPL;
200 }
201
202 static HRESULT WINAPI RecordInfo_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags,
203 PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField)
204 {
205 ok(0, "unexpected call\n");
206 return E_NOTIMPL;
207 }
208
209 static HRESULT WINAPI RecordInfo_GetFieldNames(IRecordInfo *iface, ULONG *pcNames,
210 BSTR *rgBstrNames)
211 {
212 ok(0, "unexpected call\n");
213 return E_NOTIMPL;
214 }
215
216 static BOOL WINAPI RecordInfo_IsMatchingType(IRecordInfo *iface, IRecordInfo *info2)
217 {
218 ok(0, "unexpected call\n");
219 return E_NOTIMPL;
220 }
221
222 static PVOID WINAPI RecordInfo_RecordCreate(IRecordInfo *iface)
223 {
224 ok(0, "unexpected call\n");
225 return NULL;
226 }
227
228 static HRESULT WINAPI RecordInfo_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource,
229 PVOID *ppvDest)
230 {
231 ok(0, "unexpected call\n");
232 return E_NOTIMPL;
233 }
234
235 static HRESULT WINAPI RecordInfo_RecordDestroy(IRecordInfo *iface, PVOID pvRecord)
236 {
237 ok(0, "unexpected call\n");
238 return E_NOTIMPL;
239 }
240
241 static const IRecordInfoVtbl RecordInfoVtbl =
242 {
243 RecordInfo_QueryInterface,
244 RecordInfo_AddRef,
245 RecordInfo_Release,
246 RecordInfo_RecordInit,
247 RecordInfo_RecordClear,
248 RecordInfo_RecordCopy,
249 RecordInfo_GetGuid,
250 RecordInfo_GetName,
251 RecordInfo_GetSize,
252 RecordInfo_GetTypeInfo,
253 RecordInfo_GetField,
254 RecordInfo_GetFieldNoCopy,
255 RecordInfo_PutField,
256 RecordInfo_PutFieldNoCopy,
257 RecordInfo_GetFieldNames,
258 RecordInfo_IsMatchingType,
259 RecordInfo_RecordCreate,
260 RecordInfo_RecordCreateCopy,
261 RecordInfo_RecordDestroy
262 };
263
264 static IRecordInfoImpl *IRecordInfoImpl_Construct(void)
265 {
266 IRecordInfoImpl *rec;
267
268 rec = HeapAlloc(GetProcessHeap(), 0, sizeof(IRecordInfoImpl));
269 rec->IRecordInfo_iface.lpVtbl = &RecordInfoVtbl;
270 rec->ref = START_REF_COUNT;
271 rec->clearCalled = 0;
272 rec->sizeCalled = 0;
273 return rec;
274 }
275
276 static DWORD SAFEARRAY_GetVTSize(VARTYPE vt)
277 {
278 switch (vt)
279 {
280 case VT_I1:
281 case VT_UI1: return sizeof(BYTE);
282 case VT_BOOL:
283 case VT_I2:
284 case VT_UI2: return sizeof(SHORT);
285 case VT_I4:
286 case VT_UI4:
287 case VT_R4:
288 case VT_ERROR: return sizeof(LONG);
289 case VT_R8: return sizeof(LONG64);
290 case VT_I8:
291 case VT_UI8:
292 if (has_i8)
293 return sizeof(LONG64);
294 break;
295 case VT_INT:
296 case VT_UINT: return sizeof(INT);
297 case VT_INT_PTR:
298 case VT_UINT_PTR:
299 if (has_int_ptr)
300 return sizeof(UINT_PTR);
301 break;
302 case VT_CY: return sizeof(CY);
303 case VT_DATE: return sizeof(DATE);
304 case VT_BSTR: return sizeof(BSTR);
305 case VT_DISPATCH: return sizeof(LPDISPATCH);
306 case VT_VARIANT: return sizeof(VARIANT);
307 case VT_UNKNOWN: return sizeof(LPUNKNOWN);
308 case VT_DECIMAL: return sizeof(DECIMAL);
309 }
310 return 0;
311 }
312
313 static void check_for_VT_INT_PTR(void)
314 {
315 /* Set a global flag if VT_INT_PTR is supported */
316
317 SAFEARRAY* a;
318 SAFEARRAYBOUND bound;
319 bound.cElements = 0;
320 bound.lLbound = 0;
321 a = SafeArrayCreate(VT_INT_PTR, 1, &bound);
322 if (a) {
323 HRESULT hres;
324 trace("VT_INT_PTR is supported\n");
325 has_int_ptr = TRUE;
326 hres = SafeArrayDestroy(a);
327 ok(hres == S_OK, "got 0x%08x\n", hres);
328 }
329 else {
330 trace("VT_INT_PTR is not supported\n");
331 has_int_ptr = FALSE;
332 }
333 }
334
335 #define VARTYPE_NOT_SUPPORTED 0
336 static struct {
337 VARTYPE vt; /* VT */
338 UINT elemsize; /* elementsize by VT */
339 UINT expflags; /* fFeatures from SafeArrayAllocDescriptorEx */
340 UINT addflags; /* additional fFeatures from SafeArrayCreate */
341 } vttypes[] = {
342 {VT_EMPTY, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
343 {VT_NULL, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
344 {VT_I2, 2, FADF_HAVEVARTYPE,0},
345 {VT_I4, 4, FADF_HAVEVARTYPE,0},
346 {VT_R4, 4, FADF_HAVEVARTYPE,0},
347 {VT_R8, 8, FADF_HAVEVARTYPE,0},
348 {VT_CY, 8, FADF_HAVEVARTYPE,0},
349 {VT_DATE, 8, FADF_HAVEVARTYPE,0},
350 {VT_BSTR, sizeof(BSTR), FADF_HAVEVARTYPE,FADF_BSTR},
351 {VT_DISPATCH, sizeof(LPDISPATCH), FADF_HAVEIID, FADF_DISPATCH},
352 {VT_ERROR, 4, FADF_HAVEVARTYPE,0},
353 {VT_BOOL, 2, FADF_HAVEVARTYPE,0},
354 {VT_VARIANT, sizeof(VARIANT), FADF_HAVEVARTYPE,FADF_VARIANT},
355 {VT_UNKNOWN, sizeof(LPUNKNOWN), FADF_HAVEIID, FADF_UNKNOWN},
356 {VT_DECIMAL, sizeof(DECIMAL), FADF_HAVEVARTYPE,0},
357 {15, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0}, /* no VT_xxx */
358 {VT_I1, 1, FADF_HAVEVARTYPE,0},
359 {VT_UI1, 1, FADF_HAVEVARTYPE,0},
360 {VT_UI2, 2, FADF_HAVEVARTYPE,0},
361 {VT_UI4, 4, FADF_HAVEVARTYPE,0},
362 {VT_I8, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
363 {VT_UI8, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
364 {VT_INT, sizeof(INT), FADF_HAVEVARTYPE,0},
365 {VT_UINT, sizeof(UINT), FADF_HAVEVARTYPE,0},
366 {VT_VOID, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
367 {VT_HRESULT, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
368 {VT_PTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
369 {VT_SAFEARRAY,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
370 {VT_CARRAY, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
371 {VT_USERDEFINED,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
372 {VT_LPSTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
373 {VT_LPWSTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
374 {VT_FILETIME, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
375 {VT_RECORD, VARTYPE_NOT_SUPPORTED,FADF_RECORD,0},
376 {VT_BLOB, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
377 {VT_STREAM, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
378 {VT_STORAGE, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
379 {VT_STREAMED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
380 {VT_STORED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
381 {VT_BLOB_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
382 {VT_CF, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
383 {VT_CLSID, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
384 };
385
386 static void test_safearray(void)
387 {
388 SAFEARRAY *a, b, *c;
389 unsigned int i, diff;
390 LONG indices[2];
391 HRESULT hres;
392 SAFEARRAYBOUND bound, bounds[2];
393 VARIANT v,d;
394 LPVOID data;
395 IID iid;
396 VARTYPE vt;
397 LONG l;
398 unsigned char *ptr1, *ptr2;
399
400 hres = SafeArrayDestroy( NULL);
401 ok( hres == S_OK, "SafeArrayDestroy( NULL) returned 0x%x\n", hres);
402
403 bound.cElements = 1;
404 bound.lLbound = 0;
405 a = SafeArrayCreate(-1, 1, &bound);
406 ok(NULL == a,"SAC(-1,1,[1,0]) not failed?\n");
407
408 bound.cElements = 0;
409 bound.lLbound = 42;
410 a = SafeArrayCreate(VT_I4, 1, &bound);
411 ok(NULL != a,"SAC(VT_I4,1,[0,0]) failed.\n");
412
413 hres = SafeArrayGetLBound(a, 1, &l);
414 ok(hres == S_OK, "SAGLB of 0 size dimensioned array failed with %x\n",hres);
415 ok(l == 42, "SAGLB of 0 size dimensioned array failed to return 42, but returned %d\n",l);
416 hres = SafeArrayGetUBound(a, 1, &l);
417 ok(hres == S_OK, "SAGUB of 0 size dimensioned array failed with %x\n",hres);
418 ok(l == 41, "SAGUB of 0 size dimensioned array failed to return 41, but returned %d\n",l);
419
420 hres = SafeArrayAccessData(a, &data);
421 ok(hres == S_OK, "SafeArrayAccessData of 0 size dimensioned array failed with %x\n", hres);
422 SafeArrayUnaccessData(a);
423
424 bound.cElements = 2;
425 hres = SafeArrayRedim(a, &bound);
426 ok(hres == S_OK,"SAR of a 0 elements dimension failed with hres %x\n", hres);
427 bound.cElements = 0;
428 hres = SafeArrayRedim(a, &bound);
429 ok(hres == S_OK || hres == E_OUTOFMEMORY,
430 "SAR to a 0 elements dimension failed with hres %x\n", hres);
431 hres = SafeArrayDestroy(a);
432 ok(hres == S_OK,"SAD of 0 dim array failed with hres %x\n", hres);
433
434 SafeArrayAllocDescriptor(2, &a);
435 a->rgsabound[0].cElements = 2;
436 a->rgsabound[0].lLbound = 1;
437 a->rgsabound[1].cElements = 4;
438 a->rgsabound[1].lLbound = 1;
439 a->cbElements = 2;
440 hres = SafeArrayAllocData(a);
441 ok(hres == S_OK, "SafeArrayAllocData failed with hres %x\n", hres);
442
443 indices[0] = 4;
444 indices[1] = 2;
445 hres = SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
446 ok(hres == S_OK, "SAPOI failed with hres %x\n", hres);
447 SafeArrayAccessData(a, (void **)&ptr2);
448 ok(ptr1 - ptr2 == 14, "SAPOI got wrong ptr\n");
449 *(WORD *)ptr1 = 0x55aa;
450 SafeArrayUnaccessData(a);
451
452 bound.cElements = 10;
453 bound.lLbound = 1;
454 SafeArrayRedim(a, &bound);
455 ptr1 = NULL;
456 SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
457 ok(*(WORD *)ptr1 == 0x55aa, "Data not preserved when resizing array\n");
458
459 bound.cElements = 10;
460 bound.lLbound = 0;
461 SafeArrayRedim(a, &bound);
462 SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
463 ok(*(WORD *)ptr1 == 0 ||
464 broken(*(WORD *)ptr1 != 0), /* Win 2003 */
465 "Expanded area not zero-initialized\n");
466
467 indices[1] = 1;
468 SafeArrayPtrOfIndex(a, indices, (void **)&ptr1);
469 ok(*(WORD *)ptr1 == 0x55aa ||
470 broken(*(WORD *)ptr1 != 0x55aa), /* Win 2003 */
471 "Data not preserved when resizing array\n");
472
473 hres = SafeArrayDestroy(a);
474 ok(hres == S_OK,"SAD failed with hres %x\n", hres);
475
476 bounds[0].cElements = 0; bounds[0].lLbound = 1;
477 bounds[1].cElements = 2; bounds[1].lLbound = 23;
478 a = SafeArrayCreate(VT_I4,2,bounds);
479 ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
480
481 hres = SafeArrayDestroy(a);
482 ok(hres == S_OK,"SAD failed with hres %x\n", hres);
483 bounds[0].cElements = 1; bounds[0].lLbound = 1;
484 bounds[1].cElements = 0; bounds[1].lLbound = 23;
485 a = SafeArrayCreate(VT_I4,2,bounds);
486 ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
487
488 hres = SafeArrayDestroy(a);
489 ok(hres == S_OK,"SAD failed with hres %x\n", hres);
490
491 bounds[0].cElements = 42; bounds[0].lLbound = 1;
492 bounds[1].cElements = 2; bounds[1].lLbound = 23;
493 a = SafeArrayCreate(VT_I4,2,bounds);
494 ok(a != NULL,"SAC(VT_INT32,2,...) failed.\n");
495
496 hres = SafeArrayGetLBound (a, 0, &l);
497 ok (hres == DISP_E_BADINDEX, "SAGLB 0 failed with %x\n", hres);
498 hres = SafeArrayGetLBound (a, 1, &l);
499 ok (hres == S_OK, "SAGLB 1 failed with %x\n", hres);
500 ok (l == 1, "SAGLB 1 returned %d instead of 1\n", l);
501 hres = SafeArrayGetLBound (a, 2, &l);
502 ok (hres == S_OK, "SAGLB 2 failed with %x\n", hres);
503 ok (l == 23, "SAGLB 2 returned %d instead of 23\n", l);
504 hres = SafeArrayGetLBound (a, 3, &l);
505 ok (hres == DISP_E_BADINDEX, "SAGLB 3 failed with %x\n", hres);
506
507 hres = SafeArrayGetUBound (a, 0, &l);
508 ok (hres == DISP_E_BADINDEX, "SAGUB 0 failed with %x\n", hres);
509 hres = SafeArrayGetUBound (a, 1, &l);
510 ok (hres == S_OK, "SAGUB 1 failed with %x\n", hres);
511 ok (l == 42, "SAGUB 1 returned %d instead of 42\n", l);
512 hres = SafeArrayGetUBound (a, 2, &l);
513 ok (hres == S_OK, "SAGUB 2 failed with %x\n", hres);
514 ok (l == 24, "SAGUB 2 returned %d instead of 24\n", l);
515 hres = SafeArrayGetUBound (a, 3, &l);
516 ok (hres == DISP_E_BADINDEX, "SAGUB 3 failed with %x\n", hres);
517
518 i = SafeArrayGetDim(a);
519 ok(i == 2, "getdims of 2 din array returned %d\n",i);
520
521 indices[0] = 0;
522 indices[1] = 23;
523 hres = SafeArrayGetElement(a, indices, &i);
524 ok(DISP_E_BADINDEX == hres,"SAGE failed [0,23], hres 0x%x\n",hres);
525
526 indices[0] = 1;
527 indices[1] = 22;
528 hres = SafeArrayGetElement(a, indices, &i);
529 ok(DISP_E_BADINDEX == hres,"SAGE failed [1,22], hres 0x%x\n",hres);
530
531 indices[0] = 1;
532 indices[1] = 23;
533 hres = SafeArrayGetElement(a, indices, &i);
534 ok(S_OK == hres,"SAGE failed [1,23], hres 0x%x\n",hres);
535
536 indices[0] = 1;
537 indices[1] = 25;
538 hres = SafeArrayGetElement(a, indices, &i);
539 ok(DISP_E_BADINDEX == hres,"SAGE failed [1,24], hres 0x%x\n",hres);
540
541 indices[0] = 3;
542 indices[1] = 23;
543 hres = SafeArrayGetElement(a, indices, &i);
544 ok(S_OK == hres,"SAGE failed [42,23], hres 0x%x\n",hres);
545
546 hres = SafeArrayAccessData(a, (void**)&ptr1);
547 ok(S_OK == hres, "SAAD failed with 0x%x\n", hres);
548
549 indices[0] = 3;
550 indices[1] = 23;
551 hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2);
552 ok(S_OK == hres,"SAPOI failed [1,23], hres 0x%x\n",hres);
553 diff = ptr2 - ptr1;
554 ok(diff == 8,"ptr difference is not 8, but %d (%p vs %p)\n", diff, ptr2, ptr1);
555
556 indices[0] = 3;
557 indices[1] = 24;
558 hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2);
559 ok(S_OK == hres,"SAPOI failed [5,24], hres 0x%x\n",hres);
560 diff = ptr2 - ptr1;
561 ok(diff == 176,"ptr difference is not 176, but %d (%p vs %p)\n", diff, ptr2, ptr1);
562
563 indices[0] = 20;
564 indices[1] = 23;
565 hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2);
566 ok(S_OK == hres,"SAPOI failed [20,23], hres 0x%x\n",hres);
567 diff = ptr2 - ptr1;
568 ok(diff == 76,"ptr difference is not 76, but %d (%p vs %p)\n", diff, ptr2, ptr1);
569
570 hres = SafeArrayUnaccessData(a);
571 ok(S_OK == hres, "SAUAD failed with 0x%x\n", hres);
572
573 hres = SafeArrayDestroy(a);
574 ok(hres == S_OK,"SAD failed with hres %x\n", hres);
575
576 for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) {
577 if ((i == VT_I8 || i == VT_UI8) && has_i8)
578 {
579 vttypes[i].elemsize = sizeof(LONG64);
580 }
581
582 a = SafeArrayCreate(vttypes[i].vt, 1, &bound);
583
584 ok((!a && !vttypes[i].elemsize) ||
585 (a && vttypes[i].elemsize == a->cbElements),
586 "SAC(%d,1,[1,0]), %p result %d, expected %d\n",
587 vttypes[i].vt,a,(a?a->cbElements:0),vttypes[i].elemsize);
588
589 if (a)
590 {
591 ok(a->fFeatures == (vttypes[i].expflags | vttypes[i].addflags),
592 "SAC of %d returned feature flags %x, expected %x\n",
593 vttypes[i].vt, a->fFeatures,
594 vttypes[i].expflags|vttypes[i].addflags);
595 ok(SafeArrayGetElemsize(a) == vttypes[i].elemsize,
596 "SAGE for vt %d returned elemsize %d instead of expected %d\n",
597 vttypes[i].vt, SafeArrayGetElemsize(a),vttypes[i].elemsize);
598 }
599
600 if (!a) continue;
601
602 if (pSafeArrayGetVartype)
603 {
604 hres = pSafeArrayGetVartype(a, &vt);
605 ok(hres == S_OK, "SAGVT of arra y with vt %d failed with %x\n", vttypes[i].vt, hres);
606 /* Windows prior to Vista returns VT_UNKNOWN instead of VT_DISPATCH */
607 ok(broken(vt == VT_UNKNOWN) || vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d\n", vttypes[i].vt, vt);
608 }
609
610 hres = SafeArrayCopy(a, &c);
611 ok(hres == S_OK, "failed to copy safearray of vt %d with hres %x\n", vttypes[i].vt, hres);
612
613 ok(vttypes[i].elemsize == c->cbElements,"copy of SAC(%d,1,[1,0]), result %d, expected %d\n",vttypes[i].vt,(c?c->cbElements:0),vttypes[i].elemsize
614 );
615 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);
616 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);
617
618 if (pSafeArrayGetVartype) {
619 hres = pSafeArrayGetVartype(c, &vt);
620 ok(hres == S_OK, "SAGVT of array with vt %d failed with %x\n", vttypes[i].vt, hres);
621 /* Windows prior to Vista returns VT_UNKNOWN instead of VT_DISPATCH */
622 ok(broken(vt == VT_UNKNOWN) || vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d\n", vttypes[i].vt, vt);
623 }
624
625 if (pSafeArrayCopyData) {
626 hres = pSafeArrayCopyData(a, c);
627 ok(hres == S_OK, "failed to copy safearray data of vt %d with hres %x\n", vttypes[i].vt, hres);
628
629 hres = SafeArrayDestroyData(c);
630 ok(hres == S_OK,"SADD of copy of array with vt %d failed with hres %x\n", vttypes[i].vt, hres);
631 }
632
633 hres = SafeArrayDestroy(c);
634 ok(hres == S_OK,"SAD failed with hres %x\n", hres);
635
636 hres = SafeArrayDestroy(a);
637 ok(hres == S_OK,"SAD of array with vt %d failed with hres %x\n", vttypes[i].vt, hres);
638 }
639
640 /* Test conversion of type|VT_ARRAY <-> VT_BSTR */
641 bound.lLbound = 0;
642 bound.cElements = 10;
643 a = SafeArrayCreate(VT_UI1, 1, &bound);
644 ok(a != NULL, "SAC failed.\n");
645 ok(S_OK == SafeArrayAccessData(a, &data),"SACD failed\n");
646 memcpy(data,"Hello World\n",10);
647 ok(S_OK == SafeArrayUnaccessData(a),"SAUD failed\n");
648 V_VT(&v) = VT_ARRAY|VT_UI1;
649 V_ARRAY(&v) = a;
650 hres = VariantChangeTypeEx(&v, &v, 0, 0, VT_BSTR);
651 ok(hres==S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %x\n",hres);
652 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));
653 ok(V_BSTR(&v)[0] == 0x6548,"First letter are not 'He', but %x\n", V_BSTR(&v)[0]);
654 VariantClear(&v);
655
656 VariantInit(&d);
657 V_VT(&v) = VT_BSTR;
658 V_BSTR(&v) = SysAllocStringLen(NULL, 0);
659 hres = VariantChangeTypeEx(&d, &v, 0, 0, VT_UI1|VT_ARRAY);
660 ok(hres==S_OK, "CTE VT_BSTR -> VT_UI1|VT_ARRAY failed with %x\n",hres);
661 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));
662 VariantClear(&v);
663 VariantClear(&d);
664
665 /* check locking functions */
666 a = SafeArrayCreate(VT_I4, 1, &bound);
667 ok(a!=NULL,"SAC should not fail\n");
668
669 hres = SafeArrayAccessData(a, &data);
670 ok(hres == S_OK,"SAAD failed with hres %x\n",hres);
671
672 hres = SafeArrayDestroy(a);
673 ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy not failed with DISP_E_ARRAYISLOCKED, but with hres %x\n", hres);
674
675 hres = SafeArrayDestroyData(a);
676 ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy data not failed with DISP_E_ARRAYISLOCKED, but with hres %x\n", hres);
677
678 hres = SafeArrayDestroyDescriptor(a);
679 ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy descriptor not failed with DISP_E_ARRAYISLOCKED, but with hres %x\n", hres);
680
681 hres = SafeArrayUnaccessData(a);
682 ok(hres == S_OK,"SAUD failed after lock/destroy test\n");
683
684 hres = SafeArrayDestroy(a);
685 ok(hres == S_OK,"SAD failed after lock/destroy test\n");
686
687 /* Test if we need to destroy data before descriptor */
688 a = SafeArrayCreate(VT_I4, 1, &bound);
689 ok(a!=NULL,"SAC should not fail\n");
690 hres = SafeArrayDestroyDescriptor(a);
691 ok(hres == S_OK,"SADD with data in array failed with hres %x\n",hres);
692
693 /* IID functions */
694 /* init a small stack safearray */
695 if (pSafeArraySetIID) {
696 memset(&b, 0, sizeof(b));
697 b.cDims = 1;
698 memset(&iid, 0x42, sizeof(IID));
699 hres = pSafeArraySetIID(&b,&iid);
700 ok(hres == E_INVALIDARG,"SafeArraySetIID of non IID capable safearray did not return E_INVALIDARG, but %x\n",hres);
701
702 hres = SafeArrayAllocDescriptor(1,&a);
703 ok(hres == S_OK,"SafeArrayAllocDescriptor should return S_OK, but got %x\n",hres);
704 ok((a->fFeatures & FADF_HAVEIID) == 0,"newly allocated descriptor with SAAD should not have FADF_HAVEIID\n");
705 hres = pSafeArraySetIID(a,&iid);
706 ok(hres == E_INVALIDARG,"SafeArraySetIID of newly allocated descriptor with SAAD should return E_INVALIDARG, but got %x\n",hres);
707
708 hres = SafeArrayDestroyDescriptor(a);
709 ok(hres == S_OK,"SADD failed with hres %x\n",hres);
710 }
711
712 if (!pSafeArrayAllocDescriptorEx)
713 return;
714
715 for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) {
716 a = NULL;
717 hres = pSafeArrayAllocDescriptorEx(vttypes[i].vt,1,&a);
718 ok(hres == S_OK, "SafeArrayAllocDescriptorEx gave hres 0x%x\n", hres);
719 ok(a->fFeatures == vttypes[i].expflags,"SAADE(%d) resulted with flags %x, expected %x\n", vttypes[i].vt, a->fFeatures, vttypes[i].expflags);
720 if (a->fFeatures & FADF_HAVEIID) {
721 hres = pSafeArrayGetIID(a, &iid);
722 ok(hres == S_OK,"SAGIID failed for vt %d with hres %x\n", vttypes[i].vt,hres);
723 switch (vttypes[i].vt) {
724 case VT_UNKNOWN:
725 ok(IsEqualGUID(((GUID*)a)-1,&IID_IUnknown),"guid for VT_UNKNOWN is not IID_IUnknown\n");
726 ok(IsEqualGUID(&iid, &IID_IUnknown),"SAGIID returned wrong GUID for IUnknown\n");
727 break;
728 case VT_DISPATCH:
729 ok(IsEqualGUID(((GUID*)a)-1,&IID_IDispatch),"guid for VT_UNKNOWN is not IID_IDispatch\n");
730 ok(IsEqualGUID(&iid, &IID_IDispatch),"SAGIID returned wrong GUID for IDispatch\n");
731 break;
732 default:
733 ok(FALSE,"unknown vt %d with FADF_HAVEIID\n",vttypes[i].vt);
734 break;
735 }
736 } else {
737 hres = pSafeArrayGetIID(a, &iid);
738 ok(hres == E_INVALIDARG,"SAGIID did not fail for vt %d with hres %x\n", vttypes[i].vt,hres);
739 }
740 if (a->fFeatures & FADF_RECORD) {
741 ok(vttypes[i].vt == VT_RECORD,"FADF_RECORD for non record %d\n",vttypes[i].vt);
742 }
743 if (a->fFeatures & FADF_HAVEVARTYPE) {
744 ok(vttypes[i].vt == ((DWORD*)a)[-1], "FADF_HAVEVARTYPE set, but vt %d mismatch stored %d\n",vttypes[i].vt,((DWORD*)a)[-1]);
745 }
746
747 hres = pSafeArrayGetVartype(a, &vt);
748 ok(hres == S_OK, "SAGVT of array with vt %d failed with %x\n", vttypes[i].vt, hres);
749
750 if (vttypes[i].vt == VT_DISPATCH) {
751 /* Special case. Checked against Windows. */
752 ok(vt == VT_UNKNOWN, "SAGVT of array with VT_DISPATCH returned not VT_UNKNOWN, but %d\n", vt);
753 } else {
754 ok(vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d\n", vttypes[i].vt, vt);
755 }
756
757 if (a->fFeatures & FADF_HAVEIID) {
758 hres = pSafeArraySetIID(a, &IID_IStorage); /* random IID */
759 ok(hres == S_OK,"SASIID failed with FADF_HAVEIID set for vt %d with %x\n", vttypes[i].vt, hres);
760 hres = pSafeArrayGetIID(a, &iid);
761 ok(hres == S_OK,"SAGIID failed with FADF_HAVEIID set for vt %d with %x\n", vttypes[i].vt, hres);
762 ok(IsEqualGUID(&iid, &IID_IStorage),"returned iid is not IID_IStorage\n");
763 } else {
764 hres = pSafeArraySetIID(a, &IID_IStorage); /* random IID */
765 ok(hres == E_INVALIDARG,"SASIID did not failed with !FADF_HAVEIID set for vt %d with %x\n", vttypes[i].vt, hres);
766 }
767 hres = SafeArrayDestroyDescriptor(a);
768 ok(hres == S_OK,"SADD failed with hres %x\n",hres);
769 }
770 }
771
772 static void test_SafeArrayAllocDestroyDescriptor(void)
773 {
774 SAFEARRAY *sa;
775 HRESULT hres;
776 int i;
777
778 /* Failure cases */
779 hres = SafeArrayAllocDescriptor(0, &sa);
780 ok(hres == E_INVALIDARG, "0 dimensions gave hres 0x%x\n", hres);
781
782 hres = SafeArrayAllocDescriptor(65536, &sa);
783 ok(hres == E_INVALIDARG, "65536 dimensions gave hres 0x%x\n", hres);
784
785 if (0)
786 {
787 /* Crashes on 95: XP & Wine return E_POINTER */
788 hres=SafeArrayAllocDescriptor(1, NULL);
789 ok(hres == E_POINTER,"NULL parm gave hres 0x%x\n", hres);
790 }
791
792 /* Test up to the dimension boundary case */
793 for (i = 5; i <= 65535; i += 30)
794 {
795 hres = SafeArrayAllocDescriptor(i, &sa);
796 ok(hres == S_OK, "%d dimensions failed; hres 0x%x\n", i, hres);
797
798 if (hres == S_OK)
799 {
800 ok(SafeArrayGetDim(sa) == (UINT)i, "Dimension is %d; should be %d\n",
801 SafeArrayGetDim(sa), i);
802
803 hres = SafeArrayDestroyDescriptor(sa);
804 ok(hres == S_OK, "destroy failed; hres 0x%x\n", hres);
805 }
806 }
807
808 if (!pSafeArrayAllocDescriptorEx)
809 return;
810
811 hres = pSafeArrayAllocDescriptorEx(VT_UI1, 0, &sa);
812 ok(hres == E_INVALIDARG, "0 dimensions gave hres 0x%x\n", hres);
813
814 hres = pSafeArrayAllocDescriptorEx(VT_UI1, 65536, &sa);
815 ok(hres == E_INVALIDARG, "65536 dimensions gave hres 0x%x\n", hres);
816
817 hres = pSafeArrayAllocDescriptorEx(VT_UI1, 1, NULL);
818 ok(hres == E_POINTER,"NULL parm gave hres 0x%x\n", hres);
819
820 hres = pSafeArrayAllocDescriptorEx(-1, 1, &sa);
821 ok(hres == S_OK, "VT = -1 gave hres 0x%x\n", hres);
822
823 sa->rgsabound[0].cElements = 0;
824 sa->rgsabound[0].lLbound = 1;
825
826 hres = SafeArrayAllocData(sa);
827 ok(hres == S_OK, "SafeArrayAllocData gave hres 0x%x\n", hres);
828
829 hres = SafeArrayDestroy(sa);
830 ok(hres == S_OK,"SafeArrayDestroy failed with hres %x\n",hres);
831 }
832
833 static void test_SafeArrayCreateLockDestroy(void)
834 {
835 SAFEARRAYBOUND sab[4];
836 SAFEARRAY *sa;
837 HRESULT hres;
838 VARTYPE vt;
839 int dimension;
840
841 #define NUM_DIMENSIONS (int)(sizeof(sab) / sizeof(sab[0]))
842
843 for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
844 {
845 sab[dimension].lLbound = 0;
846 sab[dimension].cElements = 8;
847 }
848
849 /* Failure cases */
850 /* This test crashes very early versions with no error checking...
851 sa = SafeArrayCreate(VT_UI1, 1, NULL);
852 ok(sa == NULL, "NULL bounds didn't fail\n");
853 */
854 sa = SafeArrayCreate(VT_UI1, 65536, sab);
855 ok(!sa, "Max bounds didn't fail\n");
856
857 memset(sab, 0, sizeof(sab));
858
859 /* Don't test 0 sized dimensions, as Windows has a bug which allows this */
860
861 for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
862 sab[dimension].cElements = 8;
863
864 /* Test all VARTYPES in 1-4 dimensions */
865 for (dimension = 1; dimension < 4; dimension++)
866 {
867 for (vt = VT_EMPTY; vt < VT_CLSID; vt++)
868 {
869 DWORD dwLen = SAFEARRAY_GetVTSize(vt);
870
871 sa = SafeArrayCreate(vt, dimension, sab);
872
873 if (dwLen)
874 ok(sa != NULL, "VARTYPE %d (@%d dimensions) failed\n", vt, dimension);
875 else
876 ok(sa == NULL || vt == VT_R8,
877 "VARTYPE %d (@%d dimensions) succeeded!\n", vt, dimension);
878
879 if (sa)
880 {
881 ok(SafeArrayGetDim(sa) == (UINT)dimension,
882 "VARTYPE %d (@%d dimensions) cDims is %d, expected %d\n",
883 vt, dimension, SafeArrayGetDim(sa), dimension);
884 ok(SafeArrayGetElemsize(sa) == dwLen || vt == VT_R8,
885 "VARTYPE %d (@%d dimensions) cbElements is %d, expected %d\n",
886 vt, dimension, SafeArrayGetElemsize(sa), dwLen);
887
888 if (vt != VT_UNKNOWN && vt != VT_DISPATCH)
889 {
890 ok((sa->fFeatures & FADF_HAVEIID) == 0,
891 "Non interface type should not have FADF_HAVEIID\n");
892 if (pSafeArraySetIID)
893 {
894 hres = pSafeArraySetIID(sa, &IID_IUnknown);
895 ok(hres == E_INVALIDARG,
896 "Non interface type allowed SetIID(), hres %x\n", hres);
897 }
898 if (vt != VT_RECORD)
899 {
900 VARTYPE aVt;
901
902 ok(sa->fFeatures & FADF_HAVEVARTYPE,
903 "Non interface type should have FADF_HAVEVARTYPE\n");
904 if (pSafeArrayGetVartype)
905 {
906 hres = pSafeArrayGetVartype(sa, &aVt);
907 ok(hres == S_OK && aVt == vt,
908 "Non interface type %d: bad type %d, hres %x\n", vt, aVt, hres);
909 }
910 }
911 }
912 else
913 {
914 ok(sa->fFeatures & FADF_HAVEIID, "Interface type should have FADF_HAVEIID\n");
915 if (pSafeArraySetIID)
916 {
917 hres = pSafeArraySetIID(sa, &IID_IUnknown);
918 ok(hres == S_OK,
919 "Non interface type disallowed SetIID(), hres %x\n", hres);
920 }
921 ok((sa->fFeatures & FADF_HAVEVARTYPE) == 0,
922 "Interface type %d should not have FADF_HAVEVARTYPE\n", vt);
923 }
924
925 hres = SafeArrayLock(sa);
926 ok(hres == S_OK, "Lock VARTYPE %d (@%d dimensions) failed; hres 0x%x\n",
927 vt, dimension, hres);
928
929 if (hres == S_OK)
930 {
931 hres = SafeArrayDestroy(sa);
932 ok(hres == DISP_E_ARRAYISLOCKED,"Destroy() got hres %x\n", hres);
933
934 hres = SafeArrayDestroyData(sa);
935 ok(hres == DISP_E_ARRAYISLOCKED,"DestroyData() got hres %x\n", hres);
936
937 hres = SafeArrayDestroyDescriptor(sa);
938 ok(hres == DISP_E_ARRAYISLOCKED,"DestroyDescriptor() got hres %x\n", hres);
939
940 hres = SafeArrayUnlock(sa);
941 ok(hres == S_OK, "Unlock VARTYPE %d (@%d dims) hres 0x%x\n",
942 vt, dimension, hres);
943
944 hres = SafeArrayDestroy(sa);
945 ok(hres == S_OK, "destroy VARTYPE %d (@%d dims) hres 0x%x\n",
946 vt, dimension, hres);
947 }
948 }
949 }
950 }
951 }
952
953 static void test_VectorCreateLockDestroy(void)
954 {
955 SAFEARRAY *sa;
956 HRESULT hres;
957 VARTYPE vt;
958 int element;
959
960 if (!pSafeArrayCreateVector)
961 {
962 win_skip("SafeArrayCreateVector not supported\n");
963 return;
964 }
965 sa = pSafeArrayCreateVector(VT_UI1, 0, 0);
966 ok(sa != NULL, "SACV with 0 elements failed.\n");
967
968 hres = SafeArrayDestroy(sa);
969 ok(hres == S_OK, "SafeArrayDestroy failed with hres %x\n",hres);
970
971 /* Test all VARTYPES in different lengths */
972 for (element = 1; element <= 101; element += 10)
973 {
974 for (vt = VT_EMPTY; vt < VT_CLSID; vt++)
975 {
976 DWORD dwLen = SAFEARRAY_GetVTSize(vt);
977
978 sa = pSafeArrayCreateVector(vt, 0, element);
979
980 if (dwLen)
981 ok(sa != NULL, "VARTYPE %d (@%d elements) failed\n", vt, element);
982 else
983 ok(sa == NULL, "VARTYPE %d (@%d elements) succeeded!\n", vt, element);
984
985 if (sa)
986 {
987 ok(SafeArrayGetDim(sa) == 1, "VARTYPE %d (@%d elements) cDims %d, not 1\n",
988 vt, element, SafeArrayGetDim(sa));
989 ok(SafeArrayGetElemsize(sa) == dwLen,
990 "VARTYPE %d (@%d elements) cbElements is %d, expected %d\n",
991 vt, element, SafeArrayGetElemsize(sa), dwLen);
992
993 hres = SafeArrayLock(sa);
994 ok(hres == S_OK, "Lock VARTYPE %d (@%d elements) failed; hres 0x%x\n",
995 vt, element, hres);
996
997 if (hres == S_OK)
998 {
999 hres = SafeArrayUnlock(sa);
1000 ok(hres == S_OK, "Unlock VARTYPE %d (@%d elements) failed; hres 0x%x\n",
1001 vt, element, hres);
1002
1003 hres = SafeArrayDestroy(sa);
1004 ok(hres == S_OK, "destroy VARTYPE %d (@%d elements) failed; hres 0x%x\n",
1005 vt, element, hres);
1006 }
1007 }
1008 }
1009 }
1010 }
1011
1012 static void test_LockUnlock(void)
1013 {
1014 SAFEARRAYBOUND sab[4];
1015 SAFEARRAY *sa;
1016 HRESULT hres;
1017 BOOL bVector = FALSE;
1018 int dimension;
1019
1020 /* Failure cases */
1021 hres = SafeArrayLock(NULL);
1022 ok(hres == E_INVALIDARG, "Lock NULL array hres 0x%x\n", hres);
1023 hres = SafeArrayUnlock(NULL);
1024 ok(hres == E_INVALIDARG, "Lock NULL array hres 0x%x\n", hres);
1025
1026 for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
1027 {
1028 sab[dimension].lLbound = 0;
1029 sab[dimension].cElements = 8;
1030 }
1031
1032 sa = SafeArrayCreate(VT_UI1, NUM_DIMENSIONS, sab);
1033
1034 /* Test maximum locks */
1035 test_LockUnlock_Vector:
1036 if (sa)
1037 {
1038 int count = 0;
1039
1040 hres = SafeArrayUnlock(sa);
1041 ok (hres == E_UNEXPECTED, "Bad %sUnlock gave hres 0x%x\n",
1042 bVector ? "vector " : "\n", hres);
1043
1044 while ((hres = SafeArrayLock(sa)) == S_OK)
1045 count++;
1046 ok (count == 65535 && hres == E_UNEXPECTED, "Lock %sfailed at %d; hres 0x%x\n",
1047 bVector ? "vector " : "\n", count, hres);
1048
1049 if (count == 65535 && hres == E_UNEXPECTED)
1050 {
1051 while ((hres = SafeArrayUnlock(sa)) == S_OK)
1052 count--;
1053 ok (count == 0 && hres == E_UNEXPECTED, "Unlock %sfailed at %d; hres 0x%x\n",
1054 bVector ? "vector " : "\n", count, hres);
1055 }
1056
1057 hres = SafeArrayDestroy(sa);
1058 ok(hres == S_OK, "got 0x%08x\n", hres);
1059 }
1060
1061 if (bVector == FALSE && pSafeArrayCreateVector)
1062 {
1063 /* Test again with a vector */
1064 sa = pSafeArrayCreateVector(VT_UI1, 0, 100);
1065 bVector = TRUE;
1066 goto test_LockUnlock_Vector;
1067 }
1068 }
1069
1070 static void test_SafeArrayGetPutElement(void)
1071 {
1072 SAFEARRAYBOUND sab[4];
1073 LONG indices[NUM_DIMENSIONS], index;
1074 SAFEARRAY *sa;
1075 HRESULT hres;
1076 int value = 0, gotvalue, dimension;
1077 IRecordInfoImpl *irec;
1078 unsigned int x,y,z,a;
1079
1080 for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
1081 {
1082 sab[dimension].lLbound = dimension * 2 + 1;
1083 sab[dimension].cElements = dimension * 3 + 1;
1084 }
1085
1086 sa = SafeArrayCreate(VT_INT, NUM_DIMENSIONS, sab);
1087 if (!sa)
1088 return; /* Some early versions can't handle > 3 dims */
1089
1090 ok(sa->cbElements == sizeof(value), "int size mismatch\n");
1091
1092 /* Failure cases */
1093 for (x = 0; x < NUM_DIMENSIONS; x++)
1094 {
1095 indices[0] = sab[0].lLbound;
1096 indices[1] = sab[1].lLbound;
1097 indices[2] = sab[2].lLbound;
1098 indices[3] = sab[3].lLbound;
1099
1100 indices[x] = indices[x] - 1;
1101 hres = SafeArrayPutElement(sa, indices, &value);
1102 ok(hres == DISP_E_BADINDEX, "Put allowed too small index in dimension %d\n", x);
1103 hres = SafeArrayGetElement(sa, indices, &value);
1104 ok(hres == DISP_E_BADINDEX, "Get allowed too small index in dimension %d\n", x);
1105
1106 indices[x] = sab[x].lLbound + sab[x].cElements;
1107 hres = SafeArrayPutElement(sa, indices, &value);
1108 ok(hres == DISP_E_BADINDEX, "Put allowed too big index in dimension %d\n", x);
1109 hres = SafeArrayGetElement(sa, indices, &value);
1110 ok(hres == DISP_E_BADINDEX, "Get allowed too big index in dimension %d\n", x);
1111 }
1112
1113 indices[0] = sab[0].lLbound;
1114 indices[1] = sab[1].lLbound;
1115 indices[2] = sab[2].lLbound;
1116 indices[3] = sab[3].lLbound;
1117
1118 hres = SafeArrayPutElement(NULL, indices, &value);
1119 ok(hres == E_INVALIDARG, "Put NULL array hres 0x%x\n", hres);
1120 hres = SafeArrayGetElement(NULL, indices, &value);
1121 ok(hres == E_INVALIDARG, "Get NULL array hres 0x%x\n", hres);
1122
1123 hres = SafeArrayPutElement(sa, NULL, &value);
1124 ok(hres == E_INVALIDARG, "Put NULL indices hres 0x%x\n", hres);
1125 hres = SafeArrayGetElement(sa, NULL, &value);
1126 ok(hres == E_INVALIDARG, "Get NULL indices hres 0x%x\n", hres);
1127
1128 if (0)
1129 {
1130 /* This is retarded. Windows checks every case of invalid parameters
1131 * except the following, which crashes. We ERR this in Wine.
1132 */
1133 hres = SafeArrayPutElement(sa, indices, NULL);
1134 ok(hres == E_INVALIDARG, "Put NULL value hres 0x%x\n", hres);
1135 }
1136
1137 hres = SafeArrayGetElement(sa, indices, NULL);
1138 ok(hres == E_INVALIDARG, "Get NULL value hres 0x%x\n", hres);
1139
1140 value = 0;
1141
1142 /* Make sure we can read and get back the correct values in 4 dimensions,
1143 * Each with a different size and lower bound.
1144 */
1145 for (x = 0; x < sab[0].cElements; x++)
1146 {
1147 indices[0] = sab[0].lLbound + x;
1148 for (y = 0; y < sab[1].cElements; y++)
1149 {
1150 indices[1] = sab[1].lLbound + y;
1151 for (z = 0; z < sab[2].cElements; z++)
1152 {
1153 indices[2] = sab[2].lLbound + z;
1154 for (a = 0; a < sab[3].cElements; a++)
1155 {
1156 indices[3] = sab[3].lLbound + a;
1157 hres = SafeArrayPutElement(sa, indices, &value);
1158 ok(hres == S_OK, "Failed to put element at (%d,%d,%d,%d) hres 0x%x\n",
1159 x, y, z, a, hres);
1160 value++;
1161 }
1162 }
1163 }
1164 }
1165
1166 value = 0;
1167
1168 for (x = 0; x < sab[0].cElements; x++)
1169 {
1170 indices[0] = sab[0].lLbound + x;
1171 for (y = 0; y < sab[1].cElements; y++)
1172 {
1173 indices[1] = sab[1].lLbound + y;
1174 for (z = 0; z < sab[2].cElements; z++)
1175 {
1176 indices[2] = sab[2].lLbound + z;
1177 for (a = 0; a < sab[3].cElements; a++)
1178 {
1179 indices[3] = sab[3].lLbound + a;
1180 gotvalue = value / 3;
1181 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1182 ok(hres == S_OK, "Failed to get element at (%d,%d,%d,%d) hres 0x%x\n",
1183 x, y, z, a, hres);
1184 if (hres == S_OK)
1185 ok(value == gotvalue, "Got value %d instead of %d at (%d,%d,%d,%d)\n",
1186 gotvalue, value, x, y, z, a);
1187 value++;
1188 }
1189 }
1190 }
1191 }
1192 hres = SafeArrayDestroy(sa);
1193 ok(hres == S_OK, "got 0x%08x\n", hres);
1194
1195 /* VT_RECORD array */
1196 irec = IRecordInfoImpl_Construct();
1197 irec->ref = 1;
1198
1199 sab[0].lLbound = 0;
1200 sab[0].cElements = 8;
1201
1202 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &irec->IRecordInfo_iface);
1203 ok(sa != NULL, "failed to create array\n");
1204 ok(irec->ref == 2, "got %d\n", irec->ref);
1205
1206 index = 0;
1207 irec->recordcopy = 0;
1208 hres = SafeArrayPutElement(sa, &index, (void*)0xdeadbeef);
1209 ok(hres == S_OK, "got 0x%08x\n", hres);
1210 ok(irec->recordcopy == 1, "got %d\n", irec->recordcopy);
1211
1212 index = 0;
1213 irec->recordcopy = 0;
1214 hres = SafeArrayGetElement(sa, &index, (void*)0xdeadbeef);
1215 ok(hres == S_OK, "got 0x%08x\n", hres);
1216 ok(irec->recordcopy == 1, "got %d\n", irec->recordcopy);
1217
1218 hres = SafeArrayDestroy(sa);
1219 ok(hres == S_OK, "got 0x%08x\n", hres);
1220 ok(irec->ref == 1, "got %d\n", irec->ref);
1221 IRecordInfo_Release(&irec->IRecordInfo_iface);
1222 }
1223
1224 static void test_SafeArrayGetPutElement_BSTR(void)
1225 {
1226 SAFEARRAYBOUND sab;
1227 LONG indices[1];
1228 SAFEARRAY *sa;
1229 HRESULT hres;
1230 BSTR value = 0, gotvalue;
1231 const OLECHAR szTest[5] = { 'T','e','s','t','\0' };
1232
1233 sab.lLbound = 1;
1234 sab.cElements = 1;
1235
1236 sa = SafeArrayCreate(VT_BSTR, 1, &sab);
1237 ok(sa != NULL, "BSTR test couldn't create array\n");
1238 if (!sa)
1239 return;
1240
1241 ok(sa->cbElements == sizeof(BSTR), "BSTR size mismatch\n");
1242
1243 indices[0] = sab.lLbound;
1244 value = SysAllocString(szTest);
1245 ok (value != NULL, "Expected non-NULL\n");
1246 hres = SafeArrayPutElement(sa, indices, value);
1247 ok(hres == S_OK, "Failed to put bstr element hres 0x%x\n", hres);
1248 gotvalue = NULL;
1249 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1250 ok(hres == S_OK, "Failed to get bstr element at hres 0x%x\n", hres);
1251 if (hres == S_OK)
1252 ok(SysStringLen(value) == SysStringLen(gotvalue), "Got len %d instead of %d\n", SysStringLen(gotvalue), SysStringLen(value));
1253 hres = SafeArrayDestroy(sa);
1254 ok(hres == S_OK, "got 0x%08x\n", hres);
1255 SysFreeString(value);
1256 SysFreeString(gotvalue);
1257 }
1258
1259 struct xtunk_impl {
1260 IUnknown IUnknown_iface;
1261 LONG ref;
1262 };
1263 static const IUnknownVtbl xtunk_vtbl;
1264
1265 static struct xtunk_impl xtunk = {{&xtunk_vtbl}, 0};
1266
1267 static HRESULT WINAPI tunk_QueryInterface(IUnknown *punk, REFIID riid, void **x)
1268 {
1269 return E_FAIL;
1270 }
1271
1272 static ULONG WINAPI tunk_AddRef(IUnknown *punk)
1273 {
1274 return ++xtunk.ref;
1275 }
1276
1277 static ULONG WINAPI tunk_Release(IUnknown *punk)
1278 {
1279 return --xtunk.ref;
1280 }
1281
1282 static const IUnknownVtbl xtunk_vtbl = {
1283 tunk_QueryInterface,
1284 tunk_AddRef,
1285 tunk_Release
1286 };
1287
1288 static void test_SafeArrayGetPutElement_IUnknown(void)
1289 {
1290 SAFEARRAYBOUND sab;
1291 LONG indices[1];
1292 SAFEARRAY *sa;
1293 HRESULT hres;
1294 IUnknown *gotvalue;
1295
1296 sab.lLbound = 1;
1297 sab.cElements = 1;
1298 sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab);
1299 ok(sa != NULL, "UNKNOWN test couldn't create array\n");
1300 if (!sa)
1301 return;
1302
1303 ok(sa->cbElements == sizeof(LPUNKNOWN), "LPUNKNOWN size mismatch\n");
1304
1305 indices[0] = sab.lLbound;
1306 xtunk.ref = 1;
1307 hres = SafeArrayPutElement(sa, indices, &xtunk.IUnknown_iface);
1308 ok(hres == S_OK, "Failed to put bstr element hres 0x%x\n", hres);
1309 ok(xtunk.ref == 2,"Failed to increment refcount of iface.\n");
1310 gotvalue = NULL;
1311 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1312 ok(xtunk.ref == 3,"Failed to increment refcount of iface.\n");
1313 ok(hres == S_OK, "Failed to get bstr element at hres 0x%x\n", hres);
1314 if (hres == S_OK)
1315 ok(gotvalue == &xtunk.IUnknown_iface, "Got %p instead of %p\n", gotvalue, &xtunk.IUnknown_iface);
1316 hres = SafeArrayDestroy(sa);
1317 ok(hres == S_OK, "got 0x%08x\n", hres);
1318 ok(xtunk.ref == 2,"Failed to decrement refcount of iface.\n");
1319 }
1320
1321 static void test_SafeArrayRedim_IUnknown(void)
1322 {
1323 SAFEARRAYBOUND sab;
1324 LONG indices[1];
1325 SAFEARRAY *sa;
1326 HRESULT hres;
1327
1328 sab.lLbound = 1;
1329 sab.cElements = 2;
1330 sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab);
1331 ok(sa != NULL, "UNKNOWN test couldn't create array\n");
1332 if (!sa)
1333 return;
1334
1335 ok(sa->cbElements == sizeof(LPUNKNOWN), "LPUNKNOWN size mismatch\n");
1336
1337 indices[0] = 2;
1338 xtunk.ref = 1;
1339 hres = SafeArrayPutElement(sa, indices, &xtunk.IUnknown_iface);
1340 ok(hres == S_OK, "Failed to put IUnknown element hres 0x%x\n", hres);
1341 ok(xtunk.ref == 2,"Failed to increment refcount of iface.\n");
1342 sab.cElements = 1;
1343 hres = SafeArrayRedim(sa, &sab);
1344 ok(hres == S_OK, "Failed to shrink array hres 0x%x\n", hres);
1345 ok(xtunk.ref == 1, "Failed to decrement refcount\n");
1346 hres = SafeArrayDestroy(sa);
1347 ok(hres == S_OK, "got 0x%08x\n", hres);
1348 }
1349
1350 static void test_SafeArrayGetPutElement_VARIANT(void)
1351 {
1352 SAFEARRAYBOUND sab;
1353 LONG indices[1];
1354 SAFEARRAY *sa;
1355 HRESULT hres;
1356 VARIANT value, gotvalue;
1357
1358 sab.lLbound = 1;
1359 sab.cElements = 1;
1360 sa = SafeArrayCreate(VT_VARIANT, 1, &sab);
1361 ok(sa != NULL, "VARIANT test couldn't create array\n");
1362 if (!sa)
1363 return;
1364
1365 ok(sa->cbElements == sizeof(VARIANT), "VARIANT size mismatch\n");
1366
1367 indices[0] = sab.lLbound;
1368 V_VT(&value) = VT_I4;
1369 V_I4(&value) = 0x42424242;
1370 hres = SafeArrayPutElement(sa, indices, &value);
1371 ok(hres == S_OK, "Failed to put Variant I4 element hres 0x%x\n", hres);
1372
1373 V_VT(&gotvalue) = 0xdead;
1374 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1375 ok(hres == S_OK, "Failed to get variant element at hres 0x%x\n", hres);
1376
1377 V_VT(&gotvalue) = VT_EMPTY;
1378 hres = SafeArrayGetElement(sa, indices, &gotvalue);
1379 ok(hres == S_OK, "Failed to get variant element at hres 0x%x\n", hres);
1380 if (hres == S_OK) {
1381 ok(V_VT(&value) == V_VT(&gotvalue), "Got type 0x%x instead of 0x%x\n", V_VT(&value), V_VT(&gotvalue));
1382 if (V_VT(&value) == V_VT(&gotvalue))
1383 ok(V_I4(&value) == V_I4(&gotvalue), "Got %d instead of %d\n", V_I4(&value), V_VT(&gotvalue));
1384 }
1385 hres = SafeArrayDestroy(sa);
1386 ok(hres == S_OK, "got 0x%08x\n", hres);
1387 }
1388
1389 static void test_SafeArrayCopyData(void)
1390 {
1391 SAFEARRAYBOUND sab[4];
1392 SAFEARRAY *sa;
1393 SAFEARRAY *sacopy;
1394 HRESULT hres;
1395 int dimension, size = 1, i;
1396
1397 if (!pSafeArrayCopyData)
1398 {
1399 win_skip("SafeArrayCopyData not supported\n");
1400 return;
1401 }
1402
1403 for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
1404 {
1405 sab[dimension].lLbound = dimension * 2 + 2;
1406 sab[dimension].cElements = dimension * 3 + 1;
1407 size *= sab[dimension].cElements;
1408 }
1409
1410 sa = SafeArrayCreate(VT_INT, NUM_DIMENSIONS, sab);
1411 ok(sa != NULL, "Copy test couldn't create array\n");
1412 sacopy = SafeArrayCreate(VT_INT, NUM_DIMENSIONS, sab);
1413 ok(sacopy != NULL, "Copy test couldn't create copy array\n");
1414
1415 if (!sa || !sacopy)
1416 return;
1417
1418 ok(sa->cbElements == sizeof(int), "int size mismatch\n");
1419
1420 /* Fill the source array with some data; it doesn't matter what */
1421 for (dimension = 0; dimension < size; dimension++)
1422 {
1423 int* data = sa->pvData;
1424 data[dimension] = dimension;
1425 }
1426
1427 hres = pSafeArrayCopyData(sa, sacopy);
1428 ok(hres == S_OK, "copy data failed hres 0x%x\n", hres);
1429 if (hres == S_OK)
1430 {
1431 ok(!memcmp(sa->pvData, sacopy->pvData, size * sizeof(int)), "compared different\n");
1432 }
1433
1434 /* Failure cases */
1435 hres = pSafeArrayCopyData(NULL, sacopy);
1436 ok(hres == E_INVALIDARG, "Null copy source hres 0x%x\n", hres);
1437 hres = pSafeArrayCopyData(sa, NULL);
1438 ok(hres == E_INVALIDARG, "Null copy hres 0x%x\n", hres);
1439
1440 sacopy->rgsabound[0].cElements += 1;
1441 hres = pSafeArrayCopyData(sa, sacopy);
1442 ok(hres == E_INVALIDARG, "Bigger copy first dimension hres 0x%x\n", hres);
1443
1444 sacopy->rgsabound[0].cElements -= 2;
1445 hres = pSafeArrayCopyData(sa, sacopy);
1446 ok(hres == E_INVALIDARG, "Smaller copy first dimension hres 0x%x\n", hres);
1447 sacopy->rgsabound[0].cElements += 1;
1448
1449 sacopy->rgsabound[3].cElements += 1;
1450 hres = pSafeArrayCopyData(sa, sacopy);
1451 ok(hres == E_INVALIDARG, "Bigger copy last dimension hres 0x%x\n", hres);
1452
1453 sacopy->rgsabound[3].cElements -= 2;
1454 hres = pSafeArrayCopyData(sa, sacopy);
1455 ok(hres == E_INVALIDARG, "Smaller copy last dimension hres 0x%x\n", hres);
1456 sacopy->rgsabound[3].cElements += 1;
1457
1458 hres = SafeArrayDestroy(sacopy);
1459 ok(hres == S_OK, "got 0x%08x\n", hres);
1460 sacopy = NULL;
1461 hres = pSafeArrayCopyData(sa, sacopy);
1462 ok(hres == E_INVALIDARG, "->Null copy hres 0x%x\n", hres);
1463
1464 hres = SafeArrayCopy(sa, &sacopy);
1465 ok(hres == S_OK, "copy failed hres 0x%x\n", hres);
1466 ok(SafeArrayGetElemsize(sa) == SafeArrayGetElemsize(sacopy),"elemsize wrong\n");
1467 ok(SafeArrayGetDim(sa) == SafeArrayGetDim(sacopy),"dimensions wrong\n");
1468 ok(!memcmp(sa->pvData, sacopy->pvData, size * sizeof(int)), "compared different\n");
1469 hres = SafeArrayDestroy(sacopy);
1470 ok(hres == S_OK, "got 0x%08x\n", hres);
1471
1472 sacopy = SafeArrayCreate(VT_INT, NUM_DIMENSIONS, sab);
1473 ok(sacopy != NULL, "Copy test couldn't create copy array\n");
1474 ok(sacopy->fFeatures == FADF_HAVEVARTYPE, "0x%04x\n", sacopy->fFeatures);
1475
1476 for (i = 0; i < sizeof(ignored_copy_features)/sizeof(USHORT); i++)
1477 {
1478 USHORT feature = ignored_copy_features[i];
1479 USHORT orig = sacopy->fFeatures;
1480
1481 sa->fFeatures |= feature;
1482 hres = SafeArrayCopyData(sa, sacopy);
1483 ok(hres == S_OK, "got 0x%08x\n", hres);
1484 ok(sacopy->fFeatures == orig && orig == FADF_HAVEVARTYPE, "got features 0x%04x\n", sacopy->fFeatures);
1485 sa->fFeatures &= ~feature;
1486 }
1487
1488 hres = SafeArrayDestroy(sacopy);
1489 ok(hres == S_OK, "got 0x%08x\n", hres);
1490 hres = SafeArrayDestroy(sa);
1491 ok(hres == S_OK, "got 0x%08x\n", hres);
1492
1493 /* copy data from a vector */
1494 sa = SafeArrayCreateVector(VT_UI1, 0, 2);
1495
1496 sacopy = SafeArrayCreateVector(VT_UI1, 0, 2);
1497 ok(sa->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1498 broken(sa->fFeatures == FADF_CREATEVECTOR /* W2k */),
1499 "got 0x%08x\n", sa->fFeatures);
1500 ok(sacopy->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1501 broken(sacopy->fFeatures == FADF_CREATEVECTOR /* W2k */),
1502 "got 0x%08x\n", sacopy->fFeatures);
1503 hres = SafeArrayCopyData(sa, sacopy);
1504 ok(hres == S_OK, "got 0x%08x\n", hres);
1505 ok(sacopy->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1506 broken(sacopy->fFeatures == FADF_CREATEVECTOR /* W2k */),
1507 "got 0x%04x\n", sacopy->fFeatures);
1508 SafeArrayDestroy(sacopy);
1509
1510 sacopy = SafeArrayCreate(VT_UI1, NUM_DIMENSIONS, sab);
1511 ok(sacopy != NULL, "Copy test couldn't create copy array\n");
1512 ok(sacopy->fFeatures == FADF_HAVEVARTYPE, "0x%04x\n", sacopy->fFeatures);
1513 hres = SafeArrayCopyData(sa, sacopy);
1514 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
1515 SafeArrayDestroy(sacopy);
1516
1517 SafeArrayDestroy(sa);
1518 }
1519
1520 static void test_SafeArrayCreateEx(void)
1521 {
1522 IRecordInfoImpl* iRec;
1523 SAFEARRAYBOUND sab[4];
1524 SAFEARRAY *sa;
1525 HRESULT hres;
1526 int dimension;
1527
1528 if (!pSafeArrayCreateEx)
1529 {
1530 win_skip("SafeArrayCreateEx not supported\n");
1531 return;
1532 }
1533
1534 for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
1535 {
1536 sab[dimension].lLbound = 0;
1537 sab[dimension].cElements = 8;
1538 }
1539
1540 /* Failure cases */
1541 sa = pSafeArrayCreateEx(VT_UI1, 1, NULL, NULL);
1542 ok(sa == NULL, "CreateEx NULL bounds didn't fail\n");
1543
1544 /* test IID storage & defaulting */
1545 sa = pSafeArrayCreateEx(VT_DISPATCH, 1, sab, (PVOID)&IID_ITypeInfo);
1546 ok(sa != NULL, "CreateEx (ITypeInfo) failed\n");
1547
1548 if (sa)
1549 {
1550 GUID guid;
1551 if (pSafeArrayGetIID)
1552 {
1553 hres = pSafeArrayGetIID(sa, &guid);
1554 ok(hres == S_OK, "CreateEx (ITypeInfo) no IID hres 0x%x\n", hres);
1555 if (hres == S_OK)
1556 {
1557 ok(IsEqualGUID(&guid, &IID_ITypeInfo), "CreateEx (ITypeInfo) bad IID\n");
1558 }
1559 }
1560 if (pSafeArraySetIID)
1561 {
1562 hres = pSafeArraySetIID(sa, &IID_IUnknown);
1563 ok(hres == S_OK, "Failed to set IID, hres = %8x\n", hres);
1564 if (hres == S_OK && pSafeArrayGetIID)
1565 {
1566 hres = pSafeArrayGetIID(sa, &guid);
1567 ok(hres == S_OK && IsEqualGUID(&guid, &IID_IUnknown), "Set bad IID\n");
1568 }
1569 }
1570 hres = SafeArrayDestroy(sa);
1571 ok(hres == S_OK, "got 0x%08x\n", hres);
1572 }
1573
1574 sa = pSafeArrayCreateEx(VT_DISPATCH, 1, sab, NULL);
1575 ok(sa != NULL, "CreateEx (NULL) failed\n");
1576
1577 if (sa)
1578 {
1579 GUID guid;
1580 if (pSafeArrayGetIID)
1581 {
1582 hres = pSafeArrayGetIID(sa, &guid);
1583 ok(hres == S_OK, "CreateEx (NULL) no IID hres 0x%x\n", hres);
1584 if (hres == S_OK)
1585 {
1586 ok(IsEqualGUID(&guid, &IID_IDispatch), "CreateEx (NULL) bad IID\n");
1587 }
1588 }
1589 hres = SafeArrayDestroy(sa);
1590 ok(hres == S_OK, "got 0x%08x\n", hres);
1591 }
1592
1593 sa = pSafeArrayCreateEx(VT_UNKNOWN, 1, sab, NULL);
1594 ok(sa != NULL, "CreateEx (NULL-Unk) failed\n");
1595
1596 if (sa)
1597 {
1598 GUID guid;
1599 if (pSafeArrayGetIID)
1600 {
1601 hres = pSafeArrayGetIID(sa, &guid);
1602 ok(hres == S_OK, "CreateEx (NULL-Unk) no IID hres 0x%x\n", hres);
1603 if (hres == S_OK)
1604 {
1605 ok(IsEqualGUID(&guid, &IID_IUnknown), "CreateEx (NULL-Unk) bad IID\n");
1606 }
1607 }
1608 hres = SafeArrayDestroy(sa);
1609 ok(hres == S_OK, "got 0x%08x\n", hres);
1610 }
1611
1612 /* VT_RECORD failure case */
1613 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, NULL);
1614 ok(sa == NULL, "CreateEx (NULL-Rec) succeeded\n");
1615
1616 iRec = IRecordInfoImpl_Construct();
1617
1618 /* Win32 doesn't care if GetSize fails */
1619 fail_GetSize = TRUE;
1620 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface);
1621 ok(sa != NULL, "CreateEx (Fail Size) failed\n");
1622 ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %d\n", iRec->ref);
1623 ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled);
1624 ok(iRec->clearCalled == 0, "Clear called %d times\n", iRec->clearCalled);
1625 if (sa)
1626 {
1627 ok(sa->cbElements == RECORD_SIZE_FAIL, "Altered size to %d\n", sa->cbElements);
1628 hres = SafeArrayDestroy(sa);
1629 ok(hres == S_OK, "got 0x%08x\n", hres);
1630 ok(iRec->clearCalled == sab[0].cElements, "Destroy->Clear called %d times\n", iRec->clearCalled);
1631 ok(iRec->ref == START_REF_COUNT, "got %d, expected %d\n", iRec->ref, START_REF_COUNT);
1632 }
1633
1634 /* Test VT_RECORD array */
1635 fail_GetSize = FALSE;
1636 iRec->ref = START_REF_COUNT;
1637 iRec->sizeCalled = 0;
1638 iRec->clearCalled = 0;
1639 sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface);
1640 ok(sa != NULL, "CreateEx (Rec) failed\n");
1641 ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %d\n", iRec->ref);
1642 ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled);
1643 ok(iRec->clearCalled == 0, "Clear called %d times\n", iRec->clearCalled);
1644 if (sa && pSafeArrayGetRecordInfo)
1645 {
1646 IRecordInfo* saRec = NULL;
1647 SAFEARRAY *sacopy;
1648
1649 hres = pSafeArrayGetRecordInfo(sa, &saRec);
1650 ok(hres == S_OK,"GRI failed\n");
1651 ok(saRec == &iRec->IRecordInfo_iface, "Different saRec\n");
1652 ok(iRec->ref == START_REF_COUNT + 2, "Didn't AddRef %d\n", iRec->ref);
1653 IRecordInfo_Release(saRec);
1654
1655 ok(sa->cbElements == RECORD_SIZE,"Elemsize is %d\n", sa->cbElements);
1656
1657 /* try to copy record based arrays */
1658 sacopy = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface);
1659 iRec->recordcopy = 0;
1660 iRec->clearCalled = 0;
1661 /* array copy code doesn't explicitly clear a record */
1662 hres = SafeArrayCopyData(sa, sacopy);
1663 ok(hres == S_OK, "got 0x%08x\n", hres);
1664 ok(iRec->recordcopy == sab[0].cElements, "got %d\n", iRec->recordcopy);
1665 ok(iRec->clearCalled == 0, "got %d\n", iRec->clearCalled);
1666
1667 hres = SafeArrayDestroy(sacopy);
1668 ok(hres == S_OK, "got 0x%08x\n", hres);
1669
1670 iRec->clearCalled = 0;
1671 iRec->sizeCalled = 0;
1672 hres = SafeArrayDestroy(sa);
1673 ok(hres == S_OK, "got 0x%08x\n", hres);
1674 ok(iRec->sizeCalled == 0, "Destroy->GetSize called %d times\n", iRec->sizeCalled);
1675 ok(iRec->clearCalled == sab[0].cElements, "Destroy->Clear called %d times\n", iRec->clearCalled);
1676 ok(iRec->ref == START_REF_COUNT, "Wrong iRec refcount %d\n", iRec->ref);
1677 }
1678 else
1679 {
1680 hres = SafeArrayDestroy(sa);
1681 ok(hres == S_OK, "got 0x%08x\n", hres);
1682 }
1683
1684 IRecordInfo_Release(&iRec->IRecordInfo_iface);
1685 }
1686
1687 static void test_SafeArrayClear(void)
1688 {
1689 SAFEARRAYBOUND sab;
1690 SAFEARRAY *sa;
1691 VARIANTARG v;
1692 HRESULT hres;
1693
1694 sab.lLbound = 0;
1695 sab.cElements = 10;
1696 sa = SafeArrayCreate(VT_UI1, 1, &sab);
1697 ok(sa != NULL, "Create() failed.\n");
1698 if (!sa)
1699 return;
1700
1701 /* Test clearing non-NULL variants containing arrays */
1702 V_VT(&v) = VT_ARRAY|VT_UI1;
1703 V_ARRAY(&v) = sa;
1704 hres = VariantClear(&v);
1705 ok(hres == S_OK && V_VT(&v) == VT_EMPTY, "VariantClear: hres 0x%x, Type %d\n", hres, V_VT(&v));
1706 ok(V_ARRAY(&v) == sa, "VariantClear: Overwrote value\n");
1707
1708 sa = SafeArrayCreate(VT_UI1, 1, &sab);
1709 ok(sa != NULL, "Create() failed.\n");
1710 if (!sa)
1711 return;
1712
1713 V_VT(&v) = VT_SAFEARRAY;
1714 V_ARRAY(&v) = sa;
1715 hres = VariantClear(&v);
1716 ok(hres == DISP_E_BADVARTYPE, "VariantClear: hres 0x%x\n", hres);
1717
1718 V_VT(&v) = VT_SAFEARRAY|VT_BYREF;
1719 V_ARRAYREF(&v) = &sa;
1720 hres = VariantClear(&v);
1721 ok(hres == DISP_E_BADVARTYPE, "VariantClear: hres 0x%x\n", hres);
1722
1723 hres = SafeArrayDestroy(sa);
1724 ok(hres == S_OK, "got 0x%08x\n", hres);
1725 }
1726
1727 static void test_SafeArrayCopy(void)
1728 {
1729 SAFEARRAYBOUND sab;
1730 SAFEARRAY *sa, *sa2;
1731 VARIANTARG vSrc, vDst;
1732 HRESULT hres;
1733 int i;
1734
1735 sab.lLbound = 0;
1736 sab.cElements = 10;
1737 sa = SafeArrayCreate(VT_UI1, 1, &sab);
1738 ok(sa != NULL, "Create() failed.\n");
1739 if (!sa)
1740 return;
1741
1742 /* Test copying non-NULL variants containing arrays */
1743 V_VT(&vSrc) = (VT_ARRAY|VT_BYREF|VT_UI1);
1744 V_ARRAYREF(&vSrc) = &sa;
1745 V_VT(&vDst) = VT_EMPTY;
1746
1747 hres = VariantCopy(&vDst, &vSrc);
1748 ok(hres == S_OK && V_VT(&vDst) == (VT_ARRAY|VT_BYREF|VT_UI1),
1749 "VariantCopy: hres 0x%x, Type %d\n", hres, V_VT(&vDst));
1750 ok(V_ARRAYREF(&vDst) == &sa, "VariantClear: Performed deep copy\n");
1751
1752 V_VT(&vSrc) = (VT_ARRAY|VT_UI1);
1753 V_ARRAY(&vSrc) = sa;
1754 V_VT(&vDst) = VT_EMPTY;
1755
1756 hres = VariantCopy(&vDst, &vSrc);
1757 ok(hres == S_OK && V_VT(&vDst) == (VT_ARRAY|VT_UI1),
1758 "VariantCopy: hres 0x%x, Type %d\n", hres, V_VT(&vDst));
1759 ok(V_ARRAY(&vDst) != sa, "VariantClear: Performed shallow copy\n");
1760
1761 hres = SafeArrayDestroy(V_ARRAY(&vSrc));
1762 ok(hres == S_OK, "got 0x%08x\n", hres);
1763 hres = SafeArrayDestroy(V_ARRAY(&vDst));
1764 ok(hres == S_OK, "got 0x%08x\n", hres);
1765
1766 hres = SafeArrayAllocDescriptor(1, &sa);
1767 ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08x\n", hres);
1768
1769 sa->cbElements = 16;
1770 hres = SafeArrayCopy(sa, &sa2);
1771 ok(hres == S_OK, "SafeArrayCopy failed with error 0x%08x\n", hres);
1772 ok(sa != sa2, "SafeArrayCopy performed shallow copy\n");
1773
1774 hres = SafeArrayDestroy(sa2);
1775 ok(hres == S_OK, "got 0x%08x\n", hres);
1776 hres = SafeArrayDestroy(sa);
1777 ok(hres == S_OK, "got 0x%08x\n", hres);
1778
1779 sa2 = (void*)0xdeadbeef;
1780 hres = SafeArrayCopy(NULL, &sa2);
1781 ok(hres == S_OK, "SafeArrayCopy failed with error 0x%08x\n", hres);
1782 ok(!sa2, "SafeArrayCopy didn't return NULL for output array\n");
1783
1784 hres = SafeArrayAllocDescriptor(1, &sa);
1785 ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08x\n", hres);
1786
1787 sa2 = (void*)0xdeadbeef;
1788 hres = SafeArrayCopy(sa, &sa2);
1789 ok(hres == E_INVALIDARG,
1790 "SafeArrayCopy with empty array should have failed with error E_INVALIDARG instead of 0x%08x\n",
1791 hres);
1792 ok(!sa2, "SafeArrayCopy didn't return NULL for output array\n");
1793
1794 hres = SafeArrayDestroy(sa2);
1795 ok(hres == S_OK, "got 0x%08x\n", hres);
1796 hres = SafeArrayDestroy(sa);
1797 ok(hres == S_OK, "got 0x%08x\n", hres);
1798
1799 /* test feature copy */
1800 hres = SafeArrayAllocDescriptor(1, &sa);
1801 ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08x\n", hres);
1802 ok(sa->fFeatures == 0, "got src features 0x%04x\n", sa->fFeatures);
1803 sa->cbElements = 16;
1804
1805 for (i = 0; i < sizeof(ignored_copy_features)/sizeof(USHORT); i++)
1806 {
1807 USHORT feature = ignored_copy_features[i];
1808
1809 sa->fFeatures |= feature;
1810 hres = SafeArrayCopy(sa, &sa2);
1811 ok(hres == S_OK, "got 0x%08x\n", hres);
1812 ok(sa2->fFeatures == 0, "got features 0x%04x\n", sa2->fFeatures);
1813 hres = SafeArrayDestroy(sa2);
1814 ok(hres == S_OK, "got 0x%08x\n", hres);
1815 sa->fFeatures &= ~feature;
1816 }
1817
1818 SafeArrayDestroy(sa);
1819
1820 /* copy from a vector */
1821 sa = SafeArrayCreateVector(VT_UI1, 0, 2);
1822 ok(sa->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) ||
1823 broken(sa->fFeatures == FADF_CREATEVECTOR /* W2k */),
1824 "got 0x%08x\n", sa->fFeatures);
1825 hres = SafeArrayCopy(sa, &sa2);
1826 ok(hres == S_OK, "got 0x%08x\n", hres);
1827 ok(sa2->fFeatures == FADF_HAVEVARTYPE ||
1828 broken(!sa2->fFeatures /* W2k */), "got 0x%04x\n",
1829 sa2->fFeatures);
1830
1831 SafeArrayDestroy(sa2);
1832 SafeArrayDestroy(sa);
1833 }
1834
1835 #define MKARRAY(low,num,typ) sab.lLbound = low; sab.cElements = num; \
1836 sa = SafeArrayCreate(typ, 1, &sab); ok(sa != NULL, "Create() failed.\n"); \
1837 if (!sa) return; \
1838 V_VT(&v) = VT_ARRAY|typ; V_ARRAY(&v) = sa; VariantInit(&v2)
1839
1840 #define MKARRAYCONT(low,num,typ) sab.lLbound = low; sab.cElements = num; \
1841 sa = SafeArrayCreate(typ, 1, &sab); if (!sa) continue; \
1842 V_VT(&v) = VT_ARRAY|typ; V_ARRAY(&v) = sa; VariantInit(&v2)
1843
1844 static void test_SafeArrayChangeTypeEx(void)
1845 {
1846 static const char *szHello = "Hello World";
1847 SAFEARRAYBOUND sab;
1848 SAFEARRAY *sa;
1849 VARIANTARG v,v2;
1850 VARTYPE vt;
1851 HRESULT hres;
1852
1853 /* VT_ARRAY|VT_UI1 -> VT_BSTR */
1854 MKARRAY(0,strlen(szHello)+1,VT_UI1);
1855 memcpy(sa->pvData, szHello, strlen(szHello)+1);
1856
1857 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR);
1858 ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %x\n", hres);
1859 if (hres == S_OK)
1860 {
1861 ok(V_VT(&v2) == VT_BSTR, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.\n",V_VT(&v2));
1862 ok(strcmp((char*)V_BSTR(&v2),szHello) == 0,"Expected string '%s', got '%s'\n", szHello,
1863 (char*)V_BSTR(&v2));
1864 VariantClear(&v2);
1865 }
1866
1867 /* VT_VECTOR|VT_UI1 -> VT_BSTR */
1868 hres = SafeArrayDestroy(sa);
1869 ok(hres == S_OK, "got 0x%08x\n", hres);
1870 if (pSafeArrayCreateVector)
1871 {
1872 sa = pSafeArrayCreateVector(VT_UI1, 0, strlen(szHello)+1);
1873 ok(sa != NULL, "CreateVector() failed.\n");
1874 if (!sa)
1875 return;
1876
1877 memcpy(sa->pvData, szHello, strlen(szHello)+1);
1878 V_VT(&v) = VT_VECTOR|VT_UI1;
1879 V_ARRAY(&v) = sa;
1880 VariantInit(&v2);
1881
1882 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR);
1883 ok(hres == DISP_E_BADVARTYPE, "CTE VT_VECTOR|VT_UI1 returned %x\n", hres);
1884
1885 /* (vector)VT_ARRAY|VT_UI1 -> VT_BSTR (In place) */
1886 V_VT(&v) = VT_ARRAY|VT_UI1;
1887 hres = VariantChangeTypeEx(&v, &v, 0, 0, VT_BSTR);
1888 ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %x\n", hres);
1889 if (hres == S_OK)
1890 {
1891 ok(V_VT(&v) == VT_BSTR, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.\n",V_VT(&v));
1892 ok(strcmp((char*)V_BSTR(&v),szHello) == 0,"Expected string '%s', got '%s'\n", szHello,
1893 (char*)V_BSTR(&v));
1894 VariantClear(&v);
1895 }
1896 }
1897
1898 /* To/from BSTR only works with arrays of VT_UI1 */
1899 for (vt = VT_EMPTY; vt <= VT_CLSID; vt++)
1900 {
1901 if (vt == VT_UI1)
1902 continue;
1903
1904 sab.lLbound = 0;
1905 sab.cElements = 1;
1906 sa = SafeArrayCreate(vt, 1, &sab);
1907 if (!sa) continue;
1908
1909 V_VT(&v) = VT_ARRAY|vt;
1910 V_ARRAY(&v) = sa;
1911 VariantInit(&v2);
1912
1913 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR);
1914 if (vt == VT_INT_PTR || vt == VT_UINT_PTR)
1915 {
1916 ok(hres == DISP_E_BADVARTYPE, "expected DISP_E_BADVARTYPE, got 0x%08x\n", hres);
1917 SafeArrayDestroy(sa);
1918 }
1919 else
1920 {
1921 ok(hres == DISP_E_TYPEMISMATCH, "got 0x%08x for vt=%d, instead of DISP_E_TYPEMISMATCH\n", hres, vt);
1922 hres = VariantClear(&v);
1923 ok(hres == S_OK, "expected S_OK, got 0x%08x\n", hres);
1924 }
1925 VariantClear(&v2);
1926 }
1927
1928 /* Can't change an array of one type into array of another type , even
1929 * if the other type is the same size
1930 */
1931 if (pSafeArrayCreateVector)
1932 {
1933 sa = pSafeArrayCreateVector(VT_UI1, 0, 1);
1934 ok(sa != NULL, "CreateVector() failed.\n");
1935 if (!sa)
1936 return;
1937
1938 V_VT(&v) = VT_ARRAY|VT_UI1;
1939 V_ARRAY(&v) = sa;
1940 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_ARRAY|VT_I1);
1941 ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_I1 returned %x\n", hres);
1942
1943 /* But can change to the same array type */
1944 hres = SafeArrayDestroy(sa);
1945 ok(hres == S_OK, "got 0x%08x\n", hres);
1946 sa = pSafeArrayCreateVector(VT_UI1, 0, 1);
1947 ok(sa != NULL, "CreateVector() failed.\n");
1948 if (!sa)
1949 return;
1950 V_VT(&v) = VT_ARRAY|VT_UI1;
1951 V_ARRAY(&v) = sa;
1952 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_ARRAY|VT_UI1);
1953 ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_UI1 returned %x\n", hres);
1954 hres = SafeArrayDestroy(sa);
1955 ok(hres == S_OK, "got 0x%08x\n", hres);
1956 VariantClear(&v2);
1957 }
1958
1959 /* NULL/EMPTY */
1960 MKARRAY(0,1,VT_UI1);
1961 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_NULL);
1962 ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1 returned %x\n", hres);
1963 VariantClear(&v);
1964 MKARRAY(0,1,VT_UI1);
1965 hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_EMPTY);
1966 ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1 returned %x\n", hres);
1967 VariantClear(&v);
1968 }
1969
1970 static void test_SafeArrayDestroyData (void)
1971 {
1972 SAFEARRAYBOUND sab;
1973 SAFEARRAY *sa;
1974 HRESULT hres;
1975 int value = 0xdeadbeef;
1976 LONG index[1];
1977 void *temp_pvData;
1978
1979 sab.lLbound = 0;
1980 sab.cElements = 10;
1981 sa = SafeArrayCreate(VT_INT, 1, &sab);
1982 ok(sa != NULL, "Create() failed.\n");
1983 if (!sa)
1984 return;
1985 index[0] = 1;
1986 SafeArrayPutElement (sa, index, &value);
1987
1988 /* SafeArrayDestroyData shouldn't free pvData if FADF_STATIC is set. */
1989 sa->fFeatures |= FADF_STATIC;
1990 temp_pvData = sa->pvData;
1991 hres = SafeArrayDestroyData(sa);
1992 ok(hres == S_OK, "SADData FADF_STATIC failed, error code %x.\n",hres);
1993 ok(sa->pvData == temp_pvData, "SADData FADF_STATIC: pvData=%p, expected %p (fFeatures = %d).\n",
1994 sa->pvData, temp_pvData, sa->fFeatures);
1995 SafeArrayGetElement (sa, index, &value);
1996 ok(value == 0, "Data not cleared after SADData\n");
1997
1998 /* Clear FADF_STATIC, now really destroy the data. */
1999 sa->fFeatures ^= FADF_STATIC;
2000 hres = SafeArrayDestroyData(sa);
2001 ok(hres == S_OK, "SADData !FADF_STATIC failed, error code %x.\n",hres);
2002 ok(sa->pvData == NULL, "SADData !FADF_STATIC: pvData=%p, expected NULL.\n", sa->pvData);
2003
2004 hres = SafeArrayDestroy(sa);
2005 ok(hres == S_OK, "SAD failed, error code %x.\n", hres);
2006 }
2007
2008 static void test_safearray_layout(void)
2009 {
2010 IRecordInfoImpl *irec;
2011 IRecordInfo *record;
2012 GUID guid, *guidptr;
2013 SAFEARRAYBOUND sab;
2014 SAFEARRAY *sa;
2015 DWORD *dwptr;
2016 HRESULT hr;
2017
2018 sab.lLbound = 0;
2019 sab.cElements = 10;
2020
2021 /* GUID field */
2022 sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab);
2023 ok(sa != NULL, "got %p\n", sa);
2024
2025 guidptr = (GUID*)sa - 1;
2026 ok(IsEqualIID(guidptr, &IID_IUnknown), "got %s\n", wine_dbgstr_guid(guidptr));
2027
2028 hr = SafeArraySetIID(sa, &IID_IDispatch);
2029 ok(hr == S_OK, "got 0x%08x\n", hr);
2030 ok(IsEqualIID(guidptr, &IID_IDispatch), "got %s\n", wine_dbgstr_guid(guidptr));
2031
2032 memcpy(guidptr, &IID_IUnknown, sizeof(GUID));
2033 hr = SafeArrayGetIID(sa, &guid);
2034 ok(hr == S_OK, "got 0x%08x\n", hr);
2035 ok(IsEqualIID(&guid, &IID_IUnknown), "got %s\n", wine_dbgstr_guid(&guid));
2036
2037 hr = SafeArrayDestroy(sa);
2038 ok(hr == S_OK, "got 0x%08x\n", hr);
2039
2040 /* VARTYPE field */
2041 sa = SafeArrayCreate(VT_UI1, 1, &sab);
2042 ok(sa != NULL, "got %p\n", sa);
2043
2044 dwptr = (DWORD*)sa - 1;
2045 ok(*dwptr == VT_UI1, "got %d\n", *dwptr);
2046
2047 hr = SafeArrayDestroy(sa);
2048 ok(hr == S_OK, "got 0x%08x\n", hr);
2049
2050 /* IRecordInfo pointer */
2051 irec = IRecordInfoImpl_Construct();
2052 irec->ref = 1;
2053
2054 sa = pSafeArrayCreateEx(VT_RECORD, 1, &sab, &irec->IRecordInfo_iface);
2055 ok(sa != NULL, "failed to create array\n");
2056
2057 record = *((IRecordInfo**)sa - 1);
2058 ok(record == &irec->IRecordInfo_iface, "got %p\n", record);
2059
2060 hr = SafeArrayDestroy(sa);
2061 ok(hr == S_OK, "got 0x%08x\n", hr);
2062 IRecordInfo_Release(&irec->IRecordInfo_iface);
2063 }
2064
2065 START_TEST(safearray)
2066 {
2067 hOleaut32 = GetModuleHandleA("oleaut32.dll");
2068
2069 has_i8 = GetProcAddress(hOleaut32, "VarI8FromI1") != NULL;
2070
2071 GETPTR(SafeArrayAllocDescriptorEx);
2072 GETPTR(SafeArrayCopyData);
2073 GETPTR(SafeArrayGetIID);
2074 GETPTR(SafeArraySetIID);
2075 GETPTR(SafeArrayGetVartype);
2076 GETPTR(SafeArrayCreateEx);
2077 GETPTR(SafeArrayCreateVector);
2078 GETPTR(SafeArrayGetRecordInfo);
2079
2080 check_for_VT_INT_PTR();
2081 test_safearray();
2082 test_SafeArrayAllocDestroyDescriptor();
2083 test_SafeArrayCreateLockDestroy();
2084 test_VectorCreateLockDestroy();
2085 test_LockUnlock();
2086 test_SafeArrayChangeTypeEx();
2087 test_SafeArrayCopy();
2088 test_SafeArrayClear();
2089 test_SafeArrayCreateEx();
2090 test_SafeArrayCopyData();
2091 test_SafeArrayDestroyData();
2092 test_SafeArrayGetPutElement();
2093 test_SafeArrayGetPutElement_BSTR();
2094 test_SafeArrayGetPutElement_IUnknown();
2095 test_SafeArrayRedim_IUnknown();
2096 test_SafeArrayGetPutElement_VARIANT();
2097 test_safearray_layout();
2098 }