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