Added SystemParametersInfo unit test.
[wine] / dlls / quartz / devenum.c
1 /*
2  * Implementation of CLSID_SystemDeviceEnum.
3  * Implements IMoniker for CLSID_CDeviceMoniker.
4  * Implements IPropertyBag. (internal)
5  *
6  * hidenori@a2.ctktv.ne.jp
7  */
8
9 #include "config.h"
10
11 #include "windef.h"
12 #include "winbase.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "winreg.h"
16 #include "winerror.h"
17 #include "objidl.h"
18 #include "oleidl.h"
19 #include "ocidl.h"
20 #include "oleauto.h"
21 #include "strmif.h"
22 #include "uuids.h"
23
24 #include "debugtools.h"
25 DEFAULT_DEBUG_CHANNEL(quartz);
26
27 #include "quartz_private.h"
28 #include "devenum.h"
29 #include "enumunk.h"
30 #include "complist.h"
31 #include "regsvr.h"
32
33 #ifndef NUMELEMS
34 #define NUMELEMS(elem)  (sizeof(elem)/sizeof(elem[0]))
35 #endif  /* NUMELEMS */
36
37 /***************************************************************************
38  *
39  *      new/delete for CLSID_SystemDeviceEnum
40  *
41  */
42
43 /* can I use offsetof safely? - FIXME? */
44 static QUARTZ_IFEntry CSysDevEnum_IFEntries[] =
45 {
46   { &IID_ICreateDevEnum, offsetof(CSysDevEnum,createdevenum)-offsetof(CSysDevEnum,unk) },
47 };
48
49
50 static void QUARTZ_DestroySystemDeviceEnum(IUnknown* punk)
51 {
52         CSysDevEnum_THIS(punk,unk);
53
54         CSysDevEnum_UninitICreateDevEnum( This );
55 }
56
57 HRESULT QUARTZ_CreateSystemDeviceEnum(IUnknown* punkOuter,void** ppobj)
58 {
59         CSysDevEnum*    psde;
60         HRESULT hr;
61
62         TRACE("(%p,%p)\n",punkOuter,ppobj);
63
64         psde = (CSysDevEnum*)QUARTZ_AllocObj( sizeof(CSysDevEnum) );
65         if ( psde == NULL )
66                 return E_OUTOFMEMORY;
67
68         QUARTZ_IUnkInit( &psde->unk, punkOuter );
69
70         hr = CSysDevEnum_InitICreateDevEnum( psde );
71         if ( FAILED(hr) )
72         {
73                 QUARTZ_FreeObj( psde );
74                 return hr;
75         }
76
77         psde->unk.pEntries = CSysDevEnum_IFEntries;
78         psde->unk.dwEntries = sizeof(CSysDevEnum_IFEntries)/sizeof(CSysDevEnum_IFEntries[0]);
79         psde->unk.pOnFinalRelease = QUARTZ_DestroySystemDeviceEnum;
80
81         *ppobj = (void*)(&psde->unk);
82
83         return S_OK;
84 }
85
86
87 /***************************************************************************
88  *
89  *      CSysDevEnum::ICreateDevEnum
90  *
91  */
92
93
94 static HRESULT WINAPI
95 ICreateDevEnum_fnQueryInterface(ICreateDevEnum* iface,REFIID riid,void** ppobj)
96 {
97         CSysDevEnum_THIS(iface,createdevenum);
98
99         TRACE("(%p)->()\n",This);
100
101         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
102 }
103
104 static ULONG WINAPI
105 ICreateDevEnum_fnAddRef(ICreateDevEnum* iface)
106 {
107         CSysDevEnum_THIS(iface,createdevenum);
108
109         TRACE("(%p)->()\n",This);
110
111         return IUnknown_AddRef(This->unk.punkControl);
112 }
113
114 static ULONG WINAPI
115 ICreateDevEnum_fnRelease(ICreateDevEnum* iface)
116 {
117         CSysDevEnum_THIS(iface,createdevenum);
118
119         TRACE("(%p)->()\n",This);
120
121         return IUnknown_Release(This->unk.punkControl);
122 }
123
124 static HRESULT WINAPI
125 ICreateDevEnum_fnCreateClassEnumerator(ICreateDevEnum* iface,REFCLSID rclsidDeviceClass,IEnumMoniker** ppobj, DWORD dwFlags)
126 {
127         CSysDevEnum_THIS(iface,createdevenum);
128         HRESULT hr;
129         HKEY    hKey;
130         QUARTZ_CompList*        pMonList;
131         IMoniker*       pMon;
132         DWORD   dwIndex;
133         LONG    lr;
134         WCHAR   wszPath[ 1024 ];
135         DWORD   dwLen;
136         DWORD   dwNameMax;
137         DWORD   cbName;
138         FILETIME        ftLastWrite;
139
140         TRACE("(%p)->(%s,%p,%08lx)\n",This,
141                 debugstr_guid(rclsidDeviceClass),ppobj,dwFlags);
142         if ( dwFlags != 0 )
143         {
144                 FIXME("unknown flags %08lx\n",dwFlags);
145                 return E_NOTIMPL;
146         }
147
148         if ( ppobj == NULL )
149                 return E_POINTER;
150         *ppobj = NULL;
151
152         hr = QUARTZ_CreateCLSIDPath(
153                 wszPath, sizeof(wszPath)/sizeof(wszPath[0]) - 16,
154                 rclsidDeviceClass, QUARTZ_wszInstance );
155         if ( FAILED(hr) )
156                 return hr;
157
158         lr = RegOpenKeyExW( HKEY_CLASSES_ROOT, wszPath,
159                 0, KEY_READ, &hKey );
160         if ( lr != ERROR_SUCCESS )
161         {
162                 TRACE("cannot open %s\n",debugstr_w(wszPath));
163                 if ( lr == ERROR_FILE_NOT_FOUND ||
164                          lr == ERROR_PATH_NOT_FOUND )
165                         return S_FALSE;
166                 return E_FAIL;
167         }
168
169         dwLen = lstrlenW(wszPath);
170         wszPath[dwLen++] = '\\'; wszPath[dwLen] = 0;
171         dwNameMax = sizeof(wszPath)/sizeof(wszPath[0]) - dwLen - 8;
172
173         pMonList = QUARTZ_CompList_Alloc();
174         if ( pMonList == NULL )
175         {
176                 hr = E_OUTOFMEMORY;
177                 goto err;
178         }
179
180         /* enumerate all subkeys. */
181         dwIndex = 0;
182         while ( 1 )
183         {
184                 cbName = dwNameMax;
185                 lr = RegEnumKeyExW(
186                         hKey, dwIndex, &wszPath[dwLen], &cbName,
187                         NULL, NULL, NULL, &ftLastWrite );
188                 if ( lr == ERROR_NO_MORE_ITEMS )
189                         break;
190                 if ( lr != ERROR_SUCCESS )
191                 {
192                         TRACE("RegEnumKeyEx returns %08lx\n",lr);
193                         hr = E_FAIL;
194                         goto err;
195                 }
196
197                 hr = QUARTZ_CreateDeviceMoniker(
198                         HKEY_CLASSES_ROOT, wszPath, &pMon );
199                 if ( FAILED(hr) )
200                         goto err;
201
202                 hr = QUARTZ_CompList_AddComp(
203                         pMonList, (IUnknown*)pMon, NULL, 0 );
204                 IMoniker_Release( pMon );
205
206                 if ( FAILED(hr) )
207                         goto err;
208
209                 dwIndex ++;
210         }
211
212         /* create an enumerator. */
213         hr = QUARTZ_CreateEnumUnknown(
214                 &IID_IEnumMoniker, (void**)ppobj, pMonList );
215         if ( FAILED(hr) )
216                 goto err;
217
218         hr = S_OK;
219 err:
220         if ( pMonList != NULL )
221                 QUARTZ_CompList_Free( pMonList );
222         RegCloseKey( hKey );
223
224         return hr;
225 }
226
227 static ICOM_VTABLE(ICreateDevEnum) icreatedevenum =
228 {
229         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
230         /* IUnknown fields */
231         ICreateDevEnum_fnQueryInterface,
232         ICreateDevEnum_fnAddRef,
233         ICreateDevEnum_fnRelease,
234         /* ICreateDevEnum fields */
235         ICreateDevEnum_fnCreateClassEnumerator,
236 };
237
238 HRESULT CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde )
239 {
240         TRACE("(%p)\n",psde);
241         ICOM_VTBL(&psde->createdevenum) = &icreatedevenum;
242
243         return NOERROR;
244 }
245
246 void CSysDevEnum_UninitICreateDevEnum( CSysDevEnum* psde )
247 {
248         TRACE("(%p)\n",psde);
249 }
250
251
252 /***************************************************************************
253  *
254  *      CDeviceMoniker::IMoniker
255  *
256  */
257
258 static HRESULT WINAPI
259 IMoniker_fnQueryInterface(IMoniker* iface,REFIID riid,void** ppobj)
260 {
261         CDeviceMoniker_THIS(iface,moniker);
262
263         TRACE("(%p)->()\n",This);
264
265         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
266 }
267
268 static ULONG WINAPI
269 IMoniker_fnAddRef(IMoniker* iface)
270 {
271         CDeviceMoniker_THIS(iface,moniker);
272
273         TRACE("(%p)->()\n",This);
274
275         return IUnknown_AddRef(This->unk.punkControl);
276 }
277
278 static ULONG WINAPI
279 IMoniker_fnRelease(IMoniker* iface)
280 {
281         CDeviceMoniker_THIS(iface,moniker);
282
283         TRACE("(%p)->()\n",This);
284
285         return IUnknown_Release(This->unk.punkControl);
286 }
287
288 static HRESULT WINAPI IMoniker_fnGetClassID(IMoniker* iface, CLSID *pClassID)
289 {
290         CDeviceMoniker_THIS(iface,moniker);
291
292         TRACE("(%p)->()\n",This);
293
294         if ( pClassID == NULL )
295                 return E_POINTER;
296         memcpy( pClassID, &CLSID_CDeviceMoniker, sizeof(CLSID) );
297
298         return NOERROR;
299 }
300
301 static HRESULT WINAPI IMoniker_fnIsDirty(IMoniker* iface)
302 {
303         CDeviceMoniker_THIS(iface,moniker);
304
305         FIXME("(%p)->() stub!\n",This);
306
307         return E_NOTIMPL;
308 }
309
310 static HRESULT WINAPI IMoniker_fnLoad(IMoniker* iface, IStream* pStm)
311 {
312         CDeviceMoniker_THIS(iface,moniker);
313
314         FIXME("(%p)->() stub!\n",This);
315
316         return E_NOTIMPL;
317 }
318
319 static HRESULT WINAPI IMoniker_fnSave(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
320 {
321         CDeviceMoniker_THIS(iface,moniker);
322
323         FIXME("(%p)->() stub!\n",This);
324
325         return E_NOTIMPL;
326 }
327
328 static HRESULT WINAPI IMoniker_fnGetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
329 {
330         CDeviceMoniker_THIS(iface,moniker);
331
332         FIXME("(%p)->() stub!\n",This);
333
334         return E_NOTIMPL;
335 }
336
337 static HRESULT WINAPI IMoniker_fnBindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
338 {
339         CDeviceMoniker_THIS(iface,moniker);
340         HRESULT hr;
341         IPropertyBag*   pPropBag;
342         IPersistPropertyBag*    pPersistPropBag;
343         VARIANT vClsid;
344         CLSID   clsid;
345
346         TRACE("(%p)->(%p,%p,%s,%p)\n",This,
347                 pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
348         if ( pbc != NULL )
349         {
350                 FIXME("IBindCtx* pbc != NULL not implemented.\n");
351                 return E_FAIL;
352         }
353         if ( pmkToLeft != NULL )
354         {
355                 FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
356                 return E_FAIL;
357         }
358         if ( ppvResult == NULL )
359                 return E_POINTER;
360
361         hr = QUARTZ_CreateRegPropertyBag(
362                         This->m_hkRoot, This->m_pwszPath, &pPropBag );
363         if ( FAILED(hr) )
364                 return hr;
365
366         vClsid.n1.n2.vt = VT_BSTR;
367         hr = IPropertyBag_Read(
368                         pPropBag, QUARTZ_wszCLSID, &vClsid, NULL );
369         IPropertyBag_Release( pPropBag );
370         if ( FAILED(hr) )
371                 return hr;
372
373         hr = CLSIDFromString( vClsid.n1.n2.n3.bstrVal, &clsid );
374         SysFreeString(vClsid.n1.n2.n3.bstrVal);
375         if ( FAILED(hr) )
376                 return hr;
377
378         hr = CoCreateInstance(
379                 &clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppvResult );
380         if ( FAILED(hr) )
381                 return hr;
382
383         hr = IUnknown_QueryInterface((IUnknown*)*ppvResult,&IID_IPersistPropertyBag,(void**)&pPersistPropBag);
384         if ( hr == E_NOINTERFACE )
385         {
386                 hr = S_OK;
387         }
388         else
389         if ( SUCCEEDED(hr) )
390         {
391                 hr = QUARTZ_CreateRegPropertyBag(
392                                 This->m_hkRoot, This->m_pwszPath, &pPropBag );
393                 if ( SUCCEEDED(hr) )
394                 {
395                         hr = IPersistPropertyBag_Load(pPersistPropBag,pPropBag,NULL);
396                         IPropertyBag_Release( pPropBag );
397                 }
398                 IPersistPropertyBag_Release(pPersistPropBag);
399         }
400
401         if ( FAILED(hr) )
402         {
403                 IUnknown_Release((IUnknown*)*ppvResult);
404                 *ppvResult = NULL;
405         }
406
407         TRACE( "hr = %08lx\n", hr );
408
409         return hr;
410 }
411
412 static HRESULT WINAPI IMoniker_fnBindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
413 {
414         CDeviceMoniker_THIS(iface,moniker);
415         HRESULT hr;
416
417         TRACE("(%p)->(%p,%p,%s,%p)\n",This,
418                 pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
419         if ( pbc != NULL )
420         {
421                 FIXME("IBindCtx* pbc != NULL not implemented.\n");
422                 return E_FAIL;
423         }
424         if ( pmkToLeft != NULL )
425         {
426                 FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
427                 return E_FAIL;
428         }
429         if ( ppvResult == NULL )
430                 return E_POINTER;
431
432         hr = E_NOINTERFACE;
433         if ( IsEqualGUID(riid,&IID_IUnknown) ||
434                  IsEqualGUID(riid,&IID_IPropertyBag) )
435         {
436                 hr = QUARTZ_CreateRegPropertyBag(
437                         This->m_hkRoot, This->m_pwszPath,
438                         (IPropertyBag**)ppvResult );
439         }
440
441         return hr;
442 }
443
444 static HRESULT WINAPI IMoniker_fnReduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
445 {
446         CDeviceMoniker_THIS(iface,moniker);
447
448         TRACE("(%p)->()\n",This);
449
450         if ( ppmkReduced == NULL )
451                 return E_POINTER;
452
453         *ppmkReduced = iface; IMoniker_AddRef(iface);
454
455         return MK_S_REDUCED_TO_SELF;
456 }
457
458 static HRESULT WINAPI IMoniker_fnComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
459 {
460         CDeviceMoniker_THIS(iface,moniker);
461
462         FIXME("(%p)->() stub!\n",This);
463
464         return E_NOTIMPL;
465 }
466
467 static HRESULT WINAPI IMoniker_fnEnum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
468 {
469         CDeviceMoniker_THIS(iface,moniker);
470
471         TRACE("(%p)->()\n",This);
472
473         if ( ppenumMoniker == NULL )
474                 return E_POINTER;
475
476         *ppenumMoniker = NULL;
477         return NOERROR;
478 }
479
480 static HRESULT WINAPI IMoniker_fnIsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
481 {
482         CDeviceMoniker_THIS(iface,moniker);
483
484         FIXME("(%p)->() stub!\n",This);
485
486         return E_NOTIMPL;
487 }
488
489 static HRESULT WINAPI IMoniker_fnHash(IMoniker* iface,DWORD* pdwHash)
490 {
491         CDeviceMoniker_THIS(iface,moniker);
492
493         FIXME("(%p)->() stub!\n",This);
494
495         return E_NOTIMPL;
496 }
497
498 static HRESULT WINAPI IMoniker_fnIsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
499 {
500         CDeviceMoniker_THIS(iface,moniker);
501
502         FIXME("(%p)->() stub!\n",This);
503
504         return E_NOTIMPL;
505 }
506
507 static HRESULT WINAPI IMoniker_fnGetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pCompositeTime)
508 {
509         CDeviceMoniker_THIS(iface,moniker);
510
511         FIXME("(%p)->() stub!\n",This);
512
513         return E_NOTIMPL;
514 }
515
516 static HRESULT WINAPI IMoniker_fnInverse(IMoniker* iface,IMoniker** ppmk)
517 {
518         CDeviceMoniker_THIS(iface,moniker);
519
520         FIXME("(%p)->() stub!\n",This);
521
522         return E_NOTIMPL;
523 }
524
525 static HRESULT WINAPI IMoniker_fnCommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix)
526 {
527         CDeviceMoniker_THIS(iface,moniker);
528
529         FIXME("(%p)->() stub!\n",This);
530
531         return E_NOTIMPL;
532 }
533
534 static HRESULT WINAPI IMoniker_fnRelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
535 {
536         CDeviceMoniker_THIS(iface,moniker);
537
538         FIXME("(%p)->() stub!\n",This);
539
540         return E_NOTIMPL;
541 }
542
543 static HRESULT WINAPI IMoniker_fnGetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
544 {
545         CDeviceMoniker_THIS(iface,moniker);
546
547         FIXME("(%p)->() stub!\n",This);
548
549         return E_NOTIMPL;
550 }
551
552 static HRESULT WINAPI IMoniker_fnParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
553 {
554         CDeviceMoniker_THIS(iface,moniker);
555
556         FIXME("(%p)->() stub!\n",This);
557
558         return E_NOTIMPL;
559 }
560
561 static HRESULT WINAPI IMoniker_fnIsSystemMoniker(IMoniker* iface,DWORD* pdwMksys)
562 {
563         CDeviceMoniker_THIS(iface,moniker);
564
565         TRACE("(%p)->()\n",This);
566         if ( pdwMksys == NULL )
567                 return E_POINTER;
568
569         *pdwMksys = MKSYS_NONE;
570         return S_FALSE;
571 }
572
573
574 static ICOM_VTABLE(IMoniker) imoniker =
575 {
576         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
577         /* IUnknown fields */
578         IMoniker_fnQueryInterface,
579         IMoniker_fnAddRef,
580         IMoniker_fnRelease,
581         /* IPersist fields */
582         IMoniker_fnGetClassID,
583         /* IPersistStream fields */
584         IMoniker_fnIsDirty,
585         IMoniker_fnLoad,
586         IMoniker_fnSave,
587         IMoniker_fnGetSizeMax,
588         /* IMoniker fields */
589         IMoniker_fnBindToObject,
590         IMoniker_fnBindToStorage,
591         IMoniker_fnReduce,
592         IMoniker_fnComposeWith,
593         IMoniker_fnEnum,
594         IMoniker_fnIsEqual,
595         IMoniker_fnHash,
596         IMoniker_fnIsRunning,
597         IMoniker_fnGetTimeOfLastChange,
598         IMoniker_fnInverse,
599         IMoniker_fnCommonPrefixWith,
600         IMoniker_fnRelativePathTo,
601         IMoniker_fnGetDisplayName,
602         IMoniker_fnParseDisplayName,
603         IMoniker_fnIsSystemMoniker,
604 };
605
606
607 static HRESULT CDeviceMoniker_InitIMoniker(
608         CDeviceMoniker* pdm, HKEY hkRoot, LPCWSTR lpKeyPath )
609 {
610         DWORD   dwLen;
611
612         ICOM_VTBL(&pdm->moniker) = &imoniker;
613         pdm->m_hkRoot = hkRoot;
614         pdm->m_pwszPath = NULL;
615
616         dwLen = sizeof(WCHAR)*(lstrlenW(lpKeyPath)+1);
617         pdm->m_pwszPath = (WCHAR*)QUARTZ_AllocMem( dwLen );
618         if ( pdm->m_pwszPath == NULL )
619                 return E_OUTOFMEMORY;
620         memcpy( pdm->m_pwszPath, lpKeyPath, dwLen );
621
622         return NOERROR;
623 }
624
625 static void CDeviceMoniker_UninitIMoniker(
626         CDeviceMoniker* pdm )
627 {
628         if ( pdm->m_pwszPath != NULL )
629                 QUARTZ_FreeMem( pdm->m_pwszPath );
630 }
631
632 /***************************************************************************
633  *
634  *      new/delete for CDeviceMoniker
635  *
636  */
637
638 static void QUARTZ_DestroyDeviceMoniker(IUnknown* punk)
639 {
640         CDeviceMoniker_THIS(punk,unk);
641
642         CDeviceMoniker_UninitIMoniker( This );
643 }
644
645 /* can I use offsetof safely? - FIXME? */
646 static QUARTZ_IFEntry CDeviceMoniker_IFEntries[] =
647 {
648   { &IID_IPersist, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
649   { &IID_IPersistStream, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
650   { &IID_IMoniker, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
651 };
652
653 HRESULT QUARTZ_CreateDeviceMoniker(
654         HKEY hkRoot, LPCWSTR lpKeyPath,
655         IMoniker** ppMoniker )
656 {
657         CDeviceMoniker* pdm;
658         HRESULT hr;
659
660         TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppMoniker );
661
662         pdm = (CDeviceMoniker*)QUARTZ_AllocObj( sizeof(CDeviceMoniker) );
663         if ( pdm == NULL )
664                 return E_OUTOFMEMORY;
665
666         QUARTZ_IUnkInit( &pdm->unk, NULL );
667         hr = CDeviceMoniker_InitIMoniker( pdm, hkRoot, lpKeyPath );
668         if ( FAILED(hr) )
669         {
670                 QUARTZ_FreeObj( pdm );
671                 return hr;
672         }
673
674         pdm->unk.pEntries = CDeviceMoniker_IFEntries;
675         pdm->unk.dwEntries = sizeof(CDeviceMoniker_IFEntries)/sizeof(CDeviceMoniker_IFEntries[0]);
676         pdm->unk.pOnFinalRelease = &QUARTZ_DestroyDeviceMoniker;
677
678         *ppMoniker = (IMoniker*)(&pdm->moniker);
679
680         return S_OK;
681 }
682
683
684 /***************************************************************************
685  *
686  *      CRegPropertyBag::IPropertyBag
687  *
688  */
689
690 static HRESULT WINAPI
691 IPropertyBag_fnQueryInterface(IPropertyBag* iface,REFIID riid,void** ppobj)
692 {
693         CRegPropertyBag_THIS(iface,propbag);
694
695         TRACE("(%p)->()\n",This);
696
697         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
698 }
699
700 static ULONG WINAPI
701 IPropertyBag_fnAddRef(IPropertyBag* iface)
702 {
703         CRegPropertyBag_THIS(iface,propbag);
704
705         TRACE("(%p)->()\n",This);
706
707         return IUnknown_AddRef(This->unk.punkControl);
708 }
709
710 static ULONG WINAPI
711 IPropertyBag_fnRelease(IPropertyBag* iface)
712 {
713         CRegPropertyBag_THIS(iface,propbag);
714
715         TRACE("(%p)->()\n",This);
716
717         return IUnknown_Release(This->unk.punkControl);
718 }
719
720 static HRESULT WINAPI
721 IPropertyBag_fnRead(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar,IErrorLog* pLog)
722 {
723         CRegPropertyBag_THIS(iface,propbag);
724         HRESULT hr;
725         LONG    lr;
726         DWORD   dwSize;
727         DWORD   dwValueType;
728         DWORD   dwDWordValue;
729         SAFEARRAYBOUND  sab;
730         SAFEARRAY*      pArray;
731
732         TRACE("(%p)->(%s,%p,%p)\n",This,
733                 debugstr_w(lpszPropName),pVar,pLog);
734
735         if ( lpszPropName == NULL || pVar == NULL )
736                 return E_POINTER;
737
738         dwSize = 0;
739         lr = RegQueryValueExW(
740                 This->m_hKey, lpszPropName, NULL,
741                 &dwValueType, NULL, &dwSize );
742         if ( lr != ERROR_SUCCESS )
743         {
744                 WARN( "RegQueryValueExW failed.\n" );
745                 return E_INVALIDARG;
746         }
747
748         switch ( dwValueType )
749         {
750         case REG_SZ:
751                 TRACE( "REG_SZ / length = %lu\n", dwSize );
752                 if ( pVar->n1.n2.vt == VT_EMPTY )
753                         pVar->n1.n2.vt = VT_BSTR;
754                 if ( pVar->n1.n2.vt != VT_BSTR )
755                 {
756                         FIXME( "type of VARIANT is not BSTR.\n" );
757                         return E_FAIL;
758                 }
759
760                 pVar->n1.n2.n3.bstrVal = SysAllocStringByteLen(
761                         NULL, dwSize );
762                 if ( pVar->n1.n2.n3.bstrVal == NULL )
763                 {
764                         WARN( "out of memory.\n" );
765                         return E_OUTOFMEMORY;
766                 }
767                 lr = RegQueryValueExW(
768                         This->m_hKey, lpszPropName, NULL,
769                         &dwValueType,
770                         (BYTE*)pVar->n1.n2.n3.bstrVal, &dwSize );
771                 if ( lr != ERROR_SUCCESS )
772                 {
773                         WARN( "failed to query value\n" );
774                         SysFreeString(pVar->n1.n2.n3.bstrVal);
775                         return E_FAIL;
776                 }
777                 TRACE( "value is BSTR; %s\n", debugstr_w(pVar->n1.n2.n3.bstrVal) );
778                 break;
779         case REG_BINARY:
780                 TRACE( "REG_BINARY / length = %lu\n", dwSize );
781                 if ( pVar->n1.n2.vt == VT_EMPTY )
782                         pVar->n1.n2.vt = VT_ARRAY|VT_UI1;
783                 if ( pVar->n1.n2.vt != (VT_ARRAY|VT_UI1) )
784                 {
785                         FIXME( "type of VARIANT is not VT_ARRAY|VT_UI1.\n" );
786                         return E_FAIL;
787                 }
788                 sab.lLbound = 0;
789                 sab.cElements = dwSize;
790                 pArray = SafeArrayCreate( VT_UI1, 1, &sab );
791                 if ( pArray == NULL )
792                         return E_OUTOFMEMORY;
793                 hr = SafeArrayLock( pArray );
794                 if ( FAILED(hr) )
795                 {
796                         WARN( "safe array can't be locked\n" );
797                         SafeArrayDestroy( pArray );
798                         return hr;
799                 }
800                 lr = RegQueryValueExW(
801                         This->m_hKey, lpszPropName, NULL,
802                         &dwValueType,
803                         (BYTE*)pArray->pvData, &dwSize );
804                 SafeArrayUnlock( pArray );
805                 if ( lr != ERROR_SUCCESS )
806                 {
807                         WARN( "failed to query value\n" );
808                         SafeArrayDestroy( pArray );
809                         return E_FAIL;
810                 }
811                 pVar->n1.n2.n3.parray = pArray;
812                 TRACE( "value is SAFEARRAY - array of BYTE; \n" );
813                 break;
814         case REG_DWORD:
815                 TRACE( "REG_DWORD / length = %lu\n", dwSize );
816                 if ( dwSize != sizeof(DWORD) )
817                 {
818                         WARN( "The length of REG_DWORD value is not sizeof(DWORD).\n" );
819                         return E_FAIL;
820                 }
821                 if ( pVar->n1.n2.vt == VT_EMPTY )
822                         pVar->n1.n2.vt = VT_I4;
823                 if ( pVar->n1.n2.vt != VT_I4 )
824                 {
825                         FIXME( "type of VARIANT is not VT_I4.\n" );
826                         return E_FAIL;
827                 }
828                 lr = RegQueryValueExW(
829                         This->m_hKey, lpszPropName, NULL,
830                         &dwValueType,
831                         (BYTE*)(&dwDWordValue), &dwSize );
832                 if ( lr != ERROR_SUCCESS )
833                 {
834                         WARN( "failed to query value\n" );
835                         return E_FAIL;
836                 }
837                 pVar->n1.n2.n3.lVal = dwDWordValue;
838                 TRACE( "value is DWORD; %08lx\n", dwDWordValue );
839                 break;
840         default:
841                 FIXME("(%p)->(%s,%p,%p) - unsupported value type.\n",This,
842                         debugstr_w(lpszPropName),pVar,pLog);
843                 return E_FAIL;
844         }
845
846         TRACE( "returned successfully.\n" );
847         return NOERROR;
848 }
849
850 static HRESULT WINAPI
851 IPropertyBag_fnWrite(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar)
852 {
853         CRegPropertyBag_THIS(iface,propbag);
854         HRESULT hr;
855         LONG    lr;
856         DWORD   dwDWordValue;
857         SAFEARRAY*      pArray;
858
859         TRACE("(%p)->(%s,%p)\n",This,
860                 debugstr_w(lpszPropName),pVar);
861
862         if ( lpszPropName == NULL || pVar == NULL )
863                 return E_POINTER;
864
865         switch ( pVar->n1.n2.vt )
866         {
867         case VT_I4: /* REG_DWORD */
868                 dwDWordValue = pVar->n1.n2.n3.lVal;
869                 lr = RegSetValueExW(
870                         This->m_hKey, lpszPropName, 0,
871                         REG_DWORD,
872                         (const BYTE*)(&dwDWordValue), sizeof(DWORD) );
873                 if ( lr != ERROR_SUCCESS )
874                 {
875                         WARN( "failed to set value\n" );
876                         return E_FAIL;
877                 }
878                 break;
879         case VT_BSTR: /* REG_SZ */
880                 lr = RegSetValueExW(
881                         This->m_hKey, lpszPropName, 0,
882                         REG_SZ,
883                         (const BYTE*)(pVar->n1.n2.n3.bstrVal),
884                         SysStringByteLen( pVar->n1.n2.n3.bstrVal ) );
885                 if ( lr != ERROR_SUCCESS )
886                 {
887                         WARN( "failed to set value\n" );
888                         return E_FAIL;
889                 }
890                 break;
891         case (VT_ARRAY|VT_UI1): /* REG_BINARY */
892                 pArray = pVar->n1.n2.n3.parray;
893                 if ( pArray->cDims != 1 || pArray->cbElements != 1 ||
894                          pArray->rgsabound[0].lLbound != 0 )
895                 {
896                         WARN( "invalid array\n" );
897                         return E_INVALIDARG;
898                 }
899                 hr = SafeArrayLock( pArray );
900                 if ( FAILED(hr) )
901                 {
902                         WARN( "safe array can't be locked\n" );
903                         return hr;
904                 }
905                 lr = RegSetValueExW(
906                         This->m_hKey, lpszPropName, 0,
907                         REG_BINARY,
908                         (const BYTE*)pArray->pvData,
909                         pArray->rgsabound[0].cElements );
910                 SafeArrayUnlock( pArray );
911                 if ( lr != ERROR_SUCCESS )
912                 {
913                         WARN( "failed to set value\n" );
914                         return E_FAIL;
915                 }
916                 break;
917         default:
918                 FIXME("(%p)->(%s,%p) invalid/unsupported VARIANT type %04x\n",This,
919                         debugstr_w(lpszPropName),pVar,pVar->n1.n2.vt);
920                 return E_INVALIDARG;
921         }
922
923         TRACE( "returned successfully.\n" );
924         return NOERROR;
925 }
926
927
928
929
930 static ICOM_VTABLE(IPropertyBag) ipropbag =
931 {
932         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
933         /* IUnknown fields */
934         IPropertyBag_fnQueryInterface,
935         IPropertyBag_fnAddRef,
936         IPropertyBag_fnRelease,
937         /* IPropertyBag fields */
938         IPropertyBag_fnRead,
939         IPropertyBag_fnWrite,
940 };
941
942 static HRESULT CRegPropertyBag_InitIPropertyBag(
943         CRegPropertyBag* prpb, HKEY hkRoot, LPCWSTR lpKeyPath )
944 {
945         WCHAR   wszREG_SZ[ NUMELEMS(QUARTZ_wszREG_SZ) ];
946         DWORD   dwDisp;
947
948         ICOM_VTBL(&prpb->propbag) = &ipropbag;
949
950         memcpy(wszREG_SZ,QUARTZ_wszREG_SZ,sizeof(QUARTZ_wszREG_SZ) );
951
952         if ( RegCreateKeyExW(
953                         hkRoot, lpKeyPath, 0, wszREG_SZ,
954                         REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
955                         &prpb->m_hKey, &dwDisp ) != ERROR_SUCCESS )
956                 return E_FAIL;
957
958         return NOERROR;
959 }
960
961 static void CRegPropertyBag_UninitIPropertyBag(
962         CRegPropertyBag* prpb )
963 {
964         RegCloseKey( prpb->m_hKey );
965 }
966
967
968 /***************************************************************************
969  *
970  *      new/delete for CRegPropertyBag
971  *
972  */
973
974 static void QUARTZ_DestroyRegPropertyBag(IUnknown* punk)
975 {
976         CRegPropertyBag_THIS(punk,unk);
977
978         CRegPropertyBag_UninitIPropertyBag(This);
979 }
980
981
982 /* can I use offsetof safely? - FIXME? */
983 static QUARTZ_IFEntry CRegPropertyBag_IFEntries[] =
984 {
985   { &IID_IPropertyBag, offsetof(CRegPropertyBag,propbag)-offsetof(CRegPropertyBag,unk) },
986 };
987
988 HRESULT QUARTZ_CreateRegPropertyBag(
989         HKEY hkRoot, LPCWSTR lpKeyPath,
990         IPropertyBag** ppPropBag )
991 {
992         CRegPropertyBag*        prpb;
993         HRESULT hr;
994
995         TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppPropBag );
996
997         prpb = (CRegPropertyBag*)QUARTZ_AllocObj( sizeof(CRegPropertyBag) );
998         if ( prpb == NULL )
999                 return E_OUTOFMEMORY;
1000
1001         QUARTZ_IUnkInit( &prpb->unk, NULL );
1002         hr = CRegPropertyBag_InitIPropertyBag( prpb, hkRoot, lpKeyPath );
1003         if ( FAILED(hr) )
1004         {
1005                 QUARTZ_FreeObj( prpb );
1006                 return hr;
1007         }
1008
1009         prpb->unk.pEntries = CRegPropertyBag_IFEntries;
1010         prpb->unk.dwEntries = sizeof(CRegPropertyBag_IFEntries)/sizeof(CRegPropertyBag_IFEntries[0]);
1011         prpb->unk.pOnFinalRelease = &QUARTZ_DestroyRegPropertyBag;
1012
1013         *ppPropBag = (IPropertyBag*)(&prpb->propbag);
1014
1015         return S_OK;
1016 }
1017
1018 /***************************************************************************
1019  *
1020  *      Helper for registering filters.
1021  *
1022  */
1023
1024 HRESULT QUARTZ_GetFilterRegPath(
1025         WCHAR** ppwszPath,      /* [OUT] path from HKEY_CLASSES_ROOT */
1026         const CLSID* pguidFilterCategory,       /* [IN] Category */
1027         const CLSID* pclsid,    /* [IN] CLSID of this filter */
1028         LPCWSTR lpInstance )    /* [IN] instance */
1029 {
1030         HRESULT hr;
1031         WCHAR   szKey[ 1024 ];
1032         WCHAR   szFilterPath[ 512 ];
1033         WCHAR   szCLSID[ 256 ];
1034         int     buflen;
1035
1036         TRACE("(%p,%s,%s,%s)\n",ppwszPath,debugstr_guid(pguidFilterCategory),debugstr_guid(pclsid),debugstr_w(lpInstance) );
1037
1038         *ppwszPath = NULL;
1039
1040         QUARTZ_GUIDtoString( szCLSID, pclsid );
1041         lstrcpyW( szFilterPath, QUARTZ_wszInstance );
1042         QUARTZ_CatPathSepW( szFilterPath );
1043         if ( lpInstance != NULL )
1044         {
1045                 if ( lstrlenW(lpInstance) >= 256 )
1046                         return E_INVALIDARG;
1047                 lstrcatW( szFilterPath, lpInstance );
1048         }
1049         else
1050         {
1051                 lstrcatW( szFilterPath, szCLSID );
1052         }
1053
1054         hr = QUARTZ_CreateCLSIDPath(
1055                 szKey, NUMELEMS(szKey),
1056                 pguidFilterCategory, szFilterPath );
1057         if ( FAILED(hr) )
1058                 return hr;
1059
1060         buflen = sizeof(WCHAR)*(lstrlenW(szKey)+1);
1061         *ppwszPath = QUARTZ_AllocMem( buflen );
1062         if ( *ppwszPath == NULL )
1063                 return E_OUTOFMEMORY;
1064         memcpy( *ppwszPath, szKey, buflen );
1065         return S_OK;
1066 }
1067
1068 HRESULT QUARTZ_RegisterFilterToMoniker(
1069         IMoniker* pMoniker,     /* [IN] Moniker */
1070         const CLSID* pclsid,    /* [IN] CLSID of this filter */
1071         LPCWSTR lpFriendlyName, /* [IN] friendly name */
1072         const BYTE* pbFilterData,       /* [IN] filter data */
1073         DWORD cbFilterData )    /* [IN] size of the filter data */
1074 {
1075         IPropertyBag*   pPropBag = NULL;
1076         WCHAR   wszClsid[128];
1077         VARIANT var;
1078         HRESULT hr;
1079         SAFEARRAYBOUND  sab;
1080         SAFEARRAY*      pArray = NULL;
1081
1082         TRACE("(%p,%s,%s,%p,%08lu)\n",pMoniker,debugstr_guid(pclsid),debugstr_w(lpFriendlyName),pbFilterData,cbFilterData);
1083
1084         hr = IMoniker_BindToStorage(pMoniker,NULL,NULL,&IID_IPropertyBag,(void**)&pPropBag);
1085         if ( FAILED(hr) )
1086                 goto err;
1087         QUARTZ_GUIDtoString( wszClsid, pclsid );
1088         var.n1.n2.vt = VT_BSTR;
1089         var.n1.n2.n3.bstrVal = SysAllocString(wszClsid);
1090         if ( var.n1.n2.n3.bstrVal == NULL )
1091         {
1092                 hr = E_OUTOFMEMORY;
1093                 goto err;
1094         }
1095         hr = IPropertyBag_Write(pPropBag,QUARTZ_wszCLSID,&var);
1096         SysFreeString(var.n1.n2.n3.bstrVal);
1097         if ( FAILED(hr) )
1098                 goto err;
1099
1100         var.n1.n2.vt = VT_BSTR;
1101         var.n1.n2.n3.bstrVal = SysAllocString(lpFriendlyName);
1102         if ( var.n1.n2.n3.bstrVal == NULL )
1103         {
1104                 hr = E_OUTOFMEMORY;
1105                 goto err;
1106         }
1107         hr = IPropertyBag_Write(pPropBag,QUARTZ_wszFriendlyName,&var);
1108         SysFreeString(var.n1.n2.n3.bstrVal);
1109         if ( FAILED(hr) )
1110                 goto err;
1111
1112         if ( pbFilterData != NULL )
1113         {
1114                 var.n1.n2.vt = VT_ARRAY|VT_UI1;
1115                 sab.lLbound = 0;
1116                 sab.cElements = cbFilterData;
1117                 pArray = SafeArrayCreate( VT_UI1, 1, &sab );
1118                 if ( pArray == NULL )
1119                 {
1120                         hr = E_OUTOFMEMORY;
1121                         goto err;
1122                 }
1123                 hr = SafeArrayLock( pArray );
1124                 if ( FAILED(hr) )
1125                         goto err;
1126                 var.n1.n2.n3.parray = pArray;
1127                 memcpy( pArray->pvData, pbFilterData, cbFilterData );
1128                 hr = IPropertyBag_Write(pPropBag,QUARTZ_wszFilterData,&var);
1129                 SafeArrayUnlock( pArray );
1130                 if ( FAILED(hr) )
1131                         goto err;
1132         }
1133
1134         hr = NOERROR;
1135 err:
1136         if ( pArray != NULL )
1137                 SafeArrayDestroy( pArray );
1138         if ( pPropBag != NULL )
1139                 IPropertyBag_Release(pPropBag);
1140
1141         return hr;
1142 }
1143
1144 HRESULT QUARTZ_RegDeleteKey( HKEY hkRoot, LPCWSTR lpKeyPath )
1145 {
1146         LONG    lr;
1147         HRESULT hr;
1148         HKEY    hKey;
1149         DWORD   dwIndex;
1150         DWORD   cbName;
1151         FILETIME        ftLastWrite;
1152         DWORD   dwType;
1153         WCHAR   wszPath[ 512 ];
1154
1155         TRACE("(%08x,%s)\n",hkRoot,debugstr_w(lpKeyPath));
1156
1157         lr = RegOpenKeyExW( hkRoot, lpKeyPath, 0, KEY_ALL_ACCESS, &hKey );
1158         if ( lr == ERROR_SUCCESS )
1159         {
1160                 dwIndex = 0;
1161                 while ( 1 )
1162                 {
1163                         cbName = NUMELEMS(wszPath);
1164                         lr = RegEnumKeyExW(
1165                                 hKey, dwIndex, wszPath, &cbName,
1166                                 NULL, NULL, NULL, &ftLastWrite );
1167                         if ( lr != ERROR_SUCCESS )
1168                                 break;
1169                         hr = QUARTZ_RegDeleteKey( hKey, wszPath );
1170                         if ( FAILED(hr) )
1171                                 return hr;
1172                         if ( hr != S_OK )
1173                                 dwIndex ++;
1174                 }
1175                 while ( 1 )
1176                 {
1177                         cbName = NUMELEMS(wszPath);
1178                         lr = RegEnumValueW(
1179                                 hKey, 0, wszPath, &cbName, 0,
1180                                 &dwType, NULL, 0 );
1181                         if ( lr != ERROR_SUCCESS )
1182                                 break;
1183                         lr = RegDeleteValueW( hKey, wszPath );
1184                         if ( lr != ERROR_SUCCESS )
1185                         {
1186                                 WARN("RegDeleteValueW - %08lx\n",lr);
1187                                 return E_FAIL;
1188                         }
1189                 }
1190         }
1191         RegCloseKey( hKey );
1192
1193         lr = RegDeleteKeyW( hkRoot, lpKeyPath );
1194         WARN("RegDeleteKeyW - %08lx\n",lr);
1195         if ( lr != ERROR_SUCCESS && lr != ERROR_FILE_NOT_FOUND )
1196                 return S_FALSE;
1197         return S_OK;
1198 }
1199
1200 static
1201 HRESULT QUARTZ_GetPropertyFromMoniker(
1202         IMoniker* pMoniker,     /* [IN] Moniker */
1203         LPCOLESTR lpszPropName, /* [IN] Property */
1204         VARIANT* pVar ) /* [OUT] */
1205 {
1206         IPropertyBag*   pPropBag = NULL;
1207         HRESULT hr;
1208
1209         TRACE("(%p,%s,%p)\n",pMoniker,debugstr_w(lpszPropName),pVar);
1210
1211         hr = IMoniker_BindToStorage(pMoniker,NULL,NULL,&IID_IPropertyBag,(void**)&pPropBag);
1212         if ( FAILED(hr) )
1213                 return hr;
1214         hr = IPropertyBag_Read(pPropBag,lpszPropName,pVar,NULL);
1215         IPropertyBag_Release(pPropBag);
1216
1217         return hr;
1218 }
1219
1220 HRESULT QUARTZ_GetCLSIDFromMoniker(
1221         IMoniker* pMoniker,     /* [IN] Moniker */
1222         CLSID* pclsid ) /* [OUT] */
1223 {
1224         VARIANT var;
1225         HRESULT hr;
1226
1227         var.n1.n2.vt = VT_BSTR;
1228         hr = QUARTZ_GetPropertyFromMoniker(
1229                 pMoniker, QUARTZ_wszCLSID, &var );
1230         if ( hr == S_OK )
1231         {
1232                 hr = CLSIDFromString(var.n1.n2.n3.bstrVal,pclsid);
1233                 SysFreeString(var.n1.n2.n3.bstrVal);
1234         }
1235
1236         return hr;
1237 }
1238
1239 HRESULT QUARTZ_GetMeritFromMoniker(
1240         IMoniker* pMoniker,     /* [IN] Moniker */
1241         DWORD* pdwMerit )       /* [OUT] */
1242 {
1243         VARIANT var;
1244         HRESULT hr;
1245
1246         var.n1.n2.vt = VT_I4;
1247         hr = QUARTZ_GetPropertyFromMoniker(
1248                 pMoniker, QUARTZ_wszMerit, &var );
1249         if ( hr == S_OK )
1250                 *pdwMerit = var.n1.n2.n3.lVal;
1251
1252         return hr;
1253 }
1254
1255 HRESULT QUARTZ_GetFilterDataFromMoniker(
1256         IMoniker* pMoniker,     /* [IN] Moniker */
1257         BYTE** ppbFilterData,   /* [OUT] */
1258         DWORD* pcbFilterData )  /* [OUT] */
1259 {
1260         VARIANT var;
1261         HRESULT hr;
1262         SAFEARRAY*      pArray;
1263
1264         var.n1.n2.vt = VT_ARRAY|VT_UI1;
1265         hr = QUARTZ_GetPropertyFromMoniker(
1266                 pMoniker, QUARTZ_wszFilterData, &var );
1267         if ( hr == S_OK )
1268         {
1269                 pArray = var.n1.n2.n3.parray;
1270                 hr = SafeArrayLock( pArray );
1271                 if ( SUCCEEDED(hr) )
1272                 {
1273                         *pcbFilterData = pArray->rgsabound[0].cElements - pArray->rgsabound[0].lLbound;
1274                         *ppbFilterData = (BYTE*)QUARTZ_AllocMem( *pcbFilterData );
1275                         if ( *ppbFilterData == NULL )
1276                                 hr = E_OUTOFMEMORY;
1277                         else
1278                                 memcpy( *ppbFilterData, pArray->pvData, *pcbFilterData );
1279
1280                         SafeArrayUnlock( pArray );
1281                 }
1282                 SafeArrayDestroy( pArray );
1283         }
1284
1285         return hr;
1286 }
1287