[SHLWAPI_WINETEST]
[reactos.git] / rostests / winetests / shlwapi / 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 WIN32_NO_STATUS
21 #define _INC_WINDOWS
22 #define COM_NO_WINDOWS_H
23
24 #define COBJMACROS
25
26 //#include <stdarg.h>
27 //#include <stdio.h>
28
29 #include <wine/test.h>
30 //#include "windef.h"
31 //#include "winbase.h"
32 #include <winnls.h>
33 #include <winreg.h>
34 #include <objbase.h>
35 //#include "shlwapi.h"
36
37
38 /* Function pointers for the SHCreateStreamOnFile functions */
39 static HMODULE hShlwapi;
40 static HRESULT (WINAPI *pSHCreateStreamOnFileA)(LPCSTR file, DWORD mode, IStream **stream);
41 static HRESULT (WINAPI *pSHCreateStreamOnFileW)(LPCWSTR file, DWORD mode, IStream **stream);
42 static HRESULT (WINAPI *pSHCreateStreamOnFileEx)(LPCWSTR file, DWORD mode, DWORD attributes, BOOL create, IStream *template, IStream **stream);
43
44 static BOOL is_win2000_IE5 = FALSE;
45
46 static void test_IStream_invalid_operations(IStream * stream, DWORD mode)
47 {
48 HRESULT ret;
49 IStream * clone;
50 ULONG refcount;
51 ULARGE_INTEGER uzero;
52 ULARGE_INTEGER uret;
53 LARGE_INTEGER zero;
54 ULONG count;
55 char data[256];
56
57 U(uzero).HighPart = 0;
58 U(uzero).LowPart = 0;
59 U(uret).HighPart = 0;
60 U(uret).LowPart = 0;
61 U(zero).HighPart = 0;
62 U(zero).LowPart = 0;
63
64 /* IStream::Read */
65
66 /* IStream_Read from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Read helper function. */
67
68 ret = stream->lpVtbl->Read(stream, NULL, 0, &count);
69 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
70
71 ret = stream->lpVtbl->Read(stream, data, 5, NULL);
72 ok(ret == S_FALSE || ret == S_OK, "expected S_FALSE or S_OK, got 0x%08x\n", ret);
73
74 ret = stream->lpVtbl->Read(stream, data, 0, NULL);
75 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
76
77 ret = stream->lpVtbl->Read(stream, data, 3, &count);
78 ok(ret == S_FALSE || ret == S_OK, "expected S_FALSE or S_OK, got 0x%08x\n", ret);
79
80 /* IStream::Write */
81
82 /* IStream_Write from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Write helper function. */
83
84 ret = stream->lpVtbl->Write(stream, NULL, 0, &count);
85 if (mode == STGM_READ)
86 {
87 ok(ret == STG_E_ACCESSDENIED /* XP */ || broken(ret == S_OK) /* Win2000 + IE5 */,
88 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
89 if (ret == S_OK)
90 is_win2000_IE5 = TRUE;
91 }
92 else
93 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
94
95 /* IStream::Write calls below hang under Win2000 + IE5, Win2000 + IE6 SP1
96 * and newer Windows versions pass these tests.
97 */
98 if (is_win2000_IE5)
99 {
100 win_skip("broken IStream::Write implementation (win2000)\n");
101 return;
102 }
103
104 strcpy(data, "Hello");
105 ret = stream->lpVtbl->Write(stream, data, 5, NULL);
106 if (mode == STGM_READ)
107 ok(ret == STG_E_ACCESSDENIED,
108 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
109 else
110 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
111
112 strcpy(data, "Hello");
113 ret = stream->lpVtbl->Write(stream, data, 0, NULL);
114 if (mode == STGM_READ)
115 ok(ret == STG_E_ACCESSDENIED,
116 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
117 else
118 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
119
120 strcpy(data, "Hello");
121 ret = stream->lpVtbl->Write(stream, data, 0, &count);
122 if (mode == STGM_READ)
123 ok(ret == STG_E_ACCESSDENIED,
124 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
125 else
126 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
127
128 strcpy(data, "Hello");
129 ret = stream->lpVtbl->Write(stream, data, 3, &count);
130 if (mode == STGM_READ)
131 ok(ret == STG_E_ACCESSDENIED,
132 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret);
133 else
134 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
135
136 /* IStream::Seek */
137
138 ret = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
139 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
140
141 ret = IStream_Seek(stream, zero, 20, NULL);
142 ok(ret == E_INVALIDARG,
143 "expected E_INVALIDARG, got 0x%08x\n", ret);
144
145 /* IStream::CopyTo */
146
147 ret = IStream_CopyTo(stream, NULL, uzero, &uret, &uret);
148 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
149
150 clone = NULL;
151 ret = IStream_CopyTo(stream, clone, uzero, &uret, &uret);
152 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
153
154 ret = IStream_CopyTo(stream, stream, uzero, &uret, &uret);
155 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
156
157 ret = IStream_CopyTo(stream, stream, uzero, &uret, NULL);
158 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
159
160 ret = IStream_CopyTo(stream, stream, uzero, NULL, &uret);
161 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
162
163 /* IStream::Commit */
164
165 ret = IStream_Commit(stream, STGC_DEFAULT);
166 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
167
168 /* IStream::Revert */
169
170 ret = IStream_Revert(stream);
171 ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret);
172
173 /* IStream::LockRegion */
174
175 ret = IStream_LockRegion(stream, uzero, uzero, 0);
176 ok(ret == E_NOTIMPL /* XP */ || ret == S_OK /* Vista */,
177 "expected E_NOTIMPL or S_OK, got 0x%08x\n", ret);
178
179 /* IStream::UnlockRegion */
180
181 if (ret == E_NOTIMPL) /* XP */ {
182 ret = IStream_UnlockRegion(stream, uzero, uzero, 0);
183 ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret);
184 } else /* Vista */ {
185 ret = IStream_UnlockRegion(stream, uzero, uzero, 0);
186 ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret);
187
188 ret = IStream_UnlockRegion(stream, uzero, uzero, 0);
189 ok(ret == STG_E_LOCKVIOLATION, "expected STG_E_LOCKVIOLATION, got 0x%08x\n", ret);
190 }
191
192 /* IStream::Stat */
193
194 ret = IStream_Stat(stream, NULL, 0);
195 ok(ret == STG_E_INVALIDPOINTER,
196 "expected STG_E_INVALIDPOINTER or E_NOTIMPL, got 0x%08x\n", ret);
197
198 /* IStream::Clone */
199
200 /* Passing a NULL pointer for the second IStream::Clone param crashes on Win7 */
201
202 clone = NULL;
203 ret = IStream_Clone(stream, &clone);
204 ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret);
205 ok(clone == NULL, "expected a NULL IStream object, got %p\n", stream);
206
207 if (clone) {
208 refcount = IStream_Release(clone);
209 ok(refcount == 0, "expected 0, got %d\n", refcount);
210 }
211 }
212
213
214 static void test_stream_read_write(IStream *stream, DWORD mode)
215 {
216 static const LARGE_INTEGER start;
217 HRESULT ret;
218 unsigned char buf[16];
219 DWORD written, count;
220
221 /* IStream_Read/Write from the COBJMACROS is undefined by shlwapi.h */
222
223 written = 0xdeadbeaf;
224 ret = stream->lpVtbl->Write(stream, "\x5e\xa7", 2, &written);
225 if (mode == STGM_WRITE || mode == STGM_READWRITE)
226 {
227 ok(ret == S_OK, "IStream_Write error %#x (access %#x)\n", ret, mode);
228 ok(written == 2, "expected 2, got %u\n", written);
229 }
230 else
231 {
232 ok(ret == STG_E_ACCESSDENIED || broken(ret == S_OK) /* win2000 */, "expected STG_E_ACCESSDENIED, got %#x (access %#x)\n", ret, mode);
233 ok(written == 0xdeadbeaf || broken(written == 2) /* win2000 */, "expected 0xdeadbeaf, got %#x\n", written);
234 written = 0;
235 if (ret == S_OK) return; /* no point in further testing */
236 }
237
238 ret = stream->lpVtbl->Seek(stream, start, STREAM_SEEK_SET, NULL);
239 ok(ret == S_OK, "Seek error %#x\n", ret);
240
241 count = 0xdeadbeaf;
242 ret = stream->lpVtbl->Read(stream, buf, 2, &count);
243 if (written != 0)
244 {
245 ok(ret == S_OK || broken(ret == S_FALSE) /* win2000 */, "IStream_Read error %#x (access %#x, written %u)\n", ret, mode, written);
246 if (ret == S_OK && (mode == STGM_WRITE || mode == STGM_READWRITE))
247 {
248 ok(count == 2, "expected 2, got %u\n", count);
249 ok(buf[0] == 0x5e && buf[1] == 0xa7, "expected 5ea7, got %02x%02x\n", buf[0], buf[1]);
250 }
251 else
252 ok(count == 0, "expected 0, got %u\n", count);
253 }
254 else
255 {
256 todo_wine
257 ok(ret == S_FALSE, "expected S_FALSE, got %#x (access %#x, written %u)\n", ret, mode, written);
258 ok(count == 0, "expected 0, got %u\n", count);
259 }
260
261 }
262
263 static void test_SHCreateStreamOnFileA(DWORD mode, DWORD stgm)
264 {
265 IStream * stream;
266 HRESULT ret;
267 ULONG refcount;
268 char test_file[MAX_PATH];
269 static const CHAR testA_txt[] = "\\testA.txt";
270
271 trace("SHCreateStreamOnFileA: testing mode %d, STGM flags %08x\n", mode, stgm);
272
273 /* Don't used a fixed path for the testA.txt file */
274 GetTempPathA(MAX_PATH, test_file);
275 lstrcatA(test_file, testA_txt);
276
277 /* invalid arguments */
278
279 stream = NULL;
280 ret = (*pSHCreateStreamOnFileA)(NULL, mode | stgm, &stream);
281 if (ret == E_INVALIDARG) /* Win98 SE */ {
282 win_skip("Not supported\n");
283 return;
284 }
285
286 ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) /* NT */ ||
287 ret == HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME) /* 9x */,
288 "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) "
289 "or HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), got 0x%08x\n", ret);
290 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
291
292 if (0) /* This test crashes on WinXP SP2 */
293 {
294 ret = (*pSHCreateStreamOnFileA)(test_file, mode | stgm, NULL);
295 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
296 }
297
298 stream = NULL;
299 ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CONVERT | stgm, &stream);
300 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
301 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
302
303 stream = NULL;
304 ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_DELETEONRELEASE | stgm, &stream);
305 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
306 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
307
308 stream = NULL;
309 ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_TRANSACTED | stgm, &stream);
310 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret);
311 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
312
313 /* file does not exist */
314
315 stream = NULL;
316 ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream);
317 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
318 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
319
320 stream = NULL;
321 ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE | stgm, &stream);
322 ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret);
323 ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
324
325 if (stream) {
326 test_IStream_invalid_operations(stream, mode);
327
328 refcount = IStream_Release(stream);
329 ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
330 }
331
332 /* NOTE: don't delete the file, as it will be used for the file exists tests. */
333
334 /* file exists */
335
336 stream = NULL;
337 ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream);
338 ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret);
339 ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
340
341 if (stream) {
342 test_IStream_invalid_operations(stream, mode);
343
344 refcount = IStream_Release(stream);
345 ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
346 }
347
348 stream = NULL;
349 ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE | stgm, &stream);
350 ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret);
351 ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
352
353 if (stream) {
354 BOOL delret;
355
356 test_stream_read_write(stream, mode);
357 test_IStream_invalid_operations(stream, mode);
358
359 refcount = IStream_Release(stream);
360 ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
361
362 delret = DeleteFileA(test_file);
363 ok(delret, "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n",
364 test_file, GetLastError());
365 }
366 }
367
368
369 static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm)
370 {
371 IStream * stream;
372 HRESULT ret;
373 ULONG refcount;
374 WCHAR test_file[MAX_PATH];
375 CHAR test_fileA[MAX_PATH];
376 static const CHAR testW_txt[] = "\\testW.txt";
377
378 trace("SHCreateStreamOnFileW: testing mode %d, STGM flags %08x\n", mode, stgm);
379
380 /* Don't used a fixed path for the testW.txt file */
381 GetTempPathA(MAX_PATH, test_fileA);
382 lstrcatA(test_fileA, testW_txt);
383 MultiByteToWideChar(CP_ACP, 0, test_fileA, -1, test_file, MAX_PATH);
384
385 /* invalid arguments */
386
387 if (0)
388 {
389 /* Crashes on NT4 */
390 stream = NULL;
391 ret = (*pSHCreateStreamOnFileW)(NULL, mode | stgm, &stream);
392 ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */
393 ret == E_INVALIDARG /* Vista */,
394 "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret);
395 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
396 }
397
398 if (0)
399 {
400 /* This test crashes on WinXP SP2 */
401 ret = (*pSHCreateStreamOnFileW)(test_file, mode | stgm, NULL);
402 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
403 }
404
405 stream = NULL;
406 ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CONVERT | stgm, &stream);
407 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
408 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
409
410 stream = NULL;
411 ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_DELETEONRELEASE | stgm, &stream);
412 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
413 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
414
415 stream = NULL;
416 ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_TRANSACTED | stgm, &stream);
417 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret);
418 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
419
420 /* file does not exist */
421
422 stream = NULL;
423 ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream);
424 if (ret == E_INVALIDARG) /* Win98 SE */ {
425 win_skip("Not supported\n");
426 return;
427 }
428
429 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
430 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
431
432 stream = NULL;
433 ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE | stgm, &stream);
434 ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret);
435 ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
436
437 if (stream) {
438 test_IStream_invalid_operations(stream, mode);
439
440 refcount = IStream_Release(stream);
441 ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
442 }
443
444 /* NOTE: don't delete the file, as it will be used for the file exists tests. */
445
446 /* file exists */
447
448 stream = NULL;
449 ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream);
450 ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret);
451 ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
452
453 if (stream) {
454 test_IStream_invalid_operations(stream, mode);
455
456 refcount = IStream_Release(stream);
457 ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
458 }
459
460 stream = NULL;
461 ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE | stgm, &stream);
462 ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret);
463 ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
464
465 if (stream) {
466 BOOL delret;
467
468 test_stream_read_write(stream, mode);
469 test_IStream_invalid_operations(stream, mode);
470
471 refcount = IStream_Release(stream);
472 ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
473
474 delret = DeleteFileA(test_fileA);
475 ok(delret, "SHCreateStreamOnFileW: could not delete the test file, got error %d\n",
476 GetLastError());
477 }
478 }
479
480
481 static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
482 {
483 IStream * stream;
484 IStream * template = NULL;
485 HRESULT ret;
486 ULONG refcount;
487 WCHAR test_file[MAX_PATH];
488 CHAR test_fileA[MAX_PATH];
489 static const CHAR testEx_txt[] = "\\testEx.txt";
490 BOOL delret;
491
492 trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm);
493
494 /* Don't used a fixed path for the testEx.txt file */
495 GetTempPathA(MAX_PATH, test_fileA);
496 lstrcatA(test_fileA, testEx_txt);
497 MultiByteToWideChar(CP_ACP, 0, test_fileA, -1, test_file, MAX_PATH);
498
499 /* invalid arguments */
500
501 if (0)
502 {
503 /* Crashes on NT4 */
504 stream = NULL;
505 ret = (*pSHCreateStreamOnFileEx)(NULL, mode, 0, FALSE, NULL, &stream);
506 ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */
507 ret == E_INVALIDARG /* Vista */,
508 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret);
509 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
510 }
511
512 stream = NULL;
513 ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream);
514 if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
515 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
516 Sleep(1000);
517 ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream);
518 }
519 ok( ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
520 ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
521 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or "
522 "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret);
523
524 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
525
526 if (0)
527 {
528 /* This test crashes on WinXP SP2 */
529 ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, NULL, NULL);
530 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileEx: expected E_INVALIDARG, got 0x%08x\n", ret);
531 }
532
533 /* file does not exist */
534
535 stream = NULL;
536 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream);
537 if ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED && mode == STGM_READ) {
538 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* XP */ || ret == E_INVALIDARG /* Vista */,
539 "SHCreateStreamOnFileEx: expected E_INVALIDARG or HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
540
541 if (ret == E_INVALIDARG) {
542 skip("SHCreateStreamOnFileEx: STGM_TRANSACTED not supported in this configuration.\n");
543 return;
544 }
545 } else {
546 ok( ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
547 ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
548 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or "
549 "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret);
550 }
551 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
552
553 stream = NULL;
554 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream);
555 /* not supported on win9x */
556 if (broken(ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) && stream == NULL)) {
557 skip("Not supported\n");
558 DeleteFileA(test_fileA);
559 return;
560 }
561
562 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
563 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
564
565 if (stream) {
566 test_IStream_invalid_operations(stream, mode);
567
568 refcount = IStream_Release(stream);
569 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
570
571 delret = DeleteFileA(test_fileA);
572 ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
573 GetLastError());
574 }
575
576 stream = NULL;
577 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream);
578 if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
579 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
580 Sleep(1000);
581 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream);
582 }
583 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
584 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
585
586 if (stream) {
587 test_IStream_invalid_operations(stream, mode);
588
589 refcount = IStream_Release(stream);
590 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
591
592 delret = DeleteFileA(test_fileA);
593 ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
594 GetLastError());
595 }
596
597 stream = NULL;
598 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream);
599 if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
600 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
601 Sleep(1000);
602 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream);
603 }
604 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
605 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
606
607 if (stream) {
608 test_IStream_invalid_operations(stream, mode);
609
610 refcount = IStream_Release(stream);
611 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
612 }
613
614 /* NOTE: don't delete the file, as it will be used for the file exists tests. */
615
616 /* file exists */
617
618 stream = NULL;
619 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream);
620 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
621 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
622
623 if (stream) {
624 test_IStream_invalid_operations(stream, mode);
625
626 refcount = IStream_Release(stream);
627 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
628 }
629
630 stream = NULL;
631 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream);
632 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), got 0x%08x\n", ret);
633 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream);
634
635 stream = NULL;
636 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream);
637 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
638 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
639
640 if (stream) {
641 test_IStream_invalid_operations(stream, mode);
642
643 refcount = IStream_Release(stream);
644 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
645 }
646
647 stream = NULL;
648 ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream);
649 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
650 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
651
652 if (stream) {
653 test_IStream_invalid_operations(stream, mode);
654
655 refcount = IStream_Release(stream);
656 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
657 }
658
659 delret = DeleteFileA(test_fileA);
660 ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
661 GetLastError());
662 }
663
664
665 static void test_SHCreateStreamOnFileEx_CopyTo(void)
666 {
667 HRESULT ret;
668 IStream *src, *dst;
669 WCHAR tmpPath[MAX_PATH];
670 WCHAR srcFileName[MAX_PATH];
671 WCHAR dstFileName[MAX_PATH];
672 ULARGE_INTEGER count, read, written;
673 LARGE_INTEGER distance;
674 static const char srcContents[1];
675 static const WCHAR prefix[] = { 'T', 'S', 'T', 0 };
676
677 GetTempPathW(MAX_PATH, tmpPath);
678 GetTempFileNameW(tmpPath, prefix, 0, srcFileName);
679 GetTempFileNameW(tmpPath, prefix, 0, dstFileName);
680
681 ret = pSHCreateStreamOnFileEx(srcFileName, STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE, FILE_ATTRIBUTE_TEMPORARY, FALSE, NULL, &src);
682 ok(SUCCEEDED(ret), "SHCreateStreamOnFileEx failed with ret=0x%08x\n", ret);
683
684 written.QuadPart = 0;
685 ret = IStream_Write(src, srcContents, sizeof(srcContents), &U(written).LowPart);
686 ok(SUCCEEDED(ret), "ISequentialStream_Write failed with ret=0x%08x\n", ret);
687
688 distance.QuadPart = 0;
689 ret = IStream_Seek(src, distance, STREAM_SEEK_SET, &written);
690 ok(SUCCEEDED(ret), "ISequentialStream_Seek failed with ret=0x%08x\n", ret);
691
692 ret = pSHCreateStreamOnFileEx(dstFileName, STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE, FILE_ATTRIBUTE_TEMPORARY, FALSE, NULL, &dst);
693 ok(SUCCEEDED(ret), "SHCreateStreamOnFileEx failed with ret=0x%08x\n", ret);
694
695 /* Test using a count larger than the source file, so that the Read operation will fall short */
696 count.QuadPart = 2;
697
698 ret = IStream_CopyTo(src, dst, count, &read, &written);
699 ok(SUCCEEDED(ret), "CopyTo failed with ret=0x%08x\n", ret);
700
701 ok(read.QuadPart == 1, "read does not match size: %d != 1\n", U(read).LowPart);
702 ok(written.QuadPart == 1, "written does not match size: %d != 1\n", U(written).LowPart);
703
704 IStream_Release(dst);
705 IStream_Release(src);
706 DeleteFileW( srcFileName );
707 DeleteFileW( dstFileName );
708 }
709
710
711 START_TEST(istream)
712 {
713 static const DWORD stgm_access[] = {
714 STGM_READ,
715 STGM_WRITE,
716 STGM_READWRITE
717 };
718
719 static const DWORD stgm_sharing[] = {
720 0,
721 STGM_SHARE_DENY_NONE,
722 STGM_SHARE_DENY_READ,
723 STGM_SHARE_DENY_WRITE,
724 STGM_SHARE_EXCLUSIVE
725 };
726
727 static const DWORD stgm_flags[] = {
728 0,
729 STGM_CONVERT,
730 STGM_DELETEONRELEASE,
731 STGM_CONVERT | STGM_DELETEONRELEASE,
732 STGM_TRANSACTED | STGM_CONVERT,
733 STGM_TRANSACTED | STGM_DELETEONRELEASE,
734 STGM_TRANSACTED | STGM_CONVERT | STGM_DELETEONRELEASE
735 };
736
737 int i, j, k;
738
739 hShlwapi = LoadLibraryA("shlwapi.dll");
740
741 pSHCreateStreamOnFileA = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileA");
742 pSHCreateStreamOnFileW = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileW");
743 pSHCreateStreamOnFileEx = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx");
744
745 if (!pSHCreateStreamOnFileA)
746 skip("SHCreateStreamOnFileA not found.\n");
747
748 if (!pSHCreateStreamOnFileW)
749 skip("SHCreateStreamOnFileW not found.\n");
750
751 if (!pSHCreateStreamOnFileEx)
752 skip("SHCreateStreamOnFileEx not found.\n");
753
754 for (i = 0; i != sizeof(stgm_access)/sizeof(stgm_access[0]); i++) {
755 for (j = 0; j != sizeof(stgm_sharing)/sizeof(stgm_sharing[0]); j ++) {
756 if (pSHCreateStreamOnFileA)
757 test_SHCreateStreamOnFileA(stgm_access[i], stgm_sharing[j]);
758
759 if (pSHCreateStreamOnFileW)
760 test_SHCreateStreamOnFileW(stgm_access[i], stgm_sharing[j]);
761
762 if (pSHCreateStreamOnFileEx) {
763 for (k = 0; k != sizeof(stgm_flags)/sizeof(stgm_flags[0]); k++)
764 test_SHCreateStreamOnFileEx(stgm_access[i], stgm_sharing[j] | stgm_flags[k]);
765 }
766 }
767 }
768
769 if (pSHCreateStreamOnFileEx) test_SHCreateStreamOnFileEx_CopyTo();
770 }