xref: /reactos/dll/win32/shlwapi/regstream.c (revision 299e4305)
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 #ifdef __REACTOS__
673   if (!strm)
674     return NULL;
675 #endif
676   return &strm->IStream_iface;
677 }
678 
679 /*************************************************************************
680  * SHCreateStreamWrapper   [SHLWAPI.@]
681  *
682  * Create an IStream object on a block of memory.
683  *
684  * PARAMS
685  * lpbData    [I] Memory block to create the IStream object on
686  * dwDataLen  [I] Length of data block
687  * dwReserved [I] Reserved, Must be 0.
688  * lppStream  [O] Destination for IStream object
689  *
690  * RETURNS
691  * Success: S_OK. lppStream contains the new IStream object.
692  * Failure: E_INVALIDARG, if any parameters are invalid,
693  *          E_OUTOFMEMORY if memory allocation fails.
694  *
695  * NOTES
696  *  The stream assumes ownership of the memory passed to it.
697  */
698 HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen,
699                                      DWORD dwReserved, IStream **lppStream)
700 {
701   ISHRegStream *strm;
702 
703   if (lppStream)
704     *lppStream = NULL;
705 
706   if(dwReserved || !lppStream)
707     return E_INVALIDARG;
708 
709   strm = IStream_Create(NULL, lpbData, dwDataLen);
710 
711   if(!strm)
712     return E_OUTOFMEMORY;
713 
714   IStream_QueryInterface(&strm->IStream_iface, &IID_IStream, (void**)lppStream);
715   IStream_Release(&strm->IStream_iface);
716   return S_OK;
717 }
718