xref: /reactos/dll/win32/windowscodecs/stream.c (revision 53221834)
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