2 * Unit tests for DPA functions
4 * Copyright 2003 Uwe Bonnes
5 * Copyright 2005 Felix Nawothnig
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wine/test.h"
34 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
36 typedef struct _STREAMDATA
41 } STREAMDATA
, *PSTREAMDATA
;
43 static HDPA (WINAPI
*pDPA_Clone
)(const HDPA
,const HDPA
);
44 static HDPA (WINAPI
*pDPA_Create
)(INT
);
45 static HDPA (WINAPI
*pDPA_CreateEx
)(INT
,HANDLE
);
46 static PVOID (WINAPI
*pDPA_DeleteAllPtrs
)(const HDPA
);
47 static PVOID (WINAPI
*pDPA_DeletePtr
)(const HDPA
,INT
);
48 static BOOL (WINAPI
*pDPA_Destroy
)(const HDPA
);
49 static VOID (WINAPI
*pDPA_DestroyCallback
)(HDPA
,PFNDPAENUMCALLBACK
,PVOID
);
50 static VOID (WINAPI
*pDPA_EnumCallback
)(HDPA
,PFNDPAENUMCALLBACK
,PVOID
);
51 static INT (WINAPI
*pDPA_GetPtr
)(const HDPA
,INT
);
52 static INT (WINAPI
*pDPA_GetPtrIndex
)(const HDPA
,PVOID
);
53 static BOOL (WINAPI
*pDPA_Grow
)(HDPA
,INT
);
54 static INT (WINAPI
*pDPA_InsertPtr
)(const HDPA
,INT
,PVOID
);
55 static HRESULT (WINAPI
*pDPA_LoadStream
)(HDPA
*,PFNDPASTREAM
,IStream
*,LPVOID
);
56 static BOOL (WINAPI
*pDPA_Merge
)(const HDPA
,const HDPA
,DWORD
,PFNDPACOMPARE
,PFNDPAMERGE
,LPARAM
);
57 static HRESULT (WINAPI
*pDPA_SaveStream
)(HDPA
,PFNDPASTREAM
,IStream
*,LPVOID
);
58 static INT (WINAPI
*pDPA_Search
)(HDPA
,PVOID
,INT
,PFNDPACOMPARE
,LPARAM
,UINT
);
59 static BOOL (WINAPI
*pDPA_SetPtr
)(const HDPA
,INT
,PVOID
);
60 static BOOL (WINAPI
*pDPA_Sort
)(const HDPA
,PFNDPACOMPARE
,LPARAM
);
62 #define COMCTL32_GET_PROC(func, ord) \
63 ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \
64 : (trace( #func " not exported\n"), 0))
66 static BOOL
InitFunctionPtrs(HMODULE hcomctl32
)
69 if(COMCTL32_GET_PROC(DPA_Clone
, 331) &&
70 COMCTL32_GET_PROC(DPA_Create
, 328) &&
71 COMCTL32_GET_PROC(DPA_CreateEx
, 340) &&
72 COMCTL32_GET_PROC(DPA_DeleteAllPtrs
, 337) &&
73 COMCTL32_GET_PROC(DPA_DeletePtr
, 336) &&
74 COMCTL32_GET_PROC(DPA_Destroy
, 329) &&
75 COMCTL32_GET_PROC(DPA_GetPtr
, 332) &&
76 COMCTL32_GET_PROC(DPA_GetPtrIndex
, 333) &&
77 COMCTL32_GET_PROC(DPA_Grow
, 330) &&
78 COMCTL32_GET_PROC(DPA_InsertPtr
, 334) &&
79 COMCTL32_GET_PROC(DPA_Search
, 339) &&
80 COMCTL32_GET_PROC(DPA_SetPtr
, 335) &&
81 COMCTL32_GET_PROC(DPA_Sort
, 338))
84 COMCTL32_GET_PROC(DPA_DestroyCallback
, 386) &&
85 COMCTL32_GET_PROC(DPA_EnumCallback
, 385) &&
86 COMCTL32_GET_PROC(DPA_LoadStream
, 9) &&
87 COMCTL32_GET_PROC(DPA_Merge
, 11) &&
88 COMCTL32_GET_PROC(DPA_SaveStream
, 10);
97 static INT CALLBACK
CB_CmpLT(PVOID p1
, PVOID p2
, LPARAM lp
)
99 ok(lp
== 0xdeadbeef, "lp=%ld\n", lp
);
100 return p1
< p2
? -1 : p1
> p2
? 1 : 0;
103 static INT CALLBACK
CB_CmpGT(PVOID p1
, PVOID p2
, LPARAM lp
)
105 ok(lp
== 0xdeadbeef, "lp=%ld\n", lp
);
106 return p1
> p2
? -1 : p1
< p2
? 1 : 0;
109 /* merge callback messages counter
113 static INT nMessages
[4];
115 static PVOID CALLBACK
CB_MergeInsertSrc(UINT op
, PVOID p1
, PVOID p2
, LPARAM lp
)
118 ok(lp
== 0xdeadbeef, "lp=%ld\n", lp
);
122 static PVOID CALLBACK
CB_MergeDeleteOddSrc(UINT op
, PVOID p1
, PVOID p2
, LPARAM lp
)
125 ok(lp
== 0xdeadbeef, "lp=%ld\n", lp
);
126 return ((PCHAR
)p2
)+1;
131 static INT CALLBACK
CB_EnumFirstThree(PVOID pItem
, PVOID lp
)
135 i
= pDPA_GetPtrIndex(lp
, pItem
);
136 ok(i
== nEnum
, "i=%d nEnum=%d\n", i
, nEnum
);
138 pDPA_SetPtr(lp
, i
, (PVOID
)7);
139 return pItem
!= (PVOID
)3;
142 static HRESULT CALLBACK
CB_Save(DPASTREAMINFO
*pInfo
, IStream
*pStm
, LPVOID lp
)
146 ok(lp
== (LPVOID
)0xdeadbeef, "lp=%p\n", lp
);
147 hRes
= IStream_Write(pStm
, &pInfo
->iPos
, sizeof(INT
), NULL
);
149 hRes
= IStream_Write(pStm
, &pInfo
->pvItem
, sizeof(PVOID
), NULL
);
154 static HRESULT CALLBACK
CB_Load(DPASTREAMINFO
*pInfo
, IStream
*pStm
, LPVOID lp
)
159 iOldPos
= pInfo
->iPos
;
160 ok(lp
== (LPVOID
)0xdeadbeef, "lp=%p\n", lp
);
161 hRes
= IStream_Read(pStm
, &pInfo
->iPos
, sizeof(INT
), NULL
);
163 ok(pInfo
->iPos
== iOldPos
, "iPos=%d iOldPos=%d\n", pInfo
->iPos
, iOldPos
);
164 hRes
= IStream_Read(pStm
, &pInfo
->pvItem
, sizeof(PVOID
), NULL
);
169 static BOOL
CheckDPA(HDPA dpa
, DWORD dwIn
, PDWORD pdwOut
)
176 ULONG_PTR ulItem
= (ULONG_PTR
)pDPA_GetPtr(dpa
, i
++);
178 dwOut
= dwOut
<< 4 | (ulItem
& 0xf);
185 pDPA_DeleteAllPtrs(dpa
);
189 pDPA_InsertPtr(dpa
, 0, (PVOID
)(ULONG_PTR
)(dwIn
& 0xf));
200 static void test_dpa(void)
204 HDPA dpa
, dpa2
, dpa3
;
211 hHeap
= HeapCreate(0, 1, 2);
212 ok(hHeap
!= NULL
, "error=%d\n", GetLastError());
213 dpa3
= pDPA_CreateEx(0, hHeap
);
214 ok(dpa3
!= NULL
, "\n");
215 ret
= pDPA_Grow(dpa3
, si
.dwPageSize
+ 1);
216 todo_wine
ok(!ret
&& GetLastError() == ERROR_NOT_ENOUGH_MEMORY
,
217 "ret=%d error=%d\n", ret
, GetLastError());
219 dpa
= pDPA_Create(0);
220 ok(dpa
!= NULL
, "\n");
222 /* Set item with out of bound index */
223 ok(pDPA_SetPtr(dpa
, 1, (PVOID
)6), "\n");
224 /* Fill the created gap */
225 ok(pDPA_SetPtr(dpa
, 0, (PVOID
)5), "\n");
226 rc
=CheckDPA(dpa
, 0x56, &dw
);
227 ok(rc
, "dw=0x%x\n", dw
);
230 ret
= pDPA_InsertPtr(dpa
, 1, (PVOID
)1);
231 ok(ret
== 1, "ret=%d\n", ret
);
232 /* Append item using correct index */
233 ret
= pDPA_InsertPtr(dpa
, 3, (PVOID
)3);
234 ok(ret
== 3, "ret=%d\n", ret
);
235 /* Append item using out of bound index */
236 ret
= pDPA_InsertPtr(dpa
, 5, (PVOID
)2);
237 ok(ret
== 4, "ret=%d\n", ret
);
238 /* Append item using DPA_APPEND */
239 ret
= pDPA_InsertPtr(dpa
, DPA_APPEND
, (PVOID
)4);
240 ok(ret
== 5, "ret=%d\n", ret
);
242 rc
=CheckDPA(dpa
, 0x516324, &dw
);
243 ok(rc
, "dw=0x%x\n", dw
);
245 for(i
= 1; i
<= 6; i
++)
248 k
= pDPA_GetPtrIndex(dpa
, (PVOID
)(INT_PTR
)i
);
249 /* Linear searches should work on unsorted DPAs */
250 j
= pDPA_Search(dpa
, (PVOID
)(INT_PTR
)i
, 0, CB_CmpLT
, 0xdeadbeef, 0);
251 ok(j
== k
, "j=%d k=%d\n", j
, k
);
255 ok(pDPA_Sort(dpa
, CB_CmpGT
, 0xdeadbeef), "\n");
256 rc
=CheckDPA(dpa
, 0x654321, &dw
);
257 ok(rc
, "dw=0x%x\n", dw
);
259 /* Clone into a new DPA */
260 dpa2
= pDPA_Clone(dpa
, NULL
);
261 ok(dpa2
!= NULL
, "\n");
262 /* The old data should have been preserved */
263 rc
=CheckDPA(dpa2
, 0x654321, &dw2
);
264 ok(rc
, "dw=0x%x\n", dw2
);
265 ok(pDPA_Sort(dpa
, CB_CmpLT
, 0xdeadbeef), "\n");
267 /* Test if the DPA itself was really copied */
268 rc
=CheckDPA(dpa
, 0x123456, &dw
);
269 ok(rc
, "dw=0x%x\n", dw
);
270 rc
=CheckDPA(dpa2
, 0x654321, &dw2
);
271 ok(rc
, "dw2=0x%x\n", dw2
);
273 /* Clone into an old DPA */
274 p
= NULL
; SetLastError(ERROR_SUCCESS
);
275 p
= pDPA_Clone(dpa
, dpa3
);
276 ok(p
== dpa3
, "p=%p\n", p
);
277 rc
=CheckDPA(dpa3
, 0x123456, &dw3
);
278 ok(rc
, "dw3=0x%x\n", dw3
);
280 for(i
= 1; i
<= 6; i
++)
284 /* The array is in order so ptr == index+1 */
285 j
= pDPA_GetPtrIndex(dpa
, (PVOID
)(INT_PTR
)i
);
286 ok(j
+1 == i
, "j=%d i=%d\n", j
, i
);
287 j
= pDPA_Search(dpa
, (PVOID
)(INT_PTR
)i
, 0, CB_CmpLT
, 0xdeadbeef, DPAS_SORTED
);
288 ok(j
+1 == i
, "j=%d i=%d\n", j
, i
);
290 /* Linear searches respect iStart ... */
291 j
= pDPA_Search(dpa
, (PVOID
)(INT_PTR
)i
, i
+1, CB_CmpLT
, 0xdeadbeef, 0);
292 ok(j
== DPA_ERR
, "j=%d\n", j
);
293 /* ... but for a binary search it's ignored */
294 j
= pDPA_Search(dpa
, (PVOID
)(INT_PTR
)i
, i
+1, CB_CmpLT
, 0xdeadbeef, DPAS_SORTED
);
295 ok(j
+1 == i
, "j=%d i=%d\n", j
, i
);
298 /* Try to get the index of a nonexistent item */
299 i
= pDPA_GetPtrIndex(dpa
, (PVOID
)7);
300 ok(i
== DPA_ERR
, "i=%d\n", i
);
302 /* Try to delete out of bound indexes */
303 p
= pDPA_DeletePtr(dpa
, -1);
304 ok(p
== NULL
, "p=%p\n", p
);
305 p
= pDPA_DeletePtr(dpa
, 6);
306 ok(p
== NULL
, "p=%p\n", p
);
308 /* Delete the third item */
309 p
= pDPA_DeletePtr(dpa
, 2);
310 ok(p
== (PVOID
)3, "p=%p\n", p
);
311 rc
=CheckDPA(dpa
, 0x12456, &dw
);
312 ok(rc
, "dw=0x%x\n", dw
);
314 /* Check where to re-insert the deleted item */
315 i
= pDPA_Search(dpa
, (PVOID
)3, 0,
316 CB_CmpLT
, 0xdeadbeef, DPAS_SORTED
|DPAS_INSERTAFTER
);
317 ok(i
== 2, "i=%d\n", i
);
318 /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */
319 i
= pDPA_Search(dpa
, (PVOID
)3, 0,
320 CB_CmpLT
, 0xdeadbeef, DPAS_SORTED
|DPAS_INSERTBEFORE
);
321 ok(i
== 2, "i=%d\n", i
);
322 /* without DPAS_INSERTBEFORE/AFTER */
323 i
= pDPA_Search(dpa
, (PVOID
)3, 0,
324 CB_CmpLT
, 0xdeadbeef, DPAS_SORTED
);
325 ok(i
== -1, "i=%d\n", i
);
327 /* Re-insert the item */
328 ret
= pDPA_InsertPtr(dpa
, 2, (PVOID
)3);
329 ok(ret
== 2, "ret=%d i=%d\n", ret
, 2);
330 rc
=CheckDPA(dpa
, 0x123456, &dw
);
331 ok(rc
, "dw=0x%x\n", dw
);
333 /* When doing a binary search while claiming reverse order all indexes
335 for(i
= 0; i
< 6; i
++)
337 INT j
= pDPA_Search(dpa
, (PVOID
)(INT_PTR
)i
, 0, CB_CmpGT
, 0xdeadbeef,
338 DPAS_SORTED
|DPAS_INSERTBEFORE
);
339 ok(j
!= i
, "i=%d\n", i
);
342 /* Setting item with huge index should work */
343 ok(pDPA_SetPtr(dpa2
, 0x12345, (PVOID
)0xdeadbeef), "\n");
344 ret
= pDPA_GetPtrIndex(dpa2
, (PVOID
)0xdeadbeef);
345 ok(ret
== 0x12345, "ret=%d\n", ret
);
347 pDPA_DeleteAllPtrs(dpa2
);
348 rc
=CheckDPA(dpa2
, 0, &dw2
);
349 ok(rc
, "dw2=0x%x\n", dw2
);
356 static void test_DPA_Merge(void)
358 HDPA dpa
, dpa2
, dpa3
;
365 win_skip("DPA_Merge() not available\n");
369 dpa
= pDPA_Create(0);
370 dpa2
= pDPA_Create(0);
371 dpa3
= pDPA_Create(0);
373 ret
= pDPA_InsertPtr(dpa
, 0, (PVOID
)1);
374 ok(ret
== 0, "ret=%d\n", ret
);
375 ret
= pDPA_InsertPtr(dpa
, 1, (PVOID
)3);
376 ok(ret
== 1, "ret=%d\n", ret
);
377 ret
= pDPA_InsertPtr(dpa
, 2, (PVOID
)5);
378 ok(ret
== 2, "ret=%d\n", ret
);
380 rc
= CheckDPA(dpa
, 0x135, &dw
);
381 ok(rc
, "dw=0x%x\n", dw
);
383 for (i
= 0; i
< 6; i
++)
385 ret
= pDPA_InsertPtr(dpa2
, i
, (PVOID
)(INT_PTR
)(6-i
));
386 ok(ret
== i
, "ret=%d\n", ret
);
387 ret
= pDPA_InsertPtr(dpa3
, i
, (PVOID
)(INT_PTR
)(i
+1));
388 ok(ret
== i
, "ret=%d\n", ret
);
391 rc
= CheckDPA(dpa2
, 0x654321, &dw
);
392 ok(rc
, "dw=0x%x\n", dw
);
393 rc
= CheckDPA(dpa3
, 0x123456, &dw
);
394 ok(rc
, "dw=0x%x\n", dw
);
396 /* Delete all odd entries from dpa2 */
397 memset(nMessages
, 0, sizeof(nMessages
));
398 pDPA_Merge(dpa2
, dpa
, DPAM_INTERSECT
,
399 CB_CmpLT
, CB_MergeDeleteOddSrc
, 0xdeadbeef);
400 rc
= CheckDPA(dpa2
, 0x246, &dw
);
401 ok(rc
, "dw=0x%x\n", dw
);
403 expect(3, nMessages
[DPAMM_MERGE
]);
404 expect(3, nMessages
[DPAMM_DELETE
]);
405 expect(0, nMessages
[DPAMM_INSERT
]);
407 for (i
= 0; i
< 6; i
++)
409 ret
= pDPA_InsertPtr(dpa2
, i
, (PVOID
)(INT_PTR
)(6-i
));
410 ok(ret
== i
, "ret=%d\n", ret
);
413 /* DPAM_INTERSECT - returning source while merging */
414 memset(nMessages
, 0, sizeof(nMessages
));
415 pDPA_Merge(dpa2
, dpa
, DPAM_INTERSECT
,
416 CB_CmpLT
, CB_MergeInsertSrc
, 0xdeadbeef);
417 rc
= CheckDPA(dpa2
, 0x135, &dw
);
418 ok(rc
, "dw=0x%x\n", dw
);
420 expect(3, nMessages
[DPAMM_MERGE
]);
421 expect(6, nMessages
[DPAMM_DELETE
]);
422 expect(0, nMessages
[DPAMM_INSERT
]);
425 pDPA_DeleteAllPtrs(dpa
);
426 pDPA_InsertPtr(dpa
, 0, (PVOID
)1);
427 pDPA_InsertPtr(dpa
, 1, (PVOID
)3);
428 pDPA_InsertPtr(dpa
, 2, (PVOID
)5);
429 pDPA_DeleteAllPtrs(dpa2
);
430 pDPA_InsertPtr(dpa2
, 0, (PVOID
)2);
431 pDPA_InsertPtr(dpa2
, 1, (PVOID
)4);
432 pDPA_InsertPtr(dpa2
, 2, (PVOID
)6);
434 memset(nMessages
, 0, sizeof(nMessages
));
435 pDPA_Merge(dpa2
, dpa
, DPAM_UNION
,
436 CB_CmpLT
, CB_MergeInsertSrc
, 0xdeadbeef);
437 rc
= CheckDPA(dpa2
, 0x123456, &dw
);
439 broken(!rc
&& dw
== 0x23456), /* 4.7x */
442 expect(0, nMessages
[DPAMM_MERGE
]);
443 expect(0, nMessages
[DPAMM_DELETE
]);
444 ok(nMessages
[DPAMM_INSERT
] == 3 ||
445 broken(nMessages
[DPAMM_INSERT
] == 2), /* 4.7x */
446 "Expected 3, got %d\n", nMessages
[DPAMM_INSERT
]);
448 /* Merge dpa3 into dpa2 and dpa */
449 memset(nMessages
, 0, sizeof(nMessages
));
450 pDPA_Merge(dpa
, dpa3
, DPAM_UNION
|DPAM_SORTED
,
451 CB_CmpLT
, CB_MergeInsertSrc
, 0xdeadbeef);
452 expect(3, nMessages
[DPAMM_MERGE
]);
453 expect(0, nMessages
[DPAMM_DELETE
]);
454 expect(3, nMessages
[DPAMM_INSERT
]);
457 pDPA_DeleteAllPtrs(dpa2
);
458 pDPA_InsertPtr(dpa2
, 0, (PVOID
)2);
459 pDPA_InsertPtr(dpa2
, 1, (PVOID
)4);
460 pDPA_InsertPtr(dpa2
, 2, (PVOID
)6);
462 memset(nMessages
, 0, sizeof(nMessages
));
463 pDPA_Merge(dpa2
, dpa3
, DPAM_UNION
|DPAM_SORTED
,
464 CB_CmpLT
, CB_MergeInsertSrc
, 0xdeadbeef);
465 expect(3, nMessages
[DPAMM_MERGE
]);
466 expect(0, nMessages
[DPAMM_DELETE
]);
467 ok(nMessages
[DPAMM_INSERT
] == 3 ||
468 broken(nMessages
[DPAMM_INSERT
] == 2), /* 4.7x */
469 "Expected 3, got %d\n", nMessages
[DPAMM_INSERT
]);
471 rc
= CheckDPA(dpa
, 0x123456, &dw
);
472 ok(rc
, "dw=0x%x\n", dw
);
473 rc
= CheckDPA(dpa2
, 0x123456, &dw
);
475 broken(!rc
), /* win98 */
477 rc
= CheckDPA(dpa3
, 0x123456, &dw
);
478 ok(rc
, "dw=0x%x\n", dw
);
485 static void test_DPA_EnumCallback(void)
492 if(!pDPA_EnumCallback
)
494 win_skip("DPA_EnumCallback() not available\n");
498 dpa
= pDPA_Create(0);
500 for (i
= 0; i
< 6; i
++)
502 ret
= pDPA_InsertPtr(dpa
, i
, (PVOID
)(INT_PTR
)(i
+1));
503 ok(ret
== i
, "ret=%d\n", ret
);
506 rc
= CheckDPA(dpa
, 0x123456, &dw
);
507 ok(rc
, "dw=0x%x\n", dw
);
510 /* test callback sets first 3 items to 7 */
511 pDPA_EnumCallback(dpa
, CB_EnumFirstThree
, dpa
);
512 rc
= CheckDPA(dpa
, 0x777456, &dw
);
513 ok(rc
, "dw=0x%x\n", dw
);
514 ok(nEnum
== 3, "nEnum=%d\n", nEnum
);
519 static void test_DPA_DestroyCallback(void)
524 if(!pDPA_DestroyCallback
)
526 win_skip("DPA_DestroyCallback() not available\n");
530 dpa
= pDPA_Create(0);
532 for (i
= 0; i
< 3; i
++)
534 ret
= pDPA_InsertPtr(dpa
, i
, (PVOID
)(INT_PTR
)(i
+1));
535 ok(ret
== i
, "ret=%d\n", ret
);
539 pDPA_DestroyCallback(dpa
, CB_EnumFirstThree
, dpa
);
540 ok(nEnum
== 3, "nEnum=%d\n", nEnum
);
543 static void test_DPA_LoadStream(void)
545 static const WCHAR szStg
[] = { 'S','t','g',0 };
546 IStorage
* pStg
= NULL
;
547 IStream
* pStm
= NULL
;
558 win_skip("DPA_LoadStream() not available. Skipping stream tests.\n");
562 hRes
= CoInitialize(NULL
);
565 ok(0, "hResult: %d\n", hRes
);
569 dwMode
= STGM_DIRECT
|STGM_CREATE
|STGM_READWRITE
|STGM_SHARE_EXCLUSIVE
;
570 hRes
= StgCreateDocfile(NULL
, dwMode
|STGM_DELETEONRELEASE
, 0, &pStg
);
573 hRes
= IStorage_CreateStream(pStg
, szStg
, dwMode
, 0, 0, &pStm
);
576 /* write less than header size */
578 hRes
= IStream_Seek(pStm
, li
, STREAM_SEEK_SET
, NULL
);
581 memset(&header
, 0, sizeof(header
));
583 uli
.QuadPart
= sizeof(header
)-1;
584 hRes
= IStream_SetSize(pStm
, uli
);
586 hRes
= IStream_Write(pStm
, &header
, sizeof(header
)-1, &written
);
588 written
-= sizeof(header
)-1;
592 hRes
= IStream_Seek(pStm
, li
, STREAM_SEEK_SET
, NULL
);
595 hRes
= pDPA_LoadStream(&dpa
, CB_Load
, pStm
, NULL
);
596 expect(E_FAIL
, hRes
);
598 /* check stream position after header read failed */
601 hRes
= IStream_Seek(pStm
, li
, STREAM_SEEK_CUR
, &uli
);
603 ok(uli
.QuadPart
== 0, "Expected to position reset\n");
605 /* write valid header for empty DPA */
606 header
.dwSize
= sizeof(header
);
612 hRes
= IStream_Seek(pStm
, li
, STREAM_SEEK_SET
, NULL
);
615 uli
.QuadPart
= sizeof(header
);
616 hRes
= IStream_SetSize(pStm
, uli
);
619 hRes
= IStream_Write(pStm
, &header
, sizeof(header
), &written
);
621 written
-= sizeof(header
);
625 hRes
= IStream_Seek(pStm
, li
, STREAM_SEEK_SET
, NULL
);
629 hRes
= pDPA_LoadStream(&dpa
, CB_Load
, pStm
, NULL
);
633 /* try with altered dwData2 field */
634 header
.dwSize
= sizeof(header
);
639 hRes
= IStream_Seek(pStm
, li
, STREAM_SEEK_SET
, NULL
);
641 hRes
= IStream_Write(pStm
, &header
, sizeof(header
), &written
);
643 written
-= sizeof(header
);
647 hRes
= IStream_Seek(pStm
, li
, STREAM_SEEK_SET
, NULL
);
650 hRes
= pDPA_LoadStream(&dpa
, CB_Load
, pStm
, (void*)0xdeadbeef);
651 expect(E_FAIL
, hRes
);
653 ret
= IStream_Release(pStm
);
654 ok(!ret
, "ret=%d\n", ret
);
656 ret
= IStorage_Release(pStg
);
657 ok(!ret
, "ret=%d\n", ret
);
662 static void test_DPA_SaveStream(void)
665 static const WCHAR szStg
[] = { 'S','t','g',0 };
666 IStorage
* pStg
= NULL
;
667 IStream
* pStm
= NULL
;
673 LARGE_INTEGER liZero
;
677 win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
681 hRes
= CoInitialize(NULL
);
684 ok(0, "hResult: %d\n", hRes
);
688 dwMode
= STGM_DIRECT
|STGM_CREATE
|STGM_READWRITE
|STGM_SHARE_EXCLUSIVE
;
689 hRes
= StgCreateDocfile(NULL
, dwMode
|STGM_DELETEONRELEASE
, 0, &pStg
);
692 hRes
= IStorage_CreateStream(pStg
, szStg
, dwMode
, 0, 0, &pStm
);
695 dpa
= pDPA_Create(0);
697 /* simple parameter check */
698 hRes
= pDPA_SaveStream(dpa
, NULL
, pStm
, NULL
);
699 ok(hRes
== E_INVALIDARG
||
700 broken(hRes
== S_OK
) /* XP and below */, "Wrong result, %d\n", hRes
);
703 hRes
= pDPA_SaveStream(NULL
, CB_Save
, pStm
, NULL
);
704 expect(E_INVALIDARG
, hRes
);
706 hRes
= pDPA_SaveStream(dpa
, CB_Save
, NULL
, NULL
);
707 expect(E_INVALIDARG
, hRes
);
711 for (i
= 0; i
< 6; i
++)
713 ret
= pDPA_InsertPtr(dpa
, i
, (PVOID
)(INT_PTR
)(i
+1));
714 ok(ret
== i
, "ret=%d\n", ret
);
718 hRes
= IStream_Seek(pStm
, liZero
, STREAM_SEEK_SET
, NULL
);
721 hRes
= pDPA_SaveStream(dpa
, CB_Save
, pStm
, (void*)0xdeadbeef);
726 hRes
= IStream_Seek(pStm
, liZero
, STREAM_SEEK_SET
, NULL
);
728 hRes
= pDPA_LoadStream(&dpa
, CB_Load
, pStm
, (void*)0xdeadbeef);
730 rc
= CheckDPA(dpa
, 0x123456, &dw
);
731 ok(rc
, "dw=0x%x\n", dw
);
734 ret
= IStream_Release(pStm
);
735 ok(!ret
, "ret=%d\n", ret
);
737 ret
= IStorage_Release(pStg
);
738 ok(!ret
, "ret=%d\n", ret
);
747 hcomctl32
= GetModuleHandleA("comctl32.dll");
749 if(!InitFunctionPtrs(hcomctl32
))
751 win_skip("Needed functions are not available\n");
757 test_DPA_EnumCallback();
758 test_DPA_DestroyCallback();
759 test_DPA_LoadStream();
760 test_DPA_SaveStream();