d3d8: Stop setting the device state in d3d8_device_SetPixelShaderConstant().
[wine.git] / dlls / comctl32 / tests / dpa.c
blob39f6b460e975017a6779b876c022472ab31ac08a
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) ok(got == expected, "Expected %d, got %d\n", expected, got)
37 typedef struct _STREAMDATA
39 DWORD dwSize;
40 DWORD dwData2;
41 DWORD dwItems;
42 } STREAMDATA, *PSTREAMDATA;
44 static HDPA (WINAPI *pDPA_Clone)(const HDPA,HDPA);
45 static HDPA (WINAPI *pDPA_Create)(INT);
46 static HDPA (WINAPI *pDPA_CreateEx)(INT,HANDLE);
47 static PVOID (WINAPI *pDPA_DeleteAllPtrs)(HDPA);
48 static PVOID (WINAPI *pDPA_DeletePtr)(HDPA,INT);
49 static BOOL (WINAPI *pDPA_Destroy)(HDPA);
50 static VOID (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
51 static VOID (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
52 static INT (WINAPI *pDPA_GetPtr)(HDPA,INT);
53 static INT (WINAPI *pDPA_GetPtrIndex)(HDPA,PVOID);
54 static BOOL (WINAPI *pDPA_Grow)(HDPA,INT);
55 static INT (WINAPI *pDPA_InsertPtr)(HDPA,INT,PVOID);
56 static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTREAM,IStream*,LPVOID);
57 static BOOL (WINAPI *pDPA_Merge)(HDPA,HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
58 static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTREAM,IStream*,LPVOID);
59 static INT (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
60 static BOOL (WINAPI *pDPA_SetPtr)(HDPA,INT,PVOID);
61 static BOOL (WINAPI *pDPA_Sort)(HDPA,PFNDPACOMPARE,LPARAM);
63 static void init_functions(void)
65 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
67 #define X2(f, ord) p##f = (void*)GetProcAddress(hComCtl32, (const char *)ord);
68 /* 4.00+ */
69 X2(DPA_Clone, 331);
70 X2(DPA_Create, 328);
71 X2(DPA_CreateEx, 340);
72 X2(DPA_DeleteAllPtrs, 337);
73 X2(DPA_DeletePtr, 336);
74 X2(DPA_Destroy, 329);
75 X2(DPA_GetPtr, 332);
76 X2(DPA_GetPtrIndex, 333);
77 X2(DPA_Grow, 330);
78 X2(DPA_InsertPtr, 334);
79 X2(DPA_Search, 339);
80 X2(DPA_SetPtr, 335);
81 X2(DPA_Sort, 338);
83 /* 4.71+ */
84 X2(DPA_DestroyCallback, 386);
85 X2(DPA_EnumCallback, 385);
86 X2(DPA_LoadStream, 9);
87 X2(DPA_Merge, 11);
88 X2(DPA_SaveStream, 10);
89 #undef X2
92 /* Callbacks */
93 static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp)
95 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
96 return p1 < p2 ? -1 : p1 > p2 ? 1 : 0;
99 static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp)
101 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
102 return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
105 /* merge callback messages counter
106 DPAMM_MERGE 1
107 DPAMM_DELETE 2
108 DPAMM_INSERT 3 */
109 static INT nMessages[4];
111 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
113 nMessages[op]++;
114 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
115 return p1;
118 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
120 nMessages[op]++;
121 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
122 return ((PCHAR)p2)+1;
125 static INT nEnum;
127 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
129 INT i;
131 i = pDPA_GetPtrIndex(lp, pItem);
132 ok(i == nEnum, "i=%d nEnum=%d\n", i, nEnum);
133 nEnum++;
134 pDPA_SetPtr(lp, i, (PVOID)7);
135 return pItem != (PVOID)3;
138 static HRESULT CALLBACK CB_Save(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
140 HRESULT hRes;
142 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
143 hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
144 expect(S_OK, hRes);
145 hRes = IStream_Write(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
146 expect(S_OK, hRes);
147 return S_OK;
150 static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
152 HRESULT hRes;
153 INT iOldPos;
155 iOldPos = pInfo->iPos;
156 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
157 hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
158 expect(S_OK, hRes);
159 ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
160 hRes = IStream_Read(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
161 expect(S_OK, hRes);
162 return S_OK;
165 static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
167 DWORD dwOut = 0;
168 INT i;
170 for(i = 0; i < 8;)
172 ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++);
173 if(!ulItem) break;
174 dwOut = dwOut << 4 | (ulItem & 0xf);
177 *pdwOut = dwOut;
179 if(dwOut != dwIn)
181 pDPA_DeleteAllPtrs(dpa);
185 pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf));
186 dwIn >>= 4;
188 while(dwIn);
190 return FALSE;
193 return TRUE;
196 static void test_dpa(void)
198 SYSTEM_INFO si;
199 HANDLE hHeap;
200 HDPA dpa, dpa2, dpa3;
201 INT ret, i;
202 PVOID p;
203 DWORD dw, dw2, dw3;
204 BOOL rc;
206 GetSystemInfo(&si);
207 hHeap = HeapCreate(0, 1, 2);
208 ok(hHeap != NULL, "error=%d\n", GetLastError());
209 dpa3 = pDPA_CreateEx(0, hHeap);
210 ok(dpa3 != NULL, "\n");
211 ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
212 ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
213 "ret=%d error=%d\n", ret, GetLastError());
215 dpa = pDPA_Create(0);
216 ok(dpa != NULL, "\n");
218 /* Set item with out of bound index */
219 ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n");
220 /* Fill the created gap */
221 ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n");
222 rc=CheckDPA(dpa, 0x56, &dw);
223 ok(rc, "dw=0x%x\n", dw);
225 /* Prepend item */
226 ret = pDPA_InsertPtr(dpa, 1, (PVOID)1);
227 ok(ret == 1, "ret=%d\n", ret);
228 /* Append item using correct index */
229 ret = pDPA_InsertPtr(dpa, 3, (PVOID)3);
230 ok(ret == 3, "ret=%d\n", ret);
231 /* Append item using out of bound index */
232 ret = pDPA_InsertPtr(dpa, 5, (PVOID)2);
233 ok(ret == 4, "ret=%d\n", ret);
234 /* Append item using DPA_APPEND */
235 ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4);
236 ok(ret == 5, "ret=%d\n", ret);
238 rc=CheckDPA(dpa, 0x516324, &dw);
239 ok(rc, "dw=0x%x\n", dw);
241 for(i = 1; i <= 6; i++)
243 INT j, k;
244 k = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
245 /* Linear searches should work on unsorted DPAs */
246 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0x1abe11ed, 0);
247 ok(j == k, "j=%d k=%d\n", j, k);
250 /* Sort DPA */
251 ok(pDPA_Sort(dpa, CB_CmpGT, 0x1abe11ed), "\n");
252 rc=CheckDPA(dpa, 0x654321, &dw);
253 ok(rc, "dw=0x%x\n", dw);
255 /* Clone into a new DPA */
256 dpa2 = pDPA_Clone(dpa, NULL);
257 ok(dpa2 != NULL, "\n");
258 /* The old data should have been preserved */
259 rc=CheckDPA(dpa2, 0x654321, &dw2);
260 ok(rc, "dw=0x%x\n", dw2);
261 ok(pDPA_Sort(dpa, CB_CmpLT, 0x1abe11ed), "\n");
263 /* Test if the DPA itself was really copied */
264 rc=CheckDPA(dpa, 0x123456, &dw);
265 ok(rc, "dw=0x%x\n", dw );
266 rc=CheckDPA(dpa2, 0x654321, &dw2);
267 ok(rc, "dw2=0x%x\n", dw2);
269 /* Clone into an old DPA */
270 SetLastError(ERROR_SUCCESS);
271 p = pDPA_Clone(dpa, dpa3);
272 ok(p == dpa3, "p=%p\n", p);
273 rc=CheckDPA(dpa3, 0x123456, &dw3);
274 ok(rc, "dw3=0x%x\n", dw3);
276 for(i = 1; i <= 6; i++)
278 INT j;
280 /* The array is in order so ptr == index+1 */
281 j = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
282 ok(j+1 == i, "j=%d i=%d\n", j, i);
283 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0x1abe11ed, DPAS_SORTED);
284 ok(j+1 == i, "j=%d i=%d\n", j, i);
286 /* Linear searches respect iStart ... */
287 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0x1abe11ed, 0);
288 ok(j == DPA_ERR, "j=%d\n", j);
289 /* ... but for a binary search it's ignored */
290 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0x1abe11ed, DPAS_SORTED);
291 ok(j+1 == i, "j=%d i=%d\n", j, i);
294 /* Try to get the index of a nonexistent item */
295 i = pDPA_GetPtrIndex(dpa, (PVOID)7);
296 ok(i == DPA_ERR, "i=%d\n", i);
298 /* Try to delete out of bound indexes */
299 p = pDPA_DeletePtr(dpa, -1);
300 ok(p == NULL, "p=%p\n", p);
301 p = pDPA_DeletePtr(dpa, 6);
302 ok(p == NULL, "p=%p\n", p);
304 /* Delete the third item */
305 p = pDPA_DeletePtr(dpa, 2);
306 ok(p == (PVOID)3, "p=%p\n", p);
307 rc=CheckDPA(dpa, 0x12456, &dw);
308 ok(rc, "dw=0x%x\n", dw);
310 /* Check where to re-insert the deleted item */
311 i = pDPA_Search(dpa, (PVOID)3, 0,
312 CB_CmpLT, 0x1abe11ed, DPAS_SORTED|DPAS_INSERTAFTER);
313 ok(i == 2, "i=%d\n", i);
314 /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */
315 i = pDPA_Search(dpa, (PVOID)3, 0,
316 CB_CmpLT, 0x1abe11ed, DPAS_SORTED|DPAS_INSERTBEFORE);
317 ok(i == 2, "i=%d\n", i);
318 /* without DPAS_INSERTBEFORE/AFTER */
319 i = pDPA_Search(dpa, (PVOID)3, 0,
320 CB_CmpLT, 0x1abe11ed, DPAS_SORTED);
321 ok(i == -1, "i=%d\n", i);
323 /* Re-insert the item */
324 ret = pDPA_InsertPtr(dpa, 2, (PVOID)3);
325 ok(ret == 2, "ret=%d i=%d\n", ret, 2);
326 rc=CheckDPA(dpa, 0x123456, &dw);
327 ok(rc, "dw=0x%x\n", dw);
329 /* When doing a binary search while claiming reverse order all indexes
330 * should be bogus */
331 for(i = 0; i < 6; i++)
333 INT j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpGT, 0x1abe11ed,
334 DPAS_SORTED|DPAS_INSERTBEFORE);
335 ok(j != i, "i=%d\n", i);
338 /* Setting item with huge index should work */
339 ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n");
340 ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef);
341 ok(ret == 0x12345, "ret=%d\n", ret);
343 pDPA_DeleteAllPtrs(dpa2);
344 rc=CheckDPA(dpa2, 0, &dw2);
345 ok(rc, "dw2=0x%x\n", dw2);
347 pDPA_Destroy(dpa);
348 pDPA_Destroy(dpa2);
349 pDPA_Destroy(dpa3);
352 static void test_DPA_Merge(void)
354 HDPA dpa, dpa2, dpa3;
355 INT ret, i;
356 DWORD dw;
357 BOOL rc;
359 if(!pDPA_Merge)
361 win_skip("DPA_Merge() not available\n");
362 return;
365 dpa = pDPA_Create(0);
366 dpa2 = pDPA_Create(0);
367 dpa3 = pDPA_Create(0);
369 ret = pDPA_InsertPtr(dpa, 0, (PVOID)1);
370 ok(ret == 0, "ret=%d\n", ret);
371 ret = pDPA_InsertPtr(dpa, 1, (PVOID)3);
372 ok(ret == 1, "ret=%d\n", ret);
373 ret = pDPA_InsertPtr(dpa, 2, (PVOID)5);
374 ok(ret == 2, "ret=%d\n", ret);
376 rc = CheckDPA(dpa, 0x135, &dw);
377 ok(rc, "dw=0x%x\n", dw);
379 for (i = 0; i < 6; i++)
381 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
382 ok(ret == i, "ret=%d\n", ret);
383 ret = pDPA_InsertPtr(dpa3, i, (PVOID)(INT_PTR)(i+1));
384 ok(ret == i, "ret=%d\n", ret);
387 rc = CheckDPA(dpa2, 0x654321, &dw);
388 ok(rc, "dw=0x%x\n", dw);
389 rc = CheckDPA(dpa3, 0x123456, &dw);
390 ok(rc, "dw=0x%x\n", dw);
392 /* Delete all odd entries from dpa2 */
393 memset(nMessages, 0, sizeof(nMessages));
394 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
395 CB_CmpLT, CB_MergeDeleteOddSrc, 0x1abe11ed);
396 rc = CheckDPA(dpa2, 0x246, &dw);
397 ok(rc, "dw=0x%x\n", dw);
399 expect(3, nMessages[DPAMM_MERGE]);
400 expect(3, nMessages[DPAMM_DELETE]);
401 expect(0, nMessages[DPAMM_INSERT]);
403 for (i = 0; i < 6; i++)
405 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
406 ok(ret == i, "ret=%d\n", ret);
409 /* DPAM_INTERSECT - returning source while merging */
410 memset(nMessages, 0, sizeof(nMessages));
411 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
412 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
413 rc = CheckDPA(dpa2, 0x135, &dw);
414 ok(rc, "dw=0x%x\n", dw);
416 expect(3, nMessages[DPAMM_MERGE]);
417 expect(6, nMessages[DPAMM_DELETE]);
418 expect(0, nMessages[DPAMM_INSERT]);
420 /* DPAM_UNION */
421 pDPA_DeleteAllPtrs(dpa);
422 pDPA_InsertPtr(dpa, 0, (PVOID)1);
423 pDPA_InsertPtr(dpa, 1, (PVOID)3);
424 pDPA_InsertPtr(dpa, 2, (PVOID)5);
425 pDPA_DeleteAllPtrs(dpa2);
426 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
427 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
428 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
430 memset(nMessages, 0, sizeof(nMessages));
431 pDPA_Merge(dpa2, dpa, DPAM_UNION,
432 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
433 rc = CheckDPA(dpa2, 0x123456, &dw);
434 ok(rc ||
435 broken(!rc && dw == 0x23456), /* 4.7x */
436 "dw=0x%x\n", dw);
438 expect(0, nMessages[DPAMM_MERGE]);
439 expect(0, nMessages[DPAMM_DELETE]);
440 ok(nMessages[DPAMM_INSERT] == 3 ||
441 broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
442 "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
444 /* Merge dpa3 into dpa2 and dpa */
445 memset(nMessages, 0, sizeof(nMessages));
446 pDPA_Merge(dpa, dpa3, DPAM_UNION|DPAM_SORTED,
447 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
448 expect(3, nMessages[DPAMM_MERGE]);
449 expect(0, nMessages[DPAMM_DELETE]);
450 expect(3, nMessages[DPAMM_INSERT]);
453 pDPA_DeleteAllPtrs(dpa2);
454 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
455 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
456 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
458 memset(nMessages, 0, sizeof(nMessages));
459 pDPA_Merge(dpa2, dpa3, DPAM_UNION|DPAM_SORTED,
460 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
461 expect(3, nMessages[DPAMM_MERGE]);
462 expect(0, nMessages[DPAMM_DELETE]);
463 ok(nMessages[DPAMM_INSERT] == 3 ||
464 broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
465 "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
467 rc = CheckDPA(dpa, 0x123456, &dw);
468 ok(rc, "dw=0x%x\n", dw);
469 rc = CheckDPA(dpa2, 0x123456, &dw);
470 ok(rc ||
471 broken(!rc), /* win98 */
472 "dw=0x%x\n", dw);
473 rc = CheckDPA(dpa3, 0x123456, &dw);
474 ok(rc, "dw=0x%x\n", dw);
476 pDPA_Destroy(dpa);
477 pDPA_Destroy(dpa2);
478 pDPA_Destroy(dpa3);
481 static void test_DPA_EnumCallback(void)
483 HDPA dpa;
484 BOOL rc;
485 DWORD dw;
486 INT i, ret;
488 if(!pDPA_EnumCallback)
490 win_skip("DPA_EnumCallback() not available\n");
491 return;
494 dpa = pDPA_Create(0);
496 for (i = 0; i < 6; i++)
498 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
499 ok(ret == i, "ret=%d\n", ret);
502 rc = CheckDPA(dpa, 0x123456, &dw);
503 ok(rc, "dw=0x%x\n", dw);
505 nEnum = 0;
506 /* test callback sets first 3 items to 7 */
507 pDPA_EnumCallback(dpa, CB_EnumFirstThree, dpa);
508 rc = CheckDPA(dpa, 0x777456, &dw);
509 ok(rc, "dw=0x%x\n", dw);
510 ok(nEnum == 3, "nEnum=%d\n", nEnum);
512 pDPA_Destroy(dpa);
515 static void test_DPA_DestroyCallback(void)
517 HDPA dpa;
518 INT i, ret;
520 if(!pDPA_DestroyCallback)
522 win_skip("DPA_DestroyCallback() not available\n");
523 return;
526 dpa = pDPA_Create(0);
528 for (i = 0; i < 3; i++)
530 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
531 ok(ret == i, "ret=%d\n", ret);
534 nEnum = 0;
535 pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa);
536 ok(nEnum == 3, "nEnum=%d\n", nEnum);
539 static void test_DPA_LoadStream(void)
541 static const WCHAR szStg[] = { 'S','t','g',0 };
542 IStorage* pStg = NULL;
543 IStream* pStm = NULL;
544 LARGE_INTEGER li;
545 ULARGE_INTEGER uli;
546 DWORD dwMode;
547 HRESULT hRes;
548 STREAMDATA header;
549 ULONG written, ret;
550 HDPA dpa;
552 if(!pDPA_LoadStream)
554 win_skip("DPA_LoadStream() not available. Skipping stream tests.\n");
555 return;
558 hRes = CoInitialize(NULL);
559 if (hRes != S_OK)
561 ok(0, "hResult: %d\n", hRes);
562 return;
565 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
566 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
567 expect(S_OK, hRes);
569 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
570 expect(S_OK, hRes);
572 /* write less than header size */
573 li.QuadPart = 0;
574 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
575 expect(S_OK, hRes);
577 memset(&header, 0, sizeof(header));
578 written = 0;
579 uli.QuadPart = sizeof(header)-1;
580 hRes = IStream_SetSize(pStm, uli);
581 expect(S_OK, hRes);
582 hRes = IStream_Write(pStm, &header, sizeof(header)-1, &written);
583 expect(S_OK, hRes);
584 written -= sizeof(header)-1;
585 expect(0, written);
587 li.QuadPart = 0;
588 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
589 expect(S_OK, hRes);
591 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
592 expect(E_FAIL, hRes);
594 /* check stream position after header read failed */
595 li.QuadPart = 0;
596 uli.QuadPart = 1;
597 hRes = IStream_Seek(pStm, li, STREAM_SEEK_CUR, &uli);
598 expect(S_OK, hRes);
599 ok(uli.QuadPart == 0, "Expected to position reset\n");
601 /* write valid header for empty DPA */
602 header.dwSize = sizeof(header);
603 header.dwData2 = 1;
604 header.dwItems = 0;
605 written = 0;
607 li.QuadPart = 0;
608 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
609 expect(S_OK, hRes);
611 uli.QuadPart = sizeof(header);
612 hRes = IStream_SetSize(pStm, uli);
613 expect(S_OK, hRes);
615 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
616 expect(S_OK, hRes);
617 written -= sizeof(header);
618 expect(0, written);
620 li.QuadPart = 0;
621 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
622 expect(S_OK, hRes);
624 dpa = NULL;
625 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
626 expect(S_OK, hRes);
627 pDPA_Destroy(dpa);
629 /* try with altered dwData2 field */
630 header.dwSize = sizeof(header);
631 header.dwData2 = 2;
632 header.dwItems = 0;
634 li.QuadPart = 0;
635 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
636 expect(S_OK, hRes);
637 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
638 expect(S_OK, hRes);
639 written -= sizeof(header);
640 expect(0, written);
642 li.QuadPart = 0;
643 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
644 expect(S_OK, hRes);
646 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
647 expect(E_FAIL, hRes);
649 ret = IStream_Release(pStm);
650 ok(!ret, "ret=%d\n", ret);
652 ret = IStorage_Release(pStg);
653 ok(!ret, "ret=%d\n", ret);
655 CoUninitialize();
658 static void test_DPA_SaveStream(void)
660 HDPA dpa;
661 static const WCHAR szStg[] = { 'S','t','g',0 };
662 IStorage* pStg = NULL;
663 IStream* pStm = NULL;
664 DWORD dwMode, dw;
665 HRESULT hRes;
666 INT ret;
667 INT i;
668 BOOL rc;
669 LARGE_INTEGER liZero;
671 if(!pDPA_SaveStream)
673 win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
674 return;
677 hRes = CoInitialize(NULL);
678 if (hRes != S_OK)
680 ok(0, "hResult: %d\n", hRes);
681 return;
684 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
685 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
686 expect(S_OK, hRes);
688 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
689 expect(S_OK, hRes);
691 dpa = pDPA_Create(0);
693 /* simple parameter check */
694 hRes = pDPA_SaveStream(dpa, NULL, pStm, NULL);
695 ok(hRes == E_INVALIDARG ||
696 broken(hRes == S_OK) /* XP and below */, "Wrong result, %d\n", hRes);
697 if (0) {
698 /* crashes on XP */
699 hRes = pDPA_SaveStream(NULL, CB_Save, pStm, NULL);
700 expect(E_INVALIDARG, hRes);
702 hRes = pDPA_SaveStream(dpa, CB_Save, NULL, NULL);
703 expect(E_INVALIDARG, hRes);
706 /* saving/loading */
707 for (i = 0; i < 6; i++)
709 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
710 ok(ret == i, "ret=%d\n", ret);
713 liZero.QuadPart = 0;
714 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
715 expect(S_OK, hRes);
717 hRes = pDPA_SaveStream(dpa, CB_Save, pStm, (void*)0xdeadbeef);
718 expect(S_OK, hRes);
719 pDPA_Destroy(dpa);
721 liZero.QuadPart = 0;
722 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
723 expect(S_OK, hRes);
724 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
725 expect(S_OK, hRes);
726 rc = CheckDPA(dpa, 0x123456, &dw);
727 ok(rc, "dw=0x%x\n", dw);
728 pDPA_Destroy(dpa);
730 ret = IStream_Release(pStm);
731 ok(!ret, "ret=%d\n", ret);
733 ret = IStorage_Release(pStg);
734 ok(!ret, "ret=%d\n", ret);
736 CoUninitialize();
739 START_TEST(dpa)
741 ULONG_PTR cookie;
742 HANDLE ctxt;
744 init_functions();
746 test_dpa();
747 test_DPA_Merge();
748 test_DPA_EnumCallback();
749 test_DPA_DestroyCallback();
750 test_DPA_LoadStream();
751 test_DPA_SaveStream();
753 if (!load_v6_module(&cookie, &ctxt))
754 return;
756 init_functions();
758 test_dpa();
759 test_DPA_Merge();
760 test_DPA_EnumCallback();
761 test_DPA_DestroyCallback();
762 test_DPA_LoadStream();
763 test_DPA_SaveStream();
765 unload_v6_module(cookie, ctxt);