ntdll: Move retrieving the startup info to the Unix library.
[wine.git] / dlls / devenum / mediacatenum.c
blob16b729ab1fdbec162a23d8f2743f96548adcf05b
1 /*
2 * IEnumMoniker implementation for DEVENUM.dll
4 * Copyright (C) 2002 Robert Shearman
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.
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.
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
20 * NOTES ON THIS FILE:
21 * - Implements IEnumMoniker interface which enumerates through moniker
22 * objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance
25 #include "devenum_private.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(devenum);
31 BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size)
33 unsigned int max_capacity, new_capacity;
34 void *new_elements;
36 if (count <= *capacity)
37 return TRUE;
39 max_capacity = ~0u / size;
40 if (count > max_capacity)
41 return FALSE;
43 new_capacity = max(8, *capacity);
44 while (new_capacity < count && new_capacity <= max_capacity / 2)
45 new_capacity *= 2;
46 if (new_capacity < count)
47 new_capacity = count;
49 if (!(new_elements = realloc(*elements, new_capacity * size)))
51 ERR("Failed to allocate memory.\n");
52 return FALSE;
55 *elements = new_elements;
56 *capacity = new_capacity;
57 return TRUE;
60 typedef struct
62 IEnumMoniker IEnumMoniker_iface;
63 CLSID class;
64 LONG ref;
65 IEnumDMO *dmo_enum, *dmo_enum2;
66 HKEY sw_key;
67 DWORD sw_index;
68 HKEY cm_key;
69 DWORD cm_index;
70 } EnumMonikerImpl;
72 static inline struct moniker *impl_from_IPropertyBag(IPropertyBag *iface)
74 return CONTAINING_RECORD(iface, struct moniker, IPropertyBag_iface);
77 static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out)
79 struct moniker *moniker = impl_from_IPropertyBag(iface);
81 TRACE("moniker %p, iid %s, out %p.\n", moniker, debugstr_guid(iid), out);
83 if (!out)
84 return E_POINTER;
86 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IPropertyBag))
88 *out = iface;
89 IPropertyBag_AddRef(iface);
90 return S_OK;
93 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
94 *out = NULL;
95 return E_NOINTERFACE;
98 static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface)
100 struct moniker *moniker = impl_from_IPropertyBag(iface);
101 return IMoniker_AddRef(&moniker->IMoniker_iface);
104 static ULONG WINAPI property_bag_Release(IPropertyBag *iface)
106 struct moniker *moniker = impl_from_IPropertyBag(iface);
107 return IMoniker_Release(&moniker->IMoniker_iface);
110 static HRESULT WINAPI property_bag_Read(IPropertyBag *iface,
111 const WCHAR *name, VARIANT *var, IErrorLog *errorlog)
113 struct moniker *moniker = impl_from_IPropertyBag(iface);
114 WCHAR dmo_name[80];
115 DWORD size, type;
116 HKEY parent, key;
117 WCHAR path[78];
118 void *data;
119 HRESULT hr;
120 LONG ret;
122 TRACE("moniker %p, name %s, var %p, errorlog %p.\n", moniker, debugstr_w(name), var, errorlog);
124 if (!name || !var)
125 return E_POINTER;
127 if (moniker->type == DEVICE_DMO)
129 if (!wcscmp(name, L"FriendlyName"))
131 if (SUCCEEDED(hr = DMOGetName(&moniker->clsid, dmo_name)))
133 V_VT(var) = VT_BSTR;
134 V_BSTR(var) = SysAllocString(dmo_name);
136 return hr;
138 else if (!wcscmp(name, L"FilterData"))
140 REGFILTERPINS2 reg_pins[2] = {{0}};
141 REGFILTER2 reg_filter =
143 .dwVersion = 2,
144 .dwMerit = MERIT_NORMAL + 0x800,
145 .cPins2 = 2,
146 .rgPins2 = reg_pins,
149 unsigned int count = 1, input_count, output_count, i;
150 DMO_PARTIAL_MEDIATYPE *types = NULL;
151 REGPINTYPES *reg_types;
152 HRESULT hr;
154 if (!(types = malloc(2 * count * sizeof(*types))))
155 return E_OUTOFMEMORY;
157 while ((hr = DMOGetTypes(&moniker->clsid, count, &input_count, types,
158 count, &output_count, types + count)) == S_FALSE)
160 count *= 2;
161 if (!(types = realloc(types, count * sizeof(*types))))
163 free(types);
164 return E_OUTOFMEMORY;
167 if (hr != S_OK)
169 free(types);
170 return hr;
173 if (!(reg_types = malloc(2 * count * sizeof(*reg_types))))
175 free(types);
176 return hr;
179 for (i = 0; i < input_count; ++i)
181 reg_types[i].clsMajorType = &types[i].type;
182 reg_types[i].clsMinorType = &types[i].subtype;
184 for (i = 0; i < output_count; ++i)
186 reg_types[count + i].clsMajorType = &types[count + i].type;
187 reg_types[count + i].clsMinorType = &types[count + i].subtype;
189 reg_pins[0].cInstances = 1;
190 reg_pins[0].nMediaTypes = input_count;
191 reg_pins[0].lpMediaType = reg_types;
192 reg_pins[1].dwFlags = REG_PINFLAG_B_OUTPUT;
193 reg_pins[1].cInstances = 1;
194 reg_pins[1].nMediaTypes = output_count;
195 reg_pins[1].lpMediaType = reg_types + count;
197 hr = create_filter_data(var, &reg_filter);
198 free(reg_types);
199 free(types);
200 return hr;
202 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
205 if (moniker->type == DEVICE_FILTER)
207 wcscpy(path, L"CLSID\\");
208 if (moniker->has_class)
210 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
211 wcscat(path, L"\\Instance");
213 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, 0, &parent)))
214 return HRESULT_FROM_WIN32(ret);
216 else if (moniker->type == DEVICE_CODEC)
218 wcscpy(path, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
219 if (moniker->has_class)
220 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
221 if ((ret = RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, 0, &parent)))
222 return HRESULT_FROM_WIN32(ret);
224 ret = RegOpenKeyExW(parent, moniker->name, 0, KEY_READ, &key);
225 RegCloseKey(parent);
226 if (ret)
227 return HRESULT_FROM_WIN32(ret);
229 if ((ret = RegQueryValueExW(key, name, NULL, NULL, NULL, &size)))
231 RegCloseKey(key);
232 return HRESULT_FROM_WIN32(ret);
235 data = malloc(size);
236 if ((ret = RegQueryValueExW(key, name, NULL, &type, data, &size)))
238 RegCloseKey(key);
239 free(data);
240 return HRESULT_FROM_WIN32(ret);
242 RegCloseKey(key);
244 switch (type)
246 case REG_SZ:
247 if (V_VT(var) == VT_EMPTY)
248 V_VT(var) = VT_BSTR;
249 if (V_VT(var) != VT_BSTR)
251 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
252 return E_INVALIDARG;
254 V_BSTR(var) = SysAllocStringLen(data, size / sizeof(WCHAR) - 1);
255 free(data);
256 return S_OK;
257 case REG_DWORD:
258 if (V_VT(var) == VT_EMPTY)
259 V_VT(var) = VT_I4;
260 if (V_VT(var) != VT_I4)
262 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
263 return E_INVALIDARG;
265 V_I4(var) = *(DWORD *)data;
266 free(data);
267 return S_OK;
268 case REG_BINARY:
270 SAFEARRAYBOUND bound = {.cElements = size};
271 void *array_data;
273 if (V_VT(var) == VT_EMPTY)
274 V_VT(var) = VT_ARRAY | VT_UI1;
275 if (V_VT(var) != (VT_ARRAY | VT_UI1))
277 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
278 return E_INVALIDARG;
281 if (!(V_ARRAY(var) = SafeArrayCreate(VT_UI1, 1, &bound)))
283 free(data);
284 return E_OUTOFMEMORY;
287 SafeArrayAccessData(V_ARRAY(var), &array_data);
288 memcpy(array_data, data, size);
289 SafeArrayUnaccessData(V_ARRAY(var));
290 free(data);
291 return S_OK;
293 default:
294 FIXME("Unhandled type %#x.\n", type);
295 free(data);
296 return E_NOTIMPL;
300 static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *name, VARIANT *var)
302 struct moniker *moniker = impl_from_IPropertyBag(iface);
303 HKEY parent, key;
304 WCHAR path[78];
305 LONG ret;
307 TRACE("moniker %p, name %s, var %s.\n", moniker, debugstr_w(name), debugstr_variant(var));
309 if (moniker->type == DEVICE_DMO)
310 return E_ACCESSDENIED;
312 if (moniker->type == DEVICE_FILTER)
314 wcscpy(path, L"CLSID\\");
315 if (moniker->has_class)
317 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
318 wcscat(path, L"\\Instance");
320 if ((ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, path, 0, NULL, 0, 0, NULL, &parent, NULL)))
321 return HRESULT_FROM_WIN32(ret);
323 else if (moniker->type == DEVICE_CODEC)
325 wcscpy(path, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
326 if (moniker->has_class)
327 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
328 if ((ret = RegCreateKeyExW(HKEY_CURRENT_USER, path, 0, NULL, 0, 0, NULL, &parent, NULL)))
329 return HRESULT_FROM_WIN32(ret);
331 ret = RegCreateKeyExW(parent, moniker->name, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL);
332 RegCloseKey(parent);
333 if (ret)
334 return HRESULT_FROM_WIN32(ret);
336 switch (V_VT(var))
338 case VT_BSTR:
339 ret = RegSetValueExW(key, name, 0, REG_SZ, (BYTE *)V_BSTR(var),
340 (wcslen(V_BSTR(var)) + 1) * sizeof(WCHAR));
341 break;
342 case VT_I4:
343 ret = RegSetValueExW(key, name, 0, REG_DWORD, (BYTE *)&V_I4(var), sizeof(DWORD));
344 break;
345 case VT_ARRAY | VT_UI1:
347 LONG lbound, ubound;
348 void *array_data;
349 SafeArrayGetLBound(V_ARRAY(var), 1, &lbound);
350 SafeArrayGetUBound(V_ARRAY(var), 1, &ubound);
351 SafeArrayAccessData(V_ARRAY(var), &array_data);
352 ret = RegSetValueExW(key, name, 0, REG_BINARY, array_data, ubound - lbound + 1);
353 SafeArrayUnaccessData(V_ARRAY(var));
354 break;
356 default:
357 WARN("Unhandled type %s.\n", debugstr_vt(V_VT(var)));
358 return E_INVALIDARG;
361 RegCloseKey(key);
362 return S_OK;
365 static const IPropertyBagVtbl IPropertyBag_Vtbl =
367 property_bag_QueryInterface,
368 property_bag_AddRef,
369 property_bag_Release,
370 property_bag_Read,
371 property_bag_Write,
374 static inline struct moniker *impl_from_IMoniker(IMoniker *iface)
376 return CONTAINING_RECORD(iface, struct moniker, IMoniker_iface);
379 static HRESULT WINAPI moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
381 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
383 if (!ppv)
384 return E_POINTER;
386 if (IsEqualGUID(riid, &IID_IUnknown) ||
387 IsEqualGUID(riid, &IID_IPersist) ||
388 IsEqualGUID(riid, &IID_IPersistStream) ||
389 IsEqualGUID(riid, &IID_IMoniker))
391 *ppv = iface;
392 IMoniker_AddRef(iface);
393 return S_OK;
396 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
397 *ppv = NULL;
398 return E_NOINTERFACE;
401 static ULONG WINAPI moniker_AddRef(IMoniker *iface)
403 struct moniker *This = impl_from_IMoniker(iface);
404 ULONG ref = InterlockedIncrement(&This->ref);
406 TRACE("(%p) ref=%d\n", This, ref);
408 return ref;
411 static ULONG WINAPI moniker_Release(IMoniker *iface)
413 struct moniker *This = impl_from_IMoniker(iface);
414 ULONG ref = InterlockedDecrement(&This->ref);
416 TRACE("(%p) ref=%d\n", This, ref);
418 if (ref == 0) {
419 free(This->name);
420 free(This);
421 DEVENUM_UnlockModule();
423 return ref;
426 static HRESULT WINAPI moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
428 struct moniker *This = impl_from_IMoniker(iface);
430 TRACE("(%p)->(%p)\n", This, pClassID);
432 if (pClassID == NULL)
433 return E_INVALIDARG;
435 *pClassID = CLSID_CDeviceMoniker;
437 return S_OK;
440 static HRESULT WINAPI moniker_IsDirty(IMoniker *iface)
442 FIXME("(%p)->(): stub\n", iface);
444 return S_FALSE;
447 static HRESULT WINAPI moniker_Load(IMoniker *iface, IStream *pStm)
449 FIXME("(%p)->(%p): stub\n", iface, pStm);
451 return E_NOTIMPL;
454 static HRESULT WINAPI moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
456 FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false");
458 return STG_E_CANTSAVE;
461 static HRESULT WINAPI moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
463 FIXME("(%p)->(%p): stub\n", iface, pcbSize);
465 ZeroMemory(pcbSize, sizeof(*pcbSize));
467 return S_OK;
470 static HRESULT WINAPI moniker_BindToObject(IMoniker *iface, IBindCtx *bind_ctx,
471 IMoniker *left, REFIID iid, void **out)
473 struct moniker *moniker = impl_from_IMoniker(iface);
474 IPersistPropertyBag *persist_bag;
475 IUnknown *unk;
476 CLSID clsid;
477 VARIANT var;
478 HRESULT hr;
480 TRACE("moniker %p, bind_ctx %p, left %p, iid %s, out %p.\n",
481 moniker, bind_ctx, left, debugstr_guid(iid), out);
483 if (!out)
484 return E_POINTER;
486 *out = NULL;
488 if (moniker->type == DEVICE_DMO)
490 IDMOWrapperFilter *wrapper;
492 if (FAILED(hr = CoCreateInstance(&CLSID_DMOWrapperFilter, NULL,
493 CLSCTX_INPROC_SERVER, &IID_IDMOWrapperFilter, (void **)&wrapper)))
494 return hr;
496 if (SUCCEEDED(hr = IDMOWrapperFilter_Init(wrapper, &moniker->clsid, &moniker->class)))
498 hr = IDMOWrapperFilter_QueryInterface(wrapper, iid, out);
500 IDMOWrapperFilter_Release(wrapper);
501 return hr;
504 VariantInit(&var);
505 V_VT(&var) = VT_BSTR;
506 if (FAILED(hr = IPropertyBag_Read(&moniker->IPropertyBag_iface, L"CLSID", &var, NULL)))
507 return hr;
509 hr = CLSIDFromString(V_BSTR(&var), &clsid);
510 VariantClear(&var);
511 if (FAILED(hr))
512 return hr;
514 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_ALL, &IID_IUnknown, (void **)&unk)))
515 return hr;
517 if (SUCCEEDED(IUnknown_QueryInterface(unk, &IID_IPersistPropertyBag, (void **)&persist_bag)))
519 hr = IPersistPropertyBag_Load(persist_bag, &moniker->IPropertyBag_iface, NULL);
520 IPersistPropertyBag_Release(persist_bag);
523 if (SUCCEEDED(hr))
524 hr = IUnknown_QueryInterface(unk, iid, out);
526 IUnknown_Release(unk);
528 return hr;
531 static HRESULT WINAPI moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc,
532 IMoniker *pmkToLeft, REFIID riid, void **out)
534 struct moniker *moniker = impl_from_IMoniker(iface);
536 TRACE("moniker %p, left %p, iid %s, out %p.\n", moniker, pmkToLeft, debugstr_guid(riid), out);
538 *out = NULL;
540 if (pmkToLeft)
541 return MK_E_NOSTORAGE;
543 if (pbc != NULL)
545 static DWORD reported;
546 if (!reported)
548 FIXME("ignoring IBindCtx %p\n", pbc);
549 reported++;
553 if (IsEqualGUID(riid, &IID_IPropertyBag))
555 *out = &moniker->IPropertyBag_iface;
556 IPropertyBag_AddRef(&moniker->IPropertyBag_iface);
557 return S_OK;
560 return MK_E_NOSTORAGE;
563 static HRESULT WINAPI moniker_Reduce(IMoniker *iface, IBindCtx *pbc,
564 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
566 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
568 if (ppmkToLeft)
569 *ppmkToLeft = NULL;
570 *ppmkReduced = iface;
572 return MK_S_REDUCED_TO_SELF;
575 static HRESULT WINAPI moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
576 BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
578 FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
580 /* FIXME: use CreateGenericComposite? */
581 *ppmkComposite = NULL;
583 return E_NOTIMPL;
586 static HRESULT WINAPI moniker_Enum(IMoniker *iface, BOOL fForward,
587 IEnumMoniker **ppenumMoniker)
589 FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker);
591 *ppenumMoniker = NULL;
593 return S_OK;
596 static HRESULT WINAPI moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
598 CLSID clsid;
599 LPOLESTR this_name, other_name;
600 IBindCtx *bind;
601 HRESULT res;
603 TRACE("(%p)->(%p)\n", iface, pmkOtherMoniker);
605 if (!pmkOtherMoniker)
606 return E_INVALIDARG;
608 IMoniker_GetClassID(pmkOtherMoniker, &clsid);
609 if (!IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker))
610 return S_FALSE;
612 res = CreateBindCtx(0, &bind);
613 if (FAILED(res))
614 return res;
616 res = S_FALSE;
617 if (SUCCEEDED(IMoniker_GetDisplayName(iface, bind, NULL, &this_name)) &&
618 SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker, bind, NULL, &other_name)))
620 int result = wcsicmp(this_name, other_name);
621 CoTaskMemFree(this_name);
622 CoTaskMemFree(other_name);
623 if (!result)
624 res = S_OK;
626 IBindCtx_Release(bind);
627 return res;
630 static HRESULT WINAPI moniker_Hash(IMoniker *iface, DWORD *pdwHash)
632 TRACE("(%p)->(%p)\n", iface, pdwHash);
634 *pdwHash = 0;
636 return S_OK;
639 static HRESULT WINAPI moniker_IsRunning(IMoniker *iface, IBindCtx *pbc,
640 IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
642 FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning);
644 return S_FALSE;
647 static HRESULT WINAPI moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
648 IMoniker *pmkToLeft, FILETIME *pFileTime)
650 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime);
652 pFileTime->dwLowDateTime = 0xFFFFFFFF;
653 pFileTime->dwHighDateTime = 0x7FFFFFFF;
655 return MK_E_UNAVAILABLE;
658 static HRESULT WINAPI moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
660 TRACE("(%p)->(%p)\n", iface, ppmk);
662 *ppmk = NULL;
664 return MK_E_NOINVERSE;
667 static HRESULT WINAPI moniker_CommonPrefixWith(IMoniker *iface,
668 IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix)
670 TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix);
672 *ppmkPrefix = NULL;
674 return MK_E_NOPREFIX;
677 static HRESULT WINAPI moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
678 IMoniker **ppmkRelPath)
680 TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath);
682 *ppmkRelPath = pmkOther;
684 return MK_S_HIM;
687 static HRESULT WINAPI moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
688 IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
690 struct moniker *This = impl_from_IMoniker(iface);
691 WCHAR *buffer;
693 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
695 *ppszDisplayName = NULL;
697 if (This->type == DEVICE_DMO)
699 buffer = CoTaskMemAlloc((12 + 2 * CHARS_IN_GUID + 1) * sizeof(WCHAR));
700 if (!buffer) return E_OUTOFMEMORY;
702 wcscpy(buffer, L"@device:dmo:");
703 StringFromGUID2(&This->clsid, buffer + wcslen(buffer), CHARS_IN_GUID);
704 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
706 else
708 buffer = CoTaskMemAlloc((11 + (This->has_class ? CHARS_IN_GUID : 0)
709 + wcslen(This->name) + 1) * sizeof(WCHAR));
710 if (!buffer) return E_OUTOFMEMORY;
712 if (This->type == DEVICE_FILTER)
713 wcscpy(buffer, L"@device:sw:");
714 else if (This->type == DEVICE_CODEC)
715 wcscpy(buffer, L"@device:cm:");
717 if (This->has_class)
719 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
720 wcscat(buffer, L"\\");
722 wcscat(buffer, This->name);
725 *ppszDisplayName = buffer;
726 return S_OK;
729 static HRESULT WINAPI moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
730 IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
732 FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
734 *pchEaten = 0;
735 *ppmkOut = NULL;
737 return MK_E_SYNTAX;
740 static HRESULT WINAPI moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
742 TRACE("(%p)->(%p)\n", iface, pdwMksys);
744 return S_FALSE;
747 static const IMonikerVtbl IMoniker_Vtbl =
749 moniker_QueryInterface,
750 moniker_AddRef,
751 moniker_Release,
752 moniker_GetClassID,
753 moniker_IsDirty,
754 moniker_Load,
755 moniker_Save,
756 moniker_GetSizeMax,
757 moniker_BindToObject,
758 moniker_BindToStorage,
759 moniker_Reduce,
760 moniker_ComposeWith,
761 moniker_Enum,
762 moniker_IsEqual,
763 moniker_Hash,
764 moniker_IsRunning,
765 moniker_GetTimeOfLastChange,
766 moniker_Inverse,
767 moniker_CommonPrefixWith,
768 moniker_RelativePathTo,
769 moniker_GetDisplayName,
770 moniker_ParseDisplayName,
771 moniker_IsSystemMoniker,
774 struct moniker *filter_moniker_create(const GUID *class, const WCHAR *name)
776 struct moniker *object;
778 if (!(object = calloc(1, sizeof(*object))))
779 return NULL;
781 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
782 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
783 object->ref = 1;
784 object->type = DEVICE_FILTER;
785 if (class)
786 object->class = *class;
787 object->has_class = !!class;
788 object->name = wcsdup(name);
790 DEVENUM_LockModule();
792 return object;
795 struct moniker *codec_moniker_create(const GUID *class, const WCHAR *name)
797 struct moniker *object;
799 if (!(object = calloc(1, sizeof(*object))))
800 return NULL;
802 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
803 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
804 object->ref = 1;
805 object->type = DEVICE_CODEC;
806 if (class)
807 object->class = *class;
808 object->has_class = !!class;
809 object->name = wcsdup(name);
811 DEVENUM_LockModule();
813 return object;
816 struct moniker *dmo_moniker_create(const GUID class, const GUID clsid)
818 struct moniker *object;
820 if (!(object = calloc(1, sizeof(*object))))
821 return NULL;
823 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
824 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
825 object->ref = 1;
826 object->type = DEVICE_DMO;
827 object->class = class;
828 object->clsid = clsid;
830 DEVENUM_LockModule();
832 return object;
835 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
837 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
840 static HRESULT WINAPI enum_moniker_QueryInterface(IEnumMoniker *iface, REFIID riid, void **ppv)
842 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
844 if (!ppv)
845 return E_POINTER;
847 if (IsEqualGUID(riid, &IID_IUnknown) ||
848 IsEqualGUID(riid, &IID_IEnumMoniker))
850 *ppv = iface;
851 IEnumMoniker_AddRef(iface);
852 return S_OK;
855 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
856 *ppv = NULL;
857 return E_NOINTERFACE;
860 static ULONG WINAPI enum_moniker_AddRef(IEnumMoniker *iface)
862 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
863 ULONG ref = InterlockedIncrement(&This->ref);
865 TRACE("(%p) ref=%d\n", This, ref);
867 return ref;
870 static ULONG WINAPI enum_moniker_Release(IEnumMoniker *iface)
872 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
873 ULONG ref = InterlockedDecrement(&This->ref);
875 TRACE("(%p) ref=%d\n", This, ref);
877 if (!ref)
879 if (This->dmo_enum)
880 IEnumDMO_Release(This->dmo_enum);
881 if (This->dmo_enum2)
882 IEnumDMO_Release(This->dmo_enum2);
883 RegCloseKey(This->sw_key);
884 RegCloseKey(This->cm_key);
885 free(This);
886 DEVENUM_UnlockModule();
887 return 0;
889 return ref;
892 static struct moniker *get_dmo_moniker(EnumMonikerImpl *enum_moniker)
894 GUID clsid;
896 if (IsEqualGUID(&enum_moniker->class, &CLSID_LegacyAmFilterCategory))
898 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
899 return dmo_moniker_create(DMOCATEGORY_AUDIO_DECODER, clsid);
900 if (enum_moniker->dmo_enum2 && IEnumDMO_Next(enum_moniker->dmo_enum2, 1, &clsid, NULL, NULL) == S_OK)
901 return dmo_moniker_create(DMOCATEGORY_VIDEO_DECODER, clsid);
903 else
905 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
906 return dmo_moniker_create(enum_moniker->class, clsid);
909 return NULL;
912 static HRESULT WINAPI enum_moniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt,
913 ULONG *pceltFetched)
915 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
916 WCHAR buffer[MAX_PATH + 1];
917 struct moniker *moniker;
918 LONG res;
919 ULONG fetched = 0;
920 HKEY hkey;
922 TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
924 while (fetched < celt)
926 /* FIXME: try PNP devices first */
928 /* try DMOs */
929 if ((moniker = get_dmo_moniker(This)))
931 /* try DirectShow filters */
932 else if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, ARRAY_SIZE(buffer))))
934 This->sw_index++;
935 if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
936 break;
938 moniker = filter_moniker_create(&This->class, buffer);
940 /* then try codecs */
941 else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, ARRAY_SIZE(buffer))))
943 This->cm_index++;
945 if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
946 break;
948 moniker = codec_moniker_create(&This->class, buffer);
950 else
951 break;
953 if (!moniker)
954 return E_OUTOFMEMORY;
956 rgelt[fetched++] = &moniker->IMoniker_iface;
959 TRACE("-- fetched %d\n", fetched);
961 if (pceltFetched)
962 *pceltFetched = fetched;
964 if (fetched != celt)
965 return S_FALSE;
966 else
967 return S_OK;
970 static HRESULT WINAPI enum_moniker_Skip(IEnumMoniker *iface, ULONG celt)
972 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
974 TRACE("(%p)->(%d)\n", iface, celt);
976 while (celt--)
978 /* FIXME: try PNP devices first */
980 /* try DMOs */
981 if (This->dmo_enum && IEnumDMO_Skip(This->dmo_enum, 1) == S_OK)
983 else if (This->dmo_enum2 && IEnumDMO_Skip(This->dmo_enum2, 1) == S_OK)
985 /* try DirectShow filters */
986 else if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
988 This->sw_index++;
990 /* then try codecs */
991 else if (RegEnumKeyW(This->cm_key, This->cm_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
993 This->cm_index++;
995 else
996 return S_FALSE;
999 return S_OK;
1002 static HRESULT WINAPI enum_moniker_Reset(IEnumMoniker *iface)
1004 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1006 TRACE("(%p)->()\n", iface);
1008 if (This->dmo_enum)
1009 IEnumDMO_Reset(This->dmo_enum);
1010 if (This->dmo_enum2)
1011 IEnumDMO_Reset(This->dmo_enum2);
1012 This->sw_index = 0;
1013 This->cm_index = 0;
1015 return S_OK;
1018 static HRESULT WINAPI enum_moniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum)
1020 FIXME("(%p)->(%p): stub\n", iface, ppenum);
1022 return E_NOTIMPL;
1025 /**********************************************************************
1026 * IEnumMoniker_Vtbl
1028 static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
1030 enum_moniker_QueryInterface,
1031 enum_moniker_AddRef,
1032 enum_moniker_Release,
1033 enum_moniker_Next,
1034 enum_moniker_Skip,
1035 enum_moniker_Reset,
1036 enum_moniker_Clone,
1039 HRESULT enum_moniker_create(REFCLSID class, IEnumMoniker **out)
1041 EnumMonikerImpl *object;
1042 WCHAR buffer[78];
1044 if (!(object = calloc(1, sizeof(*object))))
1045 return E_OUTOFMEMORY;
1047 object->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
1048 object->ref = 1;
1049 object->class = *class;
1051 wcscpy(buffer, L"CLSID\\");
1052 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1053 wcscat(buffer, L"\\Instance");
1054 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->sw_key))
1055 object->sw_key = NULL;
1057 wcscpy(buffer, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
1058 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1059 if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->cm_key))
1060 object->cm_key = NULL;
1062 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory))
1064 if (FAILED(DMOEnum(&DMOCATEGORY_AUDIO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1065 object->dmo_enum = NULL;
1066 if (FAILED(DMOEnum(&DMOCATEGORY_VIDEO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum2)))
1067 object->dmo_enum2 = NULL;
1069 else
1071 if (FAILED(DMOEnum(class, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1072 object->dmo_enum = NULL;
1075 *out = &object->IEnumMoniker_iface;
1077 DEVENUM_LockModule();
1079 return S_OK;