1 /* 2 * Copyright 2009 Tony Wasserka 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "wine/debug.h" 20 21 #define COBJMACROS 22 #include "windef.h" 23 #include "winbase.h" 24 #include "winreg.h" 25 #include "objbase.h" 26 #include "shlwapi.h" 27 #include "wincodecs_private.h" 28 29 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 30 31 /****************************************** 32 * StreamOnMemory implementation 33 * 34 * Used by IWICStream_InitializeFromMemory 35 * 36 */ 37 typedef struct StreamOnMemory { 38 IStream IStream_iface; 39 LONG ref; 40 41 BYTE *pbMemory; 42 DWORD dwMemsize; 43 DWORD dwCurPos; 44 45 CRITICAL_SECTION lock; /* must be held when pbMemory or dwCurPos is accessed */ 46 } StreamOnMemory; 47 48 static inline StreamOnMemory *StreamOnMemory_from_IStream(IStream *iface) 49 { 50 return CONTAINING_RECORD(iface, StreamOnMemory, IStream_iface); 51 } 52 53 static HRESULT WINAPI StreamOnMemory_QueryInterface(IStream *iface, 54 REFIID iid, void **ppv) 55 { 56 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 57 58 if (!ppv) return E_INVALIDARG; 59 60 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 61 IsEqualIID(&IID_ISequentialStream, iid)) 62 { 63 *ppv = iface; 64 IUnknown_AddRef((IUnknown*)*ppv); 65 return S_OK; 66 } 67 else 68 { 69 *ppv = NULL; 70 return E_NOINTERFACE; 71 } 72 } 73 74 static ULONG WINAPI StreamOnMemory_AddRef(IStream *iface) 75 { 76 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 77 ULONG ref = InterlockedIncrement(&This->ref); 78 79 TRACE("(%p) refcount=%u\n", iface, ref); 80 81 return ref; 82 } 83 84 static ULONG WINAPI StreamOnMemory_Release(IStream *iface) 85 { 86 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 87 ULONG ref = InterlockedDecrement(&This->ref); 88 89 TRACE("(%p) refcount=%u\n", iface, ref); 90 91 if (ref == 0) { 92 This->lock.DebugInfo->Spare[0] = 0; 93 DeleteCriticalSection(&This->lock); 94 HeapFree(GetProcessHeap(), 0, This); 95 } 96 return ref; 97 } 98 99 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface, 100 void *pv, ULONG cb, ULONG *pcbRead) 101 { 102 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 103 ULONG uBytesRead; 104 105 TRACE("(%p, %p, %u, %p)\n", This, pv, cb, pcbRead); 106 107 if (!pv) return E_INVALIDARG; 108 109 EnterCriticalSection(&This->lock); 110 uBytesRead = min(cb, This->dwMemsize - This->dwCurPos); 111 memmove(pv, This->pbMemory + This->dwCurPos, uBytesRead); 112 This->dwCurPos += uBytesRead; 113 LeaveCriticalSection(&This->lock); 114 115 if (pcbRead) *pcbRead = uBytesRead; 116 117 return S_OK; 118 } 119 120 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface, 121 void const *pv, ULONG cb, ULONG *pcbWritten) 122 { 123 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 124 HRESULT hr; 125 126 TRACE("(%p, %p, %u, %p)\n", This, pv, cb, pcbWritten); 127 128 if (!pv) return E_INVALIDARG; 129 130 EnterCriticalSection(&This->lock); 131 if (cb > This->dwMemsize - This->dwCurPos) { 132 hr = STG_E_MEDIUMFULL; 133 } 134 else { 135 memmove(This->pbMemory + This->dwCurPos, pv, cb); 136 This->dwCurPos += cb; 137 hr = S_OK; 138 if (pcbWritten) *pcbWritten = cb; 139 } 140 LeaveCriticalSection(&This->lock); 141 142 return hr; 143 } 144 145 static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface, 146 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 147 { 148 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 149 LARGE_INTEGER NewPosition; 150 HRESULT hr=S_OK; 151 152 TRACE("(%p, %s, %d, %p)\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition); 153 154 EnterCriticalSection(&This->lock); 155 if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart; 156 else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart; 157 else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart; 158 else hr = E_INVALIDARG; 159 160 if (SUCCEEDED(hr)) { 161 if (NewPosition.u.HighPart) hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); 162 else if (NewPosition.QuadPart > This->dwMemsize) hr = E_INVALIDARG; 163 else if (NewPosition.QuadPart < 0) hr = E_INVALIDARG; 164 } 165 166 if (SUCCEEDED(hr)) { 167 This->dwCurPos = NewPosition.u.LowPart; 168 169 if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos; 170 } 171 LeaveCriticalSection(&This->lock); 172 173 return hr; 174 } 175 176 /* SetSize isn't implemented in the native windowscodecs DLL either */ 177 static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface, 178 ULARGE_INTEGER libNewSize) 179 { 180 TRACE("(%p, %s)\n", iface, wine_dbgstr_longlong(libNewSize.QuadPart)); 181 return E_NOTIMPL; 182 } 183 184 /* CopyTo isn't implemented in the native windowscodecs DLL either */ 185 static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface, 186 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 187 { 188 TRACE("(%p, %p, %s, %p, %p)\n", iface, pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); 189 return E_NOTIMPL; 190 } 191 192 /* Commit isn't implemented in the native windowscodecs DLL either */ 193 static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface, 194 DWORD grfCommitFlags) 195 { 196 TRACE("(%p, %#x)\n", iface, grfCommitFlags); 197 return E_NOTIMPL; 198 } 199 200 /* Revert isn't implemented in the native windowscodecs DLL either */ 201 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface) 202 { 203 TRACE("(%p)\n", iface); 204 return E_NOTIMPL; 205 } 206 207 /* LockRegion isn't implemented in the native windowscodecs DLL either */ 208 static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface, 209 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 210 { 211 TRACE("(%p, %s, %s, %d)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart), 212 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 213 return E_NOTIMPL; 214 } 215 216 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */ 217 static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface, 218 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 219 { 220 TRACE("(%p, %s, %s, %d)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart), 221 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 222 return E_NOTIMPL; 223 } 224 225 static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface, 226 STATSTG *pstatstg, DWORD grfStatFlag) 227 { 228 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 229 TRACE("(%p, %p, %#x)\n", This, pstatstg, grfStatFlag); 230 231 if (!pstatstg) return E_INVALIDARG; 232 233 ZeroMemory(pstatstg, sizeof(STATSTG)); 234 pstatstg->type = STGTY_STREAM; 235 pstatstg->cbSize.QuadPart = This->dwMemsize; 236 237 return S_OK; 238 } 239 240 /* Clone isn't implemented in the native windowscodecs DLL either */ 241 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface, 242 IStream **ppstm) 243 { 244 TRACE("(%p, %p)\n", iface, ppstm); 245 return E_NOTIMPL; 246 } 247 248 249 static const IStreamVtbl StreamOnMemory_Vtbl = 250 { 251 /*** IUnknown methods ***/ 252 StreamOnMemory_QueryInterface, 253 StreamOnMemory_AddRef, 254 StreamOnMemory_Release, 255 /*** ISequentialStream methods ***/ 256 StreamOnMemory_Read, 257 StreamOnMemory_Write, 258 /*** IStream methods ***/ 259 StreamOnMemory_Seek, 260 StreamOnMemory_SetSize, 261 StreamOnMemory_CopyTo, 262 StreamOnMemory_Commit, 263 StreamOnMemory_Revert, 264 StreamOnMemory_LockRegion, 265 StreamOnMemory_UnlockRegion, 266 StreamOnMemory_Stat, 267 StreamOnMemory_Clone, 268 }; 269 270 /****************************************** 271 * StreamOnFileHandle implementation (internal) 272 * 273 */ 274 typedef struct StreamOnFileHandle { 275 IStream IStream_iface; 276 LONG ref; 277 278 HANDLE map; 279 void *mem; 280 IWICStream *stream; 281 } StreamOnFileHandle; 282 283 static inline StreamOnFileHandle *StreamOnFileHandle_from_IStream(IStream *iface) 284 { 285 return CONTAINING_RECORD(iface, StreamOnFileHandle, IStream_iface); 286 } 287 288 static HRESULT WINAPI StreamOnFileHandle_QueryInterface(IStream *iface, 289 REFIID iid, void **ppv) 290 { 291 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 292 293 if (!ppv) return E_INVALIDARG; 294 295 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 296 IsEqualIID(&IID_ISequentialStream, iid)) 297 { 298 *ppv = iface; 299 IUnknown_AddRef((IUnknown*)*ppv); 300 return S_OK; 301 } 302 else 303 { 304 *ppv = NULL; 305 return E_NOINTERFACE; 306 } 307 } 308 309 static ULONG WINAPI StreamOnFileHandle_AddRef(IStream *iface) 310 { 311 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 312 ULONG ref = InterlockedIncrement(&This->ref); 313 314 TRACE("(%p) refcount=%u\n", iface, ref); 315 316 return ref; 317 } 318 319 static ULONG WINAPI StreamOnFileHandle_Release(IStream *iface) 320 { 321 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 322 ULONG ref = InterlockedDecrement(&This->ref); 323 324 TRACE("(%p) refcount=%u\n", iface, ref); 325 326 if (ref == 0) { 327 IWICStream_Release(This->stream); 328 UnmapViewOfFile(This->mem); 329 CloseHandle(This->map); 330 HeapFree(GetProcessHeap(), 0, This); 331 } 332 return ref; 333 } 334 335 static HRESULT WINAPI StreamOnFileHandle_Read(IStream *iface, 336 void *pv, ULONG cb, ULONG *pcbRead) 337 { 338 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 339 TRACE("(%p, %p, %u, %p)\n", This, pv, cb, pcbRead); 340 341 return IWICStream_Read(This->stream, pv, cb, pcbRead); 342 } 343 344 static HRESULT WINAPI StreamOnFileHandle_Write(IStream *iface, 345 void const *pv, ULONG cb, ULONG *pcbWritten) 346 { 347 ERR("(%p, %p, %u, %p)\n", iface, pv, cb, pcbWritten); 348 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); 349 } 350 351 static HRESULT WINAPI StreamOnFileHandle_Seek(IStream *iface, 352 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 353 { 354 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 355 TRACE("(%p, %s, %d, %p)\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition); 356 357 return IWICStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition); 358 } 359 360 static HRESULT WINAPI StreamOnFileHandle_SetSize(IStream *iface, 361 ULARGE_INTEGER libNewSize) 362 { 363 TRACE("(%p, %s)\n", iface, wine_dbgstr_longlong(libNewSize.QuadPart)); 364 return E_NOTIMPL; 365 } 366 367 static HRESULT WINAPI StreamOnFileHandle_CopyTo(IStream *iface, 368 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 369 { 370 TRACE("(%p, %p, %s, %p, %p)\n", iface, pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); 371 return E_NOTIMPL; 372 } 373 374 static HRESULT WINAPI StreamOnFileHandle_Commit(IStream *iface, 375 DWORD grfCommitFlags) 376 { 377 TRACE("(%p, %#x)\n", iface, grfCommitFlags); 378 return E_NOTIMPL; 379 } 380 381 static HRESULT WINAPI StreamOnFileHandle_Revert(IStream *iface) 382 { 383 TRACE("(%p)\n", iface); 384 return E_NOTIMPL; 385 } 386 387 static HRESULT WINAPI StreamOnFileHandle_LockRegion(IStream *iface, 388 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 389 { 390 TRACE("(%p, %s, %s, %d)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart), 391 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 392 return E_NOTIMPL; 393 } 394 395 static HRESULT WINAPI StreamOnFileHandle_UnlockRegion(IStream *iface, 396 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 397 { 398 TRACE("(%p, %s, %s, %d)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart), 399 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 400 return E_NOTIMPL; 401 } 402 403 static HRESULT WINAPI StreamOnFileHandle_Stat(IStream *iface, 404 STATSTG *pstatstg, DWORD grfStatFlag) 405 { 406 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 407 TRACE("(%p, %p, %#x)\n", This, pstatstg, grfStatFlag); 408 409 return IWICStream_Stat(This->stream, pstatstg, grfStatFlag); 410 } 411 412 static HRESULT WINAPI StreamOnFileHandle_Clone(IStream *iface, 413 IStream **ppstm) 414 { 415 TRACE("(%p, %p)\n", iface, ppstm); 416 return E_NOTIMPL; 417 } 418 419 static const IStreamVtbl StreamOnFileHandle_Vtbl = 420 { 421 /*** IUnknown methods ***/ 422 StreamOnFileHandle_QueryInterface, 423 StreamOnFileHandle_AddRef, 424 StreamOnFileHandle_Release, 425 /*** ISequentialStream methods ***/ 426 StreamOnFileHandle_Read, 427 StreamOnFileHandle_Write, 428 /*** IStream methods ***/ 429 StreamOnFileHandle_Seek, 430 StreamOnFileHandle_SetSize, 431 StreamOnFileHandle_CopyTo, 432 StreamOnFileHandle_Commit, 433 StreamOnFileHandle_Revert, 434 StreamOnFileHandle_LockRegion, 435 StreamOnFileHandle_UnlockRegion, 436 StreamOnFileHandle_Stat, 437 StreamOnFileHandle_Clone, 438 }; 439 440 /****************************************** 441 * StreamOnStreamRange implementation 442 * 443 * Used by IWICStream_InitializeFromIStreamRegion 444 * 445 */ 446 typedef struct StreamOnStreamRange { 447 IStream IStream_iface; 448 LONG ref; 449 450 IStream *stream; 451 ULARGE_INTEGER pos; 452 ULARGE_INTEGER offset; 453 ULARGE_INTEGER max_size; 454 455 CRITICAL_SECTION lock; 456 } StreamOnStreamRange; 457 458 static inline StreamOnStreamRange *StreamOnStreamRange_from_IStream(IStream *iface) 459 { 460 return CONTAINING_RECORD(iface, StreamOnStreamRange, IStream_iface); 461 } 462 463 static HRESULT WINAPI StreamOnStreamRange_QueryInterface(IStream *iface, 464 REFIID iid, void **ppv) 465 { 466 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 467 468 if (!ppv) return E_INVALIDARG; 469 470 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 471 IsEqualIID(&IID_ISequentialStream, iid)) 472 { 473 *ppv = iface; 474 IUnknown_AddRef((IUnknown*)*ppv); 475 return S_OK; 476 } 477 else 478 { 479 *ppv = NULL; 480 return E_NOINTERFACE; 481 } 482 } 483 484 static ULONG WINAPI StreamOnStreamRange_AddRef(IStream *iface) 485 { 486 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 487 ULONG ref = InterlockedIncrement(&This->ref); 488 489 TRACE("(%p) refcount=%u\n", iface, ref); 490 491 return ref; 492 } 493 494 static ULONG WINAPI StreamOnStreamRange_Release(IStream *iface) 495 { 496 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 497 ULONG ref = InterlockedDecrement(&This->ref); 498 499 TRACE("(%p) refcount=%u\n", iface, ref); 500 501 if (ref == 0) { 502 This->lock.DebugInfo->Spare[0] = 0; 503 DeleteCriticalSection(&This->lock); 504 IStream_Release(This->stream); 505 HeapFree(GetProcessHeap(), 0, This); 506 } 507 return ref; 508 } 509 510 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface, 511 void *pv, ULONG cb, ULONG *pcbRead) 512 { 513 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 514 ULONG uBytesRead=0; 515 HRESULT hr; 516 ULARGE_INTEGER OldPosition; 517 LARGE_INTEGER SetPosition; 518 519 TRACE("(%p, %p, %u, %p)\n", This, pv, cb, pcbRead); 520 521 if (!pv) return E_INVALIDARG; 522 523 EnterCriticalSection(&This->lock); 524 SetPosition.QuadPart = 0; 525 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition); 526 if (SUCCEEDED(hr)) 527 { 528 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart; 529 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 530 } 531 if (SUCCEEDED(hr)) 532 { 533 if (This->pos.QuadPart + cb > This->max_size.QuadPart) 534 { 535 /* This would read past the end of the stream. */ 536 if (This->pos.QuadPart > This->max_size.QuadPart) 537 cb = 0; 538 else 539 cb = This->max_size.QuadPart - This->pos.QuadPart; 540 } 541 hr = IStream_Read(This->stream, pv, cb, &uBytesRead); 542 SetPosition.QuadPart = OldPosition.QuadPart; 543 IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 544 } 545 if (SUCCEEDED(hr)) 546 This->pos.QuadPart += uBytesRead; 547 LeaveCriticalSection(&This->lock); 548 549 if (SUCCEEDED(hr) && pcbRead) *pcbRead = uBytesRead; 550 551 return hr; 552 } 553 554 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface, 555 void const *pv, ULONG cb, ULONG *pcbWritten) 556 { 557 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 558 HRESULT hr; 559 ULARGE_INTEGER OldPosition; 560 LARGE_INTEGER SetPosition; 561 ULONG uBytesWritten=0; 562 TRACE("(%p, %p, %u, %p)\n", This, pv, cb, pcbWritten); 563 564 if (!pv) return E_INVALIDARG; 565 566 EnterCriticalSection(&This->lock); 567 SetPosition.QuadPart = 0; 568 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition); 569 if (SUCCEEDED(hr)) 570 { 571 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart; 572 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 573 } 574 if (SUCCEEDED(hr)) 575 { 576 if (This->pos.QuadPart + cb > This->max_size.QuadPart) 577 { 578 /* This would read past the end of the stream. */ 579 if (This->pos.QuadPart > This->max_size.QuadPart) 580 cb = 0; 581 else 582 cb = This->max_size.QuadPart - This->pos.QuadPart; 583 } 584 hr = IStream_Write(This->stream, pv, cb, &uBytesWritten); 585 SetPosition.QuadPart = OldPosition.QuadPart; 586 IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 587 } 588 if (SUCCEEDED(hr)) 589 This->pos.QuadPart += uBytesWritten; 590 LeaveCriticalSection(&This->lock); 591 592 if (SUCCEEDED(hr) && pcbWritten) *pcbWritten = uBytesWritten; 593 594 return hr; 595 } 596 597 static HRESULT WINAPI StreamOnStreamRange_Seek(IStream *iface, 598 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 599 { 600 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 601 ULARGE_INTEGER NewPosition, actual_size; 602 HRESULT hr=S_OK; 603 STATSTG statstg; 604 TRACE("(%p, %s, %d, %p)\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition); 605 606 EnterCriticalSection(&This->lock); 607 actual_size = This->max_size; 608 if (dwOrigin == STREAM_SEEK_SET) 609 NewPosition.QuadPart = dlibMove.QuadPart; 610 else if (dwOrigin == STREAM_SEEK_CUR) 611 NewPosition.QuadPart = This->pos.QuadPart + dlibMove.QuadPart; 612 else if (dwOrigin == STREAM_SEEK_END) 613 { 614 hr = IStream_Stat(This->stream, &statstg, STATFLAG_NONAME); 615 if (SUCCEEDED(hr)) 616 { 617 if (This->max_size.QuadPart + This->offset.QuadPart > statstg.cbSize.QuadPart) 618 actual_size.QuadPart = statstg.cbSize.QuadPart - This->offset.QuadPart; 619 NewPosition.QuadPart = dlibMove.QuadPart + actual_size.QuadPart; 620 } 621 } 622 else hr = E_INVALIDARG; 623 624 if (SUCCEEDED(hr) && (NewPosition.u.HighPart != 0 || NewPosition.QuadPart > actual_size.QuadPart)) 625 hr = WINCODEC_ERR_VALUEOUTOFRANGE; 626 627 if (SUCCEEDED(hr)) { 628 This->pos.QuadPart = NewPosition.QuadPart; 629 630 if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart; 631 } 632 LeaveCriticalSection(&This->lock); 633 634 return hr; 635 } 636 637 /* SetSize isn't implemented in the native windowscodecs DLL either */ 638 static HRESULT WINAPI StreamOnStreamRange_SetSize(IStream *iface, 639 ULARGE_INTEGER libNewSize) 640 { 641 TRACE("(%p, %s)\n", iface, wine_dbgstr_longlong(libNewSize.QuadPart)); 642 return E_NOTIMPL; 643 } 644 645 /* CopyTo isn't implemented in the native windowscodecs DLL either */ 646 static HRESULT WINAPI StreamOnStreamRange_CopyTo(IStream *iface, 647 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 648 { 649 TRACE("(%p, %p, %s, %p, %p)\n", iface, pstm, wine_dbgstr_longlong(cb.QuadPart), 650 pcbRead, pcbWritten); 651 return E_NOTIMPL; 652 } 653 654 /* Commit isn't implemented in the native windowscodecs DLL either */ 655 static HRESULT WINAPI StreamOnStreamRange_Commit(IStream *iface, 656 DWORD grfCommitFlags) 657 { 658 TRACE("(%p, %#x)\n", iface, grfCommitFlags); 659 return E_NOTIMPL; 660 } 661 662 /* Revert isn't implemented in the native windowscodecs DLL either */ 663 static HRESULT WINAPI StreamOnStreamRange_Revert(IStream *iface) 664 { 665 TRACE("(%p)\n", iface); 666 return E_NOTIMPL; 667 } 668 669 /* LockRegion isn't implemented in the native windowscodecs DLL either */ 670 static HRESULT WINAPI StreamOnStreamRange_LockRegion(IStream *iface, 671 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 672 { 673 TRACE("(%p, %s, %s, %d)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart), 674 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 675 return E_NOTIMPL; 676 } 677 678 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */ 679 static HRESULT WINAPI StreamOnStreamRange_UnlockRegion(IStream *iface, 680 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 681 { 682 TRACE("(%p, %s, %s, %d)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart), 683 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 684 return E_NOTIMPL; 685 } 686 687 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface, 688 STATSTG *pstatstg, DWORD grfStatFlag) 689 { 690 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 691 HRESULT hr; 692 TRACE("(%p, %p, %#x)\n", This, pstatstg, grfStatFlag); 693 694 if (!pstatstg) return E_INVALIDARG; 695 696 EnterCriticalSection(&This->lock); 697 hr = IStream_Stat(This->stream, pstatstg, grfStatFlag); 698 if (SUCCEEDED(hr)) 699 { 700 pstatstg->cbSize.QuadPart -= This->offset.QuadPart; 701 if (This->max_size.QuadPart < pstatstg->cbSize.QuadPart) 702 pstatstg->cbSize.QuadPart = This->max_size.QuadPart; 703 } 704 705 LeaveCriticalSection(&This->lock); 706 707 return hr; 708 } 709 710 /* Clone isn't implemented in the native windowscodecs DLL either */ 711 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface, 712 IStream **ppstm) 713 { 714 TRACE("(%p, %p)\n", iface, ppstm); 715 return E_NOTIMPL; 716 } 717 718 static const IStreamVtbl StreamOnStreamRange_Vtbl = 719 { 720 /*** IUnknown methods ***/ 721 StreamOnStreamRange_QueryInterface, 722 StreamOnStreamRange_AddRef, 723 StreamOnStreamRange_Release, 724 /*** ISequentialStream methods ***/ 725 StreamOnStreamRange_Read, 726 StreamOnStreamRange_Write, 727 /*** IStream methods ***/ 728 StreamOnStreamRange_Seek, 729 StreamOnStreamRange_SetSize, 730 StreamOnStreamRange_CopyTo, 731 StreamOnStreamRange_Commit, 732 StreamOnStreamRange_Revert, 733 StreamOnStreamRange_LockRegion, 734 StreamOnStreamRange_UnlockRegion, 735 StreamOnStreamRange_Stat, 736 StreamOnStreamRange_Clone, 737 }; 738 739 740 /****************************************** 741 * IWICStream implementation 742 * 743 */ 744 typedef struct IWICStreamImpl 745 { 746 IWICStream IWICStream_iface; 747 LONG ref; 748 749 IStream *pStream; 750 } IWICStreamImpl; 751 752 static inline IWICStreamImpl *impl_from_IWICStream(IWICStream *iface) 753 { 754 return CONTAINING_RECORD(iface, IWICStreamImpl, IWICStream_iface); 755 } 756 757 static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface, 758 REFIID iid, void **ppv) 759 { 760 IWICStreamImpl *This = impl_from_IWICStream(iface); 761 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 762 763 if (!ppv) return E_INVALIDARG; 764 765 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 766 IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid)) 767 { 768 *ppv = &This->IWICStream_iface; 769 IUnknown_AddRef((IUnknown*)*ppv); 770 return S_OK; 771 } 772 else 773 { 774 *ppv = NULL; 775 return E_NOINTERFACE; 776 } 777 } 778 779 static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface) 780 { 781 IWICStreamImpl *This = impl_from_IWICStream(iface); 782 ULONG ref = InterlockedIncrement(&This->ref); 783 784 TRACE("(%p) refcount=%u\n", iface, ref); 785 786 return ref; 787 } 788 789 static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface) 790 { 791 IWICStreamImpl *This = impl_from_IWICStream(iface); 792 ULONG ref = InterlockedDecrement(&This->ref); 793 794 TRACE("(%p) refcount=%u\n", iface, ref); 795 796 if (ref == 0) { 797 if (This->pStream) IStream_Release(This->pStream); 798 HeapFree(GetProcessHeap(), 0, This); 799 } 800 return ref; 801 } 802 803 static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface, 804 void *pv, ULONG cb, ULONG *pcbRead) 805 { 806 IWICStreamImpl *This = impl_from_IWICStream(iface); 807 TRACE("(%p, %p, %u, %p)\n", This, pv, cb, pcbRead); 808 809 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 810 return IStream_Read(This->pStream, pv, cb, pcbRead); 811 } 812 813 static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface, 814 void const *pv, ULONG cb, ULONG *pcbWritten) 815 { 816 IWICStreamImpl *This = impl_from_IWICStream(iface); 817 TRACE("(%p, %p, %u, %p)\n", This, pv, cb, pcbWritten); 818 819 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 820 return IStream_Write(This->pStream, pv, cb, pcbWritten); 821 } 822 823 static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface, 824 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 825 { 826 IWICStreamImpl *This = impl_from_IWICStream(iface); 827 TRACE("(%p, %s, %d, %p)\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), 828 dwOrigin, plibNewPosition); 829 830 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 831 return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition); 832 } 833 834 static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface, 835 ULARGE_INTEGER libNewSize) 836 { 837 IWICStreamImpl *This = impl_from_IWICStream(iface); 838 TRACE("(%p, %s)\n", This, wine_dbgstr_longlong(libNewSize.QuadPart)); 839 840 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 841 return IStream_SetSize(This->pStream, libNewSize); 842 } 843 844 static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface, 845 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 846 { 847 IWICStreamImpl *This = impl_from_IWICStream(iface); 848 TRACE("(%p, %p, %s, %p, %p)\n", This, pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); 849 850 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 851 return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten); 852 } 853 854 static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface, 855 DWORD grfCommitFlags) 856 { 857 IWICStreamImpl *This = impl_from_IWICStream(iface); 858 TRACE("(%p, %#x)\n", This, grfCommitFlags); 859 860 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 861 return IStream_Commit(This->pStream, grfCommitFlags); 862 } 863 864 static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface) 865 { 866 IWICStreamImpl *This = impl_from_IWICStream(iface); 867 TRACE("(%p)\n", This); 868 869 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 870 return IStream_Revert(This->pStream); 871 } 872 873 static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface, 874 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 875 { 876 IWICStreamImpl *This = impl_from_IWICStream(iface); 877 TRACE("(%p, %s, %s, %d)\n", This, wine_dbgstr_longlong(libOffset.QuadPart), 878 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 879 880 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 881 return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType); 882 } 883 884 static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface, 885 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 886 { 887 IWICStreamImpl *This = impl_from_IWICStream(iface); 888 TRACE("(%p, %s, %s, %d)\n", This, wine_dbgstr_longlong(libOffset.QuadPart), 889 wine_dbgstr_longlong(cb.QuadPart), dwLockType); 890 891 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 892 return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType); 893 } 894 895 static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface, 896 STATSTG *pstatstg, DWORD grfStatFlag) 897 { 898 IWICStreamImpl *This = impl_from_IWICStream(iface); 899 TRACE("(%p, %p, %#x)\n", This, pstatstg, grfStatFlag); 900 901 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 902 return IStream_Stat(This->pStream, pstatstg, grfStatFlag); 903 } 904 905 static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface, 906 IStream **ppstm) 907 { 908 IWICStreamImpl *This = impl_from_IWICStream(iface); 909 TRACE("(%p, %p)\n", This, ppstm); 910 911 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 912 return IStream_Clone(This->pStream, ppstm); 913 } 914 915 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface, IStream *stream) 916 { 917 IWICStreamImpl *This = impl_from_IWICStream(iface); 918 HRESULT hr = S_OK; 919 920 TRACE("(%p, %p)\n", iface, stream); 921 922 if (!stream) return E_INVALIDARG; 923 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 924 925 IStream_AddRef(stream); 926 927 if (InterlockedCompareExchangePointer((void **)&This->pStream, stream, NULL)) 928 { 929 /* Some other thread set the stream first. */ 930 IStream_Release(stream); 931 hr = WINCODEC_ERR_WRONGSTATE; 932 } 933 934 return hr; 935 } 936 937 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface, 938 LPCWSTR wzFileName, DWORD dwDesiredAccess) 939 { 940 IWICStreamImpl *This = impl_from_IWICStream(iface); 941 HRESULT hr; 942 DWORD dwMode; 943 IStream *stream; 944 945 TRACE("(%p, %s, %u)\n", iface, debugstr_w(wzFileName), dwDesiredAccess); 946 947 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 948 949 if(dwDesiredAccess & GENERIC_WRITE) 950 dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE; 951 else if(dwDesiredAccess & GENERIC_READ) 952 dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE; 953 else 954 return E_INVALIDARG; 955 956 hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream); 957 958 if (SUCCEEDED(hr)) 959 { 960 if (InterlockedCompareExchangePointer((void**)&This->pStream, stream, NULL)) 961 { 962 /* Some other thread set the stream first. */ 963 IStream_Release(stream); 964 hr = WINCODEC_ERR_WRONGSTATE; 965 } 966 } 967 968 return hr; 969 } 970 971 /****************************************** 972 * IWICStream_InitializeFromMemory 973 * 974 * Initializes the internal IStream object to retrieve its data from a memory chunk. 975 * 976 * PARAMS 977 * pbBuffer [I] pointer to the memory chunk 978 * cbBufferSize [I] number of bytes to use from the memory chunk 979 * 980 * RETURNS 981 * SUCCESS: S_OK 982 * FAILURE: E_INVALIDARG, if pbBuffer is NULL 983 * E_OUTOFMEMORY, if we run out of memory 984 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before 985 * 986 */ 987 static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface, 988 BYTE *pbBuffer, DWORD cbBufferSize) 989 { 990 IWICStreamImpl *This = impl_from_IWICStream(iface); 991 StreamOnMemory *pObject; 992 TRACE("(%p, %p, %u)\n", iface, pbBuffer, cbBufferSize); 993 994 if (!pbBuffer) return E_INVALIDARG; 995 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 996 997 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory)); 998 if (!pObject) return E_OUTOFMEMORY; 999 1000 pObject->IStream_iface.lpVtbl = &StreamOnMemory_Vtbl; 1001 pObject->ref = 1; 1002 pObject->pbMemory = pbBuffer; 1003 pObject->dwMemsize = cbBufferSize; 1004 pObject->dwCurPos = 0; 1005 InitializeCriticalSection(&pObject->lock); 1006 pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnMemory.lock"); 1007 1008 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL)) 1009 { 1010 /* Some other thread set the stream first. */ 1011 IStream_Release(&pObject->IStream_iface); 1012 return WINCODEC_ERR_WRONGSTATE; 1013 } 1014 1015 return S_OK; 1016 } 1017 1018 static HRESULT map_file(HANDLE file, HANDLE *map, void **mem, LARGE_INTEGER *size) 1019 { 1020 *map = NULL; 1021 if (!GetFileSizeEx(file, size)) return HRESULT_FROM_WIN32(GetLastError()); 1022 if (size->u.HighPart) 1023 { 1024 WARN("file too large\n"); 1025 return E_FAIL; 1026 } 1027 if (!(*map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, size->u.LowPart, NULL))) 1028 { 1029 return HRESULT_FROM_WIN32(GetLastError()); 1030 } 1031 if (!(*mem = MapViewOfFile(*map, FILE_MAP_READ, 0, 0, size->u.LowPart))) 1032 { 1033 CloseHandle(*map); 1034 return HRESULT_FROM_WIN32(GetLastError()); 1035 } 1036 return S_OK; 1037 } 1038 1039 HRESULT stream_initialize_from_filehandle(IWICStream *iface, HANDLE file) 1040 { 1041 IWICStreamImpl *This = impl_from_IWICStream(iface); 1042 StreamOnFileHandle *pObject; 1043 IWICStream *stream = NULL; 1044 HANDLE map; 1045 void *mem; 1046 LARGE_INTEGER size; 1047 HRESULT hr; 1048 TRACE("(%p,%p)\n", iface, file); 1049 1050 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 1051 1052 hr = map_file(file, &map, &mem, &size); 1053 if (FAILED(hr)) return hr; 1054 1055 hr = StreamImpl_Create(&stream); 1056 if (FAILED(hr)) goto error; 1057 1058 hr = IWICStreamImpl_InitializeFromMemory(stream, mem, size.u.LowPart); 1059 if (FAILED(hr)) goto error; 1060 1061 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnFileHandle)); 1062 if (!pObject) 1063 { 1064 hr = E_OUTOFMEMORY; 1065 goto error; 1066 } 1067 pObject->IStream_iface.lpVtbl = &StreamOnFileHandle_Vtbl; 1068 pObject->ref = 1; 1069 pObject->map = map; 1070 pObject->mem = mem; 1071 pObject->stream = stream; 1072 1073 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL)) 1074 { 1075 /* Some other thread set the stream first. */ 1076 IStream_Release(&pObject->IStream_iface); 1077 return WINCODEC_ERR_WRONGSTATE; 1078 } 1079 return S_OK; 1080 1081 error: 1082 if (stream) IWICStream_Release(stream); 1083 UnmapViewOfFile(mem); 1084 CloseHandle(map); 1085 return hr; 1086 } 1087 1088 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface, 1089 IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize) 1090 { 1091 IWICStreamImpl *This = impl_from_IWICStream(iface); 1092 StreamOnStreamRange *pObject; 1093 1094 TRACE("(%p,%p,%s,%s)\n", iface, pIStream, wine_dbgstr_longlong(ulOffset.QuadPart), 1095 wine_dbgstr_longlong(ulMaxSize.QuadPart)); 1096 1097 if (!pIStream) return E_INVALIDARG; 1098 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 1099 1100 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange)); 1101 if (!pObject) return E_OUTOFMEMORY; 1102 1103 pObject->IStream_iface.lpVtbl = &StreamOnStreamRange_Vtbl; 1104 pObject->ref = 1; 1105 IStream_AddRef(pIStream); 1106 pObject->stream = pIStream; 1107 pObject->pos.QuadPart = 0; 1108 pObject->offset = ulOffset; 1109 pObject->max_size = ulMaxSize; 1110 InitializeCriticalSection(&pObject->lock); 1111 pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnStreamRange.lock"); 1112 1113 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL)) 1114 { 1115 /* Some other thread set the stream first. */ 1116 IStream_Release(&pObject->IStream_iface); 1117 return WINCODEC_ERR_WRONGSTATE; 1118 } 1119 1120 return S_OK; 1121 } 1122 1123 1124 static const IWICStreamVtbl WICStream_Vtbl = 1125 { 1126 /*** IUnknown methods ***/ 1127 IWICStreamImpl_QueryInterface, 1128 IWICStreamImpl_AddRef, 1129 IWICStreamImpl_Release, 1130 /*** ISequentialStream methods ***/ 1131 IWICStreamImpl_Read, 1132 IWICStreamImpl_Write, 1133 /*** IStream methods ***/ 1134 IWICStreamImpl_Seek, 1135 IWICStreamImpl_SetSize, 1136 IWICStreamImpl_CopyTo, 1137 IWICStreamImpl_Commit, 1138 IWICStreamImpl_Revert, 1139 IWICStreamImpl_LockRegion, 1140 IWICStreamImpl_UnlockRegion, 1141 IWICStreamImpl_Stat, 1142 IWICStreamImpl_Clone, 1143 /*** IWICStream methods ***/ 1144 IWICStreamImpl_InitializeFromIStream, 1145 IWICStreamImpl_InitializeFromFilename, 1146 IWICStreamImpl_InitializeFromMemory, 1147 IWICStreamImpl_InitializeFromIStreamRegion, 1148 }; 1149 1150 HRESULT StreamImpl_Create(IWICStream **stream) 1151 { 1152 IWICStreamImpl *pObject; 1153 1154 if( !stream ) return E_INVALIDARG; 1155 1156 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl)); 1157 if( !pObject ) { 1158 *stream = NULL; 1159 return E_OUTOFMEMORY; 1160 } 1161 1162 pObject->IWICStream_iface.lpVtbl = &WICStream_Vtbl; 1163 pObject->ref = 1; 1164 pObject->pStream = NULL; 1165 1166 *stream = &pObject->IWICStream_iface; 1167 1168 return S_OK; 1169 } 1170