b72214533bba14a42310fa48f507f15067c09981
[reactos.git] / modules / rostests / winetests / comctl32 / dpa.c
1 /*
2 * Unit tests for DPA functions
3 *
4 * Copyright 2003 Uwe Bonnes
5 * Copyright 2005 Felix Nawothnig
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include "precomp.h"
23
24 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
25
26 typedef struct _STREAMDATA
27 {
28 DWORD dwSize;
29 DWORD dwData2;
30 DWORD dwItems;
31 } STREAMDATA, *PSTREAMDATA;
32
33 static HDPA (WINAPI *pDPA_Clone)(const HDPA,HDPA);
34 static HDPA (WINAPI *pDPA_Create)(INT);
35 static HDPA (WINAPI *pDPA_CreateEx)(INT,HANDLE);
36 static PVOID (WINAPI *pDPA_DeleteAllPtrs)(HDPA);
37 static PVOID (WINAPI *pDPA_DeletePtr)(HDPA,INT);
38 static BOOL (WINAPI *pDPA_Destroy)(HDPA);
39 static VOID (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
40 static VOID (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
41 static INT (WINAPI *pDPA_GetPtr)(HDPA,INT);
42 static INT (WINAPI *pDPA_GetPtrIndex)(HDPA,PVOID);
43 static BOOL (WINAPI *pDPA_Grow)(HDPA,INT);
44 static INT (WINAPI *pDPA_InsertPtr)(HDPA,INT,PVOID);
45 static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTREAM,IStream*,LPVOID);
46 static BOOL (WINAPI *pDPA_Merge)(HDPA,HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
47 static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTREAM,IStream*,LPVOID);
48 static INT (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
49 static BOOL (WINAPI *pDPA_SetPtr)(HDPA,INT,PVOID);
50 static BOOL (WINAPI *pDPA_Sort)(HDPA,PFNDPACOMPARE,LPARAM);
51
52 #define COMCTL32_GET_PROC(func, ord) \
53 ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \
54 : (trace( #func " not exported\n"), 0))
55
56 static BOOL InitFunctionPtrs(HMODULE hcomctl32)
57 {
58 /* 4.00+ */
59 if(COMCTL32_GET_PROC(DPA_Clone, 331) &&
60 COMCTL32_GET_PROC(DPA_Create, 328) &&
61 COMCTL32_GET_PROC(DPA_CreateEx, 340) &&
62 COMCTL32_GET_PROC(DPA_DeleteAllPtrs, 337) &&
63 COMCTL32_GET_PROC(DPA_DeletePtr, 336) &&
64 COMCTL32_GET_PROC(DPA_Destroy, 329) &&
65 COMCTL32_GET_PROC(DPA_GetPtr, 332) &&
66 COMCTL32_GET_PROC(DPA_GetPtrIndex, 333) &&
67 COMCTL32_GET_PROC(DPA_Grow, 330) &&
68 COMCTL32_GET_PROC(DPA_InsertPtr, 334) &&
69 COMCTL32_GET_PROC(DPA_Search, 339) &&
70 COMCTL32_GET_PROC(DPA_SetPtr, 335) &&
71 COMCTL32_GET_PROC(DPA_Sort, 338))
72 {
73 /* 4.71+ */
74 COMCTL32_GET_PROC(DPA_DestroyCallback, 386) &&
75 COMCTL32_GET_PROC(DPA_EnumCallback, 385) &&
76 COMCTL32_GET_PROC(DPA_LoadStream, 9) &&
77 COMCTL32_GET_PROC(DPA_Merge, 11) &&
78 COMCTL32_GET_PROC(DPA_SaveStream, 10);
79
80 return TRUE;
81 }
82
83 return FALSE;
84 }
85
86 /* Callbacks */
87 static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp)
88 {
89 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
90 return p1 < p2 ? -1 : p1 > p2 ? 1 : 0;
91 }
92
93 static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp)
94 {
95 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
96 return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
97 }
98
99 /* merge callback messages counter
100 DPAMM_MERGE 1
101 DPAMM_DELETE 2
102 DPAMM_INSERT 3 */
103 static INT nMessages[4];
104
105 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
106 {
107 nMessages[op]++;
108 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
109 return p1;
110 }
111
112 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
113 {
114 nMessages[op]++;
115 ok(lp == 0x1abe11ed, "lp=%ld\n", lp);
116 return ((PCHAR)p2)+1;
117 }
118
119 static INT nEnum;
120
121 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
122 {
123 INT i;
124
125 i = pDPA_GetPtrIndex(lp, pItem);
126 ok(i == nEnum, "i=%d nEnum=%d\n", i, nEnum);
127 nEnum++;
128 pDPA_SetPtr(lp, i, (PVOID)7);
129 return pItem != (PVOID)3;
130 }
131
132 static HRESULT CALLBACK CB_Save(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
133 {
134 HRESULT hRes;
135
136 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
137 hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
138 expect(S_OK, hRes);
139 hRes = IStream_Write(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
140 expect(S_OK, hRes);
141 return S_OK;
142 }
143
144 static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
145 {
146 HRESULT hRes;
147 INT iOldPos;
148
149 iOldPos = pInfo->iPos;
150 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
151 hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
152 expect(S_OK, hRes);
153 ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
154 hRes = IStream_Read(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
155 expect(S_OK, hRes);
156 return S_OK;
157 }
158
159 static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
160 {
161 DWORD dwOut = 0;
162 INT i;
163
164 for(i = 0; i < 8;)
165 {
166 ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++);
167 if(!ulItem) break;
168 dwOut = dwOut << 4 | (ulItem & 0xf);
169 }
170
171 *pdwOut = dwOut;
172
173 if(dwOut != dwIn)
174 {
175 pDPA_DeleteAllPtrs(dpa);
176
177 do
178 {
179 pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf));
180 dwIn >>= 4;
181 }
182 while(dwIn);
183
184 return FALSE;
185 }
186
187 return TRUE;
188 }
189
190 static void test_dpa(void)
191 {
192 SYSTEM_INFO si;
193 HANDLE hHeap;
194 HDPA dpa, dpa2, dpa3;
195 INT ret, i;
196 PVOID p;
197 DWORD dw, dw2, dw3;
198 BOOL rc;
199
200 GetSystemInfo(&si);
201 hHeap = HeapCreate(0, 1, 2);
202 ok(hHeap != NULL, "error=%d\n", GetLastError());
203 dpa3 = pDPA_CreateEx(0, hHeap);
204 ok(dpa3 != NULL, "\n");
205 ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
206 ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
207 "ret=%d error=%d\n", ret, GetLastError());
208
209 dpa = pDPA_Create(0);
210 ok(dpa != NULL, "\n");
211
212 /* Set item with out of bound index */
213 ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n");
214 /* Fill the created gap */
215 ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n");
216 rc=CheckDPA(dpa, 0x56, &dw);
217 ok(rc, "dw=0x%x\n", dw);
218
219 /* Prepend item */
220 ret = pDPA_InsertPtr(dpa, 1, (PVOID)1);
221 ok(ret == 1, "ret=%d\n", ret);
222 /* Append item using correct index */
223 ret = pDPA_InsertPtr(dpa, 3, (PVOID)3);
224 ok(ret == 3, "ret=%d\n", ret);
225 /* Append item using out of bound index */
226 ret = pDPA_InsertPtr(dpa, 5, (PVOID)2);
227 ok(ret == 4, "ret=%d\n", ret);
228 /* Append item using DPA_APPEND */
229 ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4);
230 ok(ret == 5, "ret=%d\n", ret);
231
232 rc=CheckDPA(dpa, 0x516324, &dw);
233 ok(rc, "dw=0x%x\n", dw);
234
235 for(i = 1; i <= 6; i++)
236 {
237 INT j, k;
238 k = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
239 /* Linear searches should work on unsorted DPAs */
240 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0x1abe11ed, 0);
241 ok(j == k, "j=%d k=%d\n", j, k);
242 }
243
244 /* Sort DPA */
245 ok(pDPA_Sort(dpa, CB_CmpGT, 0x1abe11ed), "\n");
246 rc=CheckDPA(dpa, 0x654321, &dw);
247 ok(rc, "dw=0x%x\n", dw);
248
249 /* Clone into a new DPA */
250 dpa2 = pDPA_Clone(dpa, NULL);
251 ok(dpa2 != NULL, "\n");
252 /* The old data should have been preserved */
253 rc=CheckDPA(dpa2, 0x654321, &dw2);
254 ok(rc, "dw=0x%x\n", dw2);
255 ok(pDPA_Sort(dpa, CB_CmpLT, 0x1abe11ed), "\n");
256
257 /* Test if the DPA itself was really copied */
258 rc=CheckDPA(dpa, 0x123456, &dw);
259 ok(rc, "dw=0x%x\n", dw );
260 rc=CheckDPA(dpa2, 0x654321, &dw2);
261 ok(rc, "dw2=0x%x\n", dw2);
262
263 /* Clone into an old DPA */
264 SetLastError(ERROR_SUCCESS);
265 p = pDPA_Clone(dpa, dpa3);
266 ok(p == dpa3, "p=%p\n", p);
267 rc=CheckDPA(dpa3, 0x123456, &dw3);
268 ok(rc, "dw3=0x%x\n", dw3);
269
270 for(i = 1; i <= 6; i++)
271 {
272 INT j;
273
274 /* The array is in order so ptr == index+1 */
275 j = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
276 ok(j+1 == i, "j=%d i=%d\n", j, i);
277 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0x1abe11ed, DPAS_SORTED);
278 ok(j+1 == i, "j=%d i=%d\n", j, i);
279
280 /* Linear searches respect iStart ... */
281 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0x1abe11ed, 0);
282 ok(j == DPA_ERR, "j=%d\n", j);
283 /* ... but for a binary search it's ignored */
284 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0x1abe11ed, DPAS_SORTED);
285 ok(j+1 == i, "j=%d i=%d\n", j, i);
286 }
287
288 /* Try to get the index of a nonexistent item */
289 i = pDPA_GetPtrIndex(dpa, (PVOID)7);
290 ok(i == DPA_ERR, "i=%d\n", i);
291
292 /* Try to delete out of bound indexes */
293 p = pDPA_DeletePtr(dpa, -1);
294 ok(p == NULL, "p=%p\n", p);
295 p = pDPA_DeletePtr(dpa, 6);
296 ok(p == NULL, "p=%p\n", p);
297
298 /* Delete the third item */
299 p = pDPA_DeletePtr(dpa, 2);
300 ok(p == (PVOID)3, "p=%p\n", p);
301 rc=CheckDPA(dpa, 0x12456, &dw);
302 ok(rc, "dw=0x%x\n", dw);
303
304 /* Check where to re-insert the deleted item */
305 i = pDPA_Search(dpa, (PVOID)3, 0,
306 CB_CmpLT, 0x1abe11ed, DPAS_SORTED|DPAS_INSERTAFTER);
307 ok(i == 2, "i=%d\n", i);
308 /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */
309 i = pDPA_Search(dpa, (PVOID)3, 0,
310 CB_CmpLT, 0x1abe11ed, DPAS_SORTED|DPAS_INSERTBEFORE);
311 ok(i == 2, "i=%d\n", i);
312 /* without DPAS_INSERTBEFORE/AFTER */
313 i = pDPA_Search(dpa, (PVOID)3, 0,
314 CB_CmpLT, 0x1abe11ed, DPAS_SORTED);
315 ok(i == -1, "i=%d\n", i);
316
317 /* Re-insert the item */
318 ret = pDPA_InsertPtr(dpa, 2, (PVOID)3);
319 ok(ret == 2, "ret=%d i=%d\n", ret, 2);
320 rc=CheckDPA(dpa, 0x123456, &dw);
321 ok(rc, "dw=0x%x\n", dw);
322
323 /* When doing a binary search while claiming reverse order all indexes
324 * should be bogus */
325 for(i = 0; i < 6; i++)
326 {
327 INT j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpGT, 0x1abe11ed,
328 DPAS_SORTED|DPAS_INSERTBEFORE);
329 ok(j != i, "i=%d\n", i);
330 }
331
332 /* Setting item with huge index should work */
333 ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n");
334 ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef);
335 ok(ret == 0x12345, "ret=%d\n", ret);
336
337 pDPA_DeleteAllPtrs(dpa2);
338 rc=CheckDPA(dpa2, 0, &dw2);
339 ok(rc, "dw2=0x%x\n", dw2);
340
341 pDPA_Destroy(dpa);
342 pDPA_Destroy(dpa2);
343 pDPA_Destroy(dpa3);
344 }
345
346 static void test_DPA_Merge(void)
347 {
348 HDPA dpa, dpa2, dpa3;
349 INT ret, i;
350 DWORD dw;
351 BOOL rc;
352
353 if(!pDPA_Merge)
354 {
355 win_skip("DPA_Merge() not available\n");
356 return;
357 }
358
359 dpa = pDPA_Create(0);
360 dpa2 = pDPA_Create(0);
361 dpa3 = pDPA_Create(0);
362
363 ret = pDPA_InsertPtr(dpa, 0, (PVOID)1);
364 ok(ret == 0, "ret=%d\n", ret);
365 ret = pDPA_InsertPtr(dpa, 1, (PVOID)3);
366 ok(ret == 1, "ret=%d\n", ret);
367 ret = pDPA_InsertPtr(dpa, 2, (PVOID)5);
368 ok(ret == 2, "ret=%d\n", ret);
369
370 rc = CheckDPA(dpa, 0x135, &dw);
371 ok(rc, "dw=0x%x\n", dw);
372
373 for (i = 0; i < 6; i++)
374 {
375 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
376 ok(ret == i, "ret=%d\n", ret);
377 ret = pDPA_InsertPtr(dpa3, i, (PVOID)(INT_PTR)(i+1));
378 ok(ret == i, "ret=%d\n", ret);
379 }
380
381 rc = CheckDPA(dpa2, 0x654321, &dw);
382 ok(rc, "dw=0x%x\n", dw);
383 rc = CheckDPA(dpa3, 0x123456, &dw);
384 ok(rc, "dw=0x%x\n", dw);
385
386 /* Delete all odd entries from dpa2 */
387 memset(nMessages, 0, sizeof(nMessages));
388 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
389 CB_CmpLT, CB_MergeDeleteOddSrc, 0x1abe11ed);
390 rc = CheckDPA(dpa2, 0x246, &dw);
391 ok(rc, "dw=0x%x\n", dw);
392
393 expect(3, nMessages[DPAMM_MERGE]);
394 expect(3, nMessages[DPAMM_DELETE]);
395 expect(0, nMessages[DPAMM_INSERT]);
396
397 for (i = 0; i < 6; i++)
398 {
399 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
400 ok(ret == i, "ret=%d\n", ret);
401 }
402
403 /* DPAM_INTERSECT - returning source while merging */
404 memset(nMessages, 0, sizeof(nMessages));
405 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
406 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
407 rc = CheckDPA(dpa2, 0x135, &dw);
408 ok(rc, "dw=0x%x\n", dw);
409
410 expect(3, nMessages[DPAMM_MERGE]);
411 expect(6, nMessages[DPAMM_DELETE]);
412 expect(0, nMessages[DPAMM_INSERT]);
413
414 /* DPAM_UNION */
415 pDPA_DeleteAllPtrs(dpa);
416 pDPA_InsertPtr(dpa, 0, (PVOID)1);
417 pDPA_InsertPtr(dpa, 1, (PVOID)3);
418 pDPA_InsertPtr(dpa, 2, (PVOID)5);
419 pDPA_DeleteAllPtrs(dpa2);
420 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
421 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
422 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
423
424 memset(nMessages, 0, sizeof(nMessages));
425 pDPA_Merge(dpa2, dpa, DPAM_UNION,
426 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
427 rc = CheckDPA(dpa2, 0x123456, &dw);
428 ok(rc ||
429 broken(!rc && dw == 0x23456), /* 4.7x */
430 "dw=0x%x\n", dw);
431
432 expect(0, nMessages[DPAMM_MERGE]);
433 expect(0, nMessages[DPAMM_DELETE]);
434 ok(nMessages[DPAMM_INSERT] == 3 ||
435 broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
436 "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
437
438 /* Merge dpa3 into dpa2 and dpa */
439 memset(nMessages, 0, sizeof(nMessages));
440 pDPA_Merge(dpa, dpa3, DPAM_UNION|DPAM_SORTED,
441 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
442 expect(3, nMessages[DPAMM_MERGE]);
443 expect(0, nMessages[DPAMM_DELETE]);
444 expect(3, nMessages[DPAMM_INSERT]);
445
446
447 pDPA_DeleteAllPtrs(dpa2);
448 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
449 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
450 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
451
452 memset(nMessages, 0, sizeof(nMessages));
453 pDPA_Merge(dpa2, dpa3, DPAM_UNION|DPAM_SORTED,
454 CB_CmpLT, CB_MergeInsertSrc, 0x1abe11ed);
455 expect(3, nMessages[DPAMM_MERGE]);
456 expect(0, nMessages[DPAMM_DELETE]);
457 ok(nMessages[DPAMM_INSERT] == 3 ||
458 broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
459 "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
460
461 rc = CheckDPA(dpa, 0x123456, &dw);
462 ok(rc, "dw=0x%x\n", dw);
463 rc = CheckDPA(dpa2, 0x123456, &dw);
464 ok(rc ||
465 broken(!rc), /* win98 */
466 "dw=0x%x\n", dw);
467 rc = CheckDPA(dpa3, 0x123456, &dw);
468 ok(rc, "dw=0x%x\n", dw);
469
470 pDPA_Destroy(dpa);
471 pDPA_Destroy(dpa2);
472 pDPA_Destroy(dpa3);
473 }
474
475 static void test_DPA_EnumCallback(void)
476 {
477 HDPA dpa;
478 BOOL rc;
479 DWORD dw;
480 INT i, ret;
481
482 if(!pDPA_EnumCallback)
483 {
484 win_skip("DPA_EnumCallback() not available\n");
485 return;
486 }
487
488 dpa = pDPA_Create(0);
489
490 for (i = 0; i < 6; i++)
491 {
492 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
493 ok(ret == i, "ret=%d\n", ret);
494 }
495
496 rc = CheckDPA(dpa, 0x123456, &dw);
497 ok(rc, "dw=0x%x\n", dw);
498
499 nEnum = 0;
500 /* test callback sets first 3 items to 7 */
501 pDPA_EnumCallback(dpa, CB_EnumFirstThree, dpa);
502 rc = CheckDPA(dpa, 0x777456, &dw);
503 ok(rc, "dw=0x%x\n", dw);
504 ok(nEnum == 3, "nEnum=%d\n", nEnum);
505
506 pDPA_Destroy(dpa);
507 }
508
509 static void test_DPA_DestroyCallback(void)
510 {
511 HDPA dpa;
512 INT i, ret;
513
514 if(!pDPA_DestroyCallback)
515 {
516 win_skip("DPA_DestroyCallback() not available\n");
517 return;
518 }
519
520 dpa = pDPA_Create(0);
521
522 for (i = 0; i < 3; i++)
523 {
524 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
525 ok(ret == i, "ret=%d\n", ret);
526 }
527
528 nEnum = 0;
529 pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa);
530 ok(nEnum == 3, "nEnum=%d\n", nEnum);
531 }
532
533 static void test_DPA_LoadStream(void)
534 {
535 static const WCHAR szStg[] = { 'S','t','g',0 };
536 IStorage* pStg = NULL;
537 IStream* pStm = NULL;
538 LARGE_INTEGER li;
539 ULARGE_INTEGER uli;
540 DWORD dwMode;
541 HRESULT hRes;
542 STREAMDATA header;
543 ULONG written, ret;
544 HDPA dpa;
545
546 if(!pDPA_LoadStream)
547 {
548 win_skip("DPA_LoadStream() not available. Skipping stream tests.\n");
549 return;
550 }
551
552 hRes = CoInitialize(NULL);
553 if (hRes != S_OK)
554 {
555 ok(0, "hResult: %d\n", hRes);
556 return;
557 }
558
559 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
560 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
561 expect(S_OK, hRes);
562
563 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
564 expect(S_OK, hRes);
565
566 /* write less than header size */
567 li.QuadPart = 0;
568 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
569 expect(S_OK, hRes);
570
571 memset(&header, 0, sizeof(header));
572 written = 0;
573 uli.QuadPart = sizeof(header)-1;
574 hRes = IStream_SetSize(pStm, uli);
575 expect(S_OK, hRes);
576 hRes = IStream_Write(pStm, &header, sizeof(header)-1, &written);
577 expect(S_OK, hRes);
578 written -= sizeof(header)-1;
579 expect(0, written);
580
581 li.QuadPart = 0;
582 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
583 expect(S_OK, hRes);
584
585 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
586 expect(E_FAIL, hRes);
587
588 /* check stream position after header read failed */
589 li.QuadPart = 0;
590 uli.QuadPart = 1;
591 hRes = IStream_Seek(pStm, li, STREAM_SEEK_CUR, &uli);
592 expect(S_OK, hRes);
593 ok(uli.QuadPart == 0, "Expected to position reset\n");
594
595 /* write valid header for empty DPA */
596 header.dwSize = sizeof(header);
597 header.dwData2 = 1;
598 header.dwItems = 0;
599 written = 0;
600
601 li.QuadPart = 0;
602 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
603 expect(S_OK, hRes);
604
605 uli.QuadPart = sizeof(header);
606 hRes = IStream_SetSize(pStm, uli);
607 expect(S_OK, hRes);
608
609 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
610 expect(S_OK, hRes);
611 written -= sizeof(header);
612 expect(0, written);
613
614 li.QuadPart = 0;
615 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
616 expect(S_OK, hRes);
617
618 dpa = NULL;
619 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
620 expect(S_OK, hRes);
621 DPA_Destroy(dpa);
622
623 /* try with altered dwData2 field */
624 header.dwSize = sizeof(header);
625 header.dwData2 = 2;
626 header.dwItems = 0;
627
628 li.QuadPart = 0;
629 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
630 expect(S_OK, hRes);
631 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
632 expect(S_OK, hRes);
633 written -= sizeof(header);
634 expect(0, written);
635
636 li.QuadPart = 0;
637 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
638 expect(S_OK, hRes);
639
640 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
641 expect(E_FAIL, hRes);
642
643 ret = IStream_Release(pStm);
644 ok(!ret, "ret=%d\n", ret);
645
646 ret = IStorage_Release(pStg);
647 ok(!ret, "ret=%d\n", ret);
648
649 CoUninitialize();
650 }
651
652 static void test_DPA_SaveStream(void)
653 {
654 HDPA dpa;
655 static const WCHAR szStg[] = { 'S','t','g',0 };
656 IStorage* pStg = NULL;
657 IStream* pStm = NULL;
658 DWORD dwMode, dw;
659 HRESULT hRes;
660 INT ret;
661 INT i;
662 BOOL rc;
663 LARGE_INTEGER liZero;
664
665 if(!pDPA_SaveStream)
666 {
667 win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
668 return;
669 }
670
671 hRes = CoInitialize(NULL);
672 if (hRes != S_OK)
673 {
674 ok(0, "hResult: %d\n", hRes);
675 return;
676 }
677
678 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
679 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
680 expect(S_OK, hRes);
681
682 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
683 expect(S_OK, hRes);
684
685 dpa = pDPA_Create(0);
686
687 /* simple parameter check */
688 hRes = pDPA_SaveStream(dpa, NULL, pStm, NULL);
689 ok(hRes == E_INVALIDARG ||
690 broken(hRes == S_OK) /* XP and below */, "Wrong result, %d\n", hRes);
691 if (0) {
692 /* crashes on XP */
693 hRes = pDPA_SaveStream(NULL, CB_Save, pStm, NULL);
694 expect(E_INVALIDARG, hRes);
695
696 hRes = pDPA_SaveStream(dpa, CB_Save, NULL, NULL);
697 expect(E_INVALIDARG, hRes);
698 }
699
700 /* saving/loading */
701 for (i = 0; i < 6; i++)
702 {
703 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
704 ok(ret == i, "ret=%d\n", ret);
705 }
706
707 liZero.QuadPart = 0;
708 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
709 expect(S_OK, hRes);
710
711 hRes = pDPA_SaveStream(dpa, CB_Save, pStm, (void*)0xdeadbeef);
712 expect(S_OK, hRes);
713 pDPA_Destroy(dpa);
714
715 liZero.QuadPart = 0;
716 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
717 expect(S_OK, hRes);
718 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
719 expect(S_OK, hRes);
720 rc = CheckDPA(dpa, 0x123456, &dw);
721 ok(rc, "dw=0x%x\n", dw);
722 pDPA_Destroy(dpa);
723
724 ret = IStream_Release(pStm);
725 ok(!ret, "ret=%d\n", ret);
726
727 ret = IStorage_Release(pStg);
728 ok(!ret, "ret=%d\n", ret);
729
730 CoUninitialize();
731 }
732
733 START_TEST(dpa)
734 {
735 HMODULE hcomctl32;
736
737 hcomctl32 = GetModuleHandleA("comctl32.dll");
738
739 if(!InitFunctionPtrs(hcomctl32))
740 {
741 win_skip("Needed functions are not available\n");
742 return;
743 }
744
745 test_dpa();
746 test_DPA_Merge();
747 test_DPA_EnumCallback();
748 test_DPA_DestroyCallback();
749 test_DPA_LoadStream();
750 test_DPA_SaveStream();
751 }