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 STATSTG statstg; 195 196 /* IStream_Read/Write from the COBJMACROS is undefined by shlwapi.h */ 197 198 written = 0xdeadbeaf; 199 ret = stream->lpVtbl->Write(stream, "\x5e\xa7", 2, &written); 200 if (mode == STGM_WRITE || mode == STGM_READWRITE) 201 { 202 ok(ret == S_OK, "IStream_Write error %#x (access %#x)\n", ret, mode); 203 ok(written == 2, "expected 2, got %u\n", written); 204 } 205 else 206 { 207 ok(ret == STG_E_ACCESSDENIED || broken(ret == S_OK) /* win2000 */, "expected STG_E_ACCESSDENIED, got %#x (access %#x)\n", ret, mode); 208 ok(written == 0xdeadbeaf || broken(written == 2) /* win2000 */, "expected 0xdeadbeaf, got %#x\n", written); 209 written = 0; 210 if (ret == S_OK) return; /* no point in further testing */ 211 } 212 213 ret = stream->lpVtbl->Seek(stream, start, STREAM_SEEK_SET, NULL); 214 ok(ret == S_OK, "Seek error %#x\n", ret); 215 216 count = 0xdeadbeaf; 217 ret = stream->lpVtbl->Read(stream, buf, 2, &count); 218 if (written != 0) 219 { 220 ok(ret == S_OK || broken(ret == S_FALSE) /* win2000 */, "IStream_Read error %#x (access %#x, written %u)\n", ret, mode, written); 221 if (ret == S_OK && (mode == STGM_WRITE || mode == STGM_READWRITE)) 222 { 223 ok(count == 2, "expected 2, got %u\n", count); 224 ok(buf[0] == 0x5e && buf[1] == 0xa7, "expected 5ea7, got %02x%02x\n", buf[0], buf[1]); 225 } 226 else 227 ok(count == 0, "expected 0, got %u\n", count); 228 } 229 else 230 { 231 ok(ret == S_FALSE, "expected S_FALSE, got %#x (access %#x, written %u)\n", ret, mode, written); 232 ok(count == 0, "expected 0, got %u\n", count); 233 } 234 235 ret = stream->lpVtbl->Seek(stream, start, STREAM_SEEK_SET, NULL); 236 ok(ret == S_OK, "Seek error %#x\n", ret); 237 238 count = 0xdeadbeaf; 239 ret = stream->lpVtbl->Read(stream, buf, 0, &count); 240 ok(ret == S_OK, "IStream_Read error %#x (access %#x, written %u)\n", ret, mode, written); 241 ok(count == 0, "expected 0, got %u\n", count); 242 243 count = 0xdeadbeaf; 244 ret = stream->lpVtbl->Read(stream, buf, sizeof(buf), &count); 245 ok(ret == S_FALSE, "expected S_FALSE, got %#x (access %#x, written %u)\n", ret, mode, written); 246 ok(count == written, "expected %u, got %u\n", written, count); 247 if (count) 248 ok(buf[0] == 0x5e && buf[1] == 0xa7, "expected 5ea7, got %02x%02x\n", buf[0], buf[1]); 249 250 memset(&statstg, 0xff, sizeof(statstg)); 251 ret = IStream_Stat(stream, &statstg, 0); 252 ok(ret == S_OK, "Stat failed, hr %#x.\n", ret); 253 ok(statstg.pwcsName != NULL, "Unexpected name %s.\n", wine_dbgstr_w(statstg.pwcsName)); 254 CoTaskMemFree(statstg.pwcsName); 255 256 memset(&statstg, 0xff, sizeof(statstg)); 257 ret = IStream_Stat(stream, &statstg, STATFLAG_NONAME); 258 ok(ret == S_OK, "Stat failed, hr %#x.\n", ret); 259 ok(statstg.pwcsName == NULL, "Unexpected name %s.\n", wine_dbgstr_w(statstg.pwcsName)); 260 } 261 262 static void test_stream_qi(IStream *stream) 263 { 264 IUnknown *unk; 265 HRESULT hr; 266 267 hr = IStream_QueryInterface(stream, &IID_IStream, (void **)&unk); 268 ok(SUCCEEDED(hr), "Failed to get IStream interface, hr %#x.\n", hr); 269 IUnknown_Release(unk); 270 271 unk = NULL; 272 hr = IStream_QueryInterface(stream, &IID_ISequentialStream, (void **)&unk); 273 todo_wine 274 ok(SUCCEEDED(hr) || broken(hr == E_NOINTERFACE) /* XP */, "Failed to get ISequentialStream interface, hr %#x.\n", hr); 275 if (unk) 276 IUnknown_Release(unk); 277 278 hr = IStream_QueryInterface(stream, &IID_IUnknown, (void **)&unk); 279 ok(SUCCEEDED(hr), "Failed to get IUnknown interface, hr %#x.\n", hr); 280 IUnknown_Release(unk); 281 } 282 283 static void test_SHCreateStreamOnFileA(DWORD mode, DWORD stgm) 284 { 285 IStream * stream; 286 HRESULT ret; 287 ULONG refcount; 288 char test_file[MAX_PATH]; 289 static const CHAR testA_txt[] = "\\testA.txt"; 290 291 trace("SHCreateStreamOnFileA: testing mode %d, STGM flags %08x\n", mode, stgm); 292 293 /* Don't used a fixed path for the testA.txt file */ 294 GetTempPathA(MAX_PATH, test_file); 295 lstrcatA(test_file, testA_txt); 296 297 /* invalid arguments */ 298 299 stream = NULL; 300 ret = SHCreateStreamOnFileA(NULL, mode | stgm, &stream); 301 if (ret == E_INVALIDARG) /* Win98 SE */ { 302 win_skip("Not supported\n"); 303 return; 304 } 305 306 ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) /* NT */ || 307 ret == HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME) /* 9x */, 308 "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) " 309 "or HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), got 0x%08x\n", ret); 310 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); 311 312 if (0) /* This test crashes on WinXP SP2 */ 313 { 314 ret = SHCreateStreamOnFileA(test_file, mode | stgm, NULL); 315 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); 316 } 317 318 stream = NULL; 319 ret = SHCreateStreamOnFileA(test_file, mode | STGM_CONVERT | stgm, &stream); 320 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); 321 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); 322 323 stream = NULL; 324 ret = SHCreateStreamOnFileA(test_file, mode | STGM_DELETEONRELEASE | stgm, &stream); 325 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); 326 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); 327 328 stream = NULL; 329 ret = SHCreateStreamOnFileA(test_file, mode | STGM_TRANSACTED | stgm, &stream); 330 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); 331 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); 332 333 /* file does not exist */ 334 335 stream = NULL; 336 ret = SHCreateStreamOnFileA(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); 337 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); 338 ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); 339 340 stream = NULL; 341 ret = SHCreateStreamOnFileA(test_file, mode | STGM_CREATE | stgm, &stream); 342 ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); 343 ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); 344 345 if (stream) { 346 test_stream_qi(stream); 347 test_IStream_invalid_operations(stream, mode); 348 349 refcount = IStream_Release(stream); 350 ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount); 351 } 352 353 /* NOTE: don't delete the file, as it will be used for the file exists tests. */ 354 355 /* file exists */ 356 357 stream = NULL; 358 ret = SHCreateStreamOnFileA(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); 359 ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); 360 ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); 361 362 if (stream) { 363 test_IStream_invalid_operations(stream, mode); 364 365 refcount = IStream_Release(stream); 366 ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount); 367 } 368 369 stream = NULL; 370 ret = SHCreateStreamOnFileA(test_file, mode | STGM_CREATE | stgm, &stream); 371 ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); 372 ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); 373 374 if (stream) { 375 BOOL delret; 376 377 test_stream_read_write(stream, mode); 378 test_IStream_invalid_operations(stream, mode); 379 380 refcount = IStream_Release(stream); 381 ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount); 382 383 delret = DeleteFileA(test_file); 384 ok(delret, "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n", 385 test_file, GetLastError()); 386 } 387 } 388 389 390 static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm) 391 { 392 IStream * stream; 393 HRESULT ret; 394 ULONG refcount; 395 WCHAR test_file[MAX_PATH]; 396 CHAR test_fileA[MAX_PATH]; 397 static const CHAR testW_txt[] = "\\testW.txt"; 398 399 trace("SHCreateStreamOnFileW: testing mode %d, STGM flags %08x\n", mode, stgm); 400 401 /* Don't used a fixed path for the testW.txt file */ 402 GetTempPathA(MAX_PATH, test_fileA); 403 lstrcatA(test_fileA, testW_txt); 404 MultiByteToWideChar(CP_ACP, 0, test_fileA, -1, test_file, MAX_PATH); 405 406 /* invalid arguments */ 407 408 if (0) 409 { 410 /* Crashes on NT4 */ 411 stream = NULL; 412 ret = SHCreateStreamOnFileW(NULL, mode | stgm, &stream); 413 ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */ 414 ret == E_INVALIDARG /* Vista */, 415 "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret); 416 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); 417 } 418 419 if (0) 420 { 421 /* This test crashes on WinXP SP2 */ 422 ret = SHCreateStreamOnFileW(test_file, mode | stgm, NULL); 423 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); 424 } 425 426 stream = NULL; 427 ret = SHCreateStreamOnFileW(test_file, mode | STGM_CONVERT | stgm, &stream); 428 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); 429 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); 430 431 stream = NULL; 432 ret = SHCreateStreamOnFileW(test_file, mode | STGM_DELETEONRELEASE | stgm, &stream); 433 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); 434 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); 435 436 stream = NULL; 437 ret = SHCreateStreamOnFileW(test_file, mode | STGM_TRANSACTED | stgm, &stream); 438 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); 439 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); 440 441 /* file does not exist */ 442 443 stream = NULL; 444 ret = SHCreateStreamOnFileW(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); 445 if (ret == E_INVALIDARG) /* Win98 SE */ { 446 win_skip("Not supported\n"); 447 return; 448 } 449 450 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); 451 ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); 452 453 stream = NULL; 454 ret = SHCreateStreamOnFileW(test_file, mode | STGM_CREATE | stgm, &stream); 455 ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); 456 ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); 457 458 if (stream) { 459 test_stream_qi(stream); 460 test_IStream_invalid_operations(stream, mode); 461 462 refcount = IStream_Release(stream); 463 ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); 464 } 465 466 /* NOTE: don't delete the file, as it will be used for the file exists tests. */ 467 468 /* file exists */ 469 470 stream = NULL; 471 ret = SHCreateStreamOnFileW(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); 472 ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); 473 ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); 474 475 if (stream) { 476 test_IStream_invalid_operations(stream, mode); 477 478 refcount = IStream_Release(stream); 479 ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); 480 } 481 482 stream = NULL; 483 ret = SHCreateStreamOnFileW(test_file, mode | STGM_CREATE | stgm, &stream); 484 ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); 485 ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); 486 487 if (stream) { 488 BOOL delret; 489 490 test_stream_read_write(stream, mode); 491 test_IStream_invalid_operations(stream, mode); 492 493 refcount = IStream_Release(stream); 494 ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); 495 496 delret = DeleteFileA(test_fileA); 497 ok(delret, "SHCreateStreamOnFileW: could not delete the test file, got error %d\n", 498 GetLastError()); 499 } 500 } 501 502 503 static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) 504 { 505 IStream * stream; 506 IStream * template = NULL; 507 HRESULT ret; 508 ULONG refcount; 509 WCHAR test_file[MAX_PATH]; 510 CHAR test_fileA[MAX_PATH]; 511 static const CHAR testEx_txt[] = "\\testEx.txt"; 512 BOOL delret; 513 514 if (winetest_debug > 1) 515 trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm); 516 517 /* Don't used a fixed path for the testEx.txt file */ 518 GetTempPathA(MAX_PATH, test_fileA); 519 lstrcatA(test_fileA, testEx_txt); 520 MultiByteToWideChar(CP_ACP, 0, test_fileA, -1, test_file, MAX_PATH); 521 522 /* invalid arguments */ 523 524 if (0) 525 { 526 /* Crashes on NT4 */ 527 stream = NULL; 528 ret = SHCreateStreamOnFileEx(NULL, mode, 0, FALSE, NULL, &stream); 529 ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */ 530 ret == E_INVALIDARG /* Vista */, 531 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret); 532 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); 533 } 534 535 stream = NULL; 536 ret = SHCreateStreamOnFileEx(test_file, mode, 0, FALSE, template, &stream); 537 if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { 538 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n"); 539 Sleep(1000); 540 ret = SHCreateStreamOnFileEx(test_file, mode, 0, FALSE, template, &stream); 541 } 542 ok( ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || 543 ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), 544 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or " 545 "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret); 546 547 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); 548 549 if (0) 550 { 551 /* This test crashes on WinXP SP2 */ 552 ret = SHCreateStreamOnFileEx(test_file, mode, 0, FALSE, NULL, NULL); 553 ok(ret == E_INVALIDARG, "SHCreateStreamOnFileEx: expected E_INVALIDARG, got 0x%08x\n", ret); 554 } 555 556 /* file does not exist */ 557 558 stream = NULL; 559 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream); 560 if ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED && mode == STGM_READ) { 561 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* XP */ || ret == E_INVALIDARG /* Vista */, 562 "SHCreateStreamOnFileEx: expected E_INVALIDARG or HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); 563 564 if (ret == E_INVALIDARG) { 565 skip("SHCreateStreamOnFileEx: STGM_TRANSACTED not supported in this configuration.\n"); 566 return; 567 } 568 } else { 569 ok( ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || 570 ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), 571 "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or " 572 "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret); 573 } 574 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); 575 576 stream = NULL; 577 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream); 578 /* not supported on win9x */ 579 if (broken(ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) && stream == NULL)) { 580 skip("Not supported\n"); 581 DeleteFileA(test_fileA); 582 return; 583 } 584 585 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); 586 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); 587 588 if (stream) { 589 test_stream_qi(stream); 590 test_IStream_invalid_operations(stream, mode); 591 592 refcount = IStream_Release(stream); 593 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); 594 595 delret = DeleteFileA(test_fileA); 596 ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", 597 GetLastError()); 598 } 599 600 stream = NULL; 601 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream); 602 if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { 603 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n"); 604 Sleep(1000); 605 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream); 606 } 607 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); 608 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); 609 610 if (stream) { 611 test_IStream_invalid_operations(stream, mode); 612 613 refcount = IStream_Release(stream); 614 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); 615 616 delret = DeleteFileA(test_fileA); 617 ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", 618 GetLastError()); 619 } 620 621 stream = NULL; 622 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream); 623 if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { 624 win_skip("File probably locked by Anti-Virus/Spam software, trying again\n"); 625 Sleep(1000); 626 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream); 627 } 628 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); 629 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); 630 631 if (stream) { 632 test_IStream_invalid_operations(stream, mode); 633 634 refcount = IStream_Release(stream); 635 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); 636 } 637 638 /* NOTE: don't delete the file, as it will be used for the file exists tests. */ 639 640 /* file exists */ 641 642 stream = NULL; 643 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, 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"); 646 647 if (stream) { 648 test_IStream_invalid_operations(stream, mode); 649 650 refcount = IStream_Release(stream); 651 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); 652 } 653 654 stream = NULL; 655 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream); 656 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), got 0x%08x\n", ret); 657 ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); 658 659 stream = NULL; 660 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream); 661 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); 662 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); 663 664 if (stream) { 665 test_IStream_invalid_operations(stream, mode); 666 667 refcount = IStream_Release(stream); 668 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); 669 } 670 671 stream = NULL; 672 ret = SHCreateStreamOnFileEx(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream); 673 ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); 674 ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); 675 676 if (stream) { 677 test_IStream_invalid_operations(stream, mode); 678 679 refcount = IStream_Release(stream); 680 ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); 681 } 682 683 delret = DeleteFileA(test_fileA); 684 ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", 685 GetLastError()); 686 } 687 688 689 static void test_SHCreateStreamOnFileEx_CopyTo(void) 690 { 691 HRESULT ret; 692 IStream *src, *dst; 693 WCHAR tmpPath[MAX_PATH]; 694 WCHAR srcFileName[MAX_PATH]; 695 WCHAR dstFileName[MAX_PATH]; 696 ULARGE_INTEGER count, read, written; 697 LARGE_INTEGER distance; 698 static const char srcContents[1]; 699 static const WCHAR prefix[] = { 'T', 'S', 'T', 0 }; 700 701 GetTempPathW(MAX_PATH, tmpPath); 702 ret = GetTempFileNameW(tmpPath, prefix, 0, srcFileName); 703 ok(ret != 0, "GetTempFileName failed, got error %d\n", GetLastError()); 704 ret = GetTempFileNameW(tmpPath, prefix, 0, dstFileName); 705 ok(ret != 0, "GetTempFileName failed, got error %d\n", GetLastError()); 706 707 ret = SHCreateStreamOnFileEx(srcFileName, STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE, FILE_ATTRIBUTE_TEMPORARY, FALSE, NULL, &src); 708 ok(SUCCEEDED(ret), "SHCreateStreamOnFileEx failed with ret=0x%08x\n", ret); 709 710 written.QuadPart = 0; 711 ret = IStream_Write(src, srcContents, sizeof(srcContents), &U(written).LowPart); 712 ok(SUCCEEDED(ret), "ISequentialStream_Write failed with ret=0x%08x\n", ret); 713 714 distance.QuadPart = 0; 715 ret = IStream_Seek(src, distance, STREAM_SEEK_SET, &written); 716 ok(SUCCEEDED(ret), "ISequentialStream_Seek failed with ret=0x%08x\n", ret); 717 718 ret = SHCreateStreamOnFileEx(dstFileName, STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE, FILE_ATTRIBUTE_TEMPORARY, FALSE, NULL, &dst); 719 ok(SUCCEEDED(ret), "SHCreateStreamOnFileEx failed with ret=0x%08x\n", ret); 720 721 /* Test using a count larger than the source file, so that the Read operation will fall short */ 722 count.QuadPart = 2; 723 724 ret = IStream_CopyTo(src, dst, count, &read, &written); 725 ok(SUCCEEDED(ret), "CopyTo failed with ret=0x%08x\n", ret); 726 727 ok(read.QuadPart == 1, "read does not match size: %d != 1\n", U(read).LowPart); 728 ok(written.QuadPart == 1, "written does not match size: %d != 1\n", U(written).LowPart); 729 730 IStream_Release(dst); 731 IStream_Release(src); 732 DeleteFileW( srcFileName ); 733 DeleteFileW( dstFileName ); 734 } 735 736 static void test_SHCreateMemStream(void) 737 { 738 static const BYTE initial[10]; 739 IStream *stream, *stream2; 740 IUnknown *unk; 741 char buff[10]; 742 HRESULT hr; 743 744 stream = SHCreateMemStream(initial, 0); 745 ok(stream != NULL, "Failed to create a stream.\n"); 746 IStream_Release(stream); 747 748 stream = SHCreateMemStream(NULL, 10); 749 ok(stream != NULL, "Failed to create a stream.\n"); 750 IStream_Release(stream); 751 752 stream = SHCreateMemStream(NULL, 0); 753 ok(stream != NULL, "Failed to create a stream.\n"); 754 755 hr = IStream_QueryInterface(stream, &IID_ISequentialStream, (void **)&unk); 756 todo_wine 757 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* WinXP */, "Failed to QI, hr %#x.\n", hr); 758 if (unk) 759 IUnknown_Release(unk); 760 761 hr = IStream_Read(stream, buff, sizeof(buff), NULL); 762 todo_wine 763 ok(hr == S_FALSE || broken(hr == S_OK) /* WinXP */, "Unexpected hr %#x.\n", hr); 764 765 hr = IStream_Clone(stream, &stream2); 766 todo_wine 767 ok(hr == S_OK || broken(hr == E_NOTIMPL) /* < Win8 */, "Failed to clone a stream, hr %#x.\n", hr); 768 if (hr == S_OK) 769 IStream_Release(stream2); 770 771 IStream_Release(stream); 772 } 773 774 START_TEST(istream) 775 { 776 static const DWORD stgm_access[] = { 777 STGM_READ, 778 STGM_WRITE, 779 STGM_READWRITE 780 }; 781 782 static const DWORD stgm_sharing[] = { 783 0, 784 STGM_SHARE_DENY_NONE, 785 STGM_SHARE_DENY_READ, 786 STGM_SHARE_DENY_WRITE, 787 STGM_SHARE_EXCLUSIVE 788 }; 789 790 static const DWORD stgm_flags[] = { 791 0, 792 STGM_CONVERT, 793 STGM_DELETEONRELEASE, 794 STGM_CONVERT | STGM_DELETEONRELEASE, 795 STGM_TRANSACTED | STGM_CONVERT, 796 STGM_TRANSACTED | STGM_DELETEONRELEASE, 797 STGM_TRANSACTED | STGM_CONVERT | STGM_DELETEONRELEASE 798 }; 799 800 int i, j, k; 801 802 for (i = 0; i != ARRAY_SIZE(stgm_access); i++) { 803 for (j = 0; j != ARRAY_SIZE(stgm_sharing); j ++) { 804 test_SHCreateStreamOnFileA(stgm_access[i], stgm_sharing[j]); 805 test_SHCreateStreamOnFileW(stgm_access[i], stgm_sharing[j]); 806 807 for (k = 0; k != ARRAY_SIZE(stgm_flags); k++) 808 test_SHCreateStreamOnFileEx(stgm_access[i], stgm_sharing[j] | stgm_flags[k]); 809 } 810 } 811 812 test_SHCreateStreamOnFileEx_CopyTo(); 813 test_SHCreateMemStream(); 814 } 815