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