Sync to Wine-20040914:
[reactos.git] / reactos / lib / 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 { IStreamVtbl *lpVtbl;
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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *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 ISHRegStream *This = (ISHRegStream *)iface;
247
248 TRACE("(%p)\n",This);
249 if (ppstm)
250 *ppstm = NULL;
251 return E_NOTIMPL;
252 }
253
254 static struct IStreamVtbl rstvt =
255 {
256 IStream_fnQueryInterface,
257 IStream_fnAddRef,
258 IStream_fnRelease,
259 IStream_fnRead,
260 IStream_fnWrite,
261 IStream_fnSeek,
262 IStream_fnSetSize,
263 IStream_fnCopyTo,
264 IStream_fnCommit,
265 IStream_fnRevert,
266 IStream_fnLockUnlockRegion,
267 IStream_fnLockUnlockRegion,
268 IStream_fnStat,
269 IStream_fnClone
270 };
271
272 /* Methods overridden by the dummy stream */
273
274 /**************************************************************************
275 * IStream_fnAddRefDummy
276 */
277 static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface)
278 {
279 ISHRegStream *This = (ISHRegStream *)iface;
280 TRACE("(%p)\n", This);
281 return 2;
282 }
283
284 /**************************************************************************
285 * IStream_fnReleaseDummy
286 */
287 static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface)
288 {
289 ISHRegStream *This = (ISHRegStream *)iface;
290 TRACE("(%p)\n", This);
291 return 1;
292 }
293
294 /**************************************************************************
295 * IStream_fnReadDummy
296 */
297 static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead)
298 {
299 if (pcbRead)
300 *pcbRead = 0;
301 return E_NOTIMPL;
302 }
303
304 static struct IStreamVtbl DummyRegStreamVTable =
305 {
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 regStream->lpVtbl = &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 an IStream object on a block of memory.
473 *
474 * PARAMS
475 * lpbData [I] Memory block to create the IStream object on
476 * dwDataLen [I] Length of data block
477 *
478 * RETURNS
479 * Success: A pointer to the IStream 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 SHCreateMemStream(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 an IStream object on a block of memory.
512 *
513 * PARAMS
514 * lpbData [I] Memory block to create the IStream object on
515 * dwDataLen [I] Length of data block
516 * dwReserved [I] Reserved, Must be 0.
517 * lppStream [O] Destination for IStream object
518 *
519 * RETURNS
520 * Success: S_OK. lppStream contains the new IStream 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 }