Fixed the behavior for SHGetFileInfo when the SHGFI_USEFILEATTRIBUTES
[wine] / dlls / quartz / devmon.c
1 /*
2  * Implements IMoniker for CLSID_CDeviceMoniker.
3  * Implements IPropertyBag. (internal)
4  *
5  * hidenori@a2.ctktv.ne.jp
6  */
7
8 #include "config.h"
9
10 #include "windef.h"
11 #include "winbase.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14 #include "winreg.h"
15 #include "winerror.h"
16 #include "objidl.h"
17 #include "oleidl.h"
18 #include "ocidl.h"
19 #include "oleauto.h"
20 #include "strmif.h"
21 #include "uuids.h"
22
23 #include "debugtools.h"
24 DEFAULT_DEBUG_CHANNEL(quartz);
25
26 #include "quartz_private.h"
27 #include "devmon.h"
28 #include "regsvr.h"
29
30
31 /***************************************************************************
32  *
33  *      CDeviceMoniker::IMoniker
34  *
35  */
36
37 static HRESULT WINAPI
38 IMoniker_fnQueryInterface(IMoniker* iface,REFIID riid,void** ppobj)
39 {
40         CDeviceMoniker_THIS(iface,moniker);
41
42         TRACE("(%p)->()\n",This);
43
44         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
45 }
46
47 static ULONG WINAPI
48 IMoniker_fnAddRef(IMoniker* iface)
49 {
50         CDeviceMoniker_THIS(iface,moniker);
51
52         TRACE("(%p)->()\n",This);
53
54         return IUnknown_AddRef(This->unk.punkControl);
55 }
56
57 static ULONG WINAPI
58 IMoniker_fnRelease(IMoniker* iface)
59 {
60         CDeviceMoniker_THIS(iface,moniker);
61
62         TRACE("(%p)->()\n",This);
63
64         return IUnknown_Release(This->unk.punkControl);
65 }
66
67 static HRESULT WINAPI IMoniker_fnGetClassID(IMoniker* iface, CLSID *pClassID)
68 {
69         CDeviceMoniker_THIS(iface,moniker);
70
71         TRACE("(%p)->()\n",This);
72
73         if ( pClassID == NULL )
74                 return E_POINTER;
75         memcpy( pClassID, &CLSID_CDeviceMoniker, sizeof(CLSID) );
76
77         return NOERROR;
78 }
79
80 static HRESULT WINAPI IMoniker_fnIsDirty(IMoniker* iface)
81 {
82         CDeviceMoniker_THIS(iface,moniker);
83
84         FIXME("(%p)->() stub!\n",This);
85
86         return E_NOTIMPL;
87 }
88
89 static HRESULT WINAPI IMoniker_fnLoad(IMoniker* iface, IStream* pStm)
90 {
91         CDeviceMoniker_THIS(iface,moniker);
92
93         FIXME("(%p)->() stub!\n",This);
94
95         return E_NOTIMPL;
96 }
97
98 static HRESULT WINAPI IMoniker_fnSave(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
99 {
100         CDeviceMoniker_THIS(iface,moniker);
101
102         FIXME("(%p)->() stub!\n",This);
103
104         return E_NOTIMPL;
105 }
106
107 static HRESULT WINAPI IMoniker_fnGetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
108 {
109         CDeviceMoniker_THIS(iface,moniker);
110
111         FIXME("(%p)->() stub!\n",This);
112
113         return E_NOTIMPL;
114 }
115
116 static HRESULT WINAPI IMoniker_fnBindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
117 {
118         CDeviceMoniker_THIS(iface,moniker);
119         HRESULT hr;
120         IPropertyBag*   pPropBag;
121         VARIANT vClsid;
122         CLSID   clsid;
123
124         TRACE("(%p)->(%p,%p,%s,%p)\n",This,
125                 pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
126         if ( pbc != NULL )
127         {
128                 FIXME("IBindCtx* pbc != NULL not implemented.\n");
129                 return E_FAIL;
130         }
131         if ( pmkToLeft != NULL )
132         {
133                 FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
134                 return E_FAIL;
135         }
136         if ( ppvResult == NULL )
137                 return E_POINTER;
138
139         hr = QUARTZ_CreateRegPropertyBag(
140                         This->m_hkRoot, This->m_pwszPath, &pPropBag );
141         if ( FAILED(hr) )
142                 return hr;
143
144         vClsid.n1.n2.vt = VT_BSTR;
145         hr = IPropertyBag_Read(
146                         pPropBag, QUARTZ_wszCLSID, &vClsid, NULL );
147         IPropertyBag_Release( pPropBag );
148         if ( FAILED(hr) )
149                 return hr;
150
151         hr = CLSIDFromString( vClsid.n1.n2.n3.bstrVal, &clsid );
152         SysFreeString(vClsid.n1.n2.n3.bstrVal);
153         if ( FAILED(hr) )
154                 return hr;
155
156         hr = CoCreateInstance(
157                 &clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppvResult );
158         TRACE( "hr = %08lx\n", hr );
159
160         return hr;
161 }
162
163 static HRESULT WINAPI IMoniker_fnBindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
164 {
165         CDeviceMoniker_THIS(iface,moniker);
166         HRESULT hr;
167
168         TRACE("(%p)->(%p,%p,%s,%p)\n",This,
169                 pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
170         if ( pbc != NULL )
171         {
172                 FIXME("IBindCtx* pbc != NULL not implemented.\n");
173                 return E_FAIL;
174         }
175         if ( pmkToLeft != NULL )
176         {
177                 FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
178                 return E_FAIL;
179         }
180         if ( ppvResult == NULL )
181                 return E_POINTER;
182
183         hr = E_NOINTERFACE;
184         if ( IsEqualGUID(riid,&IID_IUnknown) ||
185                  IsEqualGUID(riid,&IID_IPropertyBag) )
186         {
187                 hr = QUARTZ_CreateRegPropertyBag(
188                         This->m_hkRoot, This->m_pwszPath,
189                         (IPropertyBag**)ppvResult );
190         }
191
192         return hr;
193 }
194
195 static HRESULT WINAPI IMoniker_fnReduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
196 {
197         CDeviceMoniker_THIS(iface,moniker);
198
199         TRACE("(%p)->()\n",This);
200
201         if ( ppmkReduced == NULL )
202                 return E_POINTER;
203
204         *ppmkReduced = iface; IMoniker_AddRef(iface);
205
206         return MK_S_REDUCED_TO_SELF;
207 }
208
209 static HRESULT WINAPI IMoniker_fnComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
210 {
211         CDeviceMoniker_THIS(iface,moniker);
212
213         FIXME("(%p)->() stub!\n",This);
214
215         return E_NOTIMPL;
216 }
217
218 static HRESULT WINAPI IMoniker_fnEnum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
219 {
220         CDeviceMoniker_THIS(iface,moniker);
221
222         TRACE("(%p)->()\n",This);
223
224         if ( ppenumMoniker == NULL )
225                 return E_POINTER;
226
227         *ppenumMoniker = NULL;
228         return NOERROR;
229 }
230
231 static HRESULT WINAPI IMoniker_fnIsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
232 {
233         CDeviceMoniker_THIS(iface,moniker);
234
235         FIXME("(%p)->() stub!\n",This);
236
237         return E_NOTIMPL;
238 }
239
240 static HRESULT WINAPI IMoniker_fnHash(IMoniker* iface,DWORD* pdwHash)
241 {
242         CDeviceMoniker_THIS(iface,moniker);
243
244         FIXME("(%p)->() stub!\n",This);
245
246         return E_NOTIMPL;
247 }
248
249 static HRESULT WINAPI IMoniker_fnIsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
250 {
251         CDeviceMoniker_THIS(iface,moniker);
252
253         FIXME("(%p)->() stub!\n",This);
254
255         return E_NOTIMPL;
256 }
257
258 static HRESULT WINAPI IMoniker_fnGetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pCompositeTime)
259 {
260         CDeviceMoniker_THIS(iface,moniker);
261
262         FIXME("(%p)->() stub!\n",This);
263
264         return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI IMoniker_fnInverse(IMoniker* iface,IMoniker** ppmk)
268 {
269         CDeviceMoniker_THIS(iface,moniker);
270
271         FIXME("(%p)->() stub!\n",This);
272
273         return E_NOTIMPL;
274 }
275
276 static HRESULT WINAPI IMoniker_fnCommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix)
277 {
278         CDeviceMoniker_THIS(iface,moniker);
279
280         FIXME("(%p)->() stub!\n",This);
281
282         return E_NOTIMPL;
283 }
284
285 static HRESULT WINAPI IMoniker_fnRelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
286 {
287         CDeviceMoniker_THIS(iface,moniker);
288
289         FIXME("(%p)->() stub!\n",This);
290
291         return E_NOTIMPL;
292 }
293
294 static HRESULT WINAPI IMoniker_fnGetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
295 {
296         CDeviceMoniker_THIS(iface,moniker);
297
298         FIXME("(%p)->() stub!\n",This);
299
300         return E_NOTIMPL;
301 }
302
303 static HRESULT WINAPI IMoniker_fnParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
304 {
305         CDeviceMoniker_THIS(iface,moniker);
306
307         FIXME("(%p)->() stub!\n",This);
308
309         return E_NOTIMPL;
310 }
311
312 static HRESULT WINAPI IMoniker_fnIsSystemMoniker(IMoniker* iface,DWORD* pdwMksys)
313 {
314         CDeviceMoniker_THIS(iface,moniker);
315
316         TRACE("(%p)->()\n",This);
317         if ( pdwMksys == NULL )
318                 return E_POINTER;
319
320         *pdwMksys = MKSYS_NONE;
321         return S_FALSE;
322 }
323
324
325 static ICOM_VTABLE(IMoniker) imoniker =
326 {
327         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
328         /* IUnknown fields */
329         IMoniker_fnQueryInterface,
330         IMoniker_fnAddRef,
331         IMoniker_fnRelease,
332         /* IPersist fields */
333         IMoniker_fnGetClassID,
334         /* IPersistStream fields */
335         IMoniker_fnIsDirty,
336         IMoniker_fnLoad,
337         IMoniker_fnSave,
338         IMoniker_fnGetSizeMax,
339         /* IMoniker fields */
340         IMoniker_fnBindToObject,
341         IMoniker_fnBindToStorage,
342         IMoniker_fnReduce,
343         IMoniker_fnComposeWith,
344         IMoniker_fnEnum,
345         IMoniker_fnIsEqual,
346         IMoniker_fnHash,
347         IMoniker_fnIsRunning,
348         IMoniker_fnGetTimeOfLastChange,
349         IMoniker_fnInverse,
350         IMoniker_fnCommonPrefixWith,
351         IMoniker_fnRelativePathTo,
352         IMoniker_fnGetDisplayName,
353         IMoniker_fnParseDisplayName,
354         IMoniker_fnIsSystemMoniker,
355 };
356
357
358 static HRESULT CDeviceMoniker_InitIMoniker(
359         CDeviceMoniker* pdm, HKEY hkRoot, LPCWSTR lpKeyPath )
360 {
361         DWORD   dwLen;
362
363         ICOM_VTBL(&pdm->moniker) = &imoniker;
364         pdm->m_hkRoot = hkRoot;
365         pdm->m_pwszPath = NULL;
366
367         dwLen = sizeof(WCHAR)*(lstrlenW(lpKeyPath)+1);
368         pdm->m_pwszPath = (WCHAR*)QUARTZ_AllocMem( dwLen );
369         if ( pdm->m_pwszPath == NULL )
370                 return E_OUTOFMEMORY;
371         memcpy( pdm->m_pwszPath, lpKeyPath, dwLen );
372
373         return NOERROR;
374 }
375
376 static void CDeviceMoniker_UninitIMoniker(
377         CDeviceMoniker* pdm )
378 {
379         if ( pdm->m_pwszPath != NULL )
380                 QUARTZ_FreeMem( pdm->m_pwszPath );
381 }
382
383 /***************************************************************************
384  *
385  *      new/delete for CDeviceMoniker
386  *
387  */
388
389 static void QUARTZ_DestroyDeviceMoniker(IUnknown* punk)
390 {
391         CDeviceMoniker_THIS(punk,unk);
392
393         CDeviceMoniker_UninitIMoniker( This );
394 }
395
396 /* can I use offsetof safely? - FIXME? */
397 static QUARTZ_IFEntry CDeviceMoniker_IFEntries[] =
398 {
399   { &IID_IPersist, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
400   { &IID_IPersistStream, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
401   { &IID_IMoniker, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
402 };
403
404 HRESULT QUARTZ_CreateDeviceMoniker(
405         HKEY hkRoot, LPCWSTR lpKeyPath,
406         IMoniker** ppMoniker )
407 {
408         CDeviceMoniker* pdm;
409         HRESULT hr;
410
411         TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppMoniker );
412
413         pdm = (CDeviceMoniker*)QUARTZ_AllocObj( sizeof(CDeviceMoniker) );
414         if ( pdm == NULL )
415                 return E_OUTOFMEMORY;
416
417         QUARTZ_IUnkInit( &pdm->unk, NULL );
418         hr = CDeviceMoniker_InitIMoniker( pdm, hkRoot, lpKeyPath );
419         if ( FAILED(hr) )
420         {
421                 QUARTZ_FreeObj( pdm );
422                 return hr;
423         }
424
425         pdm->unk.pEntries = CDeviceMoniker_IFEntries;
426         pdm->unk.dwEntries = sizeof(CDeviceMoniker_IFEntries)/sizeof(CDeviceMoniker_IFEntries[0]);
427         pdm->unk.pOnFinalRelease = &QUARTZ_DestroyDeviceMoniker;
428
429         *ppMoniker = (IMoniker*)(&pdm->moniker);
430
431         return S_OK;
432 }
433
434
435 /***************************************************************************
436  *
437  *      CRegPropertyBag::IPropertyBag
438  *
439  */
440
441 static HRESULT WINAPI
442 IPropertyBag_fnQueryInterface(IPropertyBag* iface,REFIID riid,void** ppobj)
443 {
444         CRegPropertyBag_THIS(iface,propbag);
445
446         TRACE("(%p)->()\n",This);
447
448         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
449 }
450
451 static ULONG WINAPI
452 IPropertyBag_fnAddRef(IPropertyBag* iface)
453 {
454         CRegPropertyBag_THIS(iface,propbag);
455
456         TRACE("(%p)->()\n",This);
457
458         return IUnknown_AddRef(This->unk.punkControl);
459 }
460
461 static ULONG WINAPI
462 IPropertyBag_fnRelease(IPropertyBag* iface)
463 {
464         CRegPropertyBag_THIS(iface,propbag);
465
466         TRACE("(%p)->()\n",This);
467
468         return IUnknown_Release(This->unk.punkControl);
469 }
470
471 static HRESULT WINAPI
472 IPropertyBag_fnRead(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar,IErrorLog* pLog)
473 {
474         CRegPropertyBag_THIS(iface,propbag);
475         LONG    lr;
476         DWORD   dwSize;
477         DWORD   dwValueType;
478
479         TRACE("(%p)->(%s,%p,%p)\n",This,
480                 debugstr_w(lpszPropName),pVar,pLog);
481
482         if ( lpszPropName == NULL || pVar == NULL )
483                 return E_POINTER;
484
485         dwSize = 0;
486         lr = RegQueryValueExW(
487                 This->m_hKey, lpszPropName, NULL,
488                 &dwValueType, NULL, &dwSize );
489         if ( lr != ERROR_SUCCESS )
490         {
491                 TRACE( "RegQueryValueExW failed.\n" );
492                 return E_INVALIDARG;
493         }
494
495         switch ( dwValueType )
496         {
497         case REG_SZ:
498                 TRACE( "REG_SZ / length = %lu\n", dwSize );
499                 if ( pVar->n1.n2.vt == VT_EMPTY )
500                         pVar->n1.n2.vt = VT_BSTR;
501                 if ( pVar->n1.n2.vt != VT_BSTR )
502                 {
503                         TRACE( "type of VARIANT is not BSTR\n" );
504                         return E_FAIL;
505                 }
506
507                 pVar->n1.n2.n3.bstrVal = SysAllocStringByteLen(
508                         NULL, dwSize );
509                 if ( pVar->n1.n2.n3.bstrVal == NULL )
510                 {
511                         TRACE( "out of memory.\n" );
512                         return E_OUTOFMEMORY;
513                 }
514                 lr = RegQueryValueExW(
515                         This->m_hKey, lpszPropName, NULL,
516                         &dwValueType,
517                         (BYTE*)pVar->n1.n2.n3.bstrVal, &dwSize );
518                 if ( lr != ERROR_SUCCESS )
519                 {
520                         TRACE( "failed to query value\n" );
521                         SysFreeString(pVar->n1.n2.n3.bstrVal);
522                         return E_FAIL;
523                 }
524                 TRACE( "value is BSTR; %s\n", debugstr_w(pVar->n1.n2.n3.bstrVal) );
525                 break;
526         default:
527                 FIXME("(%p)->(%s,%p,%p) - unsupported value type.\n",This,
528                         debugstr_w(lpszPropName),pVar,pLog);
529                 return E_FAIL;
530         }
531
532         TRACE( "returned successfully.\n" );
533         return NOERROR;
534 }
535
536 static HRESULT WINAPI
537 IPropertyBag_fnWrite(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar)
538 {
539         CRegPropertyBag_THIS(iface,propbag);
540
541         FIXME("(%p)->(%s,%p) stub!\n",This,
542                 debugstr_w(lpszPropName),pVar);
543
544         if ( lpszPropName == NULL || pVar == NULL )
545                 return E_POINTER;
546
547         return E_NOTIMPL;
548 }
549
550
551
552
553 static ICOM_VTABLE(IPropertyBag) ipropbag =
554 {
555         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
556         /* IUnknown fields */
557         IPropertyBag_fnQueryInterface,
558         IPropertyBag_fnAddRef,
559         IPropertyBag_fnRelease,
560         /* IPropertyBag fields */
561         IPropertyBag_fnRead,
562         IPropertyBag_fnWrite,
563 };
564
565 static HRESULT CRegPropertyBag_InitIPropertyBag(
566         CRegPropertyBag* prpb, HKEY hkRoot, LPCWSTR lpKeyPath )
567 {
568         ICOM_VTBL(&prpb->propbag) = &ipropbag;
569
570         if ( RegOpenKeyExW(
571                 hkRoot, lpKeyPath, 0,
572                 KEY_ALL_ACCESS, &prpb->m_hKey ) != ERROR_SUCCESS )
573                 return E_FAIL;
574
575         return NOERROR;
576 }
577
578 static void CRegPropertyBag_UninitIPropertyBag(
579         CRegPropertyBag* prpb )
580 {
581         RegCloseKey( prpb->m_hKey );
582 }
583
584
585 /***************************************************************************
586  *
587  *      new/delete for CRegPropertyBag
588  *
589  */
590
591 static void QUARTZ_DestroyRegPropertyBag(IUnknown* punk)
592 {
593         CRegPropertyBag_THIS(punk,unk);
594
595         CRegPropertyBag_UninitIPropertyBag(This);
596 }
597
598
599 /* can I use offsetof safely? - FIXME? */
600 static QUARTZ_IFEntry CRegPropertyBag_IFEntries[] =
601 {
602   { &IID_IPropertyBag, offsetof(CRegPropertyBag,propbag)-offsetof(CRegPropertyBag,unk) },
603 };
604
605 HRESULT QUARTZ_CreateRegPropertyBag(
606         HKEY hkRoot, LPCWSTR lpKeyPath,
607         IPropertyBag** ppPropBag )
608 {
609         CRegPropertyBag*        prpb;
610         HRESULT hr;
611
612         TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppPropBag );
613
614         prpb = (CRegPropertyBag*)QUARTZ_AllocObj( sizeof(CRegPropertyBag) );
615         if ( prpb == NULL )
616                 return E_OUTOFMEMORY;
617
618         QUARTZ_IUnkInit( &prpb->unk, NULL );
619         hr = CRegPropertyBag_InitIPropertyBag( prpb, hkRoot, lpKeyPath );
620         if ( FAILED(hr) )
621         {
622                 QUARTZ_FreeObj( prpb );
623                 return hr;
624         }
625
626         prpb->unk.pEntries = CRegPropertyBag_IFEntries;
627         prpb->unk.dwEntries = sizeof(CRegPropertyBag_IFEntries)/sizeof(CRegPropertyBag_IFEntries[0]);
628         prpb->unk.pOnFinalRelease = &QUARTZ_DestroyRegPropertyBag;
629
630         *ppPropBag = (IPropertyBag*)(&prpb->propbag);
631
632         return S_OK;
633 }
634
635
636