1 /*
2  *	IEnumMoniker implementation for DEVENUM.dll
3  *
4  * Copyright (C) 2002 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * NOTES ON THIS FILE:
21  * - Implements IEnumMoniker interface which enumerates through moniker
22  *   objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance
23  */
24 
25 #include "devenum_private.h"
26 #include "oleauto.h"
27 #include "ocidl.h"
28 #include "dmoreg.h"
29 
30 #include "wine/debug.h"
31 
32 WINE_DEFAULT_DEBUG_CHANNEL(devenum);
33 
34 typedef struct
35 {
36     IEnumMoniker IEnumMoniker_iface;
37     CLSID class;
38     LONG ref;
39     IEnumDMO *dmo_enum;
40     HKEY sw_key;
41     DWORD sw_index;
42     HKEY cm_key;
43     DWORD cm_index;
44 } EnumMonikerImpl;
45 
46 typedef struct
47 {
48     IPropertyBag IPropertyBag_iface;
49     LONG ref;
50     enum device_type type;
51     union
52     {
53         WCHAR path[MAX_PATH];   /* for filters and codecs */
54         CLSID clsid;            /* for DMOs */
55     };
56 } RegPropBagImpl;
57 
58 
impl_from_IPropertyBag(IPropertyBag * iface)59 static inline RegPropBagImpl *impl_from_IPropertyBag(IPropertyBag *iface)
60 {
61     return CONTAINING_RECORD(iface, RegPropBagImpl, IPropertyBag_iface);
62 }
63 
DEVENUM_IPropertyBag_QueryInterface(LPPROPERTYBAG iface,REFIID riid,LPVOID * ppvObj)64 static HRESULT WINAPI DEVENUM_IPropertyBag_QueryInterface(
65     LPPROPERTYBAG iface,
66     REFIID riid,
67     LPVOID *ppvObj)
68 {
69     RegPropBagImpl *This = impl_from_IPropertyBag(iface);
70 
71     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObj);
72 
73     if (This == NULL || ppvObj == NULL) return E_POINTER;
74 
75     if (IsEqualGUID(riid, &IID_IUnknown) ||
76         IsEqualGUID(riid, &IID_IPropertyBag))
77     {
78         *ppvObj = iface;
79         IPropertyBag_AddRef(iface);
80         return S_OK;
81     }
82 
83     FIXME("- no interface IID: %s\n", debugstr_guid(riid));
84     return E_NOINTERFACE;
85 }
86 
87 /**********************************************************************
88  * DEVENUM_IPropertyBag_AddRef (also IUnknown)
89  */
DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface)90 static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface)
91 {
92     RegPropBagImpl *This = impl_from_IPropertyBag(iface);
93 
94     TRACE("(%p)->() AddRef from %d\n", iface, This->ref);
95 
96     return InterlockedIncrement(&This->ref);
97 }
98 
99 /**********************************************************************
100  * DEVENUM_IPropertyBag_Release (also IUnknown)
101  */
DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)102 static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)
103 {
104     RegPropBagImpl *This = impl_from_IPropertyBag(iface);
105     ULONG ref;
106 
107     TRACE("(%p)->() ReleaseThis->ref from %d\n", iface, This->ref);
108 
109     ref = InterlockedDecrement(&This->ref);
110     if (ref == 0) {
111         CoTaskMemFree(This);
112         DEVENUM_UnlockModule();
113     }
114     return ref;
115 }
116 
DEVENUM_IPropertyBag_Read(LPPROPERTYBAG iface,LPCOLESTR pszPropName,VARIANT * pVar,IErrorLog * pErrorLog)117 static HRESULT WINAPI DEVENUM_IPropertyBag_Read(
118     LPPROPERTYBAG iface,
119     LPCOLESTR pszPropName,
120     VARIANT* pVar,
121     IErrorLog* pErrorLog)
122 {
123     static const WCHAR FriendlyNameW[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
124     LPVOID pData = NULL;
125     DWORD received;
126     DWORD type = 0;
127     RegPropBagImpl *This = impl_from_IPropertyBag(iface);
128     HRESULT res = S_OK;
129     LONG reswin32 = ERROR_SUCCESS;
130     WCHAR name[80];
131     HKEY hkey;
132 
133     TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);
134 
135     if (!pszPropName || !pVar)
136         return E_POINTER;
137 
138     if (This->type == DEVICE_DMO)
139     {
140         if (!lstrcmpW(pszPropName, FriendlyNameW))
141         {
142             res = DMOGetName(&This->clsid, name);
143             if (SUCCEEDED(res))
144             {
145                 V_VT(pVar) = VT_BSTR;
146                 V_BSTR(pVar) = SysAllocString(name);
147             }
148             return res;
149         }
150         return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
151     }
152 
153     if (This->type == DEVICE_FILTER)
154         reswin32 = RegOpenKeyW(HKEY_CLASSES_ROOT, This->path, &hkey);
155     else if (This->type == DEVICE_CODEC)
156         reswin32 = RegOpenKeyW(HKEY_CURRENT_USER, This->path, &hkey);
157     res = HRESULT_FROM_WIN32(reswin32);
158 
159     if (SUCCEEDED(res))
160     {
161         reswin32 = RegQueryValueExW(hkey, pszPropName, NULL, NULL, NULL, &received);
162         res = HRESULT_FROM_WIN32(reswin32);
163     }
164 
165     if (SUCCEEDED(res))
166     {
167         pData = HeapAlloc(GetProcessHeap(), 0, received);
168 
169         /* work around a GCC bug that occurs here unless we use the reswin32 variable as well */
170         reswin32 = RegQueryValueExW(hkey, pszPropName, NULL, &type, pData, &received);
171         res = HRESULT_FROM_WIN32(reswin32);
172     }
173 
174     if (SUCCEEDED(res))
175     {
176         res = E_INVALIDARG; /* assume we cannot coerce into right type */
177 
178         TRACE("Read %d bytes (%s)\n", received, type == REG_SZ ? debugstr_w(pData) : "binary data");
179 
180         switch (type)
181         {
182         case REG_SZ:
183             switch (V_VT(pVar))
184             {
185             case VT_LPWSTR:
186                 V_BSTR(pVar) = CoTaskMemAlloc(received);
187                 memcpy(V_BSTR(pVar), pData, received);
188                 res = S_OK;
189                 break;
190             case VT_EMPTY:
191                 V_VT(pVar) = VT_BSTR;
192             /* fall through */
193             case VT_BSTR:
194                 V_BSTR(pVar) = SysAllocStringLen(pData, received/sizeof(WCHAR) - 1);
195                 res = S_OK;
196                 break;
197             }
198             break;
199         case REG_DWORD:
200             TRACE("REG_DWORD: %x\n", *(DWORD *)pData);
201             switch (V_VT(pVar))
202             {
203             case VT_EMPTY:
204                 V_VT(pVar) = VT_I4;
205                 /* fall through */
206             case VT_I4:
207             case VT_UI4:
208                 V_I4(pVar) = *(DWORD *)pData;
209                 res = S_OK;
210                 break;
211             }
212             break;
213         case REG_BINARY:
214             {
215                 SAFEARRAYBOUND bound;
216                 void * pArrayElements;
217                 bound.lLbound = 0;
218                 bound.cElements = received;
219                 TRACE("REG_BINARY: len = %d\n", received);
220                 switch (V_VT(pVar))
221                 {
222                 case VT_EMPTY:
223                     V_VT(pVar) = VT_ARRAY | VT_UI1;
224                     /* fall through */
225                 case VT_ARRAY | VT_UI1:
226                     if (!(V_ARRAY(pVar) = SafeArrayCreate(VT_UI1, 1, &bound)))
227                         res = E_OUTOFMEMORY;
228                     else
229                         res = S_OK;
230                     break;
231                 }
232 
233                 if (res == E_INVALIDARG)
234                     break;
235 
236                 res = SafeArrayAccessData(V_ARRAY(pVar), &pArrayElements);
237                 if (FAILED(res))
238                     break;
239 
240                 CopyMemory(pArrayElements, pData, received);
241                 res = SafeArrayUnaccessData(V_ARRAY(pVar));
242                 break;
243             }
244         }
245         if (res == E_INVALIDARG)
246             FIXME("Variant type %x not supported for regtype %x\n", V_VT(pVar), type);
247     }
248 
249     HeapFree(GetProcessHeap(), 0, pData);
250 
251     RegCloseKey(hkey);
252 
253     TRACE("<- %x\n", res);
254     return res;
255 }
256 
DEVENUM_IPropertyBag_Write(LPPROPERTYBAG iface,LPCOLESTR pszPropName,VARIANT * pVar)257 static HRESULT WINAPI DEVENUM_IPropertyBag_Write(
258     LPPROPERTYBAG iface,
259     LPCOLESTR pszPropName,
260     VARIANT* pVar)
261 {
262     RegPropBagImpl *This = impl_from_IPropertyBag(iface);
263     LPVOID lpData = NULL;
264     DWORD cbData = 0;
265     DWORD dwType = 0;
266     HRESULT res = S_OK;
267     LONG lres = ERROR_SUCCESS;
268     HKEY hkey;
269 
270     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);
271 
272     if (This->type == DEVICE_DMO)
273         return E_ACCESSDENIED;
274 
275     switch (V_VT(pVar))
276     {
277     case VT_BSTR:
278     case VT_LPWSTR:
279         TRACE("writing %s\n", debugstr_w(V_BSTR(pVar)));
280         lpData = V_BSTR(pVar);
281         dwType = REG_SZ;
282         cbData = (lstrlenW(V_BSTR(pVar)) + 1) * sizeof(WCHAR);
283         break;
284     case VT_I4:
285     case VT_UI4:
286         TRACE("writing %u\n", V_UI4(pVar));
287         lpData = &V_UI4(pVar);
288         dwType = REG_DWORD;
289         cbData = sizeof(DWORD);
290         break;
291     case VT_ARRAY | VT_UI1:
292     {
293         LONG lUbound = 0;
294         LONG lLbound = 0;
295         dwType = REG_BINARY;
296         res = SafeArrayGetLBound(V_ARRAY(pVar), 1, &lLbound);
297         res = SafeArrayGetUBound(V_ARRAY(pVar), 1, &lUbound);
298         cbData = (lUbound - lLbound + 1) /* * sizeof(BYTE)*/;
299         TRACE("cbData: %d\n", cbData);
300         res = SafeArrayAccessData(V_ARRAY(pVar), &lpData);
301         break;
302     }
303     default:
304         FIXME("Variant type %d not handled\n", V_VT(pVar));
305         return E_FAIL;
306     }
307 
308     if (This->type == DEVICE_FILTER)
309         lres = RegCreateKeyW(HKEY_CLASSES_ROOT, This->path, &hkey);
310     else if (This->type == DEVICE_CODEC)
311         lres = RegCreateKeyW(HKEY_CURRENT_USER, This->path, &hkey);
312     res = HRESULT_FROM_WIN32(lres);
313 
314     if (SUCCEEDED(res))
315     {
316         lres = RegSetValueExW(hkey, pszPropName, 0, dwType, lpData, cbData);
317         res = HRESULT_FROM_WIN32(lres);
318         RegCloseKey(hkey);
319     }
320 
321     if (V_VT(pVar) & VT_ARRAY)
322         res = SafeArrayUnaccessData(V_ARRAY(pVar));
323 
324     return res;
325 }
326 
327 static const IPropertyBagVtbl IPropertyBag_Vtbl =
328 {
329     DEVENUM_IPropertyBag_QueryInterface,
330     DEVENUM_IPropertyBag_AddRef,
331     DEVENUM_IPropertyBag_Release,
332     DEVENUM_IPropertyBag_Read,
333     DEVENUM_IPropertyBag_Write
334 };
335 
create_PropertyBag(MediaCatMoniker * mon,IPropertyBag ** ppBag)336 static HRESULT create_PropertyBag(MediaCatMoniker *mon, IPropertyBag **ppBag)
337 {
338     RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl));
339     if (!rpb)
340         return E_OUTOFMEMORY;
341     rpb->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
342     rpb->ref = 1;
343     rpb->type = mon->type;
344 
345     if (rpb->type == DEVICE_DMO)
346         rpb->clsid = mon->clsid;
347     else if (rpb->type == DEVICE_FILTER)
348     {
349         lstrcpyW(rpb->path, clsidW);
350         lstrcatW(rpb->path, backslashW);
351         if (mon->has_class)
352         {
353             StringFromGUID2(&mon->class, rpb->path + lstrlenW(rpb->path), CHARS_IN_GUID);
354             lstrcatW(rpb->path, instanceW);
355             lstrcatW(rpb->path, backslashW);
356         }
357         lstrcatW(rpb->path, mon->name);
358     }
359     else if (rpb->type == DEVICE_CODEC)
360     {
361         lstrcpyW(rpb->path, wszActiveMovieKey);
362         if (mon->has_class)
363         {
364             StringFromGUID2(&mon->class, rpb->path + lstrlenW(rpb->path), CHARS_IN_GUID);
365             lstrcatW(rpb->path, backslashW);
366         }
367         lstrcatW(rpb->path, mon->name);
368     }
369 
370     *ppBag = &rpb->IPropertyBag_iface;
371     DEVENUM_LockModule();
372     return S_OK;
373 }
374 
375 
impl_from_IMoniker(IMoniker * iface)376 static inline MediaCatMoniker *impl_from_IMoniker(IMoniker *iface)
377 {
378     return CONTAINING_RECORD(iface, MediaCatMoniker, IMoniker_iface);
379 }
380 
DEVENUM_IMediaCatMoniker_QueryInterface(IMoniker * iface,REFIID riid,void ** ppv)381 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_QueryInterface(IMoniker *iface, REFIID riid,
382         void **ppv)
383 {
384     TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
385 
386     if (!ppv)
387         return E_POINTER;
388 
389     if (IsEqualGUID(riid, &IID_IUnknown) ||
390         IsEqualGUID(riid, &IID_IPersist) ||
391         IsEqualGUID(riid, &IID_IPersistStream) ||
392         IsEqualGUID(riid, &IID_IMoniker))
393     {
394         *ppv = iface;
395         IMoniker_AddRef(iface);
396         return S_OK;
397     }
398 
399     FIXME("- no interface IID: %s\n", debugstr_guid(riid));
400     *ppv = NULL;
401     return E_NOINTERFACE;
402 }
403 
DEVENUM_IMediaCatMoniker_AddRef(IMoniker * iface)404 static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(IMoniker *iface)
405 {
406     MediaCatMoniker *This = impl_from_IMoniker(iface);
407     ULONG ref = InterlockedIncrement(&This->ref);
408 
409     TRACE("(%p) ref=%d\n", This, ref);
410 
411     return ref;
412 }
413 
DEVENUM_IMediaCatMoniker_Release(IMoniker * iface)414 static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(IMoniker *iface)
415 {
416     MediaCatMoniker *This = impl_from_IMoniker(iface);
417     ULONG ref = InterlockedDecrement(&This->ref);
418 
419     TRACE("(%p) ref=%d\n", This, ref);
420 
421     if (ref == 0) {
422         CoTaskMemFree(This->name);
423         CoTaskMemFree(This);
424         DEVENUM_UnlockModule();
425     }
426     return ref;
427 }
428 
DEVENUM_IMediaCatMoniker_GetClassID(IMoniker * iface,CLSID * pClassID)429 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
430 {
431     MediaCatMoniker *This = impl_from_IMoniker(iface);
432 
433     TRACE("(%p)->(%p)\n", This, pClassID);
434 
435     if (pClassID == NULL)
436         return E_INVALIDARG;
437 
438     *pClassID = CLSID_CDeviceMoniker;
439 
440     return S_OK;
441 }
442 
DEVENUM_IMediaCatMoniker_IsDirty(IMoniker * iface)443 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(IMoniker *iface)
444 {
445     FIXME("(%p)->(): stub\n", iface);
446 
447     return S_FALSE;
448 }
449 
DEVENUM_IMediaCatMoniker_Load(IMoniker * iface,IStream * pStm)450 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(IMoniker *iface, IStream *pStm)
451 {
452     FIXME("(%p)->(%p): stub\n", iface, pStm);
453 
454     return E_NOTIMPL;
455 }
456 
DEVENUM_IMediaCatMoniker_Save(IMoniker * iface,IStream * pStm,BOOL fClearDirty)457 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
458 {
459     FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false");
460 
461     return STG_E_CANTSAVE;
462 }
463 
DEVENUM_IMediaCatMoniker_GetSizeMax(IMoniker * iface,ULARGE_INTEGER * pcbSize)464 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
465 {
466     FIXME("(%p)->(%p): stub\n", iface, pcbSize);
467 
468     ZeroMemory(pcbSize, sizeof(*pcbSize));
469 
470     return S_OK;
471 }
472 
DEVENUM_IMediaCatMoniker_BindToObject(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riidResult,void ** ppvResult)473 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(IMoniker *iface, IBindCtx *pbc,
474         IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult)
475 {
476     MediaCatMoniker *This = impl_from_IMoniker(iface);
477     IUnknown * pObj = NULL;
478     IPropertyBag * pProp = NULL;
479     CLSID clsID;
480     VARIANT var;
481     HRESULT res = E_FAIL;
482 
483     TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult);
484 
485     if (!ppvResult)
486         return E_POINTER;
487 
488     VariantInit(&var);
489     *ppvResult = NULL;
490 
491     if(pmkToLeft==NULL)
492     {
493             /* first activation of this class */
494 	    LPVOID pvptr;
495             res=IMoniker_BindToStorage(iface, NULL, NULL, &IID_IPropertyBag, &pvptr);
496             pProp = pvptr;
497             if (SUCCEEDED(res))
498             {
499                 V_VT(&var) = VT_LPWSTR;
500                 res = IPropertyBag_Read(pProp, clsidW, &var, NULL);
501             }
502             if (SUCCEEDED(res))
503             {
504                 res = CLSIDFromString(V_BSTR(&var), &clsID);
505                 CoTaskMemFree(V_BSTR(&var));
506             }
507             if (SUCCEEDED(res))
508             {
509                 res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,&pvptr);
510                 pObj = pvptr;
511             }
512     }
513 
514     if (pObj!=NULL)
515     {
516         /* get the requested interface from the loaded class */
517         res = S_OK;
518         if (pProp) {
519            HRESULT res2;
520            LPVOID ppv = NULL;
521            res2 = IUnknown_QueryInterface(pObj, &IID_IPersistPropertyBag, &ppv);
522            if (SUCCEEDED(res2)) {
523               res = IPersistPropertyBag_Load((IPersistPropertyBag *) ppv, pProp, NULL);
524               IPersistPropertyBag_Release((IPersistPropertyBag *) ppv);
525            }
526         }
527         if (SUCCEEDED(res))
528            res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
529         IUnknown_Release(pObj);
530     }
531 
532     if (pProp)
533     {
534         IPropertyBag_Release(pProp);
535     }
536 
537     TRACE("<- 0x%x\n", res);
538 
539     return res;
540 }
541 
DEVENUM_IMediaCatMoniker_BindToStorage(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riid,void ** ppvObj)542 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(IMoniker *iface, IBindCtx *pbc,
543         IMoniker *pmkToLeft, REFIID riid, void **ppvObj)
544 {
545     MediaCatMoniker *This = impl_from_IMoniker(iface);
546 
547     TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObj);
548 
549     *ppvObj = NULL;
550 
551     if (pmkToLeft)
552         return MK_E_NOSTORAGE;
553 
554     if (pbc != NULL)
555     {
556         static DWORD reported;
557         if (!reported)
558         {
559             FIXME("ignoring IBindCtx %p\n", pbc);
560             reported++;
561         }
562     }
563 
564     if (IsEqualGUID(riid, &IID_IPropertyBag))
565     {
566         return create_PropertyBag(This, (IPropertyBag**)ppvObj);
567     }
568 
569     return MK_E_NOSTORAGE;
570 }
571 
DEVENUM_IMediaCatMoniker_Reduce(IMoniker * iface,IBindCtx * pbc,DWORD dwReduceHowFar,IMoniker ** ppmkToLeft,IMoniker ** ppmkReduced)572 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
573         DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
574 {
575     TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
576 
577     if (ppmkToLeft)
578         *ppmkToLeft = NULL;
579     *ppmkReduced = iface;
580 
581     return MK_S_REDUCED_TO_SELF;
582 }
583 
DEVENUM_IMediaCatMoniker_ComposeWith(IMoniker * iface,IMoniker * pmkRight,BOOL fOnlyIfNotGeneric,IMoniker ** ppmkComposite)584 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
585         BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
586 {
587     FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
588 
589     /* FIXME: use CreateGenericComposite? */
590     *ppmkComposite = NULL;
591 
592     return E_NOTIMPL;
593 }
594 
DEVENUM_IMediaCatMoniker_Enum(IMoniker * iface,BOOL fForward,IEnumMoniker ** ppenumMoniker)595 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(IMoniker *iface, BOOL fForward,
596         IEnumMoniker **ppenumMoniker)
597 {
598     FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker);
599 
600     *ppenumMoniker = NULL;
601 
602     return S_OK;
603 }
604 
DEVENUM_IMediaCatMoniker_IsEqual(IMoniker * iface,IMoniker * pmkOtherMoniker)605 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
606 {
607     CLSID clsid;
608     LPOLESTR this_name, other_name;
609     IBindCtx *bind;
610     HRESULT res;
611 
612     TRACE("(%p)->(%p)\n", iface, pmkOtherMoniker);
613 
614     if (!pmkOtherMoniker)
615         return E_INVALIDARG;
616 
617     IMoniker_GetClassID(pmkOtherMoniker, &clsid);
618     if (!IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker))
619         return S_FALSE;
620 
621     res = CreateBindCtx(0, &bind);
622     if (FAILED(res))
623        return res;
624 
625     res = S_FALSE;
626     if (SUCCEEDED(IMoniker_GetDisplayName(iface, bind, NULL, &this_name)) &&
627         SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker, bind, NULL, &other_name)))
628     {
629         int result = lstrcmpiW(this_name, other_name);
630         CoTaskMemFree(this_name);
631         CoTaskMemFree(other_name);
632         if (!result)
633             res = S_OK;
634     }
635     IBindCtx_Release(bind);
636     return res;
637 }
638 
DEVENUM_IMediaCatMoniker_Hash(IMoniker * iface,DWORD * pdwHash)639 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
640 {
641     TRACE("(%p)->(%p)\n", iface, pdwHash);
642 
643     *pdwHash = 0;
644 
645     return S_OK;
646 }
647 
DEVENUM_IMediaCatMoniker_IsRunning(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,IMoniker * pmkNewlyRunning)648 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(IMoniker *iface, IBindCtx *pbc,
649         IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
650 {
651     FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning);
652 
653     return S_FALSE;
654 }
655 
DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,FILETIME * pFileTime)656 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
657         IMoniker *pmkToLeft, FILETIME *pFileTime)
658 {
659     TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime);
660 
661     pFileTime->dwLowDateTime = 0xFFFFFFFF;
662     pFileTime->dwHighDateTime = 0x7FFFFFFF;
663 
664     return MK_E_UNAVAILABLE;
665 }
666 
DEVENUM_IMediaCatMoniker_Inverse(IMoniker * iface,IMoniker ** ppmk)667 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
668 {
669     TRACE("(%p)->(%p)\n", iface, ppmk);
670 
671     *ppmk = NULL;
672 
673     return MK_E_NOINVERSE;
674 }
675 
DEVENUM_IMediaCatMoniker_CommonPrefixWith(IMoniker * iface,IMoniker * pmkOtherMoniker,IMoniker ** ppmkPrefix)676 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(IMoniker *iface,
677         IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix)
678 {
679     TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix);
680 
681     *ppmkPrefix = NULL;
682 
683     return MK_E_NOPREFIX;
684 }
685 
DEVENUM_IMediaCatMoniker_RelativePathTo(IMoniker * iface,IMoniker * pmkOther,IMoniker ** ppmkRelPath)686 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
687         IMoniker **ppmkRelPath)
688 {
689     TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath);
690 
691     *ppmkRelPath = pmkOther;
692 
693     return MK_S_HIM;
694 }
695 
DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR * ppszDisplayName)696 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
697         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
698 {
699     MediaCatMoniker *This = impl_from_IMoniker(iface);
700     WCHAR *buffer;
701 
702     TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
703 
704     *ppszDisplayName = NULL;
705 
706     if (This->type == DEVICE_DMO)
707     {
708         buffer = CoTaskMemAlloc((lstrlenW(deviceW) + lstrlenW(dmoW)
709                                  + 2 * CHARS_IN_GUID + 1) * sizeof(WCHAR));
710         if (!buffer) return E_OUTOFMEMORY;
711 
712         lstrcpyW(buffer, deviceW);
713         lstrcatW(buffer, dmoW);
714         StringFromGUID2(&This->clsid, buffer + lstrlenW(buffer), CHARS_IN_GUID);
715         StringFromGUID2(&This->class, buffer + lstrlenW(buffer), CHARS_IN_GUID);
716     }
717     else
718     {
719         buffer = CoTaskMemAlloc((lstrlenW(deviceW) + 3 + (This->has_class ? CHARS_IN_GUID : 0)
720                                  + lstrlenW(This->name) + 1) * sizeof(WCHAR));
721         if (!buffer) return E_OUTOFMEMORY;
722 
723         lstrcpyW(buffer, deviceW);
724         if (This->type == DEVICE_FILTER)
725             lstrcatW(buffer, swW);
726         else if (This->type == DEVICE_CODEC)
727             lstrcatW(buffer, cmW);
728 
729         if (This->has_class)
730         {
731             StringFromGUID2(&This->class, buffer + lstrlenW(buffer), CHARS_IN_GUID);
732             lstrcatW(buffer, backslashW);
733         }
734         lstrcatW(buffer, This->name);
735     }
736 
737     *ppszDisplayName = buffer;
738     return S_OK;
739 }
740 
DEVENUM_IMediaCatMoniker_ParseDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR pszDisplayName,ULONG * pchEaten,IMoniker ** ppmkOut)741 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
742         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
743 {
744     FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
745 
746     *pchEaten = 0;
747     *ppmkOut = NULL;
748 
749     return MK_E_SYNTAX;
750 }
751 
DEVENUM_IMediaCatMoniker_IsSystemMoniker(IMoniker * iface,DWORD * pdwMksys)752 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
753 {
754     TRACE("(%p)->(%p)\n", iface, pdwMksys);
755 
756     return S_FALSE;
757 }
758 
759 static const IMonikerVtbl IMoniker_Vtbl =
760 {
761     DEVENUM_IMediaCatMoniker_QueryInterface,
762     DEVENUM_IMediaCatMoniker_AddRef,
763     DEVENUM_IMediaCatMoniker_Release,
764     DEVENUM_IMediaCatMoniker_GetClassID,
765     DEVENUM_IMediaCatMoniker_IsDirty,
766     DEVENUM_IMediaCatMoniker_Load,
767     DEVENUM_IMediaCatMoniker_Save,
768     DEVENUM_IMediaCatMoniker_GetSizeMax,
769     DEVENUM_IMediaCatMoniker_BindToObject,
770     DEVENUM_IMediaCatMoniker_BindToStorage,
771     DEVENUM_IMediaCatMoniker_Reduce,
772     DEVENUM_IMediaCatMoniker_ComposeWith,
773     DEVENUM_IMediaCatMoniker_Enum,
774     DEVENUM_IMediaCatMoniker_IsEqual,
775     DEVENUM_IMediaCatMoniker_Hash,
776     DEVENUM_IMediaCatMoniker_IsRunning,
777     DEVENUM_IMediaCatMoniker_GetTimeOfLastChange,
778     DEVENUM_IMediaCatMoniker_Inverse,
779     DEVENUM_IMediaCatMoniker_CommonPrefixWith,
780     DEVENUM_IMediaCatMoniker_RelativePathTo,
781     DEVENUM_IMediaCatMoniker_GetDisplayName,
782     DEVENUM_IMediaCatMoniker_ParseDisplayName,
783     DEVENUM_IMediaCatMoniker_IsSystemMoniker
784 };
785 
DEVENUM_IMediaCatMoniker_Construct(void)786 MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void)
787 {
788     MediaCatMoniker * pMoniker = NULL;
789     pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker));
790     if (!pMoniker)
791         return NULL;
792 
793     pMoniker->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
794     pMoniker->ref = 0;
795     pMoniker->has_class = FALSE;
796     pMoniker->name = NULL;
797 
798     DEVENUM_IMediaCatMoniker_AddRef(&pMoniker->IMoniker_iface);
799 
800     DEVENUM_LockModule();
801 
802     return pMoniker;
803 }
804 
impl_from_IEnumMoniker(IEnumMoniker * iface)805 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
806 {
807     return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
808 }
809 
DEVENUM_IEnumMoniker_QueryInterface(IEnumMoniker * iface,REFIID riid,void ** ppv)810 static HRESULT WINAPI DEVENUM_IEnumMoniker_QueryInterface(IEnumMoniker *iface, REFIID riid,
811         void **ppv)
812 {
813     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
814 
815     if (!ppv)
816         return E_POINTER;
817 
818     if (IsEqualGUID(riid, &IID_IUnknown) ||
819         IsEqualGUID(riid, &IID_IEnumMoniker))
820     {
821         *ppv = iface;
822         IEnumMoniker_AddRef(iface);
823         return S_OK;
824     }
825 
826     FIXME("- no interface IID: %s\n", debugstr_guid(riid));
827     *ppv = NULL;
828     return E_NOINTERFACE;
829 }
830 
DEVENUM_IEnumMoniker_AddRef(IEnumMoniker * iface)831 static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(IEnumMoniker *iface)
832 {
833     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
834     ULONG ref = InterlockedIncrement(&This->ref);
835 
836     TRACE("(%p) ref=%d\n", This, ref);
837 
838     return ref;
839 }
840 
DEVENUM_IEnumMoniker_Release(IEnumMoniker * iface)841 static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface)
842 {
843     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
844     ULONG ref = InterlockedDecrement(&This->ref);
845 
846     TRACE("(%p) ref=%d\n", This, ref);
847 
848     if (!ref)
849     {
850         IEnumDMO_Release(This->dmo_enum);
851         RegCloseKey(This->sw_key);
852         RegCloseKey(This->cm_key);
853         CoTaskMemFree(This);
854         DEVENUM_UnlockModule();
855         return 0;
856     }
857     return ref;
858 }
859 
DEVENUM_IEnumMoniker_Next(IEnumMoniker * iface,ULONG celt,IMoniker ** rgelt,ULONG * pceltFetched)860 static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt,
861         ULONG *pceltFetched)
862 {
863     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
864     WCHAR buffer[MAX_PATH + 1];
865     LONG res;
866     ULONG fetched = 0;
867     MediaCatMoniker * pMoniker;
868     CLSID clsid;
869     HRESULT hr;
870     HKEY hkey;
871 
872     TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
873 
874     while (fetched < celt)
875     {
876         /* FIXME: try PNP devices first */
877 
878         /* try DMOs */
879         if ((hr = IEnumDMO_Next(This->dmo_enum, 1, &clsid, NULL, NULL)) == S_OK)
880         {
881             if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct()))
882                 return E_OUTOFMEMORY;
883 
884             pMoniker->type = DEVICE_DMO;
885             pMoniker->clsid = clsid;
886 
887             StringFromGUID2(&clsid, buffer, CHARS_IN_GUID);
888             StringFromGUID2(&This->class, buffer + CHARS_IN_GUID - 1, CHARS_IN_GUID);
889         }
890         /* try DirectShow filters */
891         else if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, ARRAY_SIZE(buffer))))
892         {
893             This->sw_index++;
894             if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
895                 break;
896 
897             if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct()))
898                 return E_OUTOFMEMORY;
899 
900             pMoniker->type = DEVICE_FILTER;
901 
902             if (!(pMoniker->name = CoTaskMemAlloc((lstrlenW(buffer) + 1) * sizeof(WCHAR))))
903             {
904                 IMoniker_Release(&pMoniker->IMoniker_iface);
905                 return E_OUTOFMEMORY;
906             }
907             lstrcpyW(pMoniker->name, buffer);
908         }
909         /* then try codecs */
910         else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, ARRAY_SIZE(buffer))))
911         {
912             This->cm_index++;
913 
914             if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
915                 break;
916 
917             if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct()))
918                 return E_OUTOFMEMORY;
919 
920             pMoniker->type = DEVICE_CODEC;
921 
922             if (!(pMoniker->name = CoTaskMemAlloc((lstrlenW(buffer) + 1) * sizeof(WCHAR))))
923             {
924                 IMoniker_Release(&pMoniker->IMoniker_iface);
925                 return E_OUTOFMEMORY;
926             }
927             lstrcpyW(pMoniker->name, buffer);
928         }
929         else
930             break;
931 
932         pMoniker->has_class = TRUE;
933         pMoniker->class = This->class;
934 
935         rgelt[fetched] = &pMoniker->IMoniker_iface;
936         fetched++;
937     }
938 
939     TRACE("-- fetched %d\n", fetched);
940 
941     if (pceltFetched)
942         *pceltFetched = fetched;
943 
944     if (fetched != celt)
945         return S_FALSE;
946     else
947         return S_OK;
948 }
949 
DEVENUM_IEnumMoniker_Skip(IEnumMoniker * iface,ULONG celt)950 static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt)
951 {
952     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
953 
954     TRACE("(%p)->(%d)\n", iface, celt);
955 
956     while (celt--)
957     {
958         /* FIXME: try PNP devices first */
959 
960         /* try DMOs */
961         if (IEnumDMO_Skip(This->dmo_enum, 1) == S_OK)
962             ;
963         /* try DirectShow filters */
964         else if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
965         {
966             This->sw_index++;
967         }
968         /* then try codecs */
969         else if (RegEnumKeyW(This->cm_key, This->cm_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
970         {
971             This->cm_index++;
972         }
973         else
974             return S_FALSE;
975     }
976 
977     return S_OK;
978 }
979 
DEVENUM_IEnumMoniker_Reset(IEnumMoniker * iface)980 static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface)
981 {
982     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
983 
984     TRACE("(%p)->()\n", iface);
985 
986     IEnumDMO_Reset(This->dmo_enum);
987     This->sw_index = 0;
988     This->cm_index = 0;
989 
990     return S_OK;
991 }
992 
DEVENUM_IEnumMoniker_Clone(IEnumMoniker * iface,IEnumMoniker ** ppenum)993 static HRESULT WINAPI DEVENUM_IEnumMoniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum)
994 {
995     FIXME("(%p)->(%p): stub\n", iface, ppenum);
996 
997     return E_NOTIMPL;
998 }
999 
1000 /**********************************************************************
1001  * IEnumMoniker_Vtbl
1002  */
1003 static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
1004 {
1005     DEVENUM_IEnumMoniker_QueryInterface,
1006     DEVENUM_IEnumMoniker_AddRef,
1007     DEVENUM_IEnumMoniker_Release,
1008     DEVENUM_IEnumMoniker_Next,
1009     DEVENUM_IEnumMoniker_Skip,
1010     DEVENUM_IEnumMoniker_Reset,
1011     DEVENUM_IEnumMoniker_Clone
1012 };
1013 
create_EnumMoniker(REFCLSID class,IEnumMoniker ** ppEnumMoniker)1014 HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **ppEnumMoniker)
1015 {
1016     EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl));
1017     WCHAR buffer[78];
1018     HRESULT hr;
1019 
1020     if (!pEnumMoniker)
1021         return E_OUTOFMEMORY;
1022 
1023     pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
1024     pEnumMoniker->ref = 1;
1025     pEnumMoniker->sw_index = 0;
1026     pEnumMoniker->cm_index = 0;
1027     pEnumMoniker->class = *class;
1028 
1029     lstrcpyW(buffer, clsidW);
1030     lstrcatW(buffer, backslashW);
1031     StringFromGUID2(class, buffer + lstrlenW(buffer), CHARS_IN_GUID);
1032     lstrcatW(buffer, instanceW);
1033     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->sw_key))
1034         pEnumMoniker->sw_key = NULL;
1035 
1036     lstrcpyW(buffer, wszActiveMovieKey);
1037     StringFromGUID2(class, buffer + lstrlenW(buffer), CHARS_IN_GUID);
1038     if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->cm_key))
1039         pEnumMoniker->cm_key = NULL;
1040 
1041     hr = DMOEnum(class, 0, 0, NULL, 0, NULL, &pEnumMoniker->dmo_enum);
1042     if (FAILED(hr))
1043     {
1044         IEnumMoniker_Release(&pEnumMoniker->IEnumMoniker_iface);
1045         return hr;
1046     }
1047 
1048     *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface;
1049 
1050     DEVENUM_LockModule();
1051 
1052     return S_OK;
1053 }
1054