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