win32u: Don't report cloned monitors in EnumDisplayMonitors().
[wine.git] / dlls / devenum / mediacatenum.c
blob2d87709bea6db62936737102ff51302b9cd1096d
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 DMO_PARTIAL_MEDIATYPE *types = NULL, *new_array;
141 ULONG count = 1, input_count, output_count, i;
142 REGFILTERPINS2 reg_pins[2] = {{0}};
143 REGFILTER2 reg_filter = {0};
144 REGPINTYPES *reg_types;
145 HRESULT hr;
149 count *= 2;
150 if (!(new_array = realloc(types, 2 * count * sizeof(*types))))
152 free(types);
153 return E_OUTOFMEMORY;
155 types = new_array;
157 if (FAILED(hr = DMOGetTypes(&moniker->clsid, count, &input_count, types,
158 count, &output_count, types + count)))
160 free(types);
161 return hr;
163 } while (input_count == count || output_count == count);
165 if (!(reg_types = malloc(2 * count * sizeof(*reg_types))))
167 free(types);
168 return hr;
171 for (i = 0; i < input_count; ++i)
173 reg_types[i].clsMajorType = &types[i].type;
174 reg_types[i].clsMinorType = &types[i].subtype;
176 for (i = 0; i < output_count; ++i)
178 reg_types[count + i].clsMajorType = &types[count + i].type;
179 reg_types[count + i].clsMinorType = &types[count + i].subtype;
181 reg_pins[0].cInstances = 1;
182 reg_pins[0].nMediaTypes = input_count;
183 reg_pins[0].lpMediaType = reg_types;
184 reg_pins[1].dwFlags = REG_PINFLAG_B_OUTPUT;
185 reg_pins[1].cInstances = 1;
186 reg_pins[1].nMediaTypes = output_count;
187 reg_pins[1].lpMediaType = reg_types + count;
188 reg_filter.dwVersion = 2;
189 reg_filter.dwMerit = MERIT_NORMAL + 0x800;
190 reg_filter.cPins2 = 2;
191 reg_filter.rgPins2 = reg_pins;
193 hr = create_filter_data(var, &reg_filter);
194 free(reg_types);
195 free(types);
196 return hr;
198 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
201 if (moniker->type == DEVICE_FILTER)
203 wcscpy(path, L"CLSID\\");
204 if (moniker->has_class)
206 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
207 wcscat(path, L"\\Instance");
209 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, 0, &parent)))
210 return HRESULT_FROM_WIN32(ret);
212 else if (moniker->type == DEVICE_CODEC)
214 wcscpy(path, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
215 if (moniker->has_class)
216 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
217 if ((ret = RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, 0, &parent)))
218 return HRESULT_FROM_WIN32(ret);
220 ret = RegOpenKeyExW(parent, moniker->name, 0, KEY_READ, &key);
221 RegCloseKey(parent);
222 if (ret)
223 return HRESULT_FROM_WIN32(ret);
225 if ((ret = RegQueryValueExW(key, name, NULL, NULL, NULL, &size)))
227 RegCloseKey(key);
228 return HRESULT_FROM_WIN32(ret);
231 data = malloc(size);
232 if ((ret = RegQueryValueExW(key, name, NULL, &type, data, &size)))
234 RegCloseKey(key);
235 free(data);
236 return HRESULT_FROM_WIN32(ret);
238 RegCloseKey(key);
240 switch (type)
242 case REG_SZ:
243 if (V_VT(var) == VT_EMPTY)
244 V_VT(var) = VT_BSTR;
245 if (V_VT(var) != VT_BSTR)
247 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
248 return E_INVALIDARG;
250 V_BSTR(var) = SysAllocStringLen(data, size / sizeof(WCHAR) - 1);
251 free(data);
252 return S_OK;
253 case REG_DWORD:
254 if (V_VT(var) == VT_EMPTY)
255 V_VT(var) = VT_I4;
256 if (V_VT(var) != VT_I4)
258 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
259 return E_INVALIDARG;
261 V_I4(var) = *(DWORD *)data;
262 free(data);
263 return S_OK;
264 case REG_BINARY:
266 SAFEARRAYBOUND bound = {.cElements = size};
267 void *array_data;
269 if (V_VT(var) == VT_EMPTY)
270 V_VT(var) = VT_ARRAY | VT_UI1;
271 if (V_VT(var) != (VT_ARRAY | VT_UI1))
273 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
274 return E_INVALIDARG;
277 if (!(V_ARRAY(var) = SafeArrayCreate(VT_UI1, 1, &bound)))
279 free(data);
280 return E_OUTOFMEMORY;
283 SafeArrayAccessData(V_ARRAY(var), &array_data);
284 memcpy(array_data, data, size);
285 SafeArrayUnaccessData(V_ARRAY(var));
286 free(data);
287 return S_OK;
289 default:
290 FIXME("Unhandled type %#lx.\n", type);
291 free(data);
292 return E_NOTIMPL;
296 static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *name, VARIANT *var)
298 struct moniker *moniker = impl_from_IPropertyBag(iface);
299 HKEY parent, key;
300 WCHAR path[78];
301 LONG ret;
303 TRACE("moniker %p, name %s, var %s.\n", moniker, debugstr_w(name), debugstr_variant(var));
305 if (moniker->type == DEVICE_DMO)
306 return E_ACCESSDENIED;
308 if (moniker->type == DEVICE_FILTER)
310 wcscpy(path, L"CLSID\\");
311 if (moniker->has_class)
313 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
314 wcscat(path, L"\\Instance");
316 if ((ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, path, 0, NULL, 0, 0, NULL, &parent, NULL)))
317 return HRESULT_FROM_WIN32(ret);
319 else if (moniker->type == DEVICE_CODEC)
321 wcscpy(path, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
322 if (moniker->has_class)
323 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
324 if ((ret = RegCreateKeyExW(HKEY_CURRENT_USER, path, 0, NULL, 0, 0, NULL, &parent, NULL)))
325 return HRESULT_FROM_WIN32(ret);
327 ret = RegCreateKeyExW(parent, moniker->name, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL);
328 RegCloseKey(parent);
329 if (ret)
330 return HRESULT_FROM_WIN32(ret);
332 switch (V_VT(var))
334 case VT_BSTR:
335 ret = RegSetValueExW(key, name, 0, REG_SZ, (BYTE *)V_BSTR(var),
336 (wcslen(V_BSTR(var)) + 1) * sizeof(WCHAR));
337 break;
338 case VT_I4:
339 ret = RegSetValueExW(key, name, 0, REG_DWORD, (BYTE *)&V_I4(var), sizeof(DWORD));
340 break;
341 case VT_ARRAY | VT_UI1:
343 LONG lbound, ubound;
344 void *array_data;
345 SafeArrayGetLBound(V_ARRAY(var), 1, &lbound);
346 SafeArrayGetUBound(V_ARRAY(var), 1, &ubound);
347 SafeArrayAccessData(V_ARRAY(var), &array_data);
348 ret = RegSetValueExW(key, name, 0, REG_BINARY, array_data, ubound - lbound + 1);
349 SafeArrayUnaccessData(V_ARRAY(var));
350 break;
352 default:
353 WARN("Unhandled type %s.\n", debugstr_vt(V_VT(var)));
354 return E_INVALIDARG;
357 RegCloseKey(key);
358 return S_OK;
361 static const IPropertyBagVtbl IPropertyBag_Vtbl =
363 property_bag_QueryInterface,
364 property_bag_AddRef,
365 property_bag_Release,
366 property_bag_Read,
367 property_bag_Write,
370 static inline struct moniker *impl_from_IMoniker(IMoniker *iface)
372 return CONTAINING_RECORD(iface, struct moniker, IMoniker_iface);
375 static HRESULT WINAPI moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
377 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
379 if (!ppv)
380 return E_POINTER;
382 if (IsEqualGUID(riid, &IID_IUnknown) ||
383 IsEqualGUID(riid, &IID_IPersist) ||
384 IsEqualGUID(riid, &IID_IPersistStream) ||
385 IsEqualGUID(riid, &IID_IMoniker))
387 *ppv = iface;
388 IMoniker_AddRef(iface);
389 return S_OK;
392 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
393 *ppv = NULL;
394 return E_NOINTERFACE;
397 static ULONG WINAPI moniker_AddRef(IMoniker *iface)
399 struct moniker *moniker = impl_from_IMoniker(iface);
400 ULONG refcount = InterlockedIncrement(&moniker->ref);
402 TRACE("%p increasing refcount to %lu.\n", moniker, refcount);
404 return refcount;
407 static ULONG WINAPI moniker_Release(IMoniker *iface)
409 struct moniker *This = impl_from_IMoniker(iface);
410 ULONG refcount = InterlockedDecrement(&This->ref);
412 TRACE("%p decreasing refcount to %lu.\n", This, refcount);
414 if (!refcount)
416 free(This->name);
417 free(This);
419 return refcount;
422 static HRESULT WINAPI moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
424 struct moniker *This = impl_from_IMoniker(iface);
426 TRACE("(%p)->(%p)\n", This, pClassID);
428 if (pClassID == NULL)
429 return E_INVALIDARG;
431 *pClassID = CLSID_CDeviceMoniker;
433 return S_OK;
436 static HRESULT WINAPI moniker_IsDirty(IMoniker *iface)
438 FIXME("(%p)->(): stub\n", iface);
440 return S_FALSE;
443 static HRESULT WINAPI moniker_Load(IMoniker *iface, IStream *pStm)
445 FIXME("(%p)->(%p): stub\n", iface, pStm);
447 return E_NOTIMPL;
450 static HRESULT WINAPI moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
452 FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false");
454 return STG_E_CANTSAVE;
457 static HRESULT WINAPI moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
459 FIXME("(%p)->(%p): stub\n", iface, pcbSize);
461 ZeroMemory(pcbSize, sizeof(*pcbSize));
463 return S_OK;
466 static HRESULT WINAPI moniker_BindToObject(IMoniker *iface, IBindCtx *bind_ctx,
467 IMoniker *left, REFIID iid, void **out)
469 struct moniker *moniker = impl_from_IMoniker(iface);
470 IPersistPropertyBag *persist_bag;
471 IUnknown *unk;
472 CLSID clsid;
473 VARIANT var;
474 HRESULT hr;
476 TRACE("moniker %p, bind_ctx %p, left %p, iid %s, out %p.\n",
477 moniker, bind_ctx, left, debugstr_guid(iid), out);
479 if (!out)
480 return E_POINTER;
482 *out = NULL;
484 if (moniker->type == DEVICE_DMO)
486 IDMOWrapperFilter *wrapper;
488 if (FAILED(hr = CoCreateInstance(&CLSID_DMOWrapperFilter, NULL,
489 CLSCTX_INPROC_SERVER, &IID_IDMOWrapperFilter, (void **)&wrapper)))
490 return hr;
492 if (SUCCEEDED(hr = IDMOWrapperFilter_Init(wrapper, &moniker->clsid, &moniker->class)))
494 hr = IDMOWrapperFilter_QueryInterface(wrapper, iid, out);
496 IDMOWrapperFilter_Release(wrapper);
497 return hr;
500 VariantInit(&var);
501 V_VT(&var) = VT_BSTR;
502 if (FAILED(hr = IPropertyBag_Read(&moniker->IPropertyBag_iface, L"CLSID", &var, NULL)))
503 return hr;
505 hr = CLSIDFromString(V_BSTR(&var), &clsid);
506 VariantClear(&var);
507 if (FAILED(hr))
508 return hr;
510 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_ALL, &IID_IUnknown, (void **)&unk)))
511 return hr;
513 if (SUCCEEDED(IUnknown_QueryInterface(unk, &IID_IPersistPropertyBag, (void **)&persist_bag)))
515 hr = IPersistPropertyBag_Load(persist_bag, &moniker->IPropertyBag_iface, NULL);
516 IPersistPropertyBag_Release(persist_bag);
519 if (SUCCEEDED(hr))
520 hr = IUnknown_QueryInterface(unk, iid, out);
522 IUnknown_Release(unk);
524 return hr;
527 static HRESULT WINAPI moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc,
528 IMoniker *pmkToLeft, REFIID riid, void **out)
530 struct moniker *moniker = impl_from_IMoniker(iface);
532 TRACE("moniker %p, left %p, iid %s, out %p.\n", moniker, pmkToLeft, debugstr_guid(riid), out);
534 *out = NULL;
536 if (pmkToLeft)
537 return MK_E_NOSTORAGE;
539 if (pbc != NULL)
541 static DWORD reported;
542 if (!reported)
544 FIXME("ignoring IBindCtx %p\n", pbc);
545 reported++;
549 if (IsEqualGUID(riid, &IID_IPropertyBag))
551 *out = &moniker->IPropertyBag_iface;
552 IPropertyBag_AddRef(&moniker->IPropertyBag_iface);
553 return S_OK;
556 return MK_E_NOSTORAGE;
559 static HRESULT WINAPI moniker_Reduce(IMoniker *iface, IBindCtx *pbc,
560 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
562 struct moniker *moniker = impl_from_IMoniker(iface);
564 TRACE("moniker %p, bind_ctx %p, how_far %#lx, left %p, reduced %p.\n",
565 moniker, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
567 if (ppmkToLeft)
568 *ppmkToLeft = NULL;
569 *ppmkReduced = iface;
571 return MK_S_REDUCED_TO_SELF;
574 static HRESULT WINAPI moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
575 BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
577 FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
579 /* FIXME: use CreateGenericComposite? */
580 *ppmkComposite = NULL;
582 return E_NOTIMPL;
585 static HRESULT WINAPI moniker_Enum(IMoniker *iface, BOOL fForward,
586 IEnumMoniker **ppenumMoniker)
588 FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker);
590 *ppenumMoniker = NULL;
592 return S_OK;
595 static HRESULT WINAPI moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
597 CLSID clsid;
598 LPOLESTR this_name, other_name;
599 IBindCtx *bind;
600 HRESULT res;
602 TRACE("(%p)->(%p)\n", iface, pmkOtherMoniker);
604 if (!pmkOtherMoniker)
605 return E_INVALIDARG;
607 IMoniker_GetClassID(pmkOtherMoniker, &clsid);
608 if (!IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker))
609 return S_FALSE;
611 res = CreateBindCtx(0, &bind);
612 if (FAILED(res))
613 return res;
615 res = S_FALSE;
616 if (SUCCEEDED(IMoniker_GetDisplayName(iface, bind, NULL, &this_name)) &&
617 SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker, bind, NULL, &other_name)))
619 int result = wcsicmp(this_name, other_name);
620 CoTaskMemFree(this_name);
621 CoTaskMemFree(other_name);
622 if (!result)
623 res = S_OK;
625 IBindCtx_Release(bind);
626 return res;
629 static HRESULT WINAPI moniker_Hash(IMoniker *iface, DWORD *pdwHash)
631 TRACE("(%p)->(%p)\n", iface, pdwHash);
633 *pdwHash = 0;
635 return S_OK;
638 static HRESULT WINAPI moniker_IsRunning(IMoniker *iface, IBindCtx *pbc,
639 IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
641 FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning);
643 return S_FALSE;
646 static HRESULT WINAPI moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
647 IMoniker *pmkToLeft, FILETIME *pFileTime)
649 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime);
651 pFileTime->dwLowDateTime = 0xFFFFFFFF;
652 pFileTime->dwHighDateTime = 0x7FFFFFFF;
654 return MK_E_UNAVAILABLE;
657 static HRESULT WINAPI moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
659 TRACE("(%p)->(%p)\n", iface, ppmk);
661 *ppmk = NULL;
663 return MK_E_NOINVERSE;
666 static HRESULT WINAPI moniker_CommonPrefixWith(IMoniker *iface,
667 IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix)
669 TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix);
671 *ppmkPrefix = NULL;
673 return MK_E_NOPREFIX;
676 static HRESULT WINAPI moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
677 IMoniker **ppmkRelPath)
679 TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath);
681 *ppmkRelPath = pmkOther;
683 return MK_S_HIM;
686 static HRESULT WINAPI moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
687 IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
689 struct moniker *This = impl_from_IMoniker(iface);
690 WCHAR *buffer;
692 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
694 *ppszDisplayName = NULL;
696 if (This->type == DEVICE_DMO)
698 buffer = CoTaskMemAlloc((12 + 2 * CHARS_IN_GUID + 1) * sizeof(WCHAR));
699 if (!buffer) return E_OUTOFMEMORY;
701 wcscpy(buffer, L"@device:dmo:");
702 StringFromGUID2(&This->clsid, buffer + wcslen(buffer), CHARS_IN_GUID);
703 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
705 else
707 buffer = CoTaskMemAlloc((11 + (This->has_class ? CHARS_IN_GUID : 0)
708 + wcslen(This->name) + 1) * sizeof(WCHAR));
709 if (!buffer) return E_OUTOFMEMORY;
711 if (This->type == DEVICE_FILTER)
712 wcscpy(buffer, L"@device:sw:");
713 else if (This->type == DEVICE_CODEC)
714 wcscpy(buffer, L"@device:cm:");
716 if (This->has_class)
718 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
719 wcscat(buffer, L"\\");
721 wcscat(buffer, This->name);
724 *ppszDisplayName = buffer;
725 return S_OK;
728 static HRESULT WINAPI moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
729 IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
731 FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
733 *pchEaten = 0;
734 *ppmkOut = NULL;
736 return MK_E_SYNTAX;
739 static HRESULT WINAPI moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
741 TRACE("(%p)->(%p)\n", iface, pdwMksys);
743 return S_FALSE;
746 static const IMonikerVtbl IMoniker_Vtbl =
748 moniker_QueryInterface,
749 moniker_AddRef,
750 moniker_Release,
751 moniker_GetClassID,
752 moniker_IsDirty,
753 moniker_Load,
754 moniker_Save,
755 moniker_GetSizeMax,
756 moniker_BindToObject,
757 moniker_BindToStorage,
758 moniker_Reduce,
759 moniker_ComposeWith,
760 moniker_Enum,
761 moniker_IsEqual,
762 moniker_Hash,
763 moniker_IsRunning,
764 moniker_GetTimeOfLastChange,
765 moniker_Inverse,
766 moniker_CommonPrefixWith,
767 moniker_RelativePathTo,
768 moniker_GetDisplayName,
769 moniker_ParseDisplayName,
770 moniker_IsSystemMoniker,
773 struct moniker *filter_moniker_create(const GUID *class, const WCHAR *name)
775 struct moniker *object;
777 if (!(object = calloc(1, sizeof(*object))))
778 return NULL;
780 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
781 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
782 object->ref = 1;
783 object->type = DEVICE_FILTER;
784 if (class)
785 object->class = *class;
786 object->has_class = !!class;
787 object->name = wcsdup(name);
789 return object;
792 struct moniker *codec_moniker_create(const GUID *class, const WCHAR *name)
794 struct moniker *object;
796 if (!(object = calloc(1, sizeof(*object))))
797 return NULL;
799 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
800 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
801 object->ref = 1;
802 object->type = DEVICE_CODEC;
803 if (class)
804 object->class = *class;
805 object->has_class = !!class;
806 object->name = wcsdup(name);
808 return object;
811 struct moniker *dmo_moniker_create(const GUID class, const GUID clsid)
813 struct moniker *object;
815 if (!(object = calloc(1, sizeof(*object))))
816 return NULL;
818 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
819 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
820 object->ref = 1;
821 object->type = DEVICE_DMO;
822 object->class = class;
823 object->clsid = clsid;
825 return object;
828 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
830 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
833 static HRESULT WINAPI enum_moniker_QueryInterface(IEnumMoniker *iface, REFIID riid, void **ppv)
835 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
837 if (!ppv)
838 return E_POINTER;
840 if (IsEqualGUID(riid, &IID_IUnknown) ||
841 IsEqualGUID(riid, &IID_IEnumMoniker))
843 *ppv = iface;
844 IEnumMoniker_AddRef(iface);
845 return S_OK;
848 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
849 *ppv = NULL;
850 return E_NOINTERFACE;
853 static ULONG WINAPI enum_moniker_AddRef(IEnumMoniker *iface)
855 EnumMonikerImpl *enumerator = impl_from_IEnumMoniker(iface);
856 ULONG refcount = InterlockedIncrement(&enumerator->ref);
858 TRACE("%p increasing refcount to %lu.\n", enumerator, refcount);
860 return refcount;
863 static ULONG WINAPI enum_moniker_Release(IEnumMoniker *iface)
865 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
866 ULONG refcount = InterlockedDecrement(&This->ref);
868 TRACE("%p decreasing refcount to %lu.\n", This, refcount);
870 if (!refcount)
872 if (This->dmo_enum)
873 IEnumDMO_Release(This->dmo_enum);
874 if (This->dmo_enum2)
875 IEnumDMO_Release(This->dmo_enum2);
876 RegCloseKey(This->sw_key);
877 RegCloseKey(This->cm_key);
878 free(This);
879 return 0;
881 return refcount;
884 static struct moniker *get_dmo_moniker(EnumMonikerImpl *enum_moniker)
886 GUID clsid;
888 if (IsEqualGUID(&enum_moniker->class, &CLSID_LegacyAmFilterCategory))
890 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
891 return dmo_moniker_create(DMOCATEGORY_AUDIO_DECODER, clsid);
892 if (enum_moniker->dmo_enum2 && IEnumDMO_Next(enum_moniker->dmo_enum2, 1, &clsid, NULL, NULL) == S_OK)
893 return dmo_moniker_create(DMOCATEGORY_VIDEO_DECODER, clsid);
895 else
897 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
898 return dmo_moniker_create(enum_moniker->class, clsid);
901 return NULL;
904 static HRESULT WINAPI enum_moniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt,
905 ULONG *pceltFetched)
907 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
908 WCHAR buffer[MAX_PATH + 1];
909 struct moniker *moniker;
910 LONG res;
911 ULONG fetched = 0;
912 HKEY hkey;
914 TRACE("enumerator %p, count %lu, monikers %p, ret_count %p.\n", This, celt, rgelt, pceltFetched);
916 while (fetched < celt)
918 /* FIXME: try PNP devices first */
920 /* try DMOs */
921 if ((moniker = get_dmo_moniker(This)))
923 /* try DirectShow filters */
924 else if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, ARRAY_SIZE(buffer))))
926 This->sw_index++;
927 if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
928 break;
930 moniker = filter_moniker_create(&This->class, buffer);
932 /* then try codecs */
933 else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, ARRAY_SIZE(buffer))))
935 This->cm_index++;
937 if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
938 break;
940 moniker = codec_moniker_create(&This->class, buffer);
942 else
943 break;
945 if (!moniker)
946 return E_OUTOFMEMORY;
948 rgelt[fetched++] = &moniker->IMoniker_iface;
951 TRACE("Returning %lu monikers.\n", fetched);
953 if (pceltFetched)
954 *pceltFetched = fetched;
956 if (fetched != celt)
957 return S_FALSE;
958 else
959 return S_OK;
962 static HRESULT WINAPI enum_moniker_Skip(IEnumMoniker *iface, ULONG celt)
964 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
966 TRACE("enumerator %p, count %lu.\n", This, celt);
968 while (celt--)
970 /* FIXME: try PNP devices first */
972 /* try DMOs */
973 if (This->dmo_enum && IEnumDMO_Skip(This->dmo_enum, 1) == S_OK)
975 else if (This->dmo_enum2 && IEnumDMO_Skip(This->dmo_enum2, 1) == S_OK)
977 /* try DirectShow filters */
978 else if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
980 This->sw_index++;
982 /* then try codecs */
983 else if (RegEnumKeyW(This->cm_key, This->cm_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
985 This->cm_index++;
987 else
988 return S_FALSE;
991 return S_OK;
994 static HRESULT WINAPI enum_moniker_Reset(IEnumMoniker *iface)
996 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
998 TRACE("(%p)->()\n", iface);
1000 if (This->dmo_enum)
1001 IEnumDMO_Reset(This->dmo_enum);
1002 if (This->dmo_enum2)
1003 IEnumDMO_Reset(This->dmo_enum2);
1004 This->sw_index = 0;
1005 This->cm_index = 0;
1007 return S_OK;
1010 static HRESULT WINAPI enum_moniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum)
1012 FIXME("(%p)->(%p): stub\n", iface, ppenum);
1014 return E_NOTIMPL;
1017 /**********************************************************************
1018 * IEnumMoniker_Vtbl
1020 static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
1022 enum_moniker_QueryInterface,
1023 enum_moniker_AddRef,
1024 enum_moniker_Release,
1025 enum_moniker_Next,
1026 enum_moniker_Skip,
1027 enum_moniker_Reset,
1028 enum_moniker_Clone,
1031 HRESULT enum_moniker_create(REFCLSID class, IEnumMoniker **out)
1033 EnumMonikerImpl *object;
1034 WCHAR buffer[78];
1036 if (!(object = calloc(1, sizeof(*object))))
1037 return E_OUTOFMEMORY;
1039 object->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
1040 object->ref = 1;
1041 object->class = *class;
1043 wcscpy(buffer, L"CLSID\\");
1044 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1045 wcscat(buffer, L"\\Instance");
1046 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->sw_key))
1047 object->sw_key = NULL;
1049 wcscpy(buffer, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
1050 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1051 if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->cm_key))
1052 object->cm_key = NULL;
1054 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory))
1056 if (FAILED(DMOEnum(&DMOCATEGORY_AUDIO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1057 object->dmo_enum = NULL;
1058 if (FAILED(DMOEnum(&DMOCATEGORY_VIDEO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum2)))
1059 object->dmo_enum2 = NULL;
1061 else
1063 if (FAILED(DMOEnum(class, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1064 object->dmo_enum = NULL;
1067 *out = &object->IEnumMoniker_iface;
1069 return S_OK;