309b3335ec1a0bfe1a666c179c7f43e69052cb97
[reactos.git] / modules / rostests / winetests / shlwapi / clist.c
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 == sizeof(SHLWAPI_CLIST_items)/sizeof(SHLWAPI_CLIST),
367 "wrong call count\n");
368 ok(streamobj.readcalls == 0,"called Read() in write\n");
369 ok(streamobj.seekcalls == 0,"called Seek() in write\n");
370 }
371
372 /* Failure cases for writing */
373 InitDummyStream(&streamobj);
374 streamobj.failwritecall = TRUE;
375 hRet = pSHLWAPI_17(&streamobj.IStream_iface, list);
376 ok(hRet == STG_E_ACCESSDENIED, "changed object failure return\n");
377 ok(streamobj.writecalls == 1, "called object after failure\n");
378 ok(streamobj.readcalls == 0,"called Read() after failure\n");
379 ok(streamobj.seekcalls == 0,"called Seek() after failure\n");
380
381 InitDummyStream(&streamobj);
382 streamobj.failwritesize = TRUE;
383 hRet = pSHLWAPI_17(&streamobj.IStream_iface, list);
384 ok(hRet == STG_E_MEDIUMFULL || broken(hRet == E_FAIL) /* Win7 */,
385 "changed size failure return\n");
386 ok(streamobj.writecalls == 1, "called object after size failure\n");
387 ok(streamobj.readcalls == 0,"called Read() after failure\n");
388 ok(streamobj.seekcalls == 0,"called Seek() after failure\n");
389
390 /* Invalid inputs for adding */
391 inserted = (LPSHLWAPI_CLIST)buff;
392 inserted->ulSize = sizeof(SHLWAPI_CLIST) -1;
393 inserted->ulId = 33;
394 bRet = pSHLWAPI_20(&list, inserted);
395 ok(bRet == FALSE, "Expected failure\n");
396
397 inserted = pSHLWAPI_22(list, 33);
398 ok(inserted == NULL, "inserted bad element size\n");
399
400 inserted = (LPSHLWAPI_CLIST)buff;
401 inserted->ulSize = 44;
402 inserted->ulId = ~0U;
403 bRet = pSHLWAPI_20(&list, inserted);
404 ok(bRet == FALSE, "Expected failure\n");
405
406 item = SHLWAPI_CLIST_items;
407
408 /* Look for nonexistent item in populated list */
409 inserted = pSHLWAPI_22(list, 99999999);
410 ok(inserted == NULL, "found a nonexistent item\n");
411
412 while (item->ulSize)
413 {
414 /* Delete items */
415 BOOL bRet = pSHLWAPI_21(&list, item->ulId);
416 ok(bRet == TRUE, "couldn't find item to delete\n");
417 item++;
418 }
419
420 /* Look for nonexistent item in empty list */
421 inserted = pSHLWAPI_22(list, 99999999);
422 ok(inserted == NULL, "found an item in empty list\n");
423
424 /* Create a list by reading in data */
425 InitDummyStream(&streamobj);
426
427 hRet = pSHLWAPI_18(&streamobj.IStream_iface, &list);
428 ok(hRet == S_OK, "failed create from Read()\n");
429 if (hRet == S_OK)
430 {
431 ok(streamobj.readbeyondend == FALSE, "read beyond end\n");
432 /* 2 calls per item, but only 1 for the terminator */
433 ok(streamobj.readcalls == sizeof(SHLWAPI_CLIST_items)/sizeof(SHLWAPI_CLIST)*2-1,
434 "wrong call count\n");
435 ok(streamobj.writecalls == 0, "called Write() from create\n");
436 ok(streamobj.seekcalls == 0,"called Seek() from create\n");
437
438 item = SHLWAPI_CLIST_items;
439
440 /* Check the items were added correctly */
441 while (item->ulSize)
442 {
443 inserted = pSHLWAPI_22(list, item->ulId);
444 ok(inserted != NULL, "lost after adding\n");
445
446 ok(!inserted || inserted->ulId != ~0U, "find returned a container\n");
447
448 /* Check size */
449 if (inserted && inserted->ulSize & 0x3)
450 {
451 /* Contained */
452 ok(inserted[-1].ulId == ~0U, "invalid size is not countained\n");
453 ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST),
454 "container too small\n");
455 }
456 else if (inserted)
457 {
458 ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST),
459 "id %d wrong size %d\n", inserted->ulId, inserted->ulSize);
460 }
461 ok(!inserted || inserted->ulId==item->ulId, "find got wrong item\n");
462 if (inserted)
463 {
464 BOOL bDataOK = TRUE;
465 LPBYTE bufftest = (LPBYTE)inserted;
466
467 for (i = 0; i < inserted->ulSize - sizeof(SHLWAPI_CLIST); i++)
468 if (bufftest[sizeof(SHLWAPI_CLIST)+i] != i*2)
469 bDataOK = FALSE;
470
471 ok(bDataOK == TRUE, "data corrupted on insert\n");
472 }
473 item++;
474 }
475 }
476
477 /* Failure cases for reading */
478 InitDummyStream(&streamobj);
479 streamobj.failreadcall = TRUE;
480 hRet = pSHLWAPI_18(&streamobj.IStream_iface, &list);
481 ok(hRet == STG_E_ACCESSDENIED, "changed object failure return\n");
482 ok(streamobj.readbeyondend == FALSE, "read beyond end\n");
483 ok(streamobj.readcalls == 1, "called object after read failure\n");
484 ok(streamobj.writecalls == 0,"called Write() after read failure\n");
485 ok(streamobj.seekcalls == 0,"called Seek() after read failure\n");
486
487 /* Read returns large object */
488 InitDummyStream(&streamobj);
489 streamobj.readreturnlarge = TRUE;
490 hRet = pSHLWAPI_18(&streamobj.IStream_iface, &list);
491 ok(hRet == S_OK, "failed create from Read() with large item\n");
492 ok(streamobj.readbeyondend == FALSE, "read beyond end\n");
493 ok(streamobj.readcalls == 1,"wrong call count\n");
494 ok(streamobj.writecalls == 0,"called Write() after read failure\n");
495 ok(streamobj.seekcalls == 2,"wrong Seek() call count (%d)\n", streamobj.seekcalls);
496
497 pSHLWAPI_19(list);
498 }
499
500 static BOOL test_SHLWAPI_166(void)
501 {
502 struct dummystream streamobj;
503 BOOL bRet;
504
505 if (!pSHLWAPI_166)
506 return FALSE;
507
508 InitDummyStream(&streamobj);
509 bRet = pSHLWAPI_166(&streamobj.IStream_iface);
510
511 if (bRet != TRUE)
512 return FALSE; /* This version doesn't support stream ops on clists */
513
514 ok(streamobj.readcalls == 0, "called Read()\n");
515 ok(streamobj.writecalls == 0, "called Write()\n");
516 ok(streamobj.seekcalls == 0, "called Seek()\n");
517 ok(streamobj.statcalls == 1, "wrong call count\n");
518
519 streamobj.statcalls = 0;
520 streamobj.pos.QuadPart = 50001;
521
522 bRet = pSHLWAPI_166(&streamobj.IStream_iface);
523
524 ok(bRet == FALSE, "failed after seek adjusted\n");
525 ok(streamobj.readcalls == 0, "called Read()\n");
526 ok(streamobj.writecalls == 0, "called Write()\n");
527 ok(streamobj.seekcalls == 0, "called Seek()\n");
528 ok(streamobj.statcalls == 1, "wrong call count\n");
529
530 /* Failure cases */
531 InitDummyStream(&streamobj);
532 streamobj.pos.QuadPart = 50001;
533 streamobj.failstatcall = TRUE; /* 1: Stat() Bad, Read() OK */
534 bRet = pSHLWAPI_166(&streamobj.IStream_iface);
535 ok(bRet == FALSE, "should be FALSE after read is OK\n");
536 ok(streamobj.readcalls == 1, "wrong call count\n");
537 ok(streamobj.writecalls == 0, "called Write()\n");
538 ok(streamobj.seekcalls == 1, "wrong call count\n");
539 ok(streamobj.statcalls == 1, "wrong call count\n");
540 ok(streamobj.pos.QuadPart == 0, "Didn't seek to start\n");
541
542 InitDummyStream(&streamobj);
543 streamobj.pos.QuadPart = 50001;
544 streamobj.failstatcall = TRUE;
545 streamobj.failreadcall = TRUE; /* 2: Stat() Bad, Read() Bad Also */
546 bRet = pSHLWAPI_166(&streamobj.IStream_iface);
547 ok(bRet == TRUE, "Should be true after read fails\n");
548 ok(streamobj.readcalls == 1, "wrong call count\n");
549 ok(streamobj.writecalls == 0, "called Write()\n");
550 ok(streamobj.seekcalls == 0, "Called Seek()\n");
551 ok(streamobj.statcalls == 1, "wrong call count\n");
552 ok(streamobj.pos.QuadPart == 50001, "called Seek() after read failed\n");
553 return TRUE;
554 }
555
556 static void test_SHLWAPI_184(void)
557 {
558 struct dummystream streamobj;
559 char buff[256];
560 HRESULT hRet;
561
562 if (!pSHLWAPI_184)
563 return;
564
565 InitDummyStream(&streamobj);
566 hRet = pSHLWAPI_184(&streamobj.IStream_iface, buff, sizeof(buff));
567
568 ok(hRet == S_OK, "failed Read()\n");
569 ok(streamobj.readcalls == 1, "wrong call count\n");
570 ok(streamobj.writecalls == 0, "called Write()\n");
571 ok(streamobj.seekcalls == 0, "called Seek()\n");
572 }
573
574 static void test_SHLWAPI_212(void)
575 {
576 struct dummystream streamobj;
577 char buff[256];
578 HRESULT hRet;
579
580 if (!pSHLWAPI_212)
581 return;
582
583 InitDummyStream(&streamobj);
584 hRet = pSHLWAPI_212(&streamobj.IStream_iface, buff, sizeof(buff));
585
586 ok(hRet == S_OK, "failed Write()\n");
587 ok(streamobj.readcalls == 0, "called Read()\n");
588 ok(streamobj.writecalls == 1, "wrong call count\n");
589 ok(streamobj.seekcalls == 0, "called Seek()\n");
590 }
591
592 static void test_SHLWAPI_213(void)
593 {
594 struct dummystream streamobj;
595 ULARGE_INTEGER ul;
596 LARGE_INTEGER ll;
597 HRESULT hRet;
598
599 if (!pSHLWAPI_213 || !pSHLWAPI_214)
600 return;
601
602 InitDummyStream(&streamobj);
603 ll.QuadPart = 5000l;
604 Seek(&streamobj.IStream_iface, ll, 0, NULL); /* Seek to 5000l */
605
606 streamobj.seekcalls = 0;
607 pSHLWAPI_213(&streamobj.IStream_iface); /* Should rewind */
608 ok(streamobj.statcalls == 0, "called Stat()\n");
609 ok(streamobj.readcalls == 0, "called Read()\n");
610 ok(streamobj.writecalls == 0, "called Write()\n");
611 ok(streamobj.seekcalls == 1, "wrong call count\n");
612
613 ul.QuadPart = 50001;
614 hRet = pSHLWAPI_214(&streamobj.IStream_iface, &ul);
615 ok(hRet == S_OK, "failed Stat()\n");
616 ok(ul.QuadPart == 0, "213 didn't rewind stream\n");
617 }
618
619 static void test_SHLWAPI_214(void)
620 {
621 struct dummystream streamobj;
622 ULARGE_INTEGER ul;
623 LARGE_INTEGER ll;
624 HRESULT hRet;
625
626 if (!pSHLWAPI_214)
627 return;
628
629 InitDummyStream(&streamobj);
630 ll.QuadPart = 5000l;
631 Seek(&streamobj.IStream_iface, ll, 0, NULL);
632 ul.QuadPart = 0;
633 streamobj.seekcalls = 0;
634 hRet = pSHLWAPI_214(&streamobj.IStream_iface, &ul);
635
636 ok(hRet == S_OK, "failed Stat()\n");
637 ok(streamobj.statcalls == 1, "wrong call count\n");
638 ok(streamobj.readcalls == 0, "called Read()\n");
639 ok(streamobj.writecalls == 0, "called Write()\n");
640 ok(streamobj.seekcalls == 0, "called Seek()\n");
641 ok(ul.QuadPart == 5000l, "Stat gave wrong size\n");
642 }
643
644 START_TEST(clist)
645 {
646 if(!InitFunctionPtrs())
647 return;
648
649 test_CList();
650
651 /* Test streaming if this version supports it */
652 if (test_SHLWAPI_166())
653 {
654 test_SHLWAPI_184();
655 test_SHLWAPI_212();
656 test_SHLWAPI_213();
657 test_SHLWAPI_214();
658 }
659 }