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 } 752