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