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