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 } ISHRegStream; 47 48 /************************************************************************** 49 * IStream_fnQueryInterface 50 */ 51 static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj) 52 { 53 ISHRegStream *This = (ISHRegStream *)iface; 54 55 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); 56 57 *ppvObj = NULL; 58 59 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/ 60 *ppvObj = This; 61 else if(IsEqualIID(riid, &IID_IStream)) /*IStream*/ 62 *ppvObj = This; 63 64 if(*ppvObj) 65 { 66 IStream_AddRef((IStream*)*ppvObj); 67 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); 68 return S_OK; 69 } 70 TRACE("-- Interface: E_NOINTERFACE\n"); 71 return E_NOINTERFACE; 72 } 73 74 /************************************************************************** 75 * IStream_fnAddRef 76 */ 77 static ULONG WINAPI IStream_fnAddRef(IStream *iface) 78 { 79 ISHRegStream *This = (ISHRegStream *)iface; 80 ULONG refCount = InterlockedIncrement(&This->ref); 81 82 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1); 83 84 return refCount; 85 } 86 87 /************************************************************************** 88 * IStream_fnRelease 89 */ 90 static ULONG WINAPI IStream_fnRelease(IStream *iface) 91 { 92 ISHRegStream *This = (ISHRegStream *)iface; 93 ULONG refCount = InterlockedDecrement(&This->ref); 94 95 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1); 96 97 if (!refCount) 98 { 99 TRACE(" destroying SHReg IStream (%p)\n",This); 100 101 HeapFree(GetProcessHeap(),0,This->pbBuffer); 102 103 if (This->hKey) 104 RegCloseKey(This->hKey); 105 106 HeapFree(GetProcessHeap(),0,This); 107 return 0; 108 } 109 110 return refCount; 111 } 112 113 /************************************************************************** 114 * IStream_fnRead 115 */ 116 static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead) 117 { 118 ISHRegStream *This = (ISHRegStream *)iface; 119 120 DWORD dwBytesToRead, dwBytesLeft; 121 122 TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead); 123 124 if (!pv) 125 return STG_E_INVALIDPOINTER; 126 127 dwBytesLeft = This->dwLength - This->dwPos; 128 129 if ( 0 >= dwBytesLeft ) /* end of buffer */ 130 return S_FALSE; 131 132 dwBytesToRead = ( cb > dwBytesLeft) ? dwBytesLeft : cb; 133 134 memmove ( pv, (This->pbBuffer) + (This->dwPos), dwBytesToRead); 135 136 This->dwPos += dwBytesToRead; /* adjust pointer */ 137 138 if (pcbRead) 139 *pcbRead = dwBytesToRead; 140 141 return S_OK; 142 } 143 144 /************************************************************************** 145 * IStream_fnWrite 146 */ 147 static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten) 148 { 149 ISHRegStream *This = (ISHRegStream *)iface; 150 151 TRACE("(%p)\n",This); 152 153 if (pcbWritten) 154 *pcbWritten = 0; 155 156 return E_NOTIMPL; 157 } 158 159 /************************************************************************** 160 * IStream_fnSeek 161 */ 162 static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 163 { 164 ISHRegStream *This = (ISHRegStream *)iface; 165 166 TRACE("(%p)\n",This); 167 168 if (plibNewPosition) 169 plibNewPosition->QuadPart = 0; 170 return E_NOTIMPL; 171 } 172 173 /************************************************************************** 174 * IStream_fnSetSize 175 */ 176 static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize) 177 { 178 ISHRegStream *This = (ISHRegStream *)iface; 179 180 TRACE("(%p)\n",This); 181 return E_NOTIMPL; 182 } 183 184 /************************************************************************** 185 * IStream_fnCopyTo 186 */ 187 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) 188 { 189 ISHRegStream *This = (ISHRegStream *)iface; 190 191 TRACE("(%p)\n",This); 192 if (pcbRead) 193 pcbRead->QuadPart = 0; 194 if (pcbWritten) 195 pcbWritten->QuadPart = 0; 196 return E_NOTIMPL; 197 } 198 199 /************************************************************************** 200 * IStream_fnCommit 201 */ 202 static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags) 203 { 204 ISHRegStream *This = (ISHRegStream *)iface; 205 206 TRACE("(%p)\n",This); 207 208 return E_NOTIMPL; 209 } 210 211 /************************************************************************** 212 * IStream_fnRevert 213 */ 214 static HRESULT WINAPI IStream_fnRevert (IStream * iface) 215 { 216 ISHRegStream *This = (ISHRegStream *)iface; 217 218 TRACE("(%p)\n",This); 219 220 return E_NOTIMPL; 221 } 222 223 /************************************************************************** 224 * IStream_fnLockUnlockRegion 225 */ 226 static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 227 { 228 ISHRegStream *This = (ISHRegStream *)iface; 229 230 TRACE("(%p)\n",This); 231 232 return E_NOTIMPL; 233 } 234 235 /************************************************************************* 236 * IStream_fnStat 237 */ 238 static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag) 239 { 240 ISHRegStream *This = (ISHRegStream *)iface; 241 242 TRACE("(%p)\n",This); 243 244 return E_NOTIMPL; 245 } 246 247 /************************************************************************* 248 * IStream_fnClone 249 */ 250 static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm) 251 { 252 ISHRegStream *This = (ISHRegStream *)iface; 253 254 TRACE("(%p)\n",This); 255 if (ppstm) 256 *ppstm = NULL; 257 return E_NOTIMPL; 258 } 259 260 static const IStreamVtbl rstvt = 261 { 262 IStream_fnQueryInterface, 263 IStream_fnAddRef, 264 IStream_fnRelease, 265 IStream_fnRead, 266 IStream_fnWrite, 267 IStream_fnSeek, 268 IStream_fnSetSize, 269 IStream_fnCopyTo, 270 IStream_fnCommit, 271 IStream_fnRevert, 272 IStream_fnLockUnlockRegion, 273 IStream_fnLockUnlockRegion, 274 IStream_fnStat, 275 IStream_fnClone 276 }; 277 278 /* Methods overridden by the dummy stream */ 279 280 /************************************************************************** 281 * IStream_fnAddRefDummy 282 */ 283 static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface) 284 { 285 ISHRegStream *This = (ISHRegStream *)iface; 286 TRACE("(%p)\n", This); 287 return 2; 288 } 289 290 /************************************************************************** 291 * IStream_fnReleaseDummy 292 */ 293 static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface) 294 { 295 ISHRegStream *This = (ISHRegStream *)iface; 296 TRACE("(%p)\n", This); 297 return 1; 298 } 299 300 /************************************************************************** 301 * IStream_fnReadDummy 302 */ 303 static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead) 304 { 305 if (pcbRead) 306 *pcbRead = 0; 307 return E_NOTIMPL; 308 } 309 310 static const IStreamVtbl DummyRegStreamVTable = 311 { 312 IStream_fnQueryInterface, 313 IStream_fnAddRefDummy, /* Overridden */ 314 IStream_fnReleaseDummy, /* Overridden */ 315 IStream_fnReadDummy, /* Overridden */ 316 IStream_fnWrite, 317 IStream_fnSeek, 318 IStream_fnSetSize, 319 IStream_fnCopyTo, 320 IStream_fnCommit, 321 IStream_fnRevert, 322 IStream_fnLockUnlockRegion, 323 IStream_fnLockUnlockRegion, 324 IStream_fnStat, 325 IStream_fnClone 326 }; 327 328 /* Dummy registry stream object */ 329 static ISHRegStream rsDummyRegStream = 330 { 331 &DummyRegStreamVTable, 332 1, 333 NULL, 334 NULL, 335 0, 336 0 337 }; 338 339 /************************************************************************** 340 * IStream_Create 341 * 342 * Internal helper: Create and initialise a new registry stream object. 343 */ 344 static IStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength) 345 { 346 ISHRegStream* regStream; 347 348 regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream)); 349 350 if (regStream) 351 { 352 regStream->lpVtbl = &rstvt; 353 regStream->ref = 1; 354 regStream->hKey = hKey; 355 regStream->pbBuffer = pbBuffer; 356 regStream->dwLength = dwLength; 357 regStream->dwPos = 0; 358 } 359 TRACE ("Returning %p\n", regStream); 360 return (IStream *)regStream; 361 } 362 363 /************************************************************************* 364 * SHOpenRegStream2A [SHLWAPI.@] 365 * 366 * Create a stream to read binary registry data. 367 * 368 * PARAMS 369 * hKey [I] Registry handle 370 * pszSubkey [I] The sub key name 371 * pszValue [I] The value name under the sub key 372 * dwMode [I] Unused 373 * 374 * RETURNS 375 * Success: An IStream interface referring to the registry data 376 * Failure: NULL, if the registry key could not be opened or is not binary. 377 */ 378 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, LPCSTR pszSubkey, 379 LPCSTR pszValue,DWORD dwMode) 380 { 381 HKEY hStrKey = NULL; 382 LPBYTE lpBuff = NULL; 383 DWORD dwLength, dwType; 384 385 TRACE("(%p,%s,%s,0x%08x)\n", hKey, pszSubkey, pszValue, dwMode); 386 387 /* Open the key, read in binary data and create stream */ 388 if (!RegOpenKeyExA (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && 389 !RegQueryValueExA (hStrKey, pszValue, 0, 0, 0, &dwLength) && 390 (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && 391 !RegQueryValueExA (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && 392 dwType == REG_BINARY) 393 return IStream_Create(hStrKey, lpBuff, dwLength); 394 395 HeapFree (GetProcessHeap(), 0, lpBuff); 396 if (hStrKey) 397 RegCloseKey(hStrKey); 398 return NULL; 399 } 400 401 /************************************************************************* 402 * SHOpenRegStream2W [SHLWAPI.@] 403 * 404 * See SHOpenRegStream2A. 405 */ 406 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey, 407 LPCWSTR pszValue, DWORD dwMode) 408 { 409 HKEY hStrKey = NULL; 410 LPBYTE lpBuff = NULL; 411 DWORD dwLength, dwType; 412 413 TRACE("(%p,%s,%s,0x%08x)\n", hKey, debugstr_w(pszSubkey), 414 debugstr_w(pszValue), dwMode); 415 416 /* Open the key, read in binary data and create stream */ 417 if (!RegOpenKeyExW (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && 418 !RegQueryValueExW (hStrKey, pszValue, 0, 0, 0, &dwLength) && 419 (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && 420 !RegQueryValueExW (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && 421 dwType == REG_BINARY) 422 return IStream_Create(hStrKey, lpBuff, dwLength); 423 424 HeapFree (GetProcessHeap(), 0, lpBuff); 425 if (hStrKey) 426 RegCloseKey(hStrKey); 427 return NULL; 428 } 429 430 /************************************************************************* 431 * SHOpenRegStreamA [SHLWAPI.@] 432 * 433 * Create a stream to read binary registry data. 434 * 435 * PARAMS 436 * hKey [I] Registry handle 437 * pszSubkey [I] The sub key name 438 * pszValue [I] The value name under the sub key 439 * dwMode [I] STGM mode for opening the file 440 * 441 * RETURNS 442 * Success: An IStream interface referring to the registry data 443 * Failure: If the registry key could not be opened or is not binary, 444 * A dummy (empty) IStream object is returned. 445 */ 446 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, LPCSTR pszSubkey, 447 LPCSTR pszValue, DWORD dwMode) 448 { 449 IStream *iStream; 450 451 TRACE("(%p,%s,%s,0x%08x)\n", hkey, pszSubkey, pszValue, dwMode); 452 453 iStream = SHOpenRegStream2A(hkey, pszSubkey, pszValue, dwMode); 454 return iStream ? iStream : (IStream *)&rsDummyRegStream; 455 } 456 457 /************************************************************************* 458 * SHOpenRegStreamW [SHLWAPI.@] 459 * 460 * See SHOpenRegStreamA. 461 */ 462 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, LPCWSTR pszSubkey, 463 LPCWSTR pszValue, DWORD dwMode) 464 { 465 IStream *iStream; 466 467 TRACE("(%p,%s,%s,0x%08x)\n", hkey, debugstr_w(pszSubkey), 468 debugstr_w(pszValue), dwMode); 469 iStream = SHOpenRegStream2W(hkey, pszSubkey, pszValue, dwMode); 470 return iStream ? iStream : (IStream *)&rsDummyRegStream; 471 } 472 473 /************************************************************************* 474 * @ [SHLWAPI.12] 475 * 476 * Create an IStream object on a block of memory. 477 * 478 * PARAMS 479 * lpbData [I] Memory block to create the IStream object on 480 * dwDataLen [I] Length of data block 481 * 482 * RETURNS 483 * Success: A pointer to the IStream object. 484 * Failure: NULL, if any parameters are invalid or an error occurs. 485 * 486 * NOTES 487 * A copy of the memory pointed to by lpbData is made, and is freed 488 * when the stream is released. 489 */ 490 IStream * WINAPI SHCreateMemStream(LPBYTE lpbData, DWORD dwDataLen) 491 { 492 IStream *iStrmRet = NULL; 493 494 TRACE("(%p,%d)\n", lpbData, dwDataLen); 495 496 if (lpbData) 497 { 498 LPBYTE lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen); 499 500 if (lpbDup) 501 { 502 memcpy(lpbDup, lpbData, dwDataLen); 503 iStrmRet = IStream_Create(NULL, lpbDup, dwDataLen); 504 505 if (!iStrmRet) 506 HeapFree(GetProcessHeap(), 0, lpbDup); 507 } 508 } 509 return iStrmRet; 510 } 511 512 /************************************************************************* 513 * SHCreateStreamWrapper [SHLWAPI.@] 514 * 515 * Create an IStream object on a block of memory. 516 * 517 * PARAMS 518 * lpbData [I] Memory block to create the IStream object on 519 * dwDataLen [I] Length of data block 520 * dwReserved [I] Reserved, Must be 0. 521 * lppStream [O] Destination for IStream object 522 * 523 * RETURNS 524 * Success: S_OK. lppStream contains the new IStream object. 525 * Failure: E_INVALIDARG, if any parameters are invalid, 526 * E_OUTOFMEMORY if memory allocation fails. 527 * 528 * NOTES 529 * The stream assumes ownership of the memory passed to it. 530 */ 531 HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen, 532 DWORD dwReserved, IStream **lppStream) 533 { 534 IStream* lpStream; 535 536 if (lppStream) 537 *lppStream = NULL; 538 539 if(dwReserved || !lppStream) 540 return E_INVALIDARG; 541 542 lpStream = IStream_Create(NULL, lpbData, dwDataLen); 543 544 if(!lpStream) 545 return E_OUTOFMEMORY; 546 547 IStream_QueryInterface(lpStream, &IID_IStream, (void**)lppStream); 548 IStream_Release(lpStream); 549 return S_OK; 550 } 551