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