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