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 #include "v6util.h" 34 35 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) 36 37 typedef struct _STREAMDATA 38 { 39 DWORD dwSize; 40 DWORD dwData2; 41 DWORD dwItems; 42 } STREAMDATA, *PSTREAMDATA; 43 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); 62 63 static void init_functions(void) 64 { 65 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll"); 66 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); 82 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 90 } 91 92 /* Callbacks */ 93 static INT CALLBACK CB_CmpLT(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 static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp) 100 { 101 ok(lp == 0x1abe11ed, "lp=%ld\n", lp); 102 return p1 > p2 ? -1 : p1 < p2 ? 1 : 0; 103 } 104 105 /* merge callback messages counter 106 DPAMM_MERGE 1 107 DPAMM_DELETE 2 108 DPAMM_INSERT 3 */ 109 static INT nMessages[4]; 110 111 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) 112 { 113 nMessages[op]++; 114 ok(lp == 0x1abe11ed, "lp=%ld\n", lp); 115 return p1; 116 } 117 118 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) 119 { 120 nMessages[op]++; 121 ok(lp == 0x1abe11ed, "lp=%ld\n", lp); 122 return ((PCHAR)p2)+1; 123 } 124 125 static INT nEnum; 126 127 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp) 128 { 129 INT i; 130 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; 136 } 137 138 static HRESULT CALLBACK CB_Save(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp) 139 { 140 HRESULT hRes; 141 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; 148 } 149 150 static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp) 151 { 152 HRESULT hRes; 153 INT iOldPos; 154 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; 163 } 164 165 static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut) 166 { 167 DWORD dwOut = 0; 168 INT i; 169 170 for(i = 0; i < 8;) 171 { 172 ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++); 173 if(!ulItem) break; 174 dwOut = dwOut << 4 | (ulItem & 0xf); 175 } 176 177 *pdwOut = dwOut; 178 179 if(dwOut != dwIn) 180 { 181 pDPA_DeleteAllPtrs(dpa); 182 183 do 184 { 185 pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf)); 186 dwIn >>= 4; 187 } 188 while(dwIn); 189 190 return FALSE; 191 } 192 193 return TRUE; 194 } 195 196 static void test_dpa(void) 197 { 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; 205 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()); 214 215 dpa = pDPA_Create(0); 216 ok(dpa != NULL, "\n"); 217 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); 224 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); 237 238 rc=CheckDPA(dpa, 0x516324, &dw); 239 ok(rc, "dw=0x%x\n", dw); 240 241 for(i = 1; i <= 6; i++) 242 { 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); 248 } 249 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); 254 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"); 262 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); 268 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); 275 276 for(i = 1; i <= 6; i++) 277 { 278 INT j; 279 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); 285 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); 292 } 293 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); 297 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); 303 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); 309 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); 322 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); 328 329 /* When doing a binary search while claiming reverse order all indexes 330 * should be bogus */ 331 for(i = 0; i < 6; i++) 332 { 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); 336 } 337 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); 342 343 pDPA_DeleteAllPtrs(dpa2); 344 rc=CheckDPA(dpa2, 0, &dw2); 345 ok(rc, "dw2=0x%x\n", dw2); 346 347 pDPA_Destroy(dpa); 348 pDPA_Destroy(dpa2); 349 pDPA_Destroy(dpa3); 350 } 351 352 static void test_DPA_Merge(void) 353 { 354 HDPA dpa, dpa2, dpa3; 355 INT ret, i; 356 DWORD dw; 357 BOOL rc; 358 359 if(!pDPA_Merge) 360 { 361 win_skip("DPA_Merge() not available\n"); 362 return; 363 } 364 365 dpa = pDPA_Create(0); 366 dpa2 = pDPA_Create(0); 367 dpa3 = pDPA_Create(0); 368 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); 375 376 rc = CheckDPA(dpa, 0x135, &dw); 377 ok(rc, "dw=0x%x\n", dw); 378 379 for (i = 0; i < 6; i++) 380 { 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); 385 } 386 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); 391 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); 398 399 expect(3, nMessages[DPAMM_MERGE]); 400 expect(3, nMessages[DPAMM_DELETE]); 401 expect(0, nMessages[DPAMM_INSERT]); 402 403 for (i = 0; i < 6; i++) 404 { 405 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i)); 406 ok(ret == i, "ret=%d\n", ret); 407 } 408 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); 415 416 expect(3, nMessages[DPAMM_MERGE]); 417 expect(6, nMessages[DPAMM_DELETE]); 418 expect(0, nMessages[DPAMM_INSERT]); 419 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); 429 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); 437 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]); 443 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]); 451 452 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); 457 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]); 466 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); 475 476 pDPA_Destroy(dpa); 477 pDPA_Destroy(dpa2); 478 pDPA_Destroy(dpa3); 479 } 480 481 static void test_DPA_EnumCallback(void) 482 { 483 HDPA dpa; 484 BOOL rc; 485 DWORD dw; 486 INT i, ret; 487 488 if(!pDPA_EnumCallback) 489 { 490 win_skip("DPA_EnumCallback() not available\n"); 491 return; 492 } 493 494 dpa = pDPA_Create(0); 495 496 for (i = 0; i < 6; i++) 497 { 498 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1)); 499 ok(ret == i, "ret=%d\n", ret); 500 } 501 502 rc = CheckDPA(dpa, 0x123456, &dw); 503 ok(rc, "dw=0x%x\n", dw); 504 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); 511 512 pDPA_Destroy(dpa); 513 } 514 515 static void test_DPA_DestroyCallback(void) 516 { 517 HDPA dpa; 518 INT i, ret; 519 520 if(!pDPA_DestroyCallback) 521 { 522 win_skip("DPA_DestroyCallback() not available\n"); 523 return; 524 } 525 526 dpa = pDPA_Create(0); 527 528 for (i = 0; i < 3; i++) 529 { 530 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1)); 531 ok(ret == i, "ret=%d\n", ret); 532 } 533 534 nEnum = 0; 535 pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa); 536 ok(nEnum == 3, "nEnum=%d\n", nEnum); 537 } 538 539 static void test_DPA_LoadStream(void) 540 { 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; 551 552 if(!pDPA_LoadStream) 553 { 554 win_skip("DPA_LoadStream() not available. Skipping stream tests.\n"); 555 return; 556 } 557 558 hRes = CoInitialize(NULL); 559 if (hRes != S_OK) 560 { 561 ok(0, "hResult: %d\n", hRes); 562 return; 563 } 564 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); 568 569 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm); 570 expect(S_OK, hRes); 571 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); 576 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); 586 587 li.QuadPart = 0; 588 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); 589 expect(S_OK, hRes); 590 591 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL); 592 expect(E_FAIL, hRes); 593 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"); 600 601 /* write valid header for empty DPA */ 602 header.dwSize = sizeof(header); 603 header.dwData2 = 1; 604 header.dwItems = 0; 605 written = 0; 606 607 li.QuadPart = 0; 608 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); 609 expect(S_OK, hRes); 610 611 uli.QuadPart = sizeof(header); 612 hRes = IStream_SetSize(pStm, uli); 613 expect(S_OK, hRes); 614 615 hRes = IStream_Write(pStm, &header, sizeof(header), &written); 616 expect(S_OK, hRes); 617 written -= sizeof(header); 618 expect(0, written); 619 620 li.QuadPart = 0; 621 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); 622 expect(S_OK, hRes); 623 624 dpa = NULL; 625 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL); 626 expect(S_OK, hRes); 627 pDPA_Destroy(dpa); 628 629 /* try with altered dwData2 field */ 630 header.dwSize = sizeof(header); 631 header.dwData2 = 2; 632 header.dwItems = 0; 633 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); 641 642 li.QuadPart = 0; 643 hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); 644 expect(S_OK, hRes); 645 646 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef); 647 expect(E_FAIL, hRes); 648 649 ret = IStream_Release(pStm); 650 ok(!ret, "ret=%d\n", ret); 651 652 ret = IStorage_Release(pStg); 653 ok(!ret, "ret=%d\n", ret); 654 655 CoUninitialize(); 656 } 657 658 static void test_DPA_SaveStream(void) 659 { 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; 670 671 if(!pDPA_SaveStream) 672 { 673 win_skip("DPA_SaveStream() not available. Skipping stream tests.\n"); 674 return; 675 } 676 677 hRes = CoInitialize(NULL); 678 if (hRes != S_OK) 679 { 680 ok(0, "hResult: %d\n", hRes); 681 return; 682 } 683 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); 687 688 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm); 689 expect(S_OK, hRes); 690 691 dpa = pDPA_Create(0); 692 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); 701 702 hRes = pDPA_SaveStream(dpa, CB_Save, NULL, NULL); 703 expect(E_INVALIDARG, hRes); 704 } 705 706 /* saving/loading */ 707 for (i = 0; i < 6; i++) 708 { 709 ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1)); 710 ok(ret == i, "ret=%d\n", ret); 711 } 712 713 liZero.QuadPart = 0; 714 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL); 715 expect(S_OK, hRes); 716 717 hRes = pDPA_SaveStream(dpa, CB_Save, pStm, (void*)0xdeadbeef); 718 expect(S_OK, hRes); 719 pDPA_Destroy(dpa); 720 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); 729 730 ret = IStream_Release(pStm); 731 ok(!ret, "ret=%d\n", ret); 732 733 ret = IStorage_Release(pStg); 734 ok(!ret, "ret=%d\n", ret); 735 736 CoUninitialize(); 737 } 738 739 START_TEST(dpa) 740 { 741 ULONG_PTR cookie; 742 HANDLE ctxt; 743 744 init_functions(); 745 746 test_dpa(); 747 test_DPA_Merge(); 748 test_DPA_EnumCallback(); 749 test_DPA_DestroyCallback(); 750 test_DPA_LoadStream(); 751 test_DPA_SaveStream(); 752 753 if (!load_v6_module(&cookie, &ctxt)) 754 return; 755 756 init_functions(); 757 758 test_dpa(); 759 test_DPA_Merge(); 760 test_DPA_EnumCallback(); 761 test_DPA_DestroyCallback(); 762 test_DPA_LoadStream(); 763 test_DPA_SaveStream(); 764 765 unload_v6_module(cookie, ctxt); 766 } 767