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
impl_from_IStream(IStream * iface)73 static inline struct dummystream *impl_from_IStream(IStream *iface)
74 {
75 return CONTAINING_RECORD(iface, struct dummystream, IStream_iface);
76 }
77
QueryInterface(IStream * iface,REFIID riid,void ** ret_iface)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
AddRef(IStream * iface)90 static ULONG WINAPI AddRef(IStream *iface)
91 {
92 struct dummystream *This = impl_from_IStream(iface);
93
94 return InterlockedIncrement(&This->ref);
95 }
96
Release(IStream * iface)97 static ULONG WINAPI Release(IStream *iface)
98 {
99 struct dummystream *This = impl_from_IStream(iface);
100
101 return InterlockedDecrement(&This->ref);
102 }
103
Read(IStream * iface,void * lpMem,ULONG ulSize,ULONG * lpRead)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
Write(IStream * iface,const void * lpMem,ULONG ulSize,ULONG * lpWritten)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
Seek(IStream * iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER * plibNewPosition)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
Stat(IStream * iface,STATSTG * pstatstg,DWORD grfStatFlag)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
InitFunctionPtrs(void)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
InitDummyStream(struct dummystream * obj)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
test_CList(void)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
test_SHLWAPI_166(void)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
test_SHLWAPI_184(void)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
test_SHLWAPI_212(void)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
test_SHLWAPI_213(void)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
test_SHLWAPI_214(void)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
START_TEST(clist)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