1 /* Unit test suite for SHLWAPI Compact List and IStream ordinal functions 2 * 3 * Copyright 2002 Jon Griffiths 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #define COBJMACROS 21 #include <stdarg.h> 22 23 #include "wine/test.h" 24 #include "windef.h" 25 #include "winbase.h" 26 #include "objbase.h" 27 28 typedef struct tagSHLWAPI_CLIST 29 { 30 ULONG ulSize; 31 ULONG ulId; 32 } SHLWAPI_CLIST, *LPSHLWAPI_CLIST; 33 34 typedef const SHLWAPI_CLIST* LPCSHLWAPI_CLIST; 35 36 /* Items to add */ 37 static const SHLWAPI_CLIST SHLWAPI_CLIST_items[] = 38 { 39 {4, 1}, 40 {8, 3}, 41 {12, 2}, 42 {16, 8}, 43 {20, 9}, 44 {3, 11}, 45 {9, 82}, 46 {33, 16}, 47 {32, 55}, 48 {24, 100}, 49 {39, 116}, 50 { 0, 0} 51 }; 52 53 /* Dummy IStream object for testing calls */ 54 struct dummystream 55 { 56 IStream IStream_iface; 57 LONG ref; 58 int readcalls; 59 BOOL failreadcall; 60 BOOL failreadsize; 61 BOOL readbeyondend; 62 BOOL readreturnlarge; 63 int writecalls; 64 BOOL failwritecall; 65 BOOL failwritesize; 66 int seekcalls; 67 int statcalls; 68 BOOL failstatcall; 69 LPCSHLWAPI_CLIST item; 70 ULARGE_INTEGER pos; 71 }; 72 73 static inline struct dummystream *impl_from_IStream(IStream *iface) 74 { 75 return CONTAINING_RECORD(iface, struct dummystream, IStream_iface); 76 } 77 78 static HRESULT WINAPI QueryInterface(IStream *iface, REFIID riid, void **ret_iface) 79 { 80 if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IStream, riid)) { 81 *ret_iface = iface; 82 IStream_AddRef(iface); 83 return S_OK; 84 } 85 trace("Unexpected REFIID %s\n", wine_dbgstr_guid(riid)); 86 *ret_iface = NULL; 87 return E_NOINTERFACE; 88 } 89 90 static ULONG WINAPI AddRef(IStream *iface) 91 { 92 struct dummystream *This = impl_from_IStream(iface); 93 94 return InterlockedIncrement(&This->ref); 95 } 96 97 static ULONG WINAPI Release(IStream *iface) 98 { 99 struct dummystream *This = impl_from_IStream(iface); 100 101 return InterlockedDecrement(&This->ref); 102 } 103 104 static HRESULT WINAPI Read(IStream *iface, void *lpMem, ULONG ulSize, ULONG *lpRead) 105 { 106 struct dummystream *This = impl_from_IStream(iface); 107 HRESULT hRet = S_OK; 108 109 ++This->readcalls; 110 if (This->failreadcall) 111 { 112 return STG_E_ACCESSDENIED; 113 } 114 else if (This->failreadsize) 115 { 116 *lpRead = ulSize + 8; 117 return S_OK; 118 } 119 else if (This->readreturnlarge) 120 { 121 *((ULONG*)lpMem) = 0xffff01; 122 *lpRead = ulSize; 123 This->readreturnlarge = FALSE; 124 return S_OK; 125 } 126 if (ulSize == sizeof(ULONG)) 127 { 128 /* Read size of item */ 129 *((ULONG*)lpMem) = This->item->ulSize ? This->item->ulSize + sizeof(SHLWAPI_CLIST) : 0; 130 *lpRead = ulSize; 131 } 132 else 133 { 134 unsigned int i; 135 char* buff = lpMem; 136 137 /* Read item data */ 138 if (!This->item->ulSize) 139 { 140 This->readbeyondend = TRUE; 141 *lpRead = 0; 142 return E_FAIL; /* Should never happen */ 143 } 144 *((ULONG*)lpMem) = This->item->ulId; 145 *lpRead = ulSize; 146 147 for (i = 0; i < This->item->ulSize; i++) 148 buff[4+i] = i*2; 149 150 This->item++; 151 } 152 return hRet; 153 } 154 155 static HRESULT WINAPI Write(IStream *iface, const void *lpMem, ULONG ulSize, ULONG *lpWritten) 156 { 157 struct dummystream *This = impl_from_IStream(iface); 158 HRESULT hRet = S_OK; 159 160 ++This->writecalls; 161 if (This->failwritecall) 162 { 163 return STG_E_ACCESSDENIED; 164 } 165 else if (This->failwritesize) 166 { 167 *lpWritten = 0; 168 } 169 else 170 *lpWritten = ulSize; 171 return hRet; 172 } 173 174 static HRESULT WINAPI Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, 175 ULARGE_INTEGER *plibNewPosition) 176 { 177 struct dummystream *This = impl_from_IStream(iface); 178 179 ++This->seekcalls; 180 This->pos.QuadPart = dlibMove.QuadPart; 181 if (plibNewPosition) 182 plibNewPosition->QuadPart = dlibMove.QuadPart; 183 return S_OK; 184 } 185 186 static HRESULT WINAPI Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) 187 { 188 struct dummystream *This = impl_from_IStream(iface); 189 190 ++This->statcalls; 191 if (This->failstatcall) 192 return E_FAIL; 193 if (pstatstg) 194 pstatstg->cbSize.QuadPart = This->pos.QuadPart; 195 return S_OK; 196 } 197 198 /* VTable */ 199 static IStreamVtbl iclvt = 200 { 201 QueryInterface, 202 AddRef, 203 Release, 204 Read, 205 Write, 206 Seek, 207 NULL, /* SetSize */ 208 NULL, /* CopyTo */ 209 NULL, /* Commit */ 210 NULL, /* Revert */ 211 NULL, /* LockRegion */ 212 NULL, /* UnlockRegion */ 213 Stat, 214 NULL /* Clone */ 215 }; 216 217 /* Function ptrs for ordinal calls */ 218 static HMODULE SHLWAPI_hshlwapi = 0; 219 220 static VOID (WINAPI *pSHLWAPI_19)(LPSHLWAPI_CLIST); 221 static BOOL (WINAPI *pSHLWAPI_20)(LPSHLWAPI_CLIST*,LPCSHLWAPI_CLIST); 222 static BOOL (WINAPI *pSHLWAPI_21)(LPSHLWAPI_CLIST*,ULONG); 223 static LPSHLWAPI_CLIST (WINAPI *pSHLWAPI_22)(LPSHLWAPI_CLIST,ULONG); 224 static HRESULT (WINAPI *pSHLWAPI_17)(IStream*, SHLWAPI_CLIST*); 225 static HRESULT (WINAPI *pSHLWAPI_18)(IStream*, SHLWAPI_CLIST**); 226 227 static BOOL (WINAPI *pSHLWAPI_166)(IStream*); 228 static HRESULT (WINAPI *pSHLWAPI_184)(IStream*, void*, ULONG); 229 static HRESULT (WINAPI *pSHLWAPI_212)(IStream*, const void*, ULONG); 230 static HRESULT (WINAPI *pSHLWAPI_213)(IStream*); 231 static HRESULT (WINAPI *pSHLWAPI_214)(IStream*, ULARGE_INTEGER*); 232 233 234 static BOOL InitFunctionPtrs(void) 235 { 236 SHLWAPI_hshlwapi = GetModuleHandleA("shlwapi.dll"); 237 238 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */ 239 if(!GetProcAddress(SHLWAPI_hshlwapi, "SHCreateStreamOnFileEx")){ 240 win_skip("Too old shlwapi version\n"); 241 return FALSE; 242 } 243 244 pSHLWAPI_17 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)17); 245 ok(pSHLWAPI_17 != 0, "No Ordinal 17\n"); 246 pSHLWAPI_18 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)18); 247 ok(pSHLWAPI_18 != 0, "No Ordinal 18\n"); 248 pSHLWAPI_19 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)19); 249 ok(pSHLWAPI_19 != 0, "No Ordinal 19\n"); 250 pSHLWAPI_20 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)20); 251 ok(pSHLWAPI_20 != 0, "No Ordinal 20\n"); 252 pSHLWAPI_21 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)21); 253 ok(pSHLWAPI_21 != 0, "No Ordinal 21\n"); 254 pSHLWAPI_22 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)22); 255 ok(pSHLWAPI_22 != 0, "No Ordinal 22\n"); 256 pSHLWAPI_166 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)166); 257 ok(pSHLWAPI_166 != 0, "No Ordinal 166\n"); 258 pSHLWAPI_184 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)184); 259 ok(pSHLWAPI_184 != 0, "No Ordinal 184\n"); 260 pSHLWAPI_212 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)212); 261 ok(pSHLWAPI_212 != 0, "No Ordinal 212\n"); 262 pSHLWAPI_213 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)213); 263 ok(pSHLWAPI_213 != 0, "No Ordinal 213\n"); 264 pSHLWAPI_214 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)214); 265 ok(pSHLWAPI_214 != 0, "No Ordinal 214\n"); 266 267 return TRUE; 268 } 269 270 static void InitDummyStream(struct dummystream *obj) 271 { 272 obj->IStream_iface.lpVtbl = &iclvt; 273 obj->ref = 1; 274 obj->readcalls = 0; 275 obj->failreadcall = FALSE; 276 obj->failreadsize = FALSE; 277 obj->readbeyondend = FALSE; 278 obj->readreturnlarge = FALSE; 279 obj->writecalls = 0; 280 obj->failwritecall = FALSE; 281 obj->failwritesize = FALSE; 282 obj->seekcalls = 0; 283 obj->statcalls = 0; 284 obj->failstatcall = FALSE; 285 obj->item = SHLWAPI_CLIST_items; 286 obj->pos.QuadPart = 0; 287 } 288 289 290 static void test_CList(void) 291 { 292 struct dummystream streamobj; 293 LPSHLWAPI_CLIST list = NULL; 294 LPCSHLWAPI_CLIST item = SHLWAPI_CLIST_items; 295 BOOL bRet; 296 HRESULT hRet; 297 LPSHLWAPI_CLIST inserted; 298 BYTE buff[64]; 299 unsigned int i; 300 301 if (!pSHLWAPI_17 || !pSHLWAPI_18 || !pSHLWAPI_19 || !pSHLWAPI_20 || 302 !pSHLWAPI_21 || !pSHLWAPI_22) 303 return; 304 305 /* Populate a list and test the items are added correctly */ 306 while (item->ulSize) 307 { 308 /* Create item and fill with data */ 309 inserted = (LPSHLWAPI_CLIST)buff; 310 inserted->ulSize = item->ulSize + sizeof(SHLWAPI_CLIST); 311 inserted->ulId = item->ulId; 312 for (i = 0; i < item->ulSize; i++) 313 buff[sizeof(SHLWAPI_CLIST)+i] = i*2; 314 315 /* Add it */ 316 bRet = pSHLWAPI_20(&list, inserted); 317 ok(bRet == TRUE, "failed list add\n"); 318 319 if (bRet == TRUE) 320 { 321 ok(list && list->ulSize, "item not added\n"); 322 323 /* Find it */ 324 inserted = pSHLWAPI_22(list, item->ulId); 325 ok(inserted != NULL, "lost after adding\n"); 326 327 ok(!inserted || inserted->ulId != ~0U, "find returned a container\n"); 328 329 /* Check size */ 330 if (inserted && inserted->ulSize & 0x3) 331 { 332 /* Contained */ 333 ok(inserted[-1].ulId == ~0U, "invalid size is not countained\n"); 334 ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST), 335 "container too small\n"); 336 } 337 else if (inserted) 338 { 339 ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST), 340 "id %d wrong size %d\n", inserted->ulId, inserted->ulSize); 341 } 342 if (inserted) 343 { 344 BOOL bDataOK = TRUE; 345 LPBYTE bufftest = (LPBYTE)inserted; 346 347 for (i = 0; i < inserted->ulSize - sizeof(SHLWAPI_CLIST); i++) 348 if (bufftest[sizeof(SHLWAPI_CLIST)+i] != i*2) 349 bDataOK = FALSE; 350 351 ok(bDataOK == TRUE, "data corrupted on insert\n"); 352 } 353 ok(!inserted || inserted->ulId==item->ulId, "find got wrong item\n"); 354 } 355 item++; 356 } 357 358 /* Write the list */ 359 InitDummyStream(&streamobj); 360 361 hRet = pSHLWAPI_17(&streamobj.IStream_iface, list); 362 ok(hRet == S_OK, "write failed\n"); 363 if (hRet == S_OK) 364 { 365 /* 1 call for each element, + 1 for OK (use our null element for this) */ 366 ok(streamobj.writecalls == ARRAY_SIZE(SHLWAPI_CLIST_items), "wrong call count\n"); 367 ok(streamobj.readcalls == 0,"called Read() in write\n"); 368 ok(streamobj.seekcalls == 0,"called Seek() in write\n"); 369 } 370 371 /* Failure cases for writing */ 372 InitDummyStream(&streamobj); 373 streamobj.failwritecall = TRUE; 374 hRet = pSHLWAPI_17(&streamobj.IStream_iface, list); 375 ok(hRet == STG_E_ACCESSDENIED, "changed object failure return\n"); 376 ok(streamobj.writecalls == 1, "called object after failure\n"); 377 ok(streamobj.readcalls == 0,"called Read() after failure\n"); 378 ok(streamobj.seekcalls == 0,"called Seek() after failure\n"); 379 380 InitDummyStream(&streamobj); 381 streamobj.failwritesize = TRUE; 382 hRet = pSHLWAPI_17(&streamobj.IStream_iface, list); 383 ok(hRet == STG_E_MEDIUMFULL || broken(hRet == E_FAIL) /* Win7 */, 384 "changed size failure return\n"); 385 ok(streamobj.writecalls == 1, "called object after size failure\n"); 386 ok(streamobj.readcalls == 0,"called Read() after failure\n"); 387 ok(streamobj.seekcalls == 0,"called Seek() after failure\n"); 388 389 /* Invalid inputs for adding */ 390 inserted = (LPSHLWAPI_CLIST)buff; 391 inserted->ulSize = sizeof(SHLWAPI_CLIST) -1; 392 inserted->ulId = 33; 393 bRet = pSHLWAPI_20(&list, inserted); 394 ok(bRet == FALSE, "Expected failure\n"); 395 396 inserted = pSHLWAPI_22(list, 33); 397 ok(inserted == NULL, "inserted bad element size\n"); 398 399 inserted = (LPSHLWAPI_CLIST)buff; 400 inserted->ulSize = 44; 401 inserted->ulId = ~0U; 402 bRet = pSHLWAPI_20(&list, inserted); 403 ok(bRet == FALSE, "Expected failure\n"); 404 405 item = SHLWAPI_CLIST_items; 406 407 /* Look for nonexistent item in populated list */ 408 inserted = pSHLWAPI_22(list, 99999999); 409 ok(inserted == NULL, "found a nonexistent item\n"); 410 411 while (item->ulSize) 412 { 413 /* Delete items */ 414 BOOL bRet = pSHLWAPI_21(&list, item->ulId); 415 ok(bRet == TRUE, "couldn't find item to delete\n"); 416 item++; 417 } 418 419 /* Look for nonexistent item in empty list */ 420 inserted = pSHLWAPI_22(list, 99999999); 421 ok(inserted == NULL, "found an item in empty list\n"); 422 423 /* Create a list by reading in data */ 424 InitDummyStream(&streamobj); 425 426 hRet = pSHLWAPI_18(&streamobj.IStream_iface, &list); 427 ok(hRet == S_OK, "failed create from Read()\n"); 428 if (hRet == S_OK) 429 { 430 ok(streamobj.readbeyondend == FALSE, "read beyond end\n"); 431 /* 2 calls per item, but only 1 for the terminator */ 432 ok(streamobj.readcalls == ARRAY_SIZE(SHLWAPI_CLIST_items) * 2 - 1, "wrong call count\n"); 433 ok(streamobj.writecalls == 0, "called Write() from create\n"); 434 ok(streamobj.seekcalls == 0,"called Seek() from create\n"); 435 436 item = SHLWAPI_CLIST_items; 437 438 /* Check the items were added correctly */ 439 while (item->ulSize) 440 { 441 inserted = pSHLWAPI_22(list, item->ulId); 442 ok(inserted != NULL, "lost after adding\n"); 443 444 ok(!inserted || inserted->ulId != ~0U, "find returned a container\n"); 445 446 /* Check size */ 447 if (inserted && inserted->ulSize & 0x3) 448 { 449 /* Contained */ 450 ok(inserted[-1].ulId == ~0U, "invalid size is not countained\n"); 451 ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST), 452 "container too small\n"); 453 } 454 else if (inserted) 455 { 456 ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST), 457 "id %d wrong size %d\n", inserted->ulId, inserted->ulSize); 458 } 459 ok(!inserted || inserted->ulId==item->ulId, "find got wrong item\n"); 460 if (inserted) 461 { 462 BOOL bDataOK = TRUE; 463 LPBYTE bufftest = (LPBYTE)inserted; 464 465 for (i = 0; i < inserted->ulSize - sizeof(SHLWAPI_CLIST); i++) 466 if (bufftest[sizeof(SHLWAPI_CLIST)+i] != i*2) 467 bDataOK = FALSE; 468 469 ok(bDataOK == TRUE, "data corrupted on insert\n"); 470 } 471 item++; 472 } 473 } 474 475 /* Failure cases for reading */ 476 InitDummyStream(&streamobj); 477 streamobj.failreadcall = TRUE; 478 hRet = pSHLWAPI_18(&streamobj.IStream_iface, &list); 479 ok(hRet == STG_E_ACCESSDENIED, "changed object failure return\n"); 480 ok(streamobj.readbeyondend == FALSE, "read beyond end\n"); 481 ok(streamobj.readcalls == 1, "called object after read failure\n"); 482 ok(streamobj.writecalls == 0,"called Write() after read failure\n"); 483 ok(streamobj.seekcalls == 0,"called Seek() after read failure\n"); 484 485 /* Read returns large object */ 486 InitDummyStream(&streamobj); 487 streamobj.readreturnlarge = TRUE; 488 hRet = pSHLWAPI_18(&streamobj.IStream_iface, &list); 489 ok(hRet == S_OK, "failed create from Read() with large item\n"); 490 ok(streamobj.readbeyondend == FALSE, "read beyond end\n"); 491 ok(streamobj.readcalls == 1,"wrong call count\n"); 492 ok(streamobj.writecalls == 0,"called Write() after read failure\n"); 493 ok(streamobj.seekcalls == 2,"wrong Seek() call count (%d)\n", streamobj.seekcalls); 494 495 pSHLWAPI_19(list); 496 } 497 498 static BOOL test_SHLWAPI_166(void) 499 { 500 struct dummystream streamobj; 501 BOOL bRet; 502 503 if (!pSHLWAPI_166) 504 return FALSE; 505 506 InitDummyStream(&streamobj); 507 bRet = pSHLWAPI_166(&streamobj.IStream_iface); 508 509 if (bRet != TRUE) 510 return FALSE; /* This version doesn't support stream ops on clists */ 511 512 ok(streamobj.readcalls == 0, "called Read()\n"); 513 ok(streamobj.writecalls == 0, "called Write()\n"); 514 ok(streamobj.seekcalls == 0, "called Seek()\n"); 515 ok(streamobj.statcalls == 1, "wrong call count\n"); 516 517 streamobj.statcalls = 0; 518 streamobj.pos.QuadPart = 50001; 519 520 bRet = pSHLWAPI_166(&streamobj.IStream_iface); 521 522 ok(bRet == FALSE, "failed after seek adjusted\n"); 523 ok(streamobj.readcalls == 0, "called Read()\n"); 524 ok(streamobj.writecalls == 0, "called Write()\n"); 525 ok(streamobj.seekcalls == 0, "called Seek()\n"); 526 ok(streamobj.statcalls == 1, "wrong call count\n"); 527 528 /* Failure cases */ 529 InitDummyStream(&streamobj); 530 streamobj.pos.QuadPart = 50001; 531 streamobj.failstatcall = TRUE; /* 1: Stat() Bad, Read() OK */ 532 bRet = pSHLWAPI_166(&streamobj.IStream_iface); 533 ok(bRet == FALSE, "should be FALSE after read is OK\n"); 534 ok(streamobj.readcalls == 1, "wrong call count\n"); 535 ok(streamobj.writecalls == 0, "called Write()\n"); 536 ok(streamobj.seekcalls == 1, "wrong call count\n"); 537 ok(streamobj.statcalls == 1, "wrong call count\n"); 538 ok(streamobj.pos.QuadPart == 0, "Didn't seek to start\n"); 539 540 InitDummyStream(&streamobj); 541 streamobj.pos.QuadPart = 50001; 542 streamobj.failstatcall = TRUE; 543 streamobj.failreadcall = TRUE; /* 2: Stat() Bad, Read() Bad Also */ 544 bRet = pSHLWAPI_166(&streamobj.IStream_iface); 545 ok(bRet == TRUE, "Should be true after read fails\n"); 546 ok(streamobj.readcalls == 1, "wrong call count\n"); 547 ok(streamobj.writecalls == 0, "called Write()\n"); 548 ok(streamobj.seekcalls == 0, "Called Seek()\n"); 549 ok(streamobj.statcalls == 1, "wrong call count\n"); 550 ok(streamobj.pos.QuadPart == 50001, "called Seek() after read failed\n"); 551 return TRUE; 552 } 553 554 static void test_SHLWAPI_184(void) 555 { 556 struct dummystream streamobj; 557 char buff[256]; 558 HRESULT hRet; 559 560 if (!pSHLWAPI_184) 561 return; 562 563 InitDummyStream(&streamobj); 564 hRet = pSHLWAPI_184(&streamobj.IStream_iface, buff, sizeof(buff)); 565 566 ok(hRet == S_OK, "failed Read()\n"); 567 ok(streamobj.readcalls == 1, "wrong call count\n"); 568 ok(streamobj.writecalls == 0, "called Write()\n"); 569 ok(streamobj.seekcalls == 0, "called Seek()\n"); 570 } 571 572 static void test_SHLWAPI_212(void) 573 { 574 struct dummystream streamobj; 575 char buff[256]; 576 HRESULT hRet; 577 578 if (!pSHLWAPI_212) 579 return; 580 581 InitDummyStream(&streamobj); 582 hRet = pSHLWAPI_212(&streamobj.IStream_iface, buff, sizeof(buff)); 583 584 ok(hRet == S_OK, "failed Write()\n"); 585 ok(streamobj.readcalls == 0, "called Read()\n"); 586 ok(streamobj.writecalls == 1, "wrong call count\n"); 587 ok(streamobj.seekcalls == 0, "called Seek()\n"); 588 } 589 590 static void test_SHLWAPI_213(void) 591 { 592 struct dummystream streamobj; 593 ULARGE_INTEGER ul; 594 LARGE_INTEGER ll; 595 HRESULT hRet; 596 597 if (!pSHLWAPI_213 || !pSHLWAPI_214) 598 return; 599 600 InitDummyStream(&streamobj); 601 ll.QuadPart = 5000l; 602 Seek(&streamobj.IStream_iface, ll, 0, NULL); /* Seek to 5000l */ 603 604 streamobj.seekcalls = 0; 605 pSHLWAPI_213(&streamobj.IStream_iface); /* Should rewind */ 606 ok(streamobj.statcalls == 0, "called Stat()\n"); 607 ok(streamobj.readcalls == 0, "called Read()\n"); 608 ok(streamobj.writecalls == 0, "called Write()\n"); 609 ok(streamobj.seekcalls == 1, "wrong call count\n"); 610 611 ul.QuadPart = 50001; 612 hRet = pSHLWAPI_214(&streamobj.IStream_iface, &ul); 613 ok(hRet == S_OK, "failed Stat()\n"); 614 ok(ul.QuadPart == 0, "213 didn't rewind stream\n"); 615 } 616 617 static void test_SHLWAPI_214(void) 618 { 619 struct dummystream streamobj; 620 ULARGE_INTEGER ul; 621 LARGE_INTEGER ll; 622 HRESULT hRet; 623 624 if (!pSHLWAPI_214) 625 return; 626 627 InitDummyStream(&streamobj); 628 ll.QuadPart = 5000l; 629 Seek(&streamobj.IStream_iface, ll, 0, NULL); 630 ul.QuadPart = 0; 631 streamobj.seekcalls = 0; 632 hRet = pSHLWAPI_214(&streamobj.IStream_iface, &ul); 633 634 ok(hRet == S_OK, "failed Stat()\n"); 635 ok(streamobj.statcalls == 1, "wrong call count\n"); 636 ok(streamobj.readcalls == 0, "called Read()\n"); 637 ok(streamobj.writecalls == 0, "called Write()\n"); 638 ok(streamobj.seekcalls == 0, "called Seek()\n"); 639 ok(ul.QuadPart == 5000l, "Stat gave wrong size\n"); 640 } 641 642 START_TEST(clist) 643 { 644 if(!InitFunctionPtrs()) 645 return; 646 647 test_CList(); 648 649 /* Test streaming if this version supports it */ 650 if (test_SHLWAPI_166()) 651 { 652 test_SHLWAPI_184(); 653 test_SHLWAPI_212(); 654 test_SHLWAPI_213(); 655 test_SHLWAPI_214(); 656 } 657 } 658