dbghelp: Remove DMT_ entries for .DBG and .PDB files.
[wine.git] / dlls / comctl32 / tests / dpa.c
blob3eaa1d5810ff1cf34453d2af6a34d3c0f57816f4
1 /*
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
22 #define COBJMACROS
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "commctrl.h"
30 #include "objidl.h"
32 #include "wine/test.h"
33 #include "v6util.h"
35 #define expect(expected,got) expect_(__LINE__, expected, got)
36 static inline void expect_(unsigned line, DWORD expected, DWORD got)
38 ok_(__FILE__, line)(expected == got, "Expected %ld, got %ld\n", expected, got);
41 typedef struct _STREAMDATA
43 DWORD dwSize;
44 DWORD dwData2;
45 DWORD dwItems;
46 } STREAMDATA, *PSTREAMDATA;
48 static HDPA (WINAPI *pDPA_Clone)(const HDPA,HDPA);
49 static HDPA (WINAPI *pDPA_Create)(INT);
50 static HDPA (WINAPI *pDPA_CreateEx)(INT,HANDLE);
51 static PVOID (WINAPI *pDPA_DeleteAllPtrs)(HDPA);
52 static PVOID (WINAPI *pDPA_DeletePtr)(HDPA,INT);
53 static BOOL (WINAPI *pDPA_Destroy)(HDPA);
54 static VOID (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
55 static VOID (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
56 static PVOID (WINAPI *pDPA_GetPtr)(HDPA,INT_PTR);
57 static INT (WINAPI *pDPA_GetPtrIndex)(HDPA,PVOID);
58 static BOOL (WINAPI *pDPA_Grow)(HDPA,INT);
59 static INT (WINAPI *pDPA_InsertPtr)(HDPA,INT,PVOID);
60 static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTREAM,IStream*,LPVOID);
61 static BOOL (WINAPI *pDPA_Merge)(HDPA,HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
62 static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTREAM,IStream*,LPVOID);
63 static INT (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
64 static BOOL (WINAPI *pDPA_SetPtr)(HDPA,INT,PVOID);
65 static BOOL (WINAPI *pDPA_Sort)(HDPA,PFNDPACOMPARE,LPARAM);
67 static void init_functions(void)
69 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
71 #define X2(f, ord) p##f = (void*)GetProcAddress(hComCtl32, (const char *)ord);
72 /* 4.00+ */
73 X2(DPA_Clone, 331);
74 X2(DPA_Create, 328);
75 X2(DPA_CreateEx, 340);
76 X2(DPA_DeleteAllPtrs, 337);
77 X2(DPA_DeletePtr, 336);
78 X2(DPA_Destroy, 329);
79 X2(DPA_GetPtr, 332);
80 X2(DPA_GetPtrIndex, 333);
81 X2(DPA_Grow, 330);
82 X2(DPA_InsertPtr, 334);
83 X2(DPA_Search, 339);
84 X2(DPA_SetPtr, 335);
85 X2(DPA_Sort, 338);
87 /* 4.71+ */
88 X2(DPA_DestroyCallback, 386);
89 X2(DPA_EnumCallback, 385);
90 X2(DPA_LoadStream, 9);
91 X2(DPA_Merge, 11);
92 X2(DPA_SaveStream, 10);
93 #undef X2
96 /* Callbacks */
97 static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp)
99 ok(lp == 0x1abe11ed, "lp=%Id\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 == 0x1abe11ed, "lp=%Id\n", lp);
106 return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
109 /* merge callback messages counter
110 DPAMM_MERGE 1
111 DPAMM_DELETE 2
112 DPAMM_INSERT 3 */
113 static INT nMessages[4];
115 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
117 nMessages[op]++;
118 ok(lp == 0x1abe11ed, "lp=%Id\n", lp);
119 return p1;
122 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
124 nMessages[op]++;
125 ok(lp == 0x1abe11ed, "lp=%Id\n", lp);
126 return ((PCHAR)p2)+1;
129 static INT nEnum;
131 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
133 INT i;
135 i = pDPA_GetPtrIndex(lp, pItem);
136 ok(i == nEnum, "i=%d nEnum=%d\n", i, nEnum);
137 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)
144 HRESULT hRes;
146 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
147 hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
148 expect(S_OK, hRes);
149 hRes = IStream_Write(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
150 expect(S_OK, hRes);
151 return S_OK;
154 static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
156 HRESULT hRes;
157 INT iOldPos;
159 iOldPos = pInfo->iPos;
160 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
161 hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
162 expect(S_OK, hRes);
163 ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
164 hRes = IStream_Read(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
165 expect(S_OK, hRes);
166 return S_OK;
169 static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
171 DWORD dwOut = 0;
172 INT i;
174 for(i = 0; i < 8;)
176 ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++);
177 if(!ulItem) break;
178 dwOut = dwOut << 4 | (ulItem & 0xf);
181 *pdwOut = dwOut;
183 if(dwOut != dwIn)
185 pDPA_DeleteAllPtrs(dpa);
189 pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf));
190 dwIn >>= 4;
192 while(dwIn);
194 return FALSE;
197 return TRUE;
200 static void test_dpa(void)
202 SYSTEM_INFO si;
203 HANDLE hHeap;
204 HDPA dpa, dpa2, dpa3;
205 INT ret, i;
206 PVOID p;
207 DWORD dw, dw2, dw3;
208 BOOL rc;
210 GetSystemInfo(&si);
211 hHeap = HeapCreate(0, 1, 2);
212 ok(hHeap != NULL, "error=%ld\n", GetLastError());
213 dpa3 = pDPA_CreateEx(0, hHeap);
214 ok(dpa3 != NULL, "\n");
215 ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
216 ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
217 "ret=%d error=%ld\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%lx\n", dw);
229 /* Prepend item */
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%lx\n", dw);
245 for(i = 1; i <= 6; i++)
247 INT j, k;
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, 0x1abe11ed, 0);
251 ok(j == k, "j=%d k=%d\n", j, k);
254 /* Sort DPA */
255 ok(pDPA_Sort(dpa, CB_CmpGT, 0x1abe11ed), "\n");
256 rc=CheckDPA(dpa, 0x654321, &dw);
257 ok(rc, "dw=0x%lx\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%lx\n", dw2);
265 ok(pDPA_Sort(dpa, CB_CmpLT, 0x1abe11ed), "\n");
267 /* Test if the DPA itself was really copied */
268 rc=CheckDPA(dpa, 0x123456, &dw);
269 ok(rc, "dw=0x%lx\n", dw );
270 rc=CheckDPA(dpa2, 0x654321, &dw2);
271 ok(rc, "dw2=0x%lx\n", dw2);
273 /* Clone into an old DPA */
274 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%lx\n", dw3);
280 for(i = 1; i <= 6; i++)
282 INT j;
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, 0x1abe11ed, 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, 0x1abe11ed, 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, 0x1abe11ed, 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%lx\n", dw);
314 /* Check where to re-insert the deleted item */
315 i = pDPA_Search(dpa, (PVOID)3, 0,
316 CB_CmpLT, 0x1abe11ed, 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, 0x1abe11ed, 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, 0x1abe11ed, 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%lx\n", dw);
333 /* When doing a binary search while claiming reverse order all indexes
334 * should be bogus */
335 for(i = 0; i < 6; i++)
337 INT j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpGT, 0x1abe11ed,
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%lx\n", dw2);
351 pDPA_Destroy(dpa);
352 pDPA_Destroy(dpa2);
353 pDPA_Destroy(dpa3);
356 static void test_DPA_Merge(void)
358 HDPA dpa, dpa2, dpa3;
359 INT ret, i;
360 DWORD dw;
361 BOOL rc;
363 dpa = pDPA_Create(0);
364 dpa2 = pDPA_Create(0);
365 dpa3 = pDPA_Create(0);
367 ret = pDPA_InsertPtr(dpa, 0, (PVOID)1);
368 ok(ret == 0, "ret=%d\n", ret);
369 ret = pDPA_InsertPtr(dpa, 1, (PVOID)3);
370 ok(ret == 1, "ret=%d\n", ret);
371 ret = pDPA_InsertPtr(dpa, 2, (PVOID)5);
372 ok(ret == 2, "ret=%d\n", ret);
374 rc = CheckDPA(dpa, 0x135, &dw);
375 ok(rc, "dw=0x%lx\n", dw);
377 for (i = 0; i < 6; i++)
379 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
380 ok(ret == i, "ret=%d\n", ret);
381 ret = pDPA_InsertPtr(dpa3, i, (PVOID)(INT_PTR)(i+1));
382 ok(ret == i, "ret=%d\n", ret);
385 rc = CheckDPA(dpa2, 0x654321, &dw);
386 ok(rc, "dw=0x%lx\n", dw);
387 rc = CheckDPA(dpa3, 0x123456, &dw);
388 ok(rc, "dw=0x%lx\n", dw);
390 /* Delete all odd entries from dpa2 */
391 memset(nMessages, 0, sizeof(nMessages));
392 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
393 CB_CmpLT, CB_MergeDeleteOddSrc, 0x1abe11ed);
394 rc = CheckDPA(dpa2, 0x246, &dw);
395 ok(rc, "dw=0x%lx\n", dw);
397 expect(3, nMessages[DPAMM_MERGE]);
398 expect(3, nMessages[DPAMM_DELETE]);
399 expect(0, nMessages[DPAMM_INSERT]);
401 for (i = 0; i < 6; i++)
403 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
404 ok(ret == i, "ret=%d\n", ret);
407 /* DPAM_INTERSECT - returning source while merging */
408 memset(nMessages, 0, sizeof(nMessages));
409 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
410 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
411 rc = CheckDPA(dpa2, 0x135, &dw);
412 ok(rc, "dw=0x%lx\n", dw);
414 expect(3, nMessages[DPAMM_MERGE]);
415 expect(6, nMessages[DPAMM_DELETE]);
416 expect(0, nMessages[DPAMM_INSERT]);
418 /* DPAM_UNION */
419 pDPA_DeleteAllPtrs(dpa);
420 pDPA_InsertPtr(dpa, 0, (PVOID)1);
421 pDPA_InsertPtr(dpa, 1, (PVOID)3);
422 pDPA_InsertPtr(dpa, 2, (PVOID)5);
423 pDPA_DeleteAllPtrs(dpa2);
424 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
425 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
426 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
428 memset(nMessages, 0, sizeof(nMessages));
429 pDPA_Merge(dpa2, dpa, DPAM_UNION,
430 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
431 rc = CheckDPA(dpa2, 0x123456, &dw);
432 ok(rc ||
433 broken(!rc && dw == 0x23456), /* 4.7x */
434 "dw=0x%lx\n", dw);
436 expect(0, nMessages[DPAMM_MERGE]);
437 expect(0, nMessages[DPAMM_DELETE]);
438 ok(nMessages[DPAMM_INSERT] == 3 ||
439 broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
440 "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
442 /* Merge dpa3 into dpa2 and dpa */
443 memset(nMessages, 0, sizeof(nMessages));
444 pDPA_Merge(dpa, dpa3, DPAM_UNION|DPAM_SORTED,
445 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
446 expect(3, nMessages[DPAMM_MERGE]);
447 expect(0, nMessages[DPAMM_DELETE]);
448 expect(3, nMessages[DPAMM_INSERT]);
451 pDPA_DeleteAllPtrs(dpa2);
452 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
453 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
454 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
456 memset(nMessages, 0, sizeof(nMessages));
457 pDPA_Merge(dpa2, dpa3, DPAM_UNION|DPAM_SORTED,
458 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
459 expect(3, nMessages[DPAMM_MERGE]);
460 expect(0, nMessages[DPAMM_DELETE]);
461 ok(nMessages[DPAMM_INSERT] == 3 ||
462 broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
463 "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
465 rc = CheckDPA(dpa, 0x123456, &dw);
466 ok(rc, "dw=0x%lx\n", dw);
467 rc = CheckDPA(dpa2, 0x123456, &dw);
468 ok(rc ||
469 broken(!rc), /* win98 */
470 "dw=0x%lx\n", dw);
471 rc = CheckDPA(dpa3, 0x123456, &dw);
472 ok(rc, "dw=0x%lx\n", dw);
474 pDPA_Destroy(dpa);
475 pDPA_Destroy(dpa2);
476 pDPA_Destroy(dpa3);
479 static void test_DPA_EnumCallback(void)
481 HDPA dpa;
482 BOOL rc;
483 DWORD dw;
484 INT i, ret;
486 dpa = pDPA_Create(0);
488 for (i = 0; i < 6; i++)
490 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
491 ok(ret == i, "ret=%d\n", ret);
494 rc = CheckDPA(dpa, 0x123456, &dw);
495 ok(rc, "dw=0x%lx\n", dw);
497 nEnum = 0;
498 /* test callback sets first 3 items to 7 */
499 pDPA_EnumCallback(dpa, CB_EnumFirstThree, dpa);
500 rc = CheckDPA(dpa, 0x777456, &dw);
501 ok(rc, "dw=0x%lx\n", dw);
502 ok(nEnum == 3, "nEnum=%d\n", nEnum);
504 pDPA_Destroy(dpa);
507 static void test_DPA_DestroyCallback(void)
509 HDPA dpa;
510 INT i, ret;
512 dpa = pDPA_Create(0);
514 for (i = 0; i < 3; i++)
516 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
517 ok(ret == i, "ret=%d\n", ret);
520 nEnum = 0;
521 pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa);
522 ok(nEnum == 3, "nEnum=%d\n", nEnum);
525 static void test_DPA_LoadStream(void)
527 IStorage* pStg = NULL;
528 IStream* pStm = NULL;
529 LARGE_INTEGER li;
530 ULARGE_INTEGER uli;
531 DWORD dwMode;
532 HRESULT hRes;
533 STREAMDATA header;
534 ULONG written, ret;
535 HDPA dpa;
537 hRes = CoInitialize(NULL);
538 ok(hRes == S_OK, "Failed to initialize COM, hr %#lx.\n", hRes);
540 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
541 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
542 expect(S_OK, hRes);
544 hRes = IStorage_CreateStream(pStg, L"Stg", dwMode, 0, 0, &pStm);
545 expect(S_OK, hRes);
547 /* write less than header size */
548 li.QuadPart = 0;
549 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
550 expect(S_OK, hRes);
552 memset(&header, 0, sizeof(header));
553 written = 0;
554 uli.QuadPart = sizeof(header)-1;
555 hRes = IStream_SetSize(pStm, uli);
556 expect(S_OK, hRes);
557 hRes = IStream_Write(pStm, &header, sizeof(header)-1, &written);
558 expect(S_OK, hRes);
559 written -= sizeof(header)-1;
560 expect(0, written);
562 li.QuadPart = 0;
563 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
564 expect(S_OK, hRes);
566 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
567 expect(E_FAIL, hRes);
569 /* check stream position after header read failed */
570 li.QuadPart = 0;
571 uli.QuadPart = 1;
572 hRes = IStream_Seek(pStm, li, STREAM_SEEK_CUR, &uli);
573 expect(S_OK, hRes);
574 ok(uli.QuadPart == 0, "Expected to position reset\n");
576 /* write valid header for empty DPA */
577 header.dwSize = sizeof(header);
578 header.dwData2 = 1;
579 header.dwItems = 0;
580 written = 0;
582 li.QuadPart = 0;
583 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
584 expect(S_OK, hRes);
586 uli.QuadPart = sizeof(header);
587 hRes = IStream_SetSize(pStm, uli);
588 expect(S_OK, hRes);
590 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
591 expect(S_OK, hRes);
592 written -= sizeof(header);
593 expect(0, written);
595 li.QuadPart = 0;
596 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
597 expect(S_OK, hRes);
599 dpa = NULL;
600 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
601 expect(S_OK, hRes);
602 pDPA_Destroy(dpa);
604 /* try with altered dwData2 field */
605 header.dwSize = sizeof(header);
606 header.dwData2 = 2;
607 header.dwItems = 0;
609 li.QuadPart = 0;
610 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
611 expect(S_OK, hRes);
612 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
613 expect(S_OK, hRes);
614 written -= sizeof(header);
615 expect(0, written);
617 li.QuadPart = 0;
618 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
619 expect(S_OK, hRes);
621 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
622 expect(E_FAIL, hRes);
624 ret = IStream_Release(pStm);
625 ok(!ret, "ret=%ld\n", ret);
627 ret = IStorage_Release(pStg);
628 ok(!ret, "ret=%ld\n", ret);
630 CoUninitialize();
633 static void test_DPA_SaveStream(void)
635 HDPA dpa;
636 IStorage* pStg = NULL;
637 IStream* pStm = NULL;
638 DWORD dwMode, dw;
639 HRESULT hRes;
640 INT ret;
641 INT i;
642 BOOL rc;
643 LARGE_INTEGER liZero;
645 hRes = CoInitialize(NULL);
646 ok(hRes == S_OK, "Failed to initialize COM, hr %#lx.\n", hRes);
648 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
649 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
650 expect(S_OK, hRes);
652 hRes = IStorage_CreateStream(pStg, L"Stg", dwMode, 0, 0, &pStm);
653 expect(S_OK, hRes);
655 dpa = pDPA_Create(0);
657 /* simple parameter check */
658 hRes = pDPA_SaveStream(dpa, NULL, pStm, NULL);
659 ok(hRes == E_INVALIDARG ||
660 broken(hRes == S_OK) /* XP and below */, "Wrong result, %ld\n", hRes);
661 if (0) {
662 /* crashes on XP */
663 hRes = pDPA_SaveStream(NULL, CB_Save, pStm, NULL);
664 expect(E_INVALIDARG, hRes);
666 hRes = pDPA_SaveStream(dpa, CB_Save, NULL, NULL);
667 expect(E_INVALIDARG, hRes);
670 /* saving/loading */
671 for (i = 0; i < 6; i++)
673 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
674 ok(ret == i, "ret=%d\n", ret);
677 liZero.QuadPart = 0;
678 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
679 expect(S_OK, hRes);
681 hRes = pDPA_SaveStream(dpa, CB_Save, pStm, (void*)0xdeadbeef);
682 expect(S_OK, hRes);
683 pDPA_Destroy(dpa);
685 liZero.QuadPart = 0;
686 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
687 expect(S_OK, hRes);
688 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
689 expect(S_OK, hRes);
690 rc = CheckDPA(dpa, 0x123456, &dw);
691 ok(rc, "dw=0x%lx\n", dw);
692 pDPA_Destroy(dpa);
694 ret = IStream_Release(pStm);
695 ok(!ret, "ret=%d\n", ret);
697 ret = IStorage_Release(pStg);
698 ok(!ret, "ret=%d\n", ret);
700 CoUninitialize();
703 START_TEST(dpa)
705 ULONG_PTR cookie;
706 HANDLE ctxt;
708 init_functions();
710 test_dpa();
711 test_DPA_Merge();
712 test_DPA_EnumCallback();
713 test_DPA_DestroyCallback();
714 test_DPA_LoadStream();
715 test_DPA_SaveStream();
717 if (!load_v6_module(&cookie, &ctxt))
718 return;
720 init_functions();
722 test_dpa();
723 test_DPA_Merge();
724 test_DPA_EnumCallback();
725 test_DPA_DestroyCallback();
726 test_DPA_LoadStream();
727 test_DPA_SaveStream();
729 unload_v6_module(cookie, ctxt);