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