1 /* Unit test suite for SHLWAPI ShCreateStreamOnFile functions.
3 * Copyright 2008 Reece H. Dunn
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.
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.
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
25 #include "wine/test.h"
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
);
38 static BOOL is_win2000_IE5
= FALSE
;
40 static void test_IStream_invalid_operations(IStream
* stream
, DWORD mode
)
51 U(uzero
).HighPart
= 0;
60 /* IStream_Read from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Read helper function. */
62 ret
= stream
->lpVtbl
->Read(stream
, NULL
, 0, &count
);
63 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
65 ret
= stream
->lpVtbl
->Read(stream
, data
, 5, NULL
);
66 ok(ret
== S_FALSE
|| ret
== S_OK
, "expected S_FALSE or S_OK, got 0x%08x\n", ret
);
68 ret
= stream
->lpVtbl
->Read(stream
, data
, 0, NULL
);
69 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
71 ret
= stream
->lpVtbl
->Read(stream
, data
, 3, &count
);
72 ok(ret
== S_FALSE
|| ret
== S_OK
, "expected S_FALSE or S_OK, got 0x%08x\n", ret
);
76 /* IStream_Write from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Write helper function. */
78 ret
= stream
->lpVtbl
->Write(stream
, NULL
, 0, &count
);
79 if (mode
== STGM_READ
)
81 ok(ret
== STG_E_ACCESSDENIED
/* XP */ || broken(ret
== S_OK
) /* Win2000 + IE5 */,
82 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret
);
84 is_win2000_IE5
= TRUE
;
87 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
89 /* IStream::Write calls below hang under Win2000 + IE5, Win2000 + IE6 SP1
90 * and newer Windows versions pass these tests.
94 win_skip("broken IStream::Write implementation (win2000)\n");
98 strcpy(data
, "Hello");
99 ret
= stream
->lpVtbl
->Write(stream
, data
, 5, NULL
);
100 if (mode
== STGM_READ
)
101 ok(ret
== STG_E_ACCESSDENIED
,
102 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret
);
104 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
106 strcpy(data
, "Hello");
107 ret
= stream
->lpVtbl
->Write(stream
, data
, 0, NULL
);
108 if (mode
== STGM_READ
)
109 ok(ret
== STG_E_ACCESSDENIED
,
110 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret
);
112 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
114 strcpy(data
, "Hello");
115 ret
= stream
->lpVtbl
->Write(stream
, data
, 0, &count
);
116 if (mode
== STGM_READ
)
117 ok(ret
== STG_E_ACCESSDENIED
,
118 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret
);
120 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
122 strcpy(data
, "Hello");
123 ret
= stream
->lpVtbl
->Write(stream
, data
, 3, &count
);
124 if (mode
== STGM_READ
)
125 ok(ret
== STG_E_ACCESSDENIED
,
126 "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret
);
128 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
132 ret
= IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
133 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
135 ret
= IStream_Seek(stream
, zero
, 20, NULL
);
136 ok(ret
== E_INVALIDARG
,
137 "expected E_INVALIDARG, got 0x%08x\n", ret
);
139 /* IStream::CopyTo */
141 ret
= IStream_CopyTo(stream
, NULL
, uzero
, &uret
, &uret
);
142 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
145 ret
= IStream_CopyTo(stream
, clone
, uzero
, &uret
, &uret
);
146 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
148 ret
= IStream_CopyTo(stream
, stream
, uzero
, &uret
, &uret
);
149 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
151 ret
= IStream_CopyTo(stream
, stream
, uzero
, &uret
, NULL
);
152 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
154 ret
= IStream_CopyTo(stream
, stream
, uzero
, NULL
, &uret
);
155 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
157 /* IStream::Commit */
159 ret
= IStream_Commit(stream
, STGC_DEFAULT
);
160 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
162 /* IStream::Revert */
164 ret
= IStream_Revert(stream
);
165 ok(ret
== E_NOTIMPL
, "expected E_NOTIMPL, got 0x%08x\n", ret
);
167 /* IStream::LockRegion */
169 ret
= IStream_LockRegion(stream
, uzero
, uzero
, 0);
170 ok(ret
== E_NOTIMPL
/* XP */ || ret
== S_OK
/* Vista */,
171 "expected E_NOTIMPL or S_OK, got 0x%08x\n", ret
);
173 /* IStream::UnlockRegion */
175 if (ret
== E_NOTIMPL
) /* XP */ {
176 ret
= IStream_UnlockRegion(stream
, uzero
, uzero
, 0);
177 ok(ret
== E_NOTIMPL
, "expected E_NOTIMPL, got 0x%08x\n", ret
);
179 ret
= IStream_UnlockRegion(stream
, uzero
, uzero
, 0);
180 ok(ret
== S_OK
, "expected S_OK, got 0x%08x\n", ret
);
182 ret
= IStream_UnlockRegion(stream
, uzero
, uzero
, 0);
183 ok(ret
== STG_E_LOCKVIOLATION
, "expected STG_E_LOCKVIOLATION, got 0x%08x\n", ret
);
188 ret
= IStream_Stat(stream
, NULL
, 0);
189 ok(ret
== STG_E_INVALIDPOINTER
,
190 "expected STG_E_INVALIDPOINTER or E_NOTIMPL, got 0x%08x\n", ret
);
194 /* Passing a NULL pointer for the second IStream::Clone param crashes on Win7 */
197 ret
= IStream_Clone(stream
, &clone
);
198 ok(ret
== E_NOTIMPL
, "expected E_NOTIMPL, got 0x%08x\n", ret
);
199 ok(clone
== NULL
, "expected a NULL IStream object, got %p\n", stream
);
202 refcount
= IStream_Release(clone
);
203 ok(refcount
== 0, "expected 0, got %d\n", refcount
);
208 static void test_stream_read_write(IStream
*stream
, DWORD mode
)
210 static const LARGE_INTEGER start
;
212 unsigned char buf
[16];
213 DWORD written
, count
;
215 /* IStream_Read/Write from the COBJMACROS is undefined by shlwapi.h */
217 written
= 0xdeadbeaf;
218 ret
= stream
->lpVtbl
->Write(stream
, "\x5e\xa7", 2, &written
);
219 if (mode
== STGM_WRITE
|| mode
== STGM_READWRITE
)
221 ok(ret
== S_OK
, "IStream_Write error %#x (access %#x)\n", ret
, mode
);
222 ok(written
== 2, "expected 2, got %u\n", written
);
226 ok(ret
== STG_E_ACCESSDENIED
|| broken(ret
== S_OK
) /* win2000 */, "expected STG_E_ACCESSDENIED, got %#x (access %#x)\n", ret
, mode
);
227 ok(written
== 0xdeadbeaf || broken(written
== 2) /* win2000 */, "expected 0xdeadbeaf, got %#x\n", written
);
229 if (ret
== S_OK
) return; /* no point in further testing */
232 ret
= stream
->lpVtbl
->Seek(stream
, start
, STREAM_SEEK_SET
, NULL
);
233 ok(ret
== S_OK
, "Seek error %#x\n", ret
);
236 ret
= stream
->lpVtbl
->Read(stream
, buf
, 2, &count
);
239 ok(ret
== S_OK
|| broken(ret
== S_FALSE
) /* win2000 */, "IStream_Read error %#x (access %#x, written %u)\n", ret
, mode
, written
);
240 if (ret
== S_OK
&& (mode
== STGM_WRITE
|| mode
== STGM_READWRITE
))
242 ok(count
== 2, "expected 2, got %u\n", count
);
243 ok(buf
[0] == 0x5e && buf
[1] == 0xa7, "expected 5ea7, got %02x%02x\n", buf
[0], buf
[1]);
246 ok(count
== 0, "expected 0, got %u\n", count
);
251 ok(ret
== S_FALSE
, "expected S_FALSE, got %#x (access %#x, written %u)\n", ret
, mode
, written
);
252 ok(count
== 0, "expected 0, got %u\n", count
);
257 static void test_SHCreateStreamOnFileA(DWORD mode
, DWORD stgm
)
262 char test_file
[MAX_PATH
];
263 static const CHAR testA_txt
[] = "\\testA.txt";
265 trace("SHCreateStreamOnFileA: testing mode %d, STGM flags %08x\n", mode
, stgm
);
267 /* Don't used a fixed path for the testA.txt file */
268 GetTempPathA(MAX_PATH
, test_file
);
269 lstrcatA(test_file
, testA_txt
);
271 /* invalid arguments */
274 ret
= (*pSHCreateStreamOnFileA
)(NULL
, mode
| stgm
, &stream
);
275 if (ret
== E_INVALIDARG
) /* Win98 SE */ {
276 win_skip("Not supported\n");
280 ok(ret
== HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
) /* NT */ ||
281 ret
== HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME
) /* 9x */,
282 "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) "
283 "or HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), got 0x%08x\n", ret
);
284 ok(stream
== NULL
, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream
);
286 if (0) /* This test crashes on WinXP SP2 */
288 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| stgm
, NULL
);
289 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret
);
293 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| STGM_CONVERT
| stgm
, &stream
);
294 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret
);
295 ok(stream
== NULL
, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream
);
298 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| STGM_DELETEONRELEASE
| stgm
, &stream
);
299 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret
);
300 ok(stream
== NULL
, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream
);
303 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| STGM_TRANSACTED
| stgm
, &stream
);
304 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret
);
305 ok(stream
== NULL
, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream
);
307 /* file does not exist */
310 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, &stream
);
311 ok(ret
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret
);
312 ok(stream
== NULL
, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream
);
315 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| STGM_CREATE
| stgm
, &stream
);
316 ok(ret
== S_OK
, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret
);
317 ok(stream
!= NULL
, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
320 test_IStream_invalid_operations(stream
, mode
);
322 refcount
= IStream_Release(stream
);
323 ok(refcount
== 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount
);
326 /* NOTE: don't delete the file, as it will be used for the file exists tests. */
331 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, &stream
);
332 ok(ret
== S_OK
, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret
);
333 ok(stream
!= NULL
, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
336 test_IStream_invalid_operations(stream
, mode
);
338 refcount
= IStream_Release(stream
);
339 ok(refcount
== 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount
);
343 ret
= (*pSHCreateStreamOnFileA
)(test_file
, mode
| STGM_CREATE
| stgm
, &stream
);
344 ok(ret
== S_OK
, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret
);
345 ok(stream
!= NULL
, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
350 test_stream_read_write(stream
, mode
);
351 test_IStream_invalid_operations(stream
, mode
);
353 refcount
= IStream_Release(stream
);
354 ok(refcount
== 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount
);
356 delret
= DeleteFileA(test_file
);
357 ok(delret
, "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n",
358 test_file
, GetLastError());
363 static void test_SHCreateStreamOnFileW(DWORD mode
, DWORD stgm
)
368 WCHAR test_file
[MAX_PATH
];
369 CHAR test_fileA
[MAX_PATH
];
370 static const CHAR testW_txt
[] = "\\testW.txt";
372 trace("SHCreateStreamOnFileW: testing mode %d, STGM flags %08x\n", mode
, stgm
);
374 /* Don't used a fixed path for the testW.txt file */
375 GetTempPathA(MAX_PATH
, test_fileA
);
376 lstrcatA(test_fileA
, testW_txt
);
377 MultiByteToWideChar(CP_ACP
, 0, test_fileA
, -1, test_file
, MAX_PATH
);
379 /* invalid arguments */
385 ret
= (*pSHCreateStreamOnFileW
)(NULL
, mode
| stgm
, &stream
);
386 ok(ret
== HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
) || /* XP */
387 ret
== E_INVALIDARG
/* Vista */,
388 "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret
);
389 ok(stream
== NULL
, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream
);
394 /* This test crashes on WinXP SP2 */
395 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| stgm
, NULL
);
396 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret
);
400 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| STGM_CONVERT
| stgm
, &stream
);
401 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret
);
402 ok(stream
== NULL
, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream
);
405 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| STGM_DELETEONRELEASE
| stgm
, &stream
);
406 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret
);
407 ok(stream
== NULL
, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream
);
410 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| STGM_TRANSACTED
| stgm
, &stream
);
411 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret
);
412 ok(stream
== NULL
, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream
);
414 /* file does not exist */
417 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, &stream
);
418 if (ret
== E_INVALIDARG
) /* Win98 SE */ {
419 win_skip("Not supported\n");
423 ok(ret
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret
);
424 ok(stream
== NULL
, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream
);
427 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| STGM_CREATE
| stgm
, &stream
);
428 ok(ret
== S_OK
, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret
);
429 ok(stream
!= NULL
, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
432 test_IStream_invalid_operations(stream
, mode
);
434 refcount
= IStream_Release(stream
);
435 ok(refcount
== 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount
);
438 /* NOTE: don't delete the file, as it will be used for the file exists tests. */
443 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, &stream
);
444 ok(ret
== S_OK
, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret
);
445 ok(stream
!= NULL
, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
448 test_IStream_invalid_operations(stream
, mode
);
450 refcount
= IStream_Release(stream
);
451 ok(refcount
== 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount
);
455 ret
= (*pSHCreateStreamOnFileW
)(test_file
, mode
| STGM_CREATE
| stgm
, &stream
);
456 ok(ret
== S_OK
, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret
);
457 ok(stream
!= NULL
, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
462 test_stream_read_write(stream
, mode
);
463 test_IStream_invalid_operations(stream
, mode
);
465 refcount
= IStream_Release(stream
);
466 ok(refcount
== 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount
);
468 delret
= DeleteFileA(test_fileA
);
469 ok(delret
, "SHCreateStreamOnFileW: could not delete the test file, got error %d\n",
475 static void test_SHCreateStreamOnFileEx(DWORD mode
, DWORD stgm
)
478 IStream
* template = NULL
;
481 WCHAR test_file
[MAX_PATH
];
482 CHAR test_fileA
[MAX_PATH
];
483 static const CHAR testEx_txt
[] = "\\testEx.txt";
486 if (winetest_debug
> 1)
487 trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode
, stgm
);
489 /* Don't used a fixed path for the testEx.txt file */
490 GetTempPathA(MAX_PATH
, test_fileA
);
491 lstrcatA(test_fileA
, testEx_txt
);
492 MultiByteToWideChar(CP_ACP
, 0, test_fileA
, -1, test_file
, MAX_PATH
);
494 /* invalid arguments */
500 ret
= (*pSHCreateStreamOnFileEx
)(NULL
, mode
, 0, FALSE
, NULL
, &stream
);
501 ok(ret
== HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
) || /* XP */
502 ret
== E_INVALIDARG
/* Vista */,
503 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret
);
504 ok(stream
== NULL
, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream
);
508 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
, 0, FALSE
, template, &stream
);
509 if (ret
== HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
)) {
510 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
512 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
, 0, FALSE
, template, &stream
);
514 ok( ret
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
) ||
515 ret
== HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
),
516 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or "
517 "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret
);
519 ok(stream
== NULL
, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream
);
523 /* This test crashes on WinXP SP2 */
524 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
, 0, FALSE
, NULL
, NULL
);
525 ok(ret
== E_INVALIDARG
, "SHCreateStreamOnFileEx: expected E_INVALIDARG, got 0x%08x\n", ret
);
528 /* file does not exist */
531 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, 0, FALSE
, NULL
, &stream
);
532 if ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
&& mode
== STGM_READ
) {
533 ok(ret
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
) /* XP */ || ret
== E_INVALIDARG
/* Vista */,
534 "SHCreateStreamOnFileEx: expected E_INVALIDARG or HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret
);
536 if (ret
== E_INVALIDARG
) {
537 skip("SHCreateStreamOnFileEx: STGM_TRANSACTED not supported in this configuration.\n");
541 ok( ret
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
) ||
542 ret
== HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
),
543 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or "
544 "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret
);
546 ok(stream
== NULL
, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream
);
549 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, 0, TRUE
, NULL
, &stream
);
550 /* not supported on win9x */
551 if (broken(ret
== HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
) && stream
== NULL
)) {
552 skip("Not supported\n");
553 DeleteFileA(test_fileA
);
557 ok(ret
== S_OK
, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret
);
558 ok(stream
!= NULL
, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
561 test_IStream_invalid_operations(stream
, mode
);
563 refcount
= IStream_Release(stream
);
564 ok(refcount
== 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount
);
566 delret
= DeleteFileA(test_fileA
);
567 ok(delret
, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
572 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_CREATE
| stgm
, 0, FALSE
, NULL
, &stream
);
573 if (ret
== HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
)) {
574 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
576 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_CREATE
| stgm
, 0, FALSE
, NULL
, &stream
);
578 ok(ret
== S_OK
, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret
);
579 ok(stream
!= NULL
, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
582 test_IStream_invalid_operations(stream
, mode
);
584 refcount
= IStream_Release(stream
);
585 ok(refcount
== 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount
);
587 delret
= DeleteFileA(test_fileA
);
588 ok(delret
, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
593 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_CREATE
| stgm
, 0, TRUE
, NULL
, &stream
);
594 if (ret
== HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
)) {
595 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
597 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_CREATE
| stgm
, 0, TRUE
, NULL
, &stream
);
599 ok(ret
== S_OK
, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret
);
600 ok(stream
!= NULL
, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
603 test_IStream_invalid_operations(stream
, mode
);
605 refcount
= IStream_Release(stream
);
606 ok(refcount
== 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount
);
609 /* NOTE: don't delete the file, as it will be used for the file exists tests. */
614 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, 0, FALSE
, NULL
, &stream
);
615 ok(ret
== S_OK
, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret
);
616 ok(stream
!= NULL
, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
619 test_IStream_invalid_operations(stream
, mode
);
621 refcount
= IStream_Release(stream
);
622 ok(refcount
== 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount
);
626 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_FAILIFTHERE
| stgm
, 0, TRUE
, NULL
, &stream
);
627 ok(ret
== HRESULT_FROM_WIN32(ERROR_FILE_EXISTS
), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), got 0x%08x\n", ret
);
628 ok(stream
== NULL
, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream
);
631 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_CREATE
| stgm
, 0, FALSE
, NULL
, &stream
);
632 ok(ret
== S_OK
, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret
);
633 ok(stream
!= NULL
, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
636 test_IStream_invalid_operations(stream
, mode
);
638 refcount
= IStream_Release(stream
);
639 ok(refcount
== 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount
);
643 ret
= (*pSHCreateStreamOnFileEx
)(test_file
, mode
| STGM_CREATE
| stgm
, 0, TRUE
, NULL
, &stream
);
644 ok(ret
== S_OK
, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret
);
645 ok(stream
!= NULL
, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
648 test_IStream_invalid_operations(stream
, mode
);
650 refcount
= IStream_Release(stream
);
651 ok(refcount
== 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount
);
654 delret
= DeleteFileA(test_fileA
);
655 ok(delret
, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
660 static void test_SHCreateStreamOnFileEx_CopyTo(void)
664 WCHAR tmpPath
[MAX_PATH
];
665 WCHAR srcFileName
[MAX_PATH
];
666 WCHAR dstFileName
[MAX_PATH
];
667 ULARGE_INTEGER count
, read
, written
;
668 LARGE_INTEGER distance
;
669 static const char srcContents
[1];
670 static const WCHAR prefix
[] = { 'T', 'S', 'T', 0 };
672 GetTempPathW(MAX_PATH
, tmpPath
);
673 GetTempFileNameW(tmpPath
, prefix
, 0, srcFileName
);
674 GetTempFileNameW(tmpPath
, prefix
, 0, dstFileName
);
676 ret
= pSHCreateStreamOnFileEx(srcFileName
, STGM_CREATE
| STGM_READWRITE
| STGM_DELETEONRELEASE
, FILE_ATTRIBUTE_TEMPORARY
, FALSE
, NULL
, &src
);
677 ok(SUCCEEDED(ret
), "SHCreateStreamOnFileEx failed with ret=0x%08x\n", ret
);
679 written
.QuadPart
= 0;
680 ret
= IStream_Write(src
, srcContents
, sizeof(srcContents
), &U(written
).LowPart
);
681 ok(SUCCEEDED(ret
), "ISequentialStream_Write failed with ret=0x%08x\n", ret
);
683 distance
.QuadPart
= 0;
684 ret
= IStream_Seek(src
, distance
, STREAM_SEEK_SET
, &written
);
685 ok(SUCCEEDED(ret
), "ISequentialStream_Seek failed with ret=0x%08x\n", ret
);
687 ret
= pSHCreateStreamOnFileEx(dstFileName
, STGM_CREATE
| STGM_READWRITE
| STGM_DELETEONRELEASE
, FILE_ATTRIBUTE_TEMPORARY
, FALSE
, NULL
, &dst
);
688 ok(SUCCEEDED(ret
), "SHCreateStreamOnFileEx failed with ret=0x%08x\n", ret
);
690 /* Test using a count larger than the source file, so that the Read operation will fall short */
693 ret
= IStream_CopyTo(src
, dst
, count
, &read
, &written
);
694 ok(SUCCEEDED(ret
), "CopyTo failed with ret=0x%08x\n", ret
);
696 ok(read
.QuadPart
== 1, "read does not match size: %d != 1\n", U(read
).LowPart
);
697 ok(written
.QuadPart
== 1, "written does not match size: %d != 1\n", U(written
).LowPart
);
699 IStream_Release(dst
);
700 IStream_Release(src
);
701 DeleteFileW( srcFileName
);
702 DeleteFileW( dstFileName
);
708 static const DWORD stgm_access
[] = {
714 static const DWORD stgm_sharing
[] = {
716 STGM_SHARE_DENY_NONE
,
717 STGM_SHARE_DENY_READ
,
718 STGM_SHARE_DENY_WRITE
,
722 static const DWORD stgm_flags
[] = {
725 STGM_DELETEONRELEASE
,
726 STGM_CONVERT
| STGM_DELETEONRELEASE
,
727 STGM_TRANSACTED
| STGM_CONVERT
,
728 STGM_TRANSACTED
| STGM_DELETEONRELEASE
,
729 STGM_TRANSACTED
| STGM_CONVERT
| STGM_DELETEONRELEASE
734 hShlwapi
= LoadLibraryA("shlwapi.dll");
736 pSHCreateStreamOnFileA
= (void*)GetProcAddress(hShlwapi
, "SHCreateStreamOnFileA");
737 pSHCreateStreamOnFileW
= (void*)GetProcAddress(hShlwapi
, "SHCreateStreamOnFileW");
738 pSHCreateStreamOnFileEx
= (void*)GetProcAddress(hShlwapi
, "SHCreateStreamOnFileEx");
740 if (!pSHCreateStreamOnFileA
)
741 skip("SHCreateStreamOnFileA not found.\n");
743 if (!pSHCreateStreamOnFileW
)
744 skip("SHCreateStreamOnFileW not found.\n");
746 if (!pSHCreateStreamOnFileEx
)
747 skip("SHCreateStreamOnFileEx not found.\n");
749 for (i
= 0; i
!= sizeof(stgm_access
)/sizeof(stgm_access
[0]); i
++) {
750 for (j
= 0; j
!= sizeof(stgm_sharing
)/sizeof(stgm_sharing
[0]); j
++) {
751 if (pSHCreateStreamOnFileA
)
752 test_SHCreateStreamOnFileA(stgm_access
[i
], stgm_sharing
[j
]);
754 if (pSHCreateStreamOnFileW
)
755 test_SHCreateStreamOnFileW(stgm_access
[i
], stgm_sharing
[j
]);
757 if (pSHCreateStreamOnFileEx
) {
758 for (k
= 0; k
!= sizeof(stgm_flags
)/sizeof(stgm_flags
[0]); k
++)
759 test_SHCreateStreamOnFileEx(stgm_access
[i
], stgm_sharing
[j
] | stgm_flags
[k
]);
764 if (pSHCreateStreamOnFileEx
) test_SHCreateStreamOnFileEx_CopyTo();