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