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