quartz: Fix discontinuities in wave parser.
[wine] / dlls / shlwapi / tests / istream.c
1 /* Unit test suite for SHLWAPI ShCreateStreamOnFile functions.
2  *
3  * Copyright 2008 Reece H. Dunn
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
22 #include <stdarg.h>
23 #include <stdio.h>
24
25 #include "wine/test.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
29 #include "shlwapi.h"
30
31
32 /* Function pointers for the SHCreateStreamOnFile functions */
33 static HMODULE hShlwapi;
34 static HRESULT (WINAPI *pSHCreateStreamOnFileA)(LPCSTR file, DWORD mode, IStream **stream);
35 static HRESULT (WINAPI *pSHCreateStreamOnFileW)(LPCWSTR file, DWORD mode, IStream **stream);
36 static HRESULT (WINAPI *pSHCreateStreamOnFileEx)(LPCWSTR file, DWORD mode, DWORD attributes, BOOL create, IStream *template, IStream **stream);
37
38
39 static void test_IStream_invalid_operations(IStream * stream, DWORD mode)
40 {
41     HRESULT ret;
42     IStream * clone;
43     ULONG refcount;
44     ULARGE_INTEGER uzero;
45     ULARGE_INTEGER uret;
46     LARGE_INTEGER zero;
47     ULONG count;
48     char data[256];
49
50     U(uzero).HighPart = 0;
51     U(uzero).LowPart = 0;
52     U(uret).HighPart = 0;
53     U(uret).LowPart = 0;
54     U(zero).HighPart = 0;
55     U(zero).LowPart = 0;
56
57     /* IStream::Read */
58
59     /* IStream_Read from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Read helper function. */
60
61     ret = stream->lpVtbl->Read(stream, NULL, 0, &count);
62     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
63
64     ret = stream->lpVtbl->Read(stream, data, 5, NULL);
65     ok(ret == S_FALSE || ret == S_OK, "expected S_FALSE or S_OK, got 0x%08x\n", ret);
66
67     ret = stream->lpVtbl->Read(stream, data, 0, NULL);
68     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
69
70     ret = stream->lpVtbl->Read(stream, data, 3, &count);
71     ok(ret == S_FALSE || ret == S_OK, "expected S_FALSE or S_OK, got 0x%08x\n", ret);
72
73     /* IStream::Write */
74
75     /* IStream_Write from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Write helper function. */
76
77     ret = stream->lpVtbl->Write(stream, NULL, 0, &count);
78     if (mode == STGM_READ)
79         ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
80     else
81         ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
82
83     strcpy(data, "Hello");
84     ret = stream->lpVtbl->Write(stream, data, 5, NULL);
85     if (mode == STGM_READ)
86         ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
87     else
88         ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
89
90     strcpy(data, "Hello");
91     ret = stream->lpVtbl->Write(stream, data, 0, NULL);
92     if (mode == STGM_READ)
93         ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
94     else
95         ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
96
97     strcpy(data, "Hello");
98     ret = stream->lpVtbl->Write(stream, data, 0, &count);
99     if (mode == STGM_READ)
100         ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
101     else
102         ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
103
104     strcpy(data, "Hello");
105     ret = stream->lpVtbl->Write(stream, data, 3, &count);
106     if (mode == STGM_READ)
107         ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
108     else
109         ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
110
111     /* IStream::Seek */
112
113     ret = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
114     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
115
116     ret = IStream_Seek(stream, zero, 20, NULL);
117     ok(ret == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", ret);
118
119     /* IStream::CopyTo */
120
121     ret = IStream_CopyTo(stream, NULL, uzero, &uret, &uret);
122     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
123
124     clone = NULL;
125     ret = IStream_CopyTo(stream, clone, uzero, &uret, &uret);
126     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
127
128     ret = IStream_CopyTo(stream, stream, uzero, &uret, &uret);
129     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
130
131     ret = IStream_CopyTo(stream, stream, uzero, &uret, NULL);
132     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
133
134     ret = IStream_CopyTo(stream, stream, uzero, NULL, &uret);
135     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
136
137     /* IStream::Commit */
138
139     ret = IStream_Commit(stream, STGC_DEFAULT);
140     ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
141
142     /* IStream::Revert */
143
144     ret = IStream_Revert(stream);
145     ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret);
146
147     /* IStream::LockRegion */
148
149     ret = IStream_LockRegion(stream, uzero, uzero, 0);
150     ok(ret == E_NOTIMPL /* XP */ || ret == S_OK /* Vista */,
151       "expected E_NOTIMPL or S_OK, got 0x%08x\n", ret);
152
153     /* IStream::UnlockRegion */
154
155     if (ret == E_NOTIMPL) /* XP */ {
156         ret = IStream_UnlockRegion(stream, uzero, uzero, 0);
157         ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret);
158     } else /* Vista */ {
159         ret = IStream_UnlockRegion(stream, uzero, uzero, 0);
160         ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
161
162         ret = IStream_UnlockRegion(stream, uzero, uzero, 0);
163         ok(ret == STG_E_LOCKVIOLATION, "expected STG_E_LOCKVIOLATION, got 0x%08x\n", ret);
164     }
165
166     /* IStream::Stat */
167
168     ret = IStream_Stat(stream, NULL, 0);
169     ok(ret == STG_E_INVALIDPOINTER, "expected STG_E_INVALIDPOINTER, got 0x%08x\n", ret);
170
171     /* IStream::Clone */
172
173     ret = IStream_Clone(stream, NULL);
174     ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret);
175
176     clone = NULL;
177     ret = IStream_Clone(stream, &clone);
178     ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret);
179     ok(clone == NULL, "expected a NULL IStream object, got %p\n", stream);
180
181     if (clone) {
182         refcount = IStream_Release(clone);
183         ok(refcount == 0, "expected 0, got %d\n", refcount);
184     }
185 }
186
187
188 static void test_SHCreateStreamOnFileA(DWORD mode)
189 {
190     IStream * stream;
191     HRESULT ret;
192     ULONG refcount;
193     static const char * test_file = "c:\\test.txt";
194
195     trace("SHCreateStreamOnFileA: testing mode %d\n", mode);
196
197     /* invalid arguments */
198
199     stream = NULL;
200     ret = (*pSHCreateStreamOnFileA)(NULL, mode, &stream);
201     todo_wine
202     ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), got 0x%08x\n", ret);
203     ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
204
205 #if 0 /* This test crashes on WinXP SP2 */
206     ret = (*pSHCreateStreamOnFileA)(test_file, mode, NULL);
207     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
208 #endif
209
210     stream = NULL;
211     ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CONVERT, &stream);
212     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
213     ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
214
215     stream = NULL;
216     ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_DELETEONRELEASE, &stream);
217     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
218     ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
219
220     stream = NULL;
221     ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_TRANSACTED, &stream);
222     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
223     ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
224
225     /* file does not exist */
226
227     stream = NULL;
228     ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE, &stream);
229     todo_wine
230     ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
231     ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
232
233     stream = NULL;
234     ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE, &stream);
235     todo_wine
236     ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret);
237     todo_wine
238     ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
239
240     if (stream) {
241         test_IStream_invalid_operations(stream, mode);
242
243         refcount = IStream_Release(stream);
244         ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
245     }
246
247     /* NOTE: don't delete the file, as it will be used for the file exists tests. */
248
249     /* file exists */
250
251     stream = NULL;
252     ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE, &stream);
253     todo_wine
254     ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret);
255     todo_wine
256     ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
257
258     if (stream) {
259         test_IStream_invalid_operations(stream, mode);
260
261         refcount = IStream_Release(stream);
262         ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
263     }
264
265     stream = NULL;
266     ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE, &stream);
267     todo_wine
268     ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret);
269     todo_wine
270     ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
271
272     if (stream) {
273         test_IStream_invalid_operations(stream, mode);
274
275         refcount = IStream_Release(stream);
276         ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
277
278         ok(DeleteFileA(test_file), "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n", test_file, GetLastError());
279     }
280 }
281
282
283 static void test_SHCreateStreamOnFileW(DWORD mode)
284 {
285     IStream * stream;
286     HRESULT ret;
287     ULONG refcount;
288     static const WCHAR test_file[] = { 'c', ':', '\\', 't', 'e', 's', 't', '.', 't', 'x', 't', '\0' };
289
290     trace("SHCreateStreamOnFileW: testing mode %d\n", mode);
291
292     /* invalid arguments */
293
294     stream = NULL;
295     ret = (*pSHCreateStreamOnFileW)(NULL, mode, &stream);
296     ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */
297        ret == E_INVALIDARG /* Vista */,
298       "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret);
299     ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
300
301 #if 0 /* This test crashes on WinXP SP2 */
302     ret = (*pSHCreateStreamOnFileW)(test_file, mode, NULL);
303     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
304 #endif
305
306     stream = NULL;
307     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CONVERT, &stream);
308     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
309     ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
310
311     stream = NULL;
312     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_DELETEONRELEASE, &stream);
313     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
314     ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
315
316     stream = NULL;
317     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_TRANSACTED, &stream);
318     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
319     ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
320
321     /* file does not exist */
322
323     stream = NULL;
324     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE, &stream);
325     todo_wine
326     ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
327     ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
328
329     stream = NULL;
330     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE, &stream);
331     todo_wine
332     ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret);
333     todo_wine
334     ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
335
336     if (stream) {
337         test_IStream_invalid_operations(stream, mode);
338
339         refcount = IStream_Release(stream);
340         ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
341     }
342
343     /* NOTE: don't delete the file, as it will be used for the file exists tests. */
344
345     /* file exists */
346
347     stream = NULL;
348     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE, &stream);
349     todo_wine
350     ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret);
351     todo_wine
352     ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
353
354     if (stream) {
355         test_IStream_invalid_operations(stream, mode);
356
357         refcount = IStream_Release(stream);
358         ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
359     }
360
361     stream = NULL;
362     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE, &stream);
363     todo_wine
364     ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret);
365     todo_wine
366     ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
367
368     if (stream) {
369         test_IStream_invalid_operations(stream, mode);
370
371         refcount = IStream_Release(stream);
372         ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
373
374         ok(DeleteFileW(test_file), "SHCreateStreamOnFileW: could not delete the test file, got error %d\n", GetLastError());
375     }
376 }
377
378
379 static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
380 {
381     IStream * stream;
382     IStream * template = NULL;
383     HRESULT ret;
384     ULONG refcount;
385     static const WCHAR test_file[] = { 'c', ':', '\\', 't', 'e', 's', 't', '.', 't', 'x', 't', '\0' };
386
387     trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm);
388
389     /* invalid arguments */
390
391     stream = NULL;
392     ret = (*pSHCreateStreamOnFileEx)(NULL, mode, 0, FALSE, NULL, &stream);
393     ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */
394        ret == E_INVALIDARG /* Vista */,
395       "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret);
396     ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
397
398     stream = NULL;
399     ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream);
400     todo_wine
401     ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
402     ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
403
404 #if 0 /* This test crashes on WinXP SP2 */
405     ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, NULL, NULL);
406     ok(ret == E_INVALIDARG, "SHCreateStreamOnFileEx: expected E_INVALIDARG, got 0x%08x\n", ret);
407 #endif
408
409     /* file does not exist */
410
411     stream = NULL;
412     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream);
413     if ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED && mode == STGM_READ) {
414         ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* XP */ || ret == E_INVALIDARG /* Vista */,
415           "SHCreateStreamOnFileEx: expected E_INVALIDARG or HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
416
417         if (ret == E_INVALIDARG) {
418             skip("SHCreateStreamOnFileEx: STGM_TRANSACTED not supported in this configuration.\n");
419             return;
420         }
421     } else {
422         todo_wine
423         ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
424     }
425     ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
426
427     stream = NULL;
428     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream);
429     todo_wine
430     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
431     todo_wine
432     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
433
434     if (stream) {
435         test_IStream_invalid_operations(stream, mode);
436
437         refcount = IStream_Release(stream);
438         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
439
440         ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError());
441     }
442
443     stream = NULL;
444     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream);
445     todo_wine
446     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
447     todo_wine
448     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
449
450     if (stream) {
451         test_IStream_invalid_operations(stream, mode);
452
453         refcount = IStream_Release(stream);
454         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
455
456         ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError());
457     }
458
459     stream = NULL;
460     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream);
461     todo_wine
462     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
463     todo_wine
464     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
465
466     if (stream) {
467         test_IStream_invalid_operations(stream, mode);
468
469         refcount = IStream_Release(stream);
470         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
471     }
472
473     /* NOTE: don't delete the file, as it will be used for the file exists tests. */
474
475     /* file exists */
476
477     stream = NULL;
478     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream);
479     todo_wine
480     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
481     todo_wine
482     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
483
484     if (stream) {
485         test_IStream_invalid_operations(stream, mode);
486
487         refcount = IStream_Release(stream);
488         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
489     }
490
491     stream = NULL;
492     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream);
493     todo_wine
494     ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), got 0x%08x\n", ret);
495     ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
496
497     stream = NULL;
498     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream);
499     todo_wine
500     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
501     todo_wine
502     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
503
504     if (stream) {
505         test_IStream_invalid_operations(stream, mode);
506
507         refcount = IStream_Release(stream);
508         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
509     }
510
511     stream = NULL;
512     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream);
513     todo_wine
514     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
515     todo_wine
516     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
517
518     if (stream) {
519         test_IStream_invalid_operations(stream, mode);
520
521         refcount = IStream_Release(stream);
522         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
523     }
524
525     todo_wine
526     ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError());
527 }
528
529
530 START_TEST(istream)
531 {
532     static const DWORD stgm_access[] = {
533         STGM_READ,
534         STGM_WRITE,
535         STGM_READWRITE
536     };
537
538     static const DWORD stgm_flags[] = {
539         0,
540         STGM_CONVERT,
541         STGM_DELETEONRELEASE,
542         STGM_CONVERT | STGM_DELETEONRELEASE,
543         STGM_TRANSACTED | STGM_CONVERT,
544         STGM_TRANSACTED | STGM_DELETEONRELEASE,
545         STGM_TRANSACTED | STGM_CONVERT | STGM_DELETEONRELEASE
546     };
547
548     int i, j;
549
550     hShlwapi = GetModuleHandleA("shlwapi.dll");
551
552     pSHCreateStreamOnFileA = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileA");
553     pSHCreateStreamOnFileW = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileW");
554     pSHCreateStreamOnFileEx = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx");
555
556     if (!pSHCreateStreamOnFileA)
557         skip("SHCreateStreamOnFileA not found.\n");
558
559     if (!pSHCreateStreamOnFileW)
560         skip("SHCreateStreamOnFileW not found.\n");
561
562     if (!pSHCreateStreamOnFileEx)
563         skip("SHCreateStreamOnFileEx not found.\n");
564
565     for (i = 0; i != sizeof(stgm_access)/sizeof(stgm_access[0]); i++) {
566         if (pSHCreateStreamOnFileA)
567             test_SHCreateStreamOnFileA(stgm_access[i]);
568
569         if (pSHCreateStreamOnFileW)
570             test_SHCreateStreamOnFileW(stgm_access[i]);
571
572         if (pSHCreateStreamOnFileEx) {
573             for (j = 0; j != sizeof(stgm_flags)/sizeof(stgm_flags[0]); j++)
574                 test_SHCreateStreamOnFileEx(stgm_access[i], stgm_flags[j]);
575         }
576     }
577 }