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