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