[COMCTL32_WINETEST]
[reactos.git] / 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 #define COBJMACROS
23
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "commctrl.h"
30 #include "objidl.h"
31
32 #include "wine/test.h"
33
34 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
35
36 typedef struct _STREAMDATA
37 {
38 DWORD dwSize;
39 DWORD dwData2;
40 DWORD dwItems;
41 } STREAMDATA, *PSTREAMDATA;
42
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);
61
62 #define COMCTL32_GET_PROC(func, ord) \
63 ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \
64 : (trace( #func " not exported\n"), 0))
65
66 static BOOL InitFunctionPtrs(HMODULE hcomctl32)
67 {
68 /* 4.00+ */
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))
82 {
83 /* 4.71+ */
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);
89
90 return TRUE;
91 }
92
93 return FALSE;
94 }
95
96 /* Callbacks */
97 static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp)
98 {
99 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
100 return p1 < p2 ? -1 : p1 > p2 ? 1 : 0;
101 }
102
103 static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp)
104 {
105 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
106 return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
107 }
108
109 /* merge callback messages counter
110 DPAMM_MERGE 1
111 DPAMM_DELETE 2
112 DPAMM_INSERT 3 */
113 static INT nMessages[4];
114
115 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
116 {
117 nMessages[op]++;
118 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
119 return p1;
120 }
121
122 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
123 {
124 nMessages[op]++;
125 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
126 return ((PCHAR)p2)+1;
127 }
128
129 static INT nEnum;
130
131 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
132 {
133 INT i;
134
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;
140 }
141
142 static HRESULT CALLBACK CB_Save(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
143 {
144 HRESULT hRes;
145
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;
152 }
153
154 static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
155 {
156 HRESULT hRes;
157 INT iOldPos;
158
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;
167 }
168
169 static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
170 {
171 DWORD dwOut = 0;
172 INT i;
173
174 for(i = 0; i < 8;)
175 {
176 ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++);
177 if(!ulItem) break;
178 dwOut = dwOut << 4 | (ulItem & 0xf);
179 }
180
181 *pdwOut = dwOut;
182
183 if(dwOut != dwIn)
184 {
185 pDPA_DeleteAllPtrs(dpa);
186
187 do
188 {
189 pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf));
190 dwIn >>= 4;
191 }
192 while(dwIn);
193
194 return FALSE;
195 }
196
197 return TRUE;
198 }
199
200 static void test_dpa(void)
201 {
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;
209
210 GetSystemInfo(&si);
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 ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
217 "ret=%d error=%d\n", ret, GetLastError());
218
219 dpa = pDPA_Create(0);
220 ok(dpa != NULL, "\n");
221
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);
228
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);
241
242 rc=CheckDPA(dpa, 0x516324, &dw);
243 ok(rc, "dw=0x%x\n", dw);
244
245 for(i = 1; i <= 6; i++)
246 {
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, 0xdeadbeef, 0);
251 ok(j == k, "j=%d k=%d\n", j, k);
252 }
253
254 /* Sort DPA */
255 ok(pDPA_Sort(dpa, CB_CmpGT, 0xdeadbeef), "\n");
256 rc=CheckDPA(dpa, 0x654321, &dw);
257 ok(rc, "dw=0x%x\n", dw);
258
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");
266
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);
272
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);
279
280 for(i = 1; i <= 6; i++)
281 {
282 INT j;
283
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);
289
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);
296 }
297
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);
301
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);
307
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);
313
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);
326
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);
332
333 /* When doing a binary search while claiming reverse order all indexes
334 * should be bogus */
335 for(i = 0; i < 6; i++)
336 {
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);
340 }
341
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);
346
347 pDPA_DeleteAllPtrs(dpa2);
348 rc=CheckDPA(dpa2, 0, &dw2);
349 ok(rc, "dw2=0x%x\n", dw2);
350
351 pDPA_Destroy(dpa);
352 pDPA_Destroy(dpa2);
353 pDPA_Destroy(dpa3);
354 }
355
356 static void test_DPA_Merge(void)
357 {
358 HDPA dpa, dpa2, dpa3;
359 INT ret, i;
360 DWORD dw;
361 BOOL rc;
362
363 if(!pDPA_Merge)
364 {
365 win_skip("DPA_Merge() not available\n");
366 return;
367 }
368
369 dpa = pDPA_Create(0);
370 dpa2 = pDPA_Create(0);
371 dpa3 = pDPA_Create(0);
372
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);
379
380 rc = CheckDPA(dpa, 0x135, &dw);
381 ok(rc, "dw=0x%x\n", dw);
382
383 for (i = 0; i < 6; i++)
384 {
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);
389 }
390
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);
395
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);
402
403 expect(3, nMessages[DPAMM_MERGE]);
404 expect(3, nMessages[DPAMM_DELETE]);
405 expect(0, nMessages[DPAMM_INSERT]);
406
407 for (i = 0; i < 6; i++)
408 {
409 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
410 ok(ret == i, "ret=%d\n", ret);
411 }
412
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);
419
420 expect(3, nMessages[DPAMM_MERGE]);
421 expect(6, nMessages[DPAMM_DELETE]);
422 expect(0, nMessages[DPAMM_INSERT]);
423
424 /* DPAM_UNION */
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);
433
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);
438 ok(rc ||
439 broken(!rc && dw == 0x23456), /* 4.7x */
440 "dw=0x%x\n", dw);
441
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]);
447
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]);
455
456
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);
461
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]);
470
471 rc = CheckDPA(dpa, 0x123456, &dw);
472 ok(rc, "dw=0x%x\n", dw);
473 rc = CheckDPA(dpa2, 0x123456, &dw);
474 ok(rc ||
475 broken(!rc), /* win98 */
476 "dw=0x%x\n", dw);
477 rc = CheckDPA(dpa3, 0x123456, &dw);
478 ok(rc, "dw=0x%x\n", dw);
479
480 pDPA_Destroy(dpa);
481 pDPA_Destroy(dpa2);
482 pDPA_Destroy(dpa3);
483 }
484
485 static void test_DPA_EnumCallback(void)
486 {
487 HDPA dpa;
488 BOOL rc;
489 DWORD dw;
490 INT i, ret;
491
492 if(!pDPA_EnumCallback)
493 {
494 win_skip("DPA_EnumCallback() not available\n");
495 return;
496 }
497
498 dpa = pDPA_Create(0);
499
500 for (i = 0; i < 6; i++)
501 {
502 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
503 ok(ret == i, "ret=%d\n", ret);
504 }
505
506 rc = CheckDPA(dpa, 0x123456, &dw);
507 ok(rc, "dw=0x%x\n", dw);
508
509 nEnum = 0;
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);
515
516 pDPA_Destroy(dpa);
517 }
518
519 static void test_DPA_DestroyCallback(void)
520 {
521 HDPA dpa;
522 INT i, ret;
523
524 if(!pDPA_DestroyCallback)
525 {
526 win_skip("DPA_DestroyCallback() not available\n");
527 return;
528 }
529
530 dpa = pDPA_Create(0);
531
532 for (i = 0; i < 3; i++)
533 {
534 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
535 ok(ret == i, "ret=%d\n", ret);
536 }
537
538 nEnum = 0;
539 pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa);
540 ok(nEnum == 3, "nEnum=%d\n", nEnum);
541 }
542
543 static void test_DPA_LoadStream(void)
544 {
545 static const WCHAR szStg[] = { 'S','t','g',0 };
546 IStorage* pStg = NULL;
547 IStream* pStm = NULL;
548 LARGE_INTEGER li;
549 ULARGE_INTEGER uli;
550 DWORD dwMode;
551 HRESULT hRes;
552 STREAMDATA header;
553 ULONG written, ret;
554 HDPA dpa;
555
556 if(!pDPA_LoadStream)
557 {
558 win_skip("DPA_LoadStream() not available. Skipping stream tests.\n");
559 return;
560 }
561
562 hRes = CoInitialize(NULL);
563 if (hRes != S_OK)
564 {
565 ok(0, "hResult: %d\n", hRes);
566 return;
567 }
568
569 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
570 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
571 expect(S_OK, hRes);
572
573 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
574 expect(S_OK, hRes);
575
576 /* write less than header size */
577 li.QuadPart = 0;
578 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
579 expect(S_OK, hRes);
580
581 memset(&header, 0, sizeof(header));
582 written = 0;
583 uli.QuadPart = sizeof(header)-1;
584 hRes = IStream_SetSize(pStm, uli);
585 expect(S_OK, hRes);
586 hRes = IStream_Write(pStm, &header, sizeof(header)-1, &written);
587 expect(S_OK, hRes);
588 written -= sizeof(header)-1;
589 expect(0, written);
590
591 li.QuadPart = 0;
592 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
593 expect(S_OK, hRes);
594
595 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
596 expect(E_FAIL, hRes);
597
598 /* check stream position after header read failed */
599 li.QuadPart = 0;
600 uli.QuadPart = 1;
601 hRes = IStream_Seek(pStm, li, STREAM_SEEK_CUR, &uli);
602 expect(S_OK, hRes);
603 ok(uli.QuadPart == 0, "Expected to position reset\n");
604
605 /* write valid header for empty DPA */
606 header.dwSize = sizeof(header);
607 header.dwData2 = 1;
608 header.dwItems = 0;
609 written = 0;
610
611 li.QuadPart = 0;
612 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
613 expect(S_OK, hRes);
614
615 uli.QuadPart = sizeof(header);
616 hRes = IStream_SetSize(pStm, uli);
617 expect(S_OK, hRes);
618
619 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
620 expect(S_OK, hRes);
621 written -= sizeof(header);
622 expect(0, written);
623
624 li.QuadPart = 0;
625 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
626 expect(S_OK, hRes);
627
628 dpa = NULL;
629 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
630 expect(S_OK, hRes);
631 DPA_Destroy(dpa);
632
633 /* try with altered dwData2 field */
634 header.dwSize = sizeof(header);
635 header.dwData2 = 2;
636 header.dwItems = 0;
637
638 li.QuadPart = 0;
639 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
640 expect(S_OK, hRes);
641 hRes = IStream_Write(pStm, &header, sizeof(header), &written);
642 expect(S_OK, hRes);
643 written -= sizeof(header);
644 expect(0, written);
645
646 li.QuadPart = 0;
647 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
648 expect(S_OK, hRes);
649
650 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
651 expect(E_FAIL, hRes);
652
653 ret = IStream_Release(pStm);
654 ok(!ret, "ret=%d\n", ret);
655
656 ret = IStorage_Release(pStg);
657 ok(!ret, "ret=%d\n", ret);
658
659 CoUninitialize();
660 }
661
662 static void test_DPA_SaveStream(void)
663 {
664 HDPA dpa;
665 static const WCHAR szStg[] = { 'S','t','g',0 };
666 IStorage* pStg = NULL;
667 IStream* pStm = NULL;
668 DWORD dwMode, dw;
669 HRESULT hRes;
670 ULONG ret;
671 INT i;
672 BOOL rc;
673 LARGE_INTEGER liZero;
674
675 if(!pDPA_SaveStream)
676 {
677 win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
678 return;
679 }
680
681 hRes = CoInitialize(NULL);
682 if (hRes != S_OK)
683 {
684 ok(0, "hResult: %d\n", hRes);
685 return;
686 }
687
688 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
689 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
690 expect(S_OK, hRes);
691
692 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
693 expect(S_OK, hRes);
694
695 dpa = pDPA_Create(0);
696
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);
701 if (0) {
702 /* crashes on XP */
703 hRes = pDPA_SaveStream(NULL, CB_Save, pStm, NULL);
704 expect(E_INVALIDARG, hRes);
705
706 hRes = pDPA_SaveStream(dpa, CB_Save, NULL, NULL);
707 expect(E_INVALIDARG, hRes);
708 }
709
710 /* saving/loading */
711 for (i = 0; i < 6; i++)
712 {
713 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
714 ok(ret == i, "ret=%d\n", ret);
715 }
716
717 liZero.QuadPart = 0;
718 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
719 expect(S_OK, hRes);
720
721 hRes = pDPA_SaveStream(dpa, CB_Save, pStm, (void*)0xdeadbeef);
722 expect(S_OK, hRes);
723 pDPA_Destroy(dpa);
724
725 liZero.QuadPart = 0;
726 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
727 expect(S_OK, hRes);
728 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
729 expect(S_OK, hRes);
730 rc = CheckDPA(dpa, 0x123456, &dw);
731 ok(rc, "dw=0x%x\n", dw);
732 pDPA_Destroy(dpa);
733
734 ret = IStream_Release(pStm);
735 ok(!ret, "ret=%d\n", ret);
736
737 ret = IStorage_Release(pStg);
738 ok(!ret, "ret=%d\n", ret);
739
740 CoUninitialize();
741 }
742
743 START_TEST(dpa)
744 {
745 HMODULE hcomctl32;
746
747 hcomctl32 = GetModuleHandleA("comctl32.dll");
748
749 if(!InitFunctionPtrs(hcomctl32))
750 {
751 win_skip("Needed functions are not available\n");
752 return;
753 }
754
755 test_dpa();
756 test_DPA_Merge();
757 test_DPA_EnumCallback();
758 test_DPA_DestroyCallback();
759 test_DPA_LoadStream();
760 test_DPA_SaveStream();
761 }