2 * SHLWAPI Registry Stream functions
4 * Copyright 1999 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
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.
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.
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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shell);
40 IStream IStream_iface;
54 static inline ISHRegStream *impl_from_IStream(IStream *iface)
56 return CONTAINING_RECORD(iface, ISHRegStream, IStream_iface);
59 /**************************************************************************
60 * IStream_fnQueryInterface
62 static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj)
64 ISHRegStream *This = impl_from_IStream(iface);
66 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
70 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
72 else if(IsEqualIID(riid, &IID_IStream)) /*IStream*/
77 IStream_AddRef((IStream*)*ppvObj);
78 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
81 TRACE("-- Interface: E_NOINTERFACE\n");
85 /**************************************************************************
88 static ULONG WINAPI IStream_fnAddRef(IStream *iface)
90 ISHRegStream *This = impl_from_IStream(iface);
91 ULONG refCount = InterlockedIncrement(&This->ref);
93 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
98 /**************************************************************************
101 static ULONG WINAPI IStream_fnRelease(IStream *iface)
103 ISHRegStream *This = impl_from_IStream(iface);
104 ULONG refCount = InterlockedDecrement(&This->ref);
106 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
110 TRACE(" destroying SHReg IStream (%p)\n",This);
114 /* write back data in REG_BINARY */
115 if (This->dwMode == STGM_READWRITE || This->dwMode == STGM_WRITE)
120 RegSetValueExW(This->hKey, This->u.keyNameW, 0, REG_BINARY,
121 (const BYTE *) This->pbBuffer, This->dwLength);
123 RegSetValueExA(This->hKey, This->u.keyNameA, 0, REG_BINARY,
124 (const BYTE *) This->pbBuffer, This->dwLength);
129 RegDeleteValueW(This->hKey, This->u.keyNameW);
131 RegDeleteValueA(This->hKey, This->u.keyNameA);
135 RegCloseKey(This->hKey);
138 HeapFree(GetProcessHeap(),0,This->u.keyNameA);
139 HeapFree(GetProcessHeap(),0,This->pbBuffer);
140 HeapFree(GetProcessHeap(),0,This);
147 /**************************************************************************
150 static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead)
152 ISHRegStream *This = impl_from_IStream(iface);
155 TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
157 if (This->dwPos >= This->dwLength)
160 dwBytesToRead = This->dwLength - This->dwPos;
162 dwBytesToRead = (cb > dwBytesToRead) ? dwBytesToRead : cb;
163 if (dwBytesToRead != 0) /* not at end of buffer and we want to read something */
165 memmove(pv, This->pbBuffer + This->dwPos, dwBytesToRead);
166 This->dwPos += dwBytesToRead; /* adjust pointer */
170 *pcbRead = dwBytesToRead;
175 /**************************************************************************
178 static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten)
180 ISHRegStream *This = impl_from_IStream(iface);
181 DWORD newLen = This->dwPos + cb;
183 TRACE("(%p, %p, %d, %p)\n",This, pv, cb, pcbWritten);
185 if (newLen < This->dwPos) /* overflow */
186 return STG_E_INSUFFICIENTMEMORY;
188 if (newLen > This->dwLength)
190 LPBYTE newBuf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pbBuffer, newLen);
192 return STG_E_INSUFFICIENTMEMORY;
194 This->dwLength = newLen;
195 This->pbBuffer = newBuf;
197 memmove(This->pbBuffer + This->dwPos, pv, cb);
198 This->dwPos += cb; /* adjust pointer */
206 /**************************************************************************
209 static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
211 ISHRegStream *This = impl_from_IStream(iface);
213 TRACE("(%p, %s, %d %p)\n", This,
214 wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition);
216 if (dwOrigin == STREAM_SEEK_SET)
218 else if (dwOrigin == STREAM_SEEK_CUR)
219 tmp.QuadPart = This->dwPos + dlibMove.QuadPart;
220 else if (dwOrigin == STREAM_SEEK_END)
221 tmp.QuadPart = This->dwLength + dlibMove.QuadPart;
223 return STG_E_INVALIDPARAMETER;
225 if (tmp.QuadPart < 0)
226 return STG_E_INVALIDFUNCTION;
228 /* we cut off the high part here */
229 This->dwPos = tmp.u.LowPart;
232 plibNewPosition->QuadPart = This->dwPos;
236 /**************************************************************************
239 static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize)
241 ISHRegStream *This = impl_from_IStream(iface);
245 TRACE("(%p, %s)\n", This, wine_dbgstr_longlong(libNewSize.QuadPart));
247 /* we cut off the high part here */
248 newLen = libNewSize.u.LowPart;
249 newBuf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pbBuffer, newLen);
251 return STG_E_INSUFFICIENTMEMORY;
253 This->pbBuffer = newBuf;
254 This->dwLength = newLen;
259 /**************************************************************************
262 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
264 ISHRegStream *This = impl_from_IStream(iface);
266 TRACE("(%p)\n",This);
268 pcbRead->QuadPart = 0;
270 pcbWritten->QuadPart = 0;
276 /**************************************************************************
279 static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags)
281 ISHRegStream *This = impl_from_IStream(iface);
283 TRACE("(%p)\n",This);
285 /* commit not supported by this stream */
289 /**************************************************************************
292 static HRESULT WINAPI IStream_fnRevert (IStream * iface)
294 ISHRegStream *This = impl_from_IStream(iface);
296 TRACE("(%p)\n",This);
298 /* revert not supported by this stream */
302 /**************************************************************************
303 * IStream_fnLockUnlockRegion
305 static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
307 ISHRegStream *This = impl_from_IStream(iface);
309 TRACE("(%p)\n",This);
311 /* lock/unlock not supported by this stream */
315 /*************************************************************************
318 static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag)
320 ISHRegStream *This = impl_from_IStream(iface);
322 TRACE("(%p, %p, %d)\n",This,pstatstg,grfStatFlag);
324 pstatstg->pwcsName = NULL;
325 pstatstg->type = STGTY_STREAM;
326 pstatstg->cbSize.QuadPart = This->dwLength;
327 pstatstg->mtime.dwHighDateTime = 0;
328 pstatstg->mtime.dwLowDateTime = 0;
329 pstatstg->ctime.dwHighDateTime = 0;
330 pstatstg->ctime.dwLowDateTime = 0;
331 pstatstg->atime.dwHighDateTime = 0;
332 pstatstg->atime.dwLowDateTime = 0;
333 pstatstg->grfMode = This->dwMode;
334 pstatstg->grfLocksSupported = 0;
335 pstatstg->clsid = CLSID_NULL;
336 pstatstg->grfStateBits = 0;
337 pstatstg->reserved = 0;
342 /*************************************************************************
345 static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm)
347 ISHRegStream *This = impl_from_IStream(iface);
349 TRACE("(%p)\n",This);
352 /* clone not supported by this stream */
356 static const IStreamVtbl rstvt =
358 IStream_fnQueryInterface,
368 IStream_fnLockUnlockRegion,
369 IStream_fnLockUnlockRegion,
374 /* Methods overridden by the dummy stream */
376 /**************************************************************************
377 * IStream_fnAddRefDummy
379 static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface)
381 ISHRegStream *This = impl_from_IStream(iface);
382 TRACE("(%p)\n", This);
386 /**************************************************************************
387 * IStream_fnReleaseDummy
389 static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface)
391 ISHRegStream *This = impl_from_IStream(iface);
392 TRACE("(%p)\n", This);
396 /**************************************************************************
397 * IStream_fnReadDummy
399 static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead)
406 static const IStreamVtbl DummyRegStreamVTable =
408 IStream_fnQueryInterface,
409 IStream_fnAddRefDummy, /* Overridden */
410 IStream_fnReleaseDummy, /* Overridden */
411 IStream_fnReadDummy, /* Overridden */
418 IStream_fnLockUnlockRegion,
419 IStream_fnLockUnlockRegion,
424 /* Dummy registry stream object */
425 static ISHRegStream rsDummyRegStream =
427 { &DummyRegStreamVTable },
438 /**************************************************************************
441 * Internal helper: Create and initialise a new registry stream object.
443 static ISHRegStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength)
445 ISHRegStream* regStream;
447 regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream));
451 regStream->IStream_iface.lpVtbl = &rstvt;
453 regStream->hKey = hKey;
454 regStream->pbBuffer = pbBuffer;
455 regStream->dwLength = dwLength;
456 regStream->dwPos = 0;
457 regStream->dwMode = STGM_READWRITE;
458 regStream->u.keyNameA = NULL;
459 regStream->bUnicode = FALSE;
461 TRACE ("Returning %p\n", regStream);
465 /*************************************************************************
466 * SHOpenRegStream2A [SHLWAPI.@]
468 * Create a stream to read binary registry data.
471 * hKey [I] Registry handle
472 * pszSubkey [I] The sub key name
473 * pszValue [I] The value name under the sub key
477 * Success: An IStream interface referring to the registry data
478 * Failure: NULL, if the registry key could not be opened or is not binary.
480 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, LPCSTR pszSubkey,
481 LPCSTR pszValue,DWORD dwMode)
485 LPBYTE lpBuff = NULL;
489 TRACE("(%p,%s,%s,0x%08x)\n", hKey, pszSubkey, pszValue, dwMode);
491 if (dwMode == STGM_READ)
492 ret = RegOpenKeyExA(hKey, pszSubkey, 0, KEY_READ, &hStrKey);
493 else /* in write mode we make sure the subkey exits */
494 ret = RegCreateKeyExA(hKey, pszSubkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
496 if (ret == ERROR_SUCCESS)
498 if (dwMode == STGM_READ || dwMode == STGM_READWRITE)
500 /* read initial data */
501 ret = RegQueryValueExA(hStrKey, pszValue, 0, 0, 0, &dwLength);
502 if (ret == ERROR_SUCCESS && dwLength)
504 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
505 RegQueryValueExA(hStrKey, pszValue, 0, 0, lpBuff, &dwLength);
510 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
512 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
517 int len = lstrlenA(pszValue) + 1;
518 tmp->u.keyNameA = HeapAlloc(GetProcessHeap(), 0, len);
519 memcpy(tmp->u.keyNameA, pszValue, len);
522 tmp->dwMode = dwMode;
523 tmp->bUnicode = FALSE;
524 return &tmp->IStream_iface;
528 HeapFree(GetProcessHeap(), 0, lpBuff);
530 RegCloseKey(hStrKey);
534 /*************************************************************************
535 * SHOpenRegStream2W [SHLWAPI.@]
537 * See SHOpenRegStream2A.
539 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey,
540 LPCWSTR pszValue, DWORD dwMode)
544 LPBYTE lpBuff = NULL;
548 TRACE("(%p,%s,%s,0x%08x)\n", hKey, debugstr_w(pszSubkey),
549 debugstr_w(pszValue), dwMode);
551 if (dwMode == STGM_READ)
552 ret = RegOpenKeyExW(hKey, pszSubkey, 0, KEY_READ, &hStrKey);
553 else /* in write mode we make sure the subkey exits */
554 ret = RegCreateKeyExW(hKey, pszSubkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
556 if (ret == ERROR_SUCCESS)
558 if (dwMode == STGM_READ || dwMode == STGM_READWRITE)
560 /* read initial data */
561 ret = RegQueryValueExW(hStrKey, pszValue, 0, 0, 0, &dwLength);
562 if (ret == ERROR_SUCCESS && dwLength)
564 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
565 RegQueryValueExW(hStrKey, pszValue, 0, 0, lpBuff, &dwLength);
570 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
572 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
577 int len = lstrlenW(pszValue) + 1;
578 tmp->u.keyNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
579 memcpy(tmp->u.keyNameW, pszValue, len * sizeof(WCHAR));
582 tmp->dwMode = dwMode;
583 tmp->bUnicode = TRUE;
584 return &tmp->IStream_iface;
588 HeapFree(GetProcessHeap(), 0, lpBuff);
590 RegCloseKey(hStrKey);
594 /*************************************************************************
595 * SHOpenRegStreamA [SHLWAPI.@]
597 * Create a stream to read binary registry data.
600 * hKey [I] Registry handle
601 * pszSubkey [I] The sub key name
602 * pszValue [I] The value name under the sub key
603 * dwMode [I] STGM mode for opening the file
606 * Success: An IStream interface referring to the registry data
607 * Failure: If the registry key could not be opened or is not binary,
608 * A dummy (empty) IStream object is returned.
610 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, LPCSTR pszSubkey,
611 LPCSTR pszValue, DWORD dwMode)
615 TRACE("(%p,%s,%s,0x%08x)\n", hkey, pszSubkey, pszValue, dwMode);
617 iStream = SHOpenRegStream2A(hkey, pszSubkey, pszValue, dwMode);
618 return iStream ? iStream : &rsDummyRegStream.IStream_iface;
621 /*************************************************************************
622 * SHOpenRegStreamW [SHLWAPI.@]
624 * See SHOpenRegStreamA.
626 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, LPCWSTR pszSubkey,
627 LPCWSTR pszValue, DWORD dwMode)
631 TRACE("(%p,%s,%s,0x%08x)\n", hkey, debugstr_w(pszSubkey),
632 debugstr_w(pszValue), dwMode);
633 iStream = SHOpenRegStream2W(hkey, pszSubkey, pszValue, dwMode);
634 return iStream ? iStream : &rsDummyRegStream.IStream_iface;
637 /*************************************************************************
640 * Create an IStream object on a block of memory.
643 * lpbData [I] Memory block to create the IStream object on
644 * dwDataLen [I] Length of data block
647 * Success: A pointer to the IStream object.
648 * Failure: NULL, if any parameters are invalid or an error occurs.
651 * A copy of the memory pointed to by lpbData is made, and is freed
652 * when the stream is released.
654 IStream * WINAPI SHCreateMemStream(const BYTE *lpbData, UINT dwDataLen)
656 ISHRegStream *strm = NULL;
659 TRACE("(%p,%d)\n", lpbData, dwDataLen);
664 lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen);
668 memcpy(lpbDup, lpbData, dwDataLen);
669 strm = IStream_Create(NULL, lpbDup, dwDataLen);
672 HeapFree(GetProcessHeap(), 0, lpbDup);
674 return &strm->IStream_iface;
677 /*************************************************************************
678 * SHCreateStreamWrapper [SHLWAPI.@]
680 * Create an IStream object on a block of memory.
683 * lpbData [I] Memory block to create the IStream object on
684 * dwDataLen [I] Length of data block
685 * dwReserved [I] Reserved, Must be 0.
686 * lppStream [O] Destination for IStream object
689 * Success: S_OK. lppStream contains the new IStream object.
690 * Failure: E_INVALIDARG, if any parameters are invalid,
691 * E_OUTOFMEMORY if memory allocation fails.
694 * The stream assumes ownership of the memory passed to it.
696 HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen,
697 DWORD dwReserved, IStream **lppStream)
704 if(dwReserved || !lppStream)
707 strm = IStream_Create(NULL, lpbData, dwDataLen);
710 return E_OUTOFMEMORY;
712 IStream_QueryInterface(&strm->IStream_iface, &IID_IStream, (void**)lppStream);
713 IStream_Release(&strm->IStream_iface);