oleaut32/tests: Test more return values.
[wine.git] / dlls / shlwapi / regstream.c
blob63615d3d9cf16a8633e2cc88fd3a772c3262c4ef
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) || IsEqualIID(riid, &IID_IStream))
71 *ppvObj = &This->IStream_iface;
73 if(*ppvObj)
75 IStream_AddRef((IStream*)*ppvObj);
76 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
77 return S_OK;
79 TRACE("-- Interface: E_NOINTERFACE\n");
80 return E_NOINTERFACE;
83 /**************************************************************************
84 * IStream_fnAddRef
86 static ULONG WINAPI IStream_fnAddRef(IStream *iface)
88 ISHRegStream *This = impl_from_IStream(iface);
89 ULONG refCount = InterlockedIncrement(&This->ref);
91 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
93 return refCount;
96 /**************************************************************************
97 * IStream_fnRelease
99 static ULONG WINAPI IStream_fnRelease(IStream *iface)
101 ISHRegStream *This = impl_from_IStream(iface);
102 ULONG refCount = InterlockedDecrement(&This->ref);
104 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
106 if (!refCount)
108 TRACE(" destroying SHReg IStream (%p)\n",This);
110 if (This->hKey)
112 /* write back data in REG_BINARY */
113 if (This->dwMode == STGM_READWRITE || This->dwMode == STGM_WRITE)
115 if (This->dwLength)
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);
124 else
126 if (This->bUnicode)
127 RegDeleteValueW(This->hKey, This->u.keyNameW);
128 else
129 RegDeleteValueA(This->hKey, This->u.keyNameA);
133 RegCloseKey(This->hKey);
136 HeapFree(GetProcessHeap(),0,This->u.keyNameA);
137 HeapFree(GetProcessHeap(),0,This->pbBuffer);
138 HeapFree(GetProcessHeap(),0,This);
139 return 0;
142 return refCount;
145 /**************************************************************************
146 * IStream_fnRead
148 static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead)
150 ISHRegStream *This = impl_from_IStream(iface);
151 DWORD dwBytesToRead;
153 TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
155 if (This->dwPos >= This->dwLength)
156 dwBytesToRead = 0;
157 else
158 dwBytesToRead = This->dwLength - This->dwPos;
160 dwBytesToRead = (cb > dwBytesToRead) ? dwBytesToRead : cb;
161 if (dwBytesToRead != 0) /* not at end of buffer and we want to read something */
163 memmove(pv, This->pbBuffer + This->dwPos, dwBytesToRead);
164 This->dwPos += dwBytesToRead; /* adjust pointer */
167 if (pcbRead)
168 *pcbRead = dwBytesToRead;
170 return S_OK;
173 /**************************************************************************
174 * IStream_fnWrite
176 static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten)
178 ISHRegStream *This = impl_from_IStream(iface);
179 DWORD newLen = This->dwPos + cb;
181 TRACE("(%p, %p, %d, %p)\n",This, pv, cb, pcbWritten);
183 if (newLen < This->dwPos) /* overflow */
184 return STG_E_INSUFFICIENTMEMORY;
186 if (newLen > This->dwLength)
188 LPBYTE newBuf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pbBuffer, newLen);
189 if (!newBuf)
190 return STG_E_INSUFFICIENTMEMORY;
192 This->dwLength = newLen;
193 This->pbBuffer = newBuf;
195 memmove(This->pbBuffer + This->dwPos, pv, cb);
196 This->dwPos += cb; /* adjust pointer */
198 if (pcbWritten)
199 *pcbWritten = cb;
201 return S_OK;
204 /**************************************************************************
205 * IStream_fnSeek
207 static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
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);
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;
223 if (tmp.QuadPart < 0)
224 return STG_E_INVALIDFUNCTION;
226 /* we cut off the high part here */
227 This->dwPos = tmp.u.LowPart;
229 if (plibNewPosition)
230 plibNewPosition->QuadPart = This->dwPos;
231 return S_OK;
234 /**************************************************************************
235 * IStream_fnSetSize
237 static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize)
239 ISHRegStream *This = impl_from_IStream(iface);
240 DWORD newLen;
241 LPBYTE newBuf;
243 TRACE("(%p, %s)\n", This, wine_dbgstr_longlong(libNewSize.QuadPart));
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;
251 This->pbBuffer = newBuf;
252 This->dwLength = newLen;
254 return S_OK;
257 /**************************************************************************
258 * IStream_fnCopyTo
260 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
262 ISHRegStream *This = impl_from_IStream(iface);
264 TRACE("(%p)\n",This);
265 if (pcbRead)
266 pcbRead->QuadPart = 0;
267 if (pcbWritten)
268 pcbWritten->QuadPart = 0;
270 /* TODO implement */
271 return E_NOTIMPL;
274 /**************************************************************************
275 * IStream_fnCommit
277 static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags)
279 ISHRegStream *This = impl_from_IStream(iface);
281 TRACE("(%p)\n",This);
283 /* commit not supported by this stream */
284 return E_NOTIMPL;
287 /**************************************************************************
288 * IStream_fnRevert
290 static HRESULT WINAPI IStream_fnRevert (IStream * iface)
292 ISHRegStream *This = impl_from_IStream(iface);
294 TRACE("(%p)\n",This);
296 /* revert not supported by this stream */
297 return E_NOTIMPL;
300 /**************************************************************************
301 * IStream_fnLockUnlockRegion
303 static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
305 ISHRegStream *This = impl_from_IStream(iface);
307 TRACE("(%p)\n",This);
309 /* lock/unlock not supported by this stream */
310 return E_NOTIMPL;
313 /*************************************************************************
314 * IStream_fnStat
316 static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag)
318 ISHRegStream *This = impl_from_IStream(iface);
320 TRACE("(%p, %p, %d)\n",This,pstatstg,grfStatFlag);
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;
337 return S_OK;
340 /*************************************************************************
341 * IStream_fnClone
343 static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm)
345 ISHRegStream *This = impl_from_IStream(iface);
347 TRACE("(%p)\n",This);
348 *ppstm = NULL;
350 /* clone not supported by this stream */
351 return E_NOTIMPL;
354 static const IStreamVtbl rstvt =
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
372 /* Methods overridden by the dummy stream */
374 /**************************************************************************
375 * IStream_fnAddRefDummy
377 static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface)
379 ISHRegStream *This = impl_from_IStream(iface);
380 TRACE("(%p)\n", This);
381 return 2;
384 /**************************************************************************
385 * IStream_fnReleaseDummy
387 static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface)
389 ISHRegStream *This = impl_from_IStream(iface);
390 TRACE("(%p)\n", This);
391 return 1;
394 /**************************************************************************
395 * IStream_fnReadDummy
397 static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead)
399 if (pcbRead)
400 *pcbRead = 0;
401 return E_NOTIMPL;
404 static const IStreamVtbl DummyRegStreamVTable =
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
422 /* Dummy registry stream object */
423 static ISHRegStream rsDummyRegStream =
425 { &DummyRegStreamVTable },
427 NULL,
428 NULL,
431 STGM_READWRITE,
432 {NULL},
433 FALSE
436 /**************************************************************************
437 * IStream_Create
439 * Internal helper: Create and initialise a new registry stream object.
441 static ISHRegStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength)
443 ISHRegStream* regStream;
445 regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream));
447 if (regStream)
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;
459 TRACE ("Returning %p\n", regStream);
460 return regStream;
463 /*************************************************************************
464 * SHOpenRegStream2A [SHLWAPI.@]
466 * Create a stream to read binary registry data.
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
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.
478 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, LPCSTR pszSubkey,
479 LPCSTR pszValue,DWORD dwMode)
481 ISHRegStream *tmp;
482 HKEY hStrKey = NULL;
483 LPBYTE lpBuff = NULL;
484 DWORD dwLength = 0;
485 LONG ret;
487 TRACE("(%p,%s,%s,0x%08x)\n", hKey, pszSubkey, pszValue, dwMode);
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);
494 if (ret == ERROR_SUCCESS)
496 if (dwMode == STGM_READ || dwMode == STGM_READWRITE)
498 /* read initial data */
499 ret = RegQueryValueExA(hStrKey, pszValue, 0, 0, 0, &dwLength);
500 if (ret == ERROR_SUCCESS && dwLength)
502 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
503 RegQueryValueExA(hStrKey, pszValue, 0, 0, lpBuff, &dwLength);
507 if (!dwLength)
508 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
510 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
511 if(tmp)
513 if(pszValue)
515 int len = lstrlenA(pszValue) + 1;
516 tmp->u.keyNameA = HeapAlloc(GetProcessHeap(), 0, len);
517 memcpy(tmp->u.keyNameA, pszValue, len);
520 tmp->dwMode = dwMode;
521 tmp->bUnicode = FALSE;
522 return &tmp->IStream_iface;
526 HeapFree(GetProcessHeap(), 0, lpBuff);
527 if (hStrKey)
528 RegCloseKey(hStrKey);
529 return NULL;
532 /*************************************************************************
533 * SHOpenRegStream2W [SHLWAPI.@]
535 * See SHOpenRegStream2A.
537 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey,
538 LPCWSTR pszValue, DWORD dwMode)
540 ISHRegStream *tmp;
541 HKEY hStrKey = NULL;
542 LPBYTE lpBuff = NULL;
543 DWORD dwLength = 0;
544 LONG ret;
546 TRACE("(%p,%s,%s,0x%08x)\n", hKey, debugstr_w(pszSubkey),
547 debugstr_w(pszValue), dwMode);
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);
554 if (ret == ERROR_SUCCESS)
556 if (dwMode == STGM_READ || dwMode == STGM_READWRITE)
558 /* read initial data */
559 ret = RegQueryValueExW(hStrKey, pszValue, 0, 0, 0, &dwLength);
560 if (ret == ERROR_SUCCESS && dwLength)
562 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
563 RegQueryValueExW(hStrKey, pszValue, 0, 0, lpBuff, &dwLength);
567 if (!dwLength)
568 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwLength);
570 tmp = IStream_Create(hStrKey, lpBuff, dwLength);
571 if(tmp)
573 if(pszValue)
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));
580 tmp->dwMode = dwMode;
581 tmp->bUnicode = TRUE;
582 return &tmp->IStream_iface;
586 HeapFree(GetProcessHeap(), 0, lpBuff);
587 if (hStrKey)
588 RegCloseKey(hStrKey);
589 return NULL;
592 /*************************************************************************
593 * SHOpenRegStreamA [SHLWAPI.@]
595 * Create a stream to read binary registry data.
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
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.
608 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, LPCSTR pszSubkey,
609 LPCSTR pszValue, DWORD dwMode)
611 IStream *iStream;
613 TRACE("(%p,%s,%s,0x%08x)\n", hkey, pszSubkey, pszValue, dwMode);
615 iStream = SHOpenRegStream2A(hkey, pszSubkey, pszValue, dwMode);
616 return iStream ? iStream : &rsDummyRegStream.IStream_iface;
619 /*************************************************************************
620 * SHOpenRegStreamW [SHLWAPI.@]
622 * See SHOpenRegStreamA.
624 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, LPCWSTR pszSubkey,
625 LPCWSTR pszValue, DWORD dwMode)
627 IStream *iStream;
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;
635 /*************************************************************************
636 * @ [SHLWAPI.12]
638 * Create an IStream object on a block of memory.
640 * PARAMS
641 * lpbData [I] Memory block to create the IStream object on
642 * dwDataLen [I] Length of data block
644 * RETURNS
645 * Success: A pointer to the IStream object.
646 * Failure: NULL, if any parameters are invalid or an error occurs.
648 * NOTES
649 * A copy of the memory pointed to by lpbData is made, and is freed
650 * when the stream is released.
652 IStream * WINAPI SHCreateMemStream(const BYTE *lpbData, UINT dwDataLen)
654 ISHRegStream *strm = NULL;
655 LPBYTE lpbDup;
657 TRACE("(%p,%d)\n", lpbData, dwDataLen);
659 if (!lpbData)
660 dwDataLen = 0;
662 lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen);
664 if (lpbDup)
666 memcpy(lpbDup, lpbData, dwDataLen);
667 strm = IStream_Create(NULL, lpbDup, dwDataLen);
669 if (!strm)
670 HeapFree(GetProcessHeap(), 0, lpbDup);
672 return &strm->IStream_iface;
675 /*************************************************************************
676 * SHCreateStreamWrapper [SHLWAPI.@]
678 * Create an IStream object on a block of memory.
680 * PARAMS
681 * lpbData [I] Memory block to create the IStream object on
682 * dwDataLen [I] Length of data block
683 * dwReserved [I] Reserved, Must be 0.
684 * lppStream [O] Destination for IStream object
686 * RETURNS
687 * Success: S_OK. lppStream contains the new IStream object.
688 * Failure: E_INVALIDARG, if any parameters are invalid,
689 * E_OUTOFMEMORY if memory allocation fails.
691 * NOTES
692 * The stream assumes ownership of the memory passed to it.
694 HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen,
695 DWORD dwReserved, IStream **lppStream)
697 ISHRegStream *strm;
699 if (lppStream)
700 *lppStream = NULL;
702 if(dwReserved || !lppStream)
703 return E_INVALIDARG;
705 strm = IStream_Create(NULL, lpbData, dwDataLen);
707 if(!strm)
708 return E_OUTOFMEMORY;
710 IStream_QueryInterface(&strm->IStream_iface, &IID_IStream, (void**)lppStream);
711 IStream_Release(&strm->IStream_iface);
712 return S_OK;