Sync with trunk r58151 to bring the latest changes from Amine and Timo.
[reactos.git] / dll / win32 / shlwapi / regstream.c
1 /*
2 * SHLWAPI Registry Stream functions
3 *
4 * Copyright 1999 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdarg.h>
23 #include <string.h>
24
25 #define COBJMACROS
26
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(shell);
37
38 typedef struct
39 {
40 IStream IStream_iface;
41 LONG ref;
42 HKEY hKey;
43 LPBYTE pbBuffer;
44 DWORD dwLength;
45 DWORD dwPos;
46 DWORD dwMode;
47 union {
48 LPSTR keyNameA;
49 LPWSTR keyNameW;
50 }u;
51 BOOL bUnicode;
52 } ISHRegStream;
53
54 static inline ISHRegStream *impl_from_IStream(IStream *iface)
55 {
56 return CONTAINING_RECORD(iface, ISHRegStream, IStream_iface);
57 }
58
59 /**************************************************************************
60 * IStream_fnQueryInterface
61 */
62 static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj)
63 {
64 ISHRegStream *This = impl_from_IStream(iface);
65
66 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
67
68 *ppvObj = NULL;
69
70 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
71 *ppvObj = This;
72 else if(IsEqualIID(riid, &IID_IStream)) /*IStream*/
73 *ppvObj = This;
74
75 if(*ppvObj)
76 {
77 IStream_AddRef((IStream*)*ppvObj);
78 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
79 return S_OK;
80 }
81 TRACE("-- Interface: E_NOINTERFACE\n");
82 return E_NOINTERFACE;
83 }
84
85 /**************************************************************************
86 * IStream_fnAddRef
87 */
88 static ULONG WINAPI IStream_fnAddRef(IStream *iface)
89 {
90 ISHRegStream *This = impl_from_IStream(iface);
91 ULONG refCount = InterlockedIncrement(&This->ref);
92
93 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
94
95 return refCount;
96 }
97
98 /**************************************************************************
99 * IStream_fnRelease
100 */
101 static ULONG WINAPI IStream_fnRelease(IStream *iface)
102 {
103 ISHRegStream *This = impl_from_IStream(iface);
104 ULONG refCount = InterlockedDecrement(&This->ref);
105
106 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
107
108 if (!refCount)
109 {
110 TRACE(" destroying SHReg IStream (%p)\n",This);
111
112 if (This->hKey)
113 {
114 /* write back data in REG_BINARY */
115 if (This->dwMode == STGM_READWRITE || This->dwMode == STGM_WRITE)
116 {
117 if (This->dwLength)
118 {
119 if (This->bUnicode)
120 RegSetValueExW(This->hKey, This->u.keyNameW, 0, REG_BINARY,
121 (const BYTE *) This->pbBuffer, This->dwLength);
122 else
123 RegSetValueExA(This->hKey, This->u.keyNameA, 0, REG_BINARY,
124 (const BYTE *) This->pbBuffer, This->dwLength);
125 }
126 else
127 {
128 if (This->bUnicode)
129 RegDeleteValueW(This->hKey, This->u.keyNameW);
130 else
131 RegDeleteValueA(This->hKey, This->u.keyNameA);
132 }
133 }
134
135 RegCloseKey(This->hKey);
136 }
137
138 HeapFree(GetProcessHeap(),0,This->u.keyNameA);
139 HeapFree(GetProcessHeap(),0,This->pbBuffer);
140 HeapFree(GetProcessHeap(),0,This);
141 return 0;
142 }
143
144 return refCount;
145 }
146
147 /**************************************************************************
148 * IStream_fnRead
149 */
150 static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead)
151 {
152 ISHRegStream *This = impl_from_IStream(iface);
153 DWORD dwBytesToRead;
154
155 TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
156
157 if (This->dwPos >= This->dwLength)
158 dwBytesToRead = 0;
159 else
160 dwBytesToRead = This->dwLength - This->dwPos;
161
162 dwBytesToRead = (cb > dwBytesToRead) ? dwBytesToRead : cb;
163 if (dwBytesToRead != 0) /* not at end of buffer and we want to read something */
164 {
165 memmove(pv, This->pbBuffer + This->dwPos, dwBytesToRead);
166 This->dwPos += dwBytesToRead; /* adjust pointer */
167 }
168
169 if (pcbRead)
170 *pcbRead = dwBytesToRead;
171
172 return S_OK;
173 }
174
175 /**************************************************************************
176 * IStream_fnWrite
177 */
178 static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten)
179 {
180 ISHRegStream *This = impl_from_IStream(iface);
181 DWORD newLen = This->dwPos + cb;
182
183 TRACE("(%p, %p, %d, %p)\n",This, pv, cb, pcbWritten);
184
185 if (newLen < This->dwPos) /* overflow */
186 return STG_E_INSUFFICIENTMEMORY;
187
188 if (newLen > This->dwLength)
189 {
190 LPBYTE newBuf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pbBuffer, newLen);
191 if (!newBuf)
192 return STG_E_INSUFFICIENTMEMORY;
193
194 This->dwLength = newLen;
195 This->pbBuffer = newBuf;
196 }
197 memmove(This->pbBuffer + This->dwPos, pv, cb);
198 This->dwPos += cb; /* adjust pointer */
199
200 if (pcbWritten)
201 *pcbWritten = cb;
202
203 return S_OK;
204 }
205
206 /**************************************************************************
207 * IStream_fnSeek
208 */
209 static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
210 {
211 ISHRegStream *This = impl_from_IStream(iface);
212 LARGE_INTEGER tmp;
213 TRACE("(%p, %s, %d %p)\n", This,
214 wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition);
215
216 if (dwOrigin == STREAM_SEEK_SET)
217 tmp = dlibMove;
218 else if (dwOrigin == STREAM_SEEK_CUR)
219 tmp.QuadPart = This->dwPos + dlibMove.QuadPart;
220 else if (dwOrigin == STREAM_SEEK_END)
221 tmp.QuadPart = This->dwLength + dlibMove.QuadPart;
222 else
223 return STG_E_INVALIDPARAMETER;
224
225 if (tmp.QuadPart < 0)
226 return STG_E_INVALIDFUNCTION;
227
228 /* we cut off the high part here */
229 This->dwPos = tmp.u.LowPart;
230
231 if (plibNewPosition)
232 plibNewPosition->QuadPart = This->dwPos;
233 return S_OK;
234 }
235
236 /**************************************************************************
237 * IStream_fnSetSize
238 */
239 static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize)
240 {
241 ISHRegStream *This = impl_from_IStream(iface);
242 DWORD newLen;
243 LPBYTE newBuf;
244
245 TRACE("(%p, %s)\n", This, wine_dbgstr_longlong(libNewSize.QuadPart));
246
247 /* we cut off the high part here */
248 newLen = libNewSize.u.LowPart;
249 newBuf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pbBuffer, newLen);
250 if (!newBuf)
251 return STG_E_INSUFFICIENTMEMORY;
252
253 This->pbBuffer = newBuf;
254 This->dwLength = newLen;
255
256 return S_OK;
257 }
258
259 /**************************************************************************
260 * IStream_fnCopyTo
261 */
262 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
263 {
264 ISHRegStream *This = impl_from_IStream(iface);
265
266 TRACE("(%p)\n",This);
267 if (pcbRead)
268 pcbRead->QuadPart = 0;
269 if (pcbWritten)
270 pcbWritten->QuadPart = 0;
271
272 /* TODO implement */
273 return E_NOTIMPL;
274 }
275
276 /**************************************************************************
277 * IStream_fnCommit
278 */
279 static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags)
280 {
281 ISHRegStream *This = impl_from_IStream(iface);
282
283 TRACE("(%p)\n",This);
284
285 /* commit not supported by this stream */
286 return E_NOTIMPL;
287 }
288
289 /**************************************************************************
290 * IStream_fnRevert
291 */
292 static HRESULT WINAPI IStream_fnRevert (IStream * iface)
293 {
294 ISHRegStream *This = impl_from_IStream(iface);
295
296 TRACE("(%p)\n",This);
297
298 /* revert not supported by this stream */
299 return E_NOTIMPL;
300 }
301
302 /**************************************************************************
303 * IStream_fnLockUnlockRegion
304 */
305 static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
306 {
307 ISHRegStream *This = impl_from_IStream(iface);
308
309 TRACE("(%p)\n",This);
310
311 /* lock/unlock not supported by this stream */
312 return E_NOTIMPL;
313 }
314
315 /*************************************************************************
316 * IStream_fnStat
317 */
318 static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag)
319 {
320 ISHRegStream *This = impl_from_IStream(iface);
321
322 TRACE("(%p, %p, %d)\n",This,pstatstg,grfStatFlag);
323
324 pstatstg->pwcsName = NULL;
325 pstatstg->type = STGTY_STREAM;
326 pstatstg->cbSize.QuadPart = This->dwLength;
327 pstatstg->mtime.dwHighDateTime = 0;
328 pstatstg->mtime.dwLowDateTime = 0;
329 pstatstg->ctime.dwHighDateTime = 0;
330 pstatstg->ctime.dwLowDateTime = 0;
331 pstatstg->atime.dwHighDateTime = 0;
332 pstatstg->atime.dwLowDateTime = 0;
333 pstatstg->grfMode = This->dwMode;
334 pstatstg->grfLocksSupported = 0;
335 pstatstg->clsid = CLSID_NULL;
336 pstatstg->grfStateBits = 0;
337 pstatstg->reserved = 0;
338
339 return S_OK;
340 }
341
342 /*************************************************************************
343 * IStream_fnClone
344 */
345 static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm)
346 {
347 ISHRegStream *This = impl_from_IStream(iface);
348
349 TRACE("(%p)\n",This);
350 *ppstm = NULL;
351
352 /* clone not supported by this stream */
353 return E_NOTIMPL;
354 }
355
356 static const IStreamVtbl rstvt =
357 {
358 IStream_fnQueryInterface,
359 IStream_fnAddRef,
360 IStream_fnRelease,
361 IStream_fnRead,
362 IStream_fnWrite,
363 IStream_fnSeek,
364 IStream_fnSetSize,
365 IStream_fnCopyTo,
366 IStream_fnCommit,
367 IStream_fnRevert,
368 IStream_fnLockUnlockRegion,
369 IStream_fnLockUnlockRegion,
370 IStream_fnStat,
371 IStream_fnClone
372 };
373
374 /* Methods overridden by the dummy stream */
375
376 /**************************************************************************
377 * IStream_fnAddRefDummy
378 */
379 static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface)
380 {
381 ISHRegStream *This = impl_from_IStream(iface);
382 TRACE("(%p)\n", This);
383 return 2;
384 }
385
386 /**************************************************************************
387 * IStream_fnReleaseDummy
388 */
389 static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface)
390 {
391 ISHRegStream *This = impl_from_IStream(iface);
392 TRACE("(%p)\n", This);
393 return 1;
394 }
395
396 /**************************************************************************
397 * IStream_fnReadDummy
398 */
399 static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead)
400 {
401 if (pcbRead)
402 *pcbRead = 0;
403 return E_NOTIMPL;
404 }
405
406 static const IStreamVtbl DummyRegStreamVTable =
407 {
408 IStream_fnQueryInterface,
409 IStream_fnAddRefDummy, /* Overridden */
410 IStream_fnReleaseDummy, /* Overridden */
411 IStream_fnReadDummy, /* Overridden */
412 IStream_fnWrite,
413 IStream_fnSeek,
414 IStream_fnSetSize,
415 IStream_fnCopyTo,
416 IStream_fnCommit,
417 IStream_fnRevert,
418 IStream_fnLockUnlockRegion,
419 IStream_fnLockUnlockRegion,
420 IStream_fnStat,
421 IStream_fnClone
422 };
423
424 /* Dummy registry stream object */
425 static ISHRegStream rsDummyRegStream =
426 {
427 { &DummyRegStreamVTable },
428 1,
429 NULL,
430 NULL,
431 0,
432 0,
433 STGM_READWRITE,
434 {NULL},
435 FALSE
436 };
437
438 /**************************************************************************
439 * IStream_Create
440 *
441 * Internal helper: Create and initialise a new registry stream object.
442 */
443 static ISHRegStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength)
444 {
445 ISHRegStream* regStream;
446
447 regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream));
448
449 if (regStream)
450 {
451 regStream->IStream_iface.lpVtbl = &rstvt;
452 regStream->ref = 1;
453 regStream->hKey = hKey;
454 regStream->pbBuffer = pbBuffer;
455 regStream->dwLength = dwLength;
456 regStream->dwPos = 0;
457 regStream->dwMode = STGM_READWRITE;
458 regStream->u.keyNameA = NULL;
459 regStream->bUnicode = FALSE;
460 }
461 TRACE ("Returning %p\n", regStream);
462 return regStream;
463 }
464
465 /*************************************************************************
466 * SHOpenRegStream2A [SHLWAPI.@]
467 *
468 * Create a stream to read binary registry data.
469 *
470 * PARAMS
471 * hKey [I] Registry handle
472 * pszSubkey [I] The sub key name
473 * pszValue [I] The value name under the sub key
474 * dwMode [I] Unused
475 *
476 * RETURNS
477 * Success: An IStream interface referring to the registry data
478 * Failure: NULL, if the registry key could not be opened or is not binary.
479 */
480 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, LPCSTR pszSubkey,
481 LPCSTR pszValue,DWORD dwMode)
482 {
483 ISHRegStream *tmp;
484 HKEY hStrKey = NULL;
485 LPBYTE lpBuff = NULL;
486 DWORD dwLength = 0;
487 LONG ret;
488
489 TRACE("(%p,%s,%s,0x%08x)\n", hKey, pszSubkey, pszValue, dwMode);
490
491 if (dwMode == STGM_READ)
492 ret = RegOpenKeyExA(hKey, pszSubkey, 0, KEY_READ, &hStrKey);
493 else /* in write mode we make sure the subkey exits */
494 ret = RegCreateKeyExA(hKey, pszSubkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
495
496 if (ret == ERROR_SUCCESS)
497 {
498 if (dwMode == STGM_READ || dwMode == STGM_READWRITE)
499 {
500 /* read initial data */
501 ret = RegQueryValueExA(hStrKey, pszValue, 0, 0, 0, &dwLength);
502 if (ret == ERROR_SUCCESS && dwLength)
503 {
504 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
505 RegQueryValueExA(hStrKey, pszValue, 0, 0, lpBuff, &dwLength);
506 }
507 }
508
509 if (!dwLength)
510 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
511
512 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
513 if(tmp)
514 {
515 if(pszValue)
516 {
517 int len = lstrlenA(pszValue) + 1;
518 tmp->u.keyNameA = HeapAlloc(GetProcessHeap(), 0, len);
519 memcpy(tmp->u.keyNameA, pszValue, len);
520 }
521
522 tmp->dwMode = dwMode;
523 tmp->bUnicode = FALSE;
524 return &tmp->IStream_iface;
525 }
526 }
527
528 HeapFree(GetProcessHeap(), 0, lpBuff);
529 if (hStrKey)
530 RegCloseKey(hStrKey);
531 return NULL;
532 }
533
534 /*************************************************************************
535 * SHOpenRegStream2W [SHLWAPI.@]
536 *
537 * See SHOpenRegStream2A.
538 */
539 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey,
540 LPCWSTR pszValue, DWORD dwMode)
541 {
542 ISHRegStream *tmp;
543 HKEY hStrKey = NULL;
544 LPBYTE lpBuff = NULL;
545 DWORD dwLength = 0;
546 LONG ret;
547
548 TRACE("(%p,%s,%s,0x%08x)\n", hKey, debugstr_w(pszSubkey),
549 debugstr_w(pszValue), dwMode);
550
551 if (dwMode == STGM_READ)
552 ret = RegOpenKeyExW(hKey, pszSubkey, 0, KEY_READ, &hStrKey);
553 else /* in write mode we make sure the subkey exits */
554 ret = RegCreateKeyExW(hKey, pszSubkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
555
556 if (ret == ERROR_SUCCESS)
557 {
558 if (dwMode == STGM_READ || dwMode == STGM_READWRITE)
559 {
560 /* read initial data */
561 ret = RegQueryValueExW(hStrKey, pszValue, 0, 0, 0, &dwLength);
562 if (ret == ERROR_SUCCESS && dwLength)
563 {
564 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
565 RegQueryValueExW(hStrKey, pszValue, 0, 0, lpBuff, &dwLength);
566 }
567 }
568
569 if (!dwLength)
570 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
571
572 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
573 if(tmp)
574 {
575 if(pszValue)
576 {
577 int len = lstrlenW(pszValue) + 1;
578 tmp->u.keyNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
579 memcpy(tmp->u.keyNameW, pszValue, len * sizeof(WCHAR));
580 }
581
582 tmp->dwMode = dwMode;
583 tmp->bUnicode = TRUE;
584 return &tmp->IStream_iface;
585 }
586 }
587
588 HeapFree(GetProcessHeap(), 0, lpBuff);
589 if (hStrKey)
590 RegCloseKey(hStrKey);
591 return NULL;
592 }
593
594 /*************************************************************************
595 * SHOpenRegStreamA [SHLWAPI.@]
596 *
597 * Create a stream to read binary registry data.
598 *
599 * PARAMS
600 * hKey [I] Registry handle
601 * pszSubkey [I] The sub key name
602 * pszValue [I] The value name under the sub key
603 * dwMode [I] STGM mode for opening the file
604 *
605 * RETURNS
606 * Success: An IStream interface referring to the registry data
607 * Failure: If the registry key could not be opened or is not binary,
608 * A dummy (empty) IStream object is returned.
609 */
610 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, LPCSTR pszSubkey,
611 LPCSTR pszValue, DWORD dwMode)
612 {
613 IStream *iStream;
614
615 TRACE("(%p,%s,%s,0x%08x)\n", hkey, pszSubkey, pszValue, dwMode);
616
617 iStream = SHOpenRegStream2A(hkey, pszSubkey, pszValue, dwMode);
618 return iStream ? iStream : &rsDummyRegStream.IStream_iface;
619 }
620
621 /*************************************************************************
622 * SHOpenRegStreamW [SHLWAPI.@]
623 *
624 * See SHOpenRegStreamA.
625 */
626 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, LPCWSTR pszSubkey,
627 LPCWSTR pszValue, DWORD dwMode)
628 {
629 IStream *iStream;
630
631 TRACE("(%p,%s,%s,0x%08x)\n", hkey, debugstr_w(pszSubkey),
632 debugstr_w(pszValue), dwMode);
633 iStream = SHOpenRegStream2W(hkey, pszSubkey, pszValue, dwMode);
634 return iStream ? iStream : &rsDummyRegStream.IStream_iface;
635 }
636
637 /*************************************************************************
638 * @ [SHLWAPI.12]
639 *
640 * Create an IStream object on a block of memory.
641 *
642 * PARAMS
643 * lpbData [I] Memory block to create the IStream object on
644 * dwDataLen [I] Length of data block
645 *
646 * RETURNS
647 * Success: A pointer to the IStream object.
648 * Failure: NULL, if any parameters are invalid or an error occurs.
649 *
650 * NOTES
651 * A copy of the memory pointed to by lpbData is made, and is freed
652 * when the stream is released.
653 */
654 IStream * WINAPI SHCreateMemStream(const BYTE *lpbData, UINT dwDataLen)
655 {
656 ISHRegStream *strm = NULL;
657 LPBYTE lpbDup;
658
659 TRACE("(%p,%d)\n", lpbData, dwDataLen);
660
661 if (!lpbData)
662 dwDataLen = 0;
663
664 lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen);
665
666 if (lpbDup)
667 {
668 memcpy(lpbDup, lpbData, dwDataLen);
669 strm = IStream_Create(NULL, lpbDup, dwDataLen);
670
671 if (!strm)
672 HeapFree(GetProcessHeap(), 0, lpbDup);
673 }
674 return &strm->IStream_iface;
675 }
676
677 /*************************************************************************
678 * SHCreateStreamWrapper [SHLWAPI.@]
679 *
680 * Create an IStream object on a block of memory.
681 *
682 * PARAMS
683 * lpbData [I] Memory block to create the IStream object on
684 * dwDataLen [I] Length of data block
685 * dwReserved [I] Reserved, Must be 0.
686 * lppStream [O] Destination for IStream object
687 *
688 * RETURNS
689 * Success: S_OK. lppStream contains the new IStream object.
690 * Failure: E_INVALIDARG, if any parameters are invalid,
691 * E_OUTOFMEMORY if memory allocation fails.
692 *
693 * NOTES
694 * The stream assumes ownership of the memory passed to it.
695 */
696 HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen,
697 DWORD dwReserved, IStream **lppStream)
698 {
699 ISHRegStream *strm;
700
701 if (lppStream)
702 *lppStream = NULL;
703
704 if(dwReserved || !lppStream)
705 return E_INVALIDARG;
706
707 strm = IStream_Create(NULL, lpbData, dwDataLen);
708
709 if(!strm)
710 return E_OUTOFMEMORY;
711
712 IStream_QueryInterface(&strm->IStream_iface, &IID_IStream, (void**)lppStream);
713 IStream_Release(&strm->IStream_iface);
714 return S_OK;
715 }