1 /* 2 * Stream on HGLOBAL Tests 3 * 4 * Copyright 2006 Robert Shearman (for CodeWeavers) 5 * Copyright 2016 Dmitry Timoshkov 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "precomp.h" 23 24 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr) 25 26 static char const * const *expected_method_list; 27 28 #define CHECK_EXPECTED_METHOD(method_name) \ 29 do { \ 30 ok(*expected_method_list != NULL, "Extra method %s called\n", method_name); \ 31 if (*expected_method_list) \ 32 { \ 33 ok(!strcmp(*expected_method_list, method_name), "Expected %s to be called instead of %s\n", \ 34 *expected_method_list, method_name); \ 35 expected_method_list++; \ 36 } \ 37 } while(0) 38 39 static void test_streamonhglobal(IStream *pStream) 40 { 41 const char data[] = "Test String"; 42 ULARGE_INTEGER ull; 43 LARGE_INTEGER ll; 44 char buffer[128]; 45 ULONG read; 46 STATSTG statstg; 47 HRESULT hr; 48 49 ull.QuadPart = sizeof(data); 50 hr = IStream_SetSize(pStream, ull); 51 ok_ole_success(hr, "IStream_SetSize"); 52 53 hr = IStream_Write(pStream, data, sizeof(data), NULL); 54 ok_ole_success(hr, "IStream_Write"); 55 56 ll.QuadPart = 0; 57 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, NULL); 58 ok_ole_success(hr, "IStream_Seek"); 59 60 /* should return S_OK, not S_FALSE */ 61 hr = IStream_Read(pStream, buffer, sizeof(buffer), &read); 62 ok_ole_success(hr, "IStream_Read"); 63 ok(read == sizeof(data), "IStream_Read returned read %d\n", read); 64 65 /* ignores HighPart */ 66 ull.u.HighPart = -1; 67 ull.u.LowPart = 0; 68 hr = IStream_SetSize(pStream, ull); 69 ok_ole_success(hr, "IStream_SetSize"); 70 71 /* IStream_Seek -- NULL position argument */ 72 ll.u.HighPart = 0; 73 ll.u.LowPart = 0; 74 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, NULL); 75 ok_ole_success(hr, "IStream_Seek"); 76 77 /* IStream_Seek -- valid position argument (seek from current position) */ 78 ull.u.HighPart = 0xCAFECAFE; 79 ull.u.LowPart = 0xCAFECAFE; 80 ll.u.HighPart = 0; 81 ll.u.LowPart = 0; 82 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 83 ok_ole_success(hr, "IStream_Seek"); 84 ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart); 85 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 86 87 /* IStream_Seek -- invalid seek argument */ 88 ull.u.HighPart = 0xCAFECAFE; 89 ull.u.LowPart = 0xCAFECAFE; 90 ll.u.HighPart = 0; 91 ll.u.LowPart = 123; 92 hr = IStream_Seek(pStream, ll, STREAM_SEEK_END+1, &ull); 93 ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr); 94 ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart); 95 ok(ull.u.HighPart == 0, "should not have changed HighPart, got %d\n", ull.u.HighPart); 96 97 /* IStream_Seek -- valid position argument (seek to beginning) */ 98 ull.u.HighPart = 0xCAFECAFE; 99 ull.u.LowPart = 0xCAFECAFE; 100 ll.u.HighPart = 0; 101 ll.u.LowPart = 0; 102 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 103 ok_ole_success(hr, "IStream_Seek"); 104 ok(ull.u.LowPart == 0, "should have set LowPart to 0 instead of %d\n", ull.u.LowPart); 105 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 106 107 /* IStream_Seek -- valid position argument (seek to end) */ 108 ull.u.HighPart = 0xCAFECAFE; 109 ull.u.LowPart = 0xCAFECAFE; 110 ll.u.HighPart = 0; 111 ll.u.LowPart = 0; 112 hr = IStream_Seek(pStream, ll, STREAM_SEEK_END, &ull); 113 ok_ole_success(hr, "IStream_Seek"); 114 ok(ull.u.LowPart == 0, "should have set LowPart to 0 instead of %d\n", ull.u.LowPart); 115 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 116 117 /* IStream_Seek -- ignore HighPart in the move value (seek from current position) */ 118 ll.u.HighPart = 0; 119 ll.u.LowPart = sizeof(data); 120 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 121 ok_ole_success(hr, "IStream_Seek"); 122 123 ull.u.HighPart = 0xCAFECAFE; 124 ull.u.LowPart = 0xCAFECAFE; 125 ll.u.HighPart = -1; 126 ll.u.LowPart = 0; 127 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 128 ok_ole_success(hr, "IStream_Seek"); 129 ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart); 130 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 131 132 /* IStream_Seek -- ignore HighPart in the move value (seek to beginning) */ 133 ll.u.HighPart = 0; 134 ll.u.LowPart = sizeof(data); 135 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 136 ok_ole_success(hr, "IStream_Seek"); 137 138 ull.u.HighPart = 0xCAFECAFE; 139 ull.u.LowPart = 0xCAFECAFE; 140 ll.u.HighPart = -1; 141 ll.u.LowPart = 0; 142 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 143 ok_ole_success(hr, "IStream_Seek"); 144 ok(ull.u.LowPart == 0, "should have set LowPart to 0 instead of %d\n", ull.u.LowPart); 145 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 146 147 /* IStream_Seek -- invalid LowPart value (seek before start of stream) */ 148 ll.u.HighPart = 0; 149 ll.u.LowPart = sizeof(data); 150 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 151 ok_ole_success(hr, "IStream_Seek"); 152 153 ull.u.HighPart = 0xCAFECAFE; 154 ull.u.LowPart = 0xCAFECAFE; 155 ll.u.HighPart = 0; 156 ll.u.LowPart = 0x80000000; 157 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 158 ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr); 159 ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart); 160 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 161 162 /* IStream_Seek -- valid LowPart value (seek to start of stream) */ 163 ll.u.HighPart = 0; 164 ll.u.LowPart = sizeof(data); 165 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 166 ok_ole_success(hr, "IStream_Seek"); 167 168 ull.u.HighPart = 0xCAFECAFE; 169 ull.u.LowPart = 0xCAFECAFE; 170 ll.u.HighPart = 0; 171 ll.u.LowPart = -(DWORD)sizeof(data); 172 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 173 ok_ole_success(hr, "IStream_Seek"); 174 ok(ull.u.LowPart == 0, "LowPart set to %d\n", ull.u.LowPart); 175 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 176 177 /* IStream_Seek -- invalid LowPart value (seek to start of stream-1) */ 178 ll.u.HighPart = 0; 179 ll.u.LowPart = sizeof(data); 180 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 181 ok_ole_success(hr, "IStream_Seek"); 182 183 ull.u.HighPart = 0xCAFECAFE; 184 ull.u.LowPart = 0xCAFECAFE; 185 ll.u.HighPart = 0; 186 ll.u.LowPart = -(DWORD)sizeof(data)-1; 187 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 188 ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr); 189 ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart); 190 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 191 192 /* IStream_Seek -- valid LowPart value (seek forward to 0x80000000) */ 193 ll.u.HighPart = 0; 194 ll.u.LowPart = sizeof(data); 195 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 196 ok_ole_success(hr, "IStream_Seek"); 197 198 ull.u.HighPart = 0xCAFECAFE; 199 ull.u.LowPart = 0xCAFECAFE; 200 ll.u.HighPart = 0; 201 ll.u.LowPart = 0x80000000 - sizeof(data); 202 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 203 ok_ole_success(hr, "IStream_Seek"); 204 ok(ull.u.LowPart == 0x80000000, "LowPart set to %d\n", ull.u.LowPart); 205 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 206 207 /* IStream_Seek -- invalid LowPart value (seek to beginning) */ 208 ll.u.HighPart = 0; 209 ll.u.LowPart = sizeof(data); 210 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 211 ok_ole_success(hr, "IStream_Seek"); 212 213 ull.u.HighPart = 0xCAFECAFE; 214 ull.u.LowPart = 0xCAFECAFE; 215 ll.u.HighPart = 0; 216 ll.u.LowPart = 0x80000000; 217 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 218 ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr); 219 ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart); 220 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 221 222 /* IStream_Seek -- valid LowPart value (seek to beginning) */ 223 ull.u.HighPart = 0xCAFECAFE; 224 ull.u.LowPart = 0xCAFECAFE; 225 ll.u.HighPart = 0; 226 ll.u.LowPart = 0x7FFFFFFF; 227 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 228 ok_ole_success(hr, "IStream_Seek"); 229 ok(ull.u.LowPart == 0x7FFFFFFF, "should have set LowPart to 0x7FFFFFFF instead of %08x\n", ull.u.LowPart); 230 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 231 232 /* IStream_Seek -- valid LowPart value (seek from current position) */ 233 ll.u.HighPart = 0; 234 ll.u.LowPart = 0; 235 hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull); 236 ok_ole_success(hr, "IStream_Seek"); 237 238 ull.u.HighPart = 0xCAFECAFE; 239 ull.u.LowPart = 0xCAFECAFE; 240 ll.u.HighPart = 0; 241 ll.u.LowPart = 0x7FFFFFFF; 242 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 243 ok_ole_success(hr, "IStream_Seek"); 244 ok(ull.u.LowPart == 0x7FFFFFFF, "should have set LowPart to 0x7FFFFFFF instead of %08x\n", ull.u.LowPart); 245 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 246 247 /* IStream_Seek -- second seek allows you to go past 0x7FFFFFFF size */ 248 ull.u.HighPart = 0xCAFECAFE; 249 ull.u.LowPart = 0xCAFECAFE; 250 ll.u.HighPart = 0; 251 ll.u.LowPart = 9; 252 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 253 ok_ole_success(hr, "IStream_Seek"); 254 ok(ull.u.LowPart == 0x80000008, "should have set LowPart to 0x80000008 instead of %08x\n", ull.u.LowPart); 255 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 256 257 /* IStream_Seek -- seek wraps position/size on integer overflow, but not on win8 */ 258 ull.u.HighPart = 0xCAFECAFE; 259 ull.u.LowPart = 0xCAFECAFE; 260 ll.u.HighPart = 0; 261 ll.u.LowPart = 0x7FFFFFFF; 262 hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull); 263 ok(hr == S_OK || hr == STG_E_SEEKERROR /* win8 */, "IStream_Seek\n"); 264 if (SUCCEEDED(hr)) 265 ok(ull.u.LowPart == 0x00000007, "should have set LowPart to 0x00000007 instead of %08x\n", ull.u.LowPart); 266 else 267 ok(ull.u.LowPart == 0x80000008, "should have set LowPart to 0x80000008 instead of %08x\n", ull.u.LowPart); 268 ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart); 269 270 hr = IStream_Commit(pStream, STGC_DEFAULT); 271 ok_ole_success(hr, "IStream_Commit"); 272 273 hr = IStream_Revert(pStream); 274 ok_ole_success(hr, "IStream_Revert"); 275 276 hr = IStream_LockRegion(pStream, ull, ull, LOCK_WRITE); 277 ok(hr == STG_E_INVALIDFUNCTION, "IStream_LockRegion should have returned STG_E_INVALIDFUNCTION instead of 0x%08x\n", hr); 278 279 hr = IStream_Stat(pStream, &statstg, STATFLAG_DEFAULT); 280 ok_ole_success(hr, "IStream_Stat"); 281 ok(statstg.type == STGTY_STREAM, "statstg.type should have been STGTY_STREAM instead of %d\n", statstg.type); 282 283 /* test OOM condition */ 284 ull.u.HighPart = -1; 285 ull.u.LowPart = -1; 286 hr = IStream_SetSize(pStream, ull); 287 ok(hr == E_OUTOFMEMORY || broken(hr == S_OK), /* win9x */ 288 "IStream_SetSize with large size should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr); 289 } 290 291 static HRESULT WINAPI TestStream_QueryInterface(IStream *iface, REFIID riid, void **ppv) 292 { 293 if (IsEqualIID(riid, &IID_IUnknown) || 294 IsEqualIID(riid, &IID_ISequentialStream) || 295 IsEqualIID(riid, &IID_IStream)) 296 { 297 *ppv = iface; 298 IStream_AddRef(iface); 299 return S_OK; 300 } 301 *ppv = NULL; 302 return E_NOINTERFACE; 303 } 304 305 static ULONG WINAPI TestStream_AddRef(IStream *iface) 306 { 307 return 2; 308 } 309 310 static ULONG WINAPI TestStream_Release(IStream *iface) 311 { 312 return 1; 313 } 314 315 static HRESULT WINAPI TestStream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead) 316 { 317 CHECK_EXPECTED_METHOD("TestStream_Read"); 318 return E_NOTIMPL; 319 } 320 321 static HRESULT WINAPI TestStream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten) 322 { 323 CHECK_EXPECTED_METHOD("TestStream_Write"); 324 *pcbWritten = 5; 325 return S_OK; 326 } 327 328 static HRESULT WINAPI TestStream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 329 { 330 CHECK_EXPECTED_METHOD("TestStream_Seek"); 331 return E_NOTIMPL; 332 } 333 334 static HRESULT WINAPI TestStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) 335 { 336 CHECK_EXPECTED_METHOD("TestStream_SetSize"); 337 return E_NOTIMPL; 338 } 339 340 static HRESULT WINAPI TestStream_CopyTo(IStream *iface, IStream *pStream, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 341 { 342 CHECK_EXPECTED_METHOD("TestStream_CopyTo"); 343 return E_NOTIMPL; 344 } 345 346 static HRESULT WINAPI TestStream_Commit(IStream *iface, DWORD grfCommitFlags) 347 { 348 CHECK_EXPECTED_METHOD("TestStream_Commit"); 349 return E_NOTIMPL; 350 } 351 352 static HRESULT WINAPI TestStream_Revert(IStream *iface) 353 { 354 CHECK_EXPECTED_METHOD("TestStream_Revert"); 355 return E_NOTIMPL; 356 } 357 358 static HRESULT WINAPI TestStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 359 { 360 CHECK_EXPECTED_METHOD("TestStream_LockRegion"); 361 return E_NOTIMPL; 362 } 363 364 static HRESULT WINAPI TestStream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 365 { 366 CHECK_EXPECTED_METHOD("TestStream_UnlockRegion"); 367 return E_NOTIMPL; 368 } 369 370 static HRESULT WINAPI TestStream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) 371 { 372 CHECK_EXPECTED_METHOD("TestStream_Stat"); 373 return E_NOTIMPL; 374 } 375 376 static HRESULT WINAPI TestStream_Clone(IStream *iface, IStream **pStream) 377 { 378 CHECK_EXPECTED_METHOD("TestStream_Clone"); 379 return E_NOTIMPL; 380 } 381 382 static /*const*/ IStreamVtbl StreamVtbl = 383 { 384 TestStream_QueryInterface, 385 TestStream_AddRef, 386 TestStream_Release, 387 TestStream_Read, 388 TestStream_Write, 389 TestStream_Seek, 390 TestStream_SetSize, 391 TestStream_CopyTo, 392 TestStream_Commit, 393 TestStream_Revert, 394 TestStream_LockRegion, 395 TestStream_UnlockRegion, 396 TestStream_Stat, 397 TestStream_Clone 398 }; 399 400 static IStream Test_Stream = { &StreamVtbl }; 401 402 static void test_copyto(void) 403 { 404 IStream *pStream, *pStream2; 405 HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); 406 static const char szHello[] = "Hello"; 407 ULARGE_INTEGER cb; 408 static const char *methods_copyto[] = 409 { 410 "TestStream_Write", 411 NULL 412 }; 413 ULONG written; 414 ULARGE_INTEGER ullRead; 415 ULARGE_INTEGER ullWritten; 416 ULARGE_INTEGER libNewPosition; 417 static const LARGE_INTEGER llZero; 418 char buffer[15]; 419 420 ok_ole_success(hr, "CreateStreamOnHGlobal"); 421 422 expected_method_list = methods_copyto; 423 424 hr = IStream_Write(pStream, szHello, sizeof(szHello), &written); 425 ok_ole_success(hr, "IStream_Write"); 426 ok(written == sizeof(szHello), "only %d bytes written\n", written); 427 428 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); 429 ok_ole_success(hr, "IStream_Seek"); 430 431 cb.QuadPart = sizeof(szHello); 432 hr = IStream_CopyTo(pStream, &Test_Stream, cb, &ullRead, &ullWritten); 433 ok(ullWritten.QuadPart == 5, "ullWritten was %d instead\n", (ULONG)ullWritten.QuadPart); 434 ok(ullRead.QuadPart == sizeof(szHello), "only %d bytes read\n", (ULONG)ullRead.QuadPart); 435 ok_ole_success(hr, "IStream_CopyTo"); 436 437 ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); 438 439 hr = IStream_Clone(pStream, &pStream2); 440 ok_ole_success(hr, "IStream_Clone"); 441 442 hr = IStream_Seek(pStream2, llZero, STREAM_SEEK_CUR, &libNewPosition); 443 ok_ole_success(hr, "IStream_Seek"); 444 ok(libNewPosition.QuadPart == sizeof(szHello), "libNewPosition wasn't set correctly for the cloned stream\n"); 445 446 hr = IStream_Seek(pStream2, llZero, STREAM_SEEK_SET, NULL); 447 ok_ole_success(hr, "IStream_Seek"); 448 449 hr = IStream_Read(pStream2, buffer, sizeof(buffer), NULL); 450 ok_ole_success(hr, "IStream_Read"); 451 ok(!strcmp(buffer, szHello), "read data \"%s\" didn't match originally written data\n", buffer); 452 453 IStream_Release(pStream2); 454 IStream_Release(pStream); 455 } 456 457 static void test_freed_hglobal(void) 458 { 459 static const char teststring[] = "this is a test string"; 460 HRESULT hr; 461 IStream *pStream; 462 HGLOBAL hglobal; 463 char *p; 464 char buffer[sizeof(teststring) + 8]; 465 ULARGE_INTEGER ull; 466 ULONG read, written; 467 468 hglobal = GlobalAlloc(GMEM_DDESHARE|GMEM_NODISCARD|GMEM_MOVEABLE, strlen(teststring) + 1); 469 ok(hglobal != NULL, "GlobalAlloc failed with error %d\n", GetLastError()); 470 p = GlobalLock(hglobal); 471 strcpy(p, teststring); 472 GlobalUnlock(hglobal); 473 474 hr = CreateStreamOnHGlobal(hglobal, FALSE, &pStream); 475 ok_ole_success(hr, "CreateStreamOnHGlobal"); 476 477 hr = IStream_Read(pStream, buffer, sizeof(buffer), &read); 478 ok_ole_success(hr, "IStream_Read"); 479 ok(!strcmp(buffer, teststring), "buffer data %s differs\n", buffer); 480 ok(read == sizeof(teststring) || 481 broken(read == ((sizeof(teststring) + 3) & ~3)), /* win9x rounds the size */ 482 "read should be sizeof(teststring) instead of %d\n", read); 483 484 GlobalFree(hglobal); 485 486 memset(buffer, 0, sizeof(buffer)); 487 read = -1; 488 hr = IStream_Read(pStream, buffer, sizeof(buffer), &read); 489 ok_ole_success(hr, "IStream_Read"); 490 ok(buffer[0] == 0, "buffer data should be untouched\n"); 491 ok(read == 0, "read should be 0 instead of %d\n", read); 492 493 ull.QuadPart = sizeof(buffer); 494 hr = IStream_SetSize(pStream, ull); 495 ok(hr == E_OUTOFMEMORY, "IStream_SetSize with invalid HGLOBAL should return E_OUTOFMEMORY instead of 0x%08x\n", hr); 496 497 hr = IStream_Write(pStream, buffer, sizeof(buffer), &written); 498 ok(hr == E_OUTOFMEMORY, "IStream_Write with invalid HGLOBAL should return E_OUTOFMEMORY instead of 0x%08x\n", hr); 499 ok(written == 0, "written should be 0 instead of %d\n", written); 500 501 IStream_Release(pStream); 502 } 503 504 static void stream_info(IStream *stream, HGLOBAL *hmem, int *size, int *pos) 505 { 506 HRESULT hr; 507 STATSTG stat; 508 LARGE_INTEGER offset; 509 ULARGE_INTEGER newpos; 510 511 *hmem = 0; 512 *size = *pos = -1; 513 514 hr = GetHGlobalFromStream(stream, hmem); 515 ok(hr == S_OK, "unexpected %#x\n", hr); 516 517 memset(&stat, 0x55, sizeof(stat)); 518 hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT); 519 ok(hr == S_OK, "unexpected %#x\n", hr); 520 ok(stat.type == STGTY_STREAM, "unexpected %#x\n", stat.type); 521 ok(!stat.pwcsName, "unexpected %p\n", stat.pwcsName); 522 ok(IsEqualIID(&stat.clsid, &GUID_NULL), "unexpected %s\n", wine_dbgstr_guid(&stat.clsid)); 523 ok(!stat.cbSize.HighPart, "unexpected %#x\n", stat.cbSize.HighPart); 524 *size = stat.cbSize.LowPart; 525 526 offset.QuadPart = 0; 527 hr = IStream_Seek(stream, offset, STREAM_SEEK_CUR, &newpos); 528 ok(hr == S_OK, "unexpected %#x\n", hr); 529 ok(!newpos.HighPart, "unexpected %#x\n", newpos.HighPart); 530 *pos = newpos.LowPart; 531 } 532 533 static void test_IStream_Clone(void) 534 { 535 static const char hello[] = "Hello World!"; 536 char buf[32]; 537 HRESULT hr; 538 IStream *stream, *clone; 539 HGLOBAL orig_hmem, hmem, hmem_clone; 540 ULARGE_INTEGER newsize; 541 LARGE_INTEGER offset; 542 int size, pos, ret; 543 544 /* test simple case for Clone */ 545 orig_hmem = GlobalAlloc(GMEM_MOVEABLE, 0); 546 ok(orig_hmem != 0, "unexpected %p\n", orig_hmem); 547 hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream); 548 ok(hr == S_OK, "unexpected %#x\n", hr); 549 550 hr = GetHGlobalFromStream(stream, NULL); 551 ok(hr == E_INVALIDARG, "unexpected %#x\n", hr); 552 553 hr = GetHGlobalFromStream(NULL, &hmem); 554 ok(hr == E_INVALIDARG, "unexpected %#x\n", hr); 555 556 stream_info(stream, &hmem, &size, &pos); 557 ok(hmem == orig_hmem, "handles should match\n"); 558 ok(size == 0, "unexpected %d\n", size); 559 ok(pos == 0, "unexpected %d\n", pos); 560 561 hr = IStream_Clone(stream, &clone); 562 ok(hr == S_OK, "unexpected %#x\n", hr); 563 564 hr = IStream_Write(stream, hello, sizeof(hello), NULL); 565 ok(hr == S_OK, "unexpected %#x\n", hr); 566 567 stream_info(stream, &hmem, &size, &pos); 568 ok(hmem != 0, "unexpected %p\n", hmem); 569 ok(size == 13, "unexpected %d\n", size); 570 ok(pos == 13, "unexpected %d\n", pos); 571 572 stream_info(clone, &hmem_clone, &size, &pos); 573 ok(hmem_clone == hmem, "handles should match\n"); 574 ok(size == 13, "unexpected %d\n", size); 575 ok(pos == 0, "unexpected %d\n", pos); 576 577 buf[0] = 0; 578 hr = IStream_Read(clone, buf, sizeof(buf), NULL); 579 ok(hr == S_OK, "unexpected %#x\n", hr); 580 ok(!strcmp(buf, hello), "wrong stream contents\n"); 581 582 newsize.QuadPart = 0x8000; 583 hr = IStream_SetSize(stream, newsize); 584 ok(hr == S_OK, "unexpected %#x\n", hr); 585 586 stream_info(stream, &hmem, &size, &pos); 587 ok(hmem != 0, "unexpected %p\n", hmem); 588 ok(hmem == orig_hmem, "unexpected %p\n", hmem); 589 ok(size == 0x8000, "unexpected %#x\n", size); 590 ok(pos == 13, "unexpected %d\n", pos); 591 592 stream_info(clone, &hmem_clone, &size, &pos); 593 ok(hmem_clone == hmem, "handles should match\n"); 594 ok(size == 0x8000, "unexpected %#x\n", size); 595 ok(pos == 13, "unexpected %d\n", pos); 596 597 IStream_Release(clone); 598 IStream_Release(stream); 599 600 /* exploit GMEM_FIXED forced move for the same base streams */ 601 orig_hmem = GlobalAlloc(GMEM_FIXED, 1); 602 ok(orig_hmem != 0, "unexpected %p\n", orig_hmem); 603 hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream); 604 ok(hr == S_OK, "unexpected %#x\n", hr); 605 606 hr = IStream_Clone(stream, &clone); 607 ok(hr == S_OK, "unexpected %#x\n", hr); 608 609 stream_info(stream, &hmem, &size, &pos); 610 ok(hmem != 0, "unexpected %p\n", hmem); 611 ok(size == 1, "unexpected %d\n", size); 612 ok(pos == 0, "unexpected %d\n", pos); 613 614 stream_info(clone, &hmem_clone, &size, &pos); 615 ok(hmem_clone == hmem, "handles should match\n"); 616 ok(size == 1, "unexpected %d\n", size); 617 ok(pos == 0, "unexpected %d\n", pos); 618 619 newsize.QuadPart = 0x8000; 620 hr = IStream_SetSize(stream, newsize); 621 ok(hr == S_OK, "unexpected %#x\n", hr); 622 623 stream_info(stream, &hmem, &size, &pos); 624 ok(hmem != 0, "unexpected %p\n", hmem); 625 ok(hmem != orig_hmem, "unexpected %p\n", hmem); 626 ok(size == 0x8000, "unexpected %#x\n", size); 627 ok(pos == 0, "unexpected %d\n", pos); 628 629 stream_info(clone, &hmem_clone, &size, &pos); 630 ok(hmem_clone == hmem, "handles should match\n"); 631 ok(size == 0x8000, "unexpected %#x\n", size); 632 ok(pos == 0, "unexpected %d\n", pos); 633 634 IStream_Release(stream); 635 IStream_Release(clone); 636 637 /* exploit GMEM_FIXED forced move for different base streams */ 638 orig_hmem = GlobalAlloc(GMEM_FIXED, 1); 639 ok(orig_hmem != 0, "unexpected %p\n", orig_hmem); 640 hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream); 641 ok(hr == S_OK, "unexpected %#x\n", hr); 642 643 hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &clone); 644 ok(hr == S_OK, "unexpected %#x\n", hr); 645 646 stream_info(stream, &hmem, &size, &pos); 647 ok(hmem != 0, "unexpected %p\n", hmem); 648 ok(size == 1, "unexpected %d\n", size); 649 ok(pos == 0, "unexpected %d\n", pos); 650 651 stream_info(clone, &hmem_clone, &size, &pos); 652 ok(hmem_clone == hmem, "handles should match\n"); 653 ok(size == 1, "unexpected %d\n", size); 654 ok(pos == 0, "unexpected %d\n", pos); 655 656 newsize.QuadPart = 0x8000; 657 hr = IStream_SetSize(stream, newsize); 658 ok(hr == S_OK, "unexpected %#x\n", hr); 659 660 stream_info(stream, &hmem, &size, &pos); 661 ok(hmem != 0, "unexpected %p\n", hmem); 662 ok(hmem != orig_hmem, "unexpected %p\n", hmem); 663 ok(size == 0x8000, "unexpected %#x\n", size); 664 ok(pos == 0, "unexpected %d\n", pos); 665 666 stream_info(clone, &hmem_clone, &size, &pos); 667 ok(hmem_clone != hmem, "handles should not match\n"); 668 ok(size == 1, "unexpected %#x\n", size); 669 ok(pos == 0, "unexpected %d\n", pos); 670 671 IStream_Release(stream); 672 /* releasing clone leads to test termination under windows 673 IStream_Release(clone); 674 */ 675 676 /* test Release for a being cloned stream */ 677 hr = CreateStreamOnHGlobal(0, TRUE, &stream); 678 ok(hr == S_OK, "unexpected %#x\n", hr); 679 680 hr = IStream_Clone(stream, &clone); 681 ok(hr == S_OK, "unexpected %#x\n", hr); 682 683 stream_info(stream, &hmem, &size, &pos); 684 ok(hmem != 0, "unexpected %p\n", hmem); 685 ok(size == 0, "unexpected %d\n", size); 686 ok(pos == 0, "unexpected %d\n", pos); 687 688 stream_info(clone, &hmem_clone, &size, &pos); 689 ok(hmem_clone == hmem, "handles should match\n"); 690 ok(size == 0, "unexpected %#x\n", size); 691 ok(pos == 0, "unexpected %d\n", pos); 692 693 ret = IStream_Release(stream); 694 ok(ret == 0, "unexpected %d\n", ret); 695 696 newsize.QuadPart = 0x8000; 697 hr = IStream_SetSize(clone, newsize); 698 ok(hr == S_OK, "unexpected %#x\n", hr); 699 700 stream_info(clone, &hmem_clone, &size, &pos); 701 ok(hmem_clone == hmem, "handles should match\n"); 702 ok(size == 0x8000, "unexpected %#x\n", size); 703 ok(pos == 0, "unexpected %d\n", pos); 704 705 hr = IStream_Write(clone, hello, sizeof(hello), NULL); 706 ok(hr == S_OK, "unexpected %#x\n", hr); 707 708 stream_info(clone, &hmem_clone, &size, &pos); 709 ok(hmem_clone == hmem, "handles should match\n"); 710 ok(size == 0x8000, "unexpected %#x\n", size); 711 ok(pos == 13, "unexpected %d\n", pos); 712 713 offset.QuadPart = 0; 714 hr = IStream_Seek(clone, offset, STREAM_SEEK_SET, NULL); 715 ok(hr == S_OK, "unexpected %#x\n", hr); 716 717 buf[0] = 0; 718 hr = IStream_Read(clone, buf, sizeof(buf), NULL); 719 ok(hr == S_OK, "unexpected %#x\n", hr); 720 ok(!strcmp(buf, hello), "wrong stream contents\n"); 721 722 stream_info(clone, &hmem_clone, &size, &pos); 723 ok(hmem_clone == hmem, "handles should match\n"); 724 ok(size == 0x8000, "unexpected %#x\n", size); 725 ok(pos == 32, "unexpected %d\n", pos); 726 727 ret = IStream_Release(clone); 728 ok(ret == 0, "unexpected %d\n", ret); 729 } 730 731 START_TEST(hglobalstream) 732 { 733 HRESULT hr; 734 IStream *pStream; 735 736 test_IStream_Clone(); 737 738 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); 739 ok_ole_success(hr, "CreateStreamOnHGlobal"); 740 741 test_streamonhglobal(pStream); 742 IStream_Release(pStream); 743 test_copyto(); 744 test_freed_hglobal(); 745 } 746