gdiplus: Don't bother to free memory at process exit.
[wine/wine-gecko.git] / dlls / shlwapi / regstream.c
blob1b0ca4edf67edd44fe4f69a725d60ff28d9780f6
1 /*
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
22 #include <stdarg.h>
23 #include <string.h>
25 #define COBJMACROS
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shell);
38 typedef struct
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;
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);
68 *ppvObj = NULL;
70 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
71 *ppvObj = This;
72 else if(IsEqualIID(riid, &IID_IStream)) /*IStream*/
73 *ppvObj = This;
75 if(*ppvObj)
77 IStream_AddRef((IStream*)*ppvObj);
78 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
79 return S_OK;
81 TRACE("-- Interface: E_NOINTERFACE\n");
82 return E_NOINTERFACE;
85 /**************************************************************************
86 * IStream_fnAddRef
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);
95 return refCount;
98 /**************************************************************************
99 * IStream_fnRelease
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);
108 if (!refCount)
110 TRACE(" destroying SHReg IStream (%p)\n",This);
112 if (This->hKey)
114 /* write back data in REG_BINARY */
115 if (This->dwMode == STGM_READWRITE || This->dwMode == STGM_WRITE)
117 if (This->dwLength)
119 if (This->bUnicode)
120 RegSetValueExW(This->hKey, This->u.keyNameW, 0, REG_BINARY,
121 (const BYTE *) This->pbBuffer, This->dwLength);
122 else
123 RegSetValueExA(This->hKey, This->u.keyNameA, 0, REG_BINARY,
124 (const BYTE *) This->pbBuffer, This->dwLength);
126 else
128 if (This->bUnicode)
129 RegDeleteValueW(This->hKey, This->u.keyNameW);
130 else
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);
141 return 0;
144 return refCount;
147 /**************************************************************************
148 * IStream_fnRead
150 static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead)
152 ISHRegStream *This = impl_from_IStream(iface);
153 DWORD dwBytesToRead;
155 TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
157 if (This->dwPos >= This->dwLength)
158 dwBytesToRead = 0;
159 else
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 */
169 if (pcbRead)
170 *pcbRead = dwBytesToRead;
172 return S_OK;
175 /**************************************************************************
176 * IStream_fnWrite
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);
191 if (!newBuf)
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 */
200 if (pcbWritten)
201 *pcbWritten = cb;
203 return S_OK;
206 /**************************************************************************
207 * IStream_fnSeek
209 static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
211 ISHRegStream *This = impl_from_IStream(iface);
212 LARGE_INTEGER tmp;
213 TRACE("(%p, %s, %d %p)\n", This,
214 wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition);
216 if (dwOrigin == STREAM_SEEK_SET)
217 tmp = dlibMove;
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;
222 else
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;
231 if (plibNewPosition)
232 plibNewPosition->QuadPart = This->dwPos;
233 return S_OK;
236 /**************************************************************************
237 * IStream_fnSetSize
239 static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize)
241 ISHRegStream *This = impl_from_IStream(iface);
242 DWORD newLen;
243 LPBYTE newBuf;
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);
250 if (!newBuf)
251 return STG_E_INSUFFICIENTMEMORY;
253 This->pbBuffer = newBuf;
254 This->dwLength = newLen;
256 return S_OK;
259 /**************************************************************************
260 * IStream_fnCopyTo
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);
267 if (pcbRead)
268 pcbRead->QuadPart = 0;
269 if (pcbWritten)
270 pcbWritten->QuadPart = 0;
272 /* TODO implement */
273 return E_NOTIMPL;
276 /**************************************************************************
277 * IStream_fnCommit
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 */
286 return E_NOTIMPL;
289 /**************************************************************************
290 * IStream_fnRevert
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 */
299 return E_NOTIMPL;
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 */
312 return E_NOTIMPL;
315 /*************************************************************************
316 * IStream_fnStat
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;
339 return S_OK;
342 /*************************************************************************
343 * IStream_fnClone
345 static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm)
347 ISHRegStream *This = impl_from_IStream(iface);
349 TRACE("(%p)\n",This);
350 *ppstm = NULL;
352 /* clone not supported by this stream */
353 return E_NOTIMPL;
356 static const IStreamVtbl rstvt =
358 IStream_fnQueryInterface,
359 IStream_fnAddRef,
360 IStream_fnRelease,
361 IStream_fnRead,
362 IStream_fnWrite,
363 IStream_fnSeek,
364 IStream_fnSetSize,
365 IStream_fnCopyTo,
366 IStream_fnCommit,
367 IStream_fnRevert,
368 IStream_fnLockUnlockRegion,
369 IStream_fnLockUnlockRegion,
370 IStream_fnStat,
371 IStream_fnClone
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);
383 return 2;
386 /**************************************************************************
387 * IStream_fnReleaseDummy
389 static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface)
391 ISHRegStream *This = impl_from_IStream(iface);
392 TRACE("(%p)\n", This);
393 return 1;
396 /**************************************************************************
397 * IStream_fnReadDummy
399 static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead)
401 if (pcbRead)
402 *pcbRead = 0;
403 return E_NOTIMPL;
406 static const IStreamVtbl DummyRegStreamVTable =
408 IStream_fnQueryInterface,
409 IStream_fnAddRefDummy, /* Overridden */
410 IStream_fnReleaseDummy, /* Overridden */
411 IStream_fnReadDummy, /* Overridden */
412 IStream_fnWrite,
413 IStream_fnSeek,
414 IStream_fnSetSize,
415 IStream_fnCopyTo,
416 IStream_fnCommit,
417 IStream_fnRevert,
418 IStream_fnLockUnlockRegion,
419 IStream_fnLockUnlockRegion,
420 IStream_fnStat,
421 IStream_fnClone
424 /* Dummy registry stream object */
425 static ISHRegStream rsDummyRegStream =
427 { &DummyRegStreamVTable },
429 NULL,
430 NULL,
433 STGM_READWRITE,
434 {NULL},
435 FALSE
438 /**************************************************************************
439 * IStream_Create
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));
449 if (regStream)
451 regStream->IStream_iface.lpVtbl = &rstvt;
452 regStream->ref = 1;
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);
462 return regStream;
465 /*************************************************************************
466 * SHOpenRegStream2A [SHLWAPI.@]
468 * Create a stream to read binary registry data.
470 * PARAMS
471 * hKey [I] Registry handle
472 * pszSubkey [I] The sub key name
473 * pszValue [I] The value name under the sub key
474 * dwMode [I] Unused
476 * RETURNS
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)
483 ISHRegStream *tmp;
484 HKEY hStrKey = NULL;
485 LPBYTE lpBuff = NULL;
486 DWORD dwLength = 0;
487 LONG ret;
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);
509 if (!dwLength)
510 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
512 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
513 if(tmp)
515 if(pszValue)
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);
529 if (hStrKey)
530 RegCloseKey(hStrKey);
531 return NULL;
534 /*************************************************************************
535 * SHOpenRegStream2W [SHLWAPI.@]
537 * See SHOpenRegStream2A.
539 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey,
540 LPCWSTR pszValue, DWORD dwMode)
542 ISHRegStream *tmp;
543 HKEY hStrKey = NULL;
544 LPBYTE lpBuff = NULL;
545 DWORD dwLength = 0;
546 LONG ret;
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);
569 if (!dwLength)
570 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
572 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
573 if(tmp)
575 if(pszValue)
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);
589 if (hStrKey)
590 RegCloseKey(hStrKey);
591 return NULL;
594 /*************************************************************************
595 * SHOpenRegStreamA [SHLWAPI.@]
597 * Create a stream to read binary registry data.
599 * PARAMS
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
605 * RETURNS
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)
613 IStream *iStream;
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)
629 IStream *iStream;
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 /*************************************************************************
638 * @ [SHLWAPI.12]
640 * Create an IStream object on a block of memory.
642 * PARAMS
643 * lpbData [I] Memory block to create the IStream object on
644 * dwDataLen [I] Length of data block
646 * RETURNS
647 * Success: A pointer to the IStream object.
648 * Failure: NULL, if any parameters are invalid or an error occurs.
650 * NOTES
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;
657 LPBYTE lpbDup;
659 TRACE("(%p,%d)\n", lpbData, dwDataLen);
661 if (!lpbData)
662 dwDataLen = 0;
664 lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen);
666 if (lpbDup)
668 memcpy(lpbDup, lpbData, dwDataLen);
669 strm = IStream_Create(NULL, lpbDup, dwDataLen);
671 if (!strm)
672 HeapFree(GetProcessHeap(), 0, lpbDup);
674 return &strm->IStream_iface;
677 /*************************************************************************
678 * SHCreateStreamWrapper [SHLWAPI.@]
680 * Create an IStream object on a block of memory.
682 * PARAMS
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
688 * RETURNS
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.
693 * NOTES
694 * The stream assumes ownership of the memory passed to it.
696 HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen,
697 DWORD dwReserved, IStream **lppStream)
699 ISHRegStream *strm;
701 if (lppStream)
702 *lppStream = NULL;
704 if(dwReserved || !lppStream)
705 return E_INVALIDARG;
707 strm = IStream_Create(NULL, lpbData, dwDataLen);
709 if(!strm)
710 return E_OUTOFMEMORY;
712 IStream_QueryInterface(&strm->IStream_iface, &IID_IStream, (void**)lppStream);
713 IStream_Release(&strm->IStream_iface);
714 return S_OK;