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