Release 9.12.
[wine.git] / dlls / devenum / mediacatenum.c
blob906d01b20576acb7dfa717c55deab3beb0c48b43
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 switch (moniker->type)
129 case DEVICE_DMO:
130 if (!wcscmp(name, L"FriendlyName"))
132 if (SUCCEEDED(hr = DMOGetName(&moniker->clsid, dmo_name)))
134 V_VT(var) = VT_BSTR;
135 V_BSTR(var) = SysAllocString(dmo_name);
137 return hr;
139 if (!wcscmp(name, L"FilterData"))
141 DMO_PARTIAL_MEDIATYPE *types = NULL, *new_array;
142 ULONG count = 1, input_count, output_count, i;
143 REGFILTERPINS2 reg_pins[2] = {{0}};
144 REGFILTER2 reg_filter = {0};
145 REGPINTYPES *reg_types;
146 HRESULT hr;
150 count *= 2;
151 if (!(new_array = realloc(types, 2 * count * sizeof(*types))))
153 free(types);
154 return E_OUTOFMEMORY;
156 types = new_array;
158 if (FAILED(hr = DMOGetTypes(&moniker->clsid, count, &input_count, types,
159 count, &output_count, types + count)))
161 free(types);
162 return hr;
164 } while (input_count == count || output_count == count);
166 if (!(reg_types = malloc(2 * count * sizeof(*reg_types))))
168 free(types);
169 return hr;
172 for (i = 0; i < input_count; ++i)
174 reg_types[i].clsMajorType = &types[i].type;
175 reg_types[i].clsMinorType = &types[i].subtype;
177 for (i = 0; i < output_count; ++i)
179 reg_types[count + i].clsMajorType = &types[count + i].type;
180 reg_types[count + i].clsMinorType = &types[count + i].subtype;
182 reg_pins[0].cInstances = 1;
183 reg_pins[0].nMediaTypes = input_count;
184 reg_pins[0].lpMediaType = reg_types;
185 reg_pins[1].dwFlags = REG_PINFLAG_B_OUTPUT;
186 reg_pins[1].cInstances = 1;
187 reg_pins[1].nMediaTypes = output_count;
188 reg_pins[1].lpMediaType = reg_types + count;
189 reg_filter.dwVersion = 2;
190 reg_filter.dwMerit = MERIT_NORMAL + 0x800;
191 reg_filter.cPins2 = 2;
192 reg_filter.rgPins2 = reg_pins;
194 hr = create_filter_data(var, &reg_filter);
195 free(reg_types);
196 free(types);
197 return hr;
199 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
201 case DEVICE_FILTER:
202 wcscpy(path, L"CLSID\\");
203 if (moniker->has_class)
205 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
206 wcscat(path, L"\\Instance");
208 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, 0, &parent)))
209 return HRESULT_FROM_WIN32(ret);
210 break;
212 case DEVICE_CODEC:
213 wcscpy(path, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
214 if (moniker->has_class)
215 StringFromGUID2(&moniker->class, path + wcslen(path), CHARS_IN_GUID);
216 if ((ret = RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, 0, &parent)))
217 return HRESULT_FROM_WIN32(ret);
218 break;
220 DEFAULT_UNREACHABLE;
223 ret = RegOpenKeyExW(parent, moniker->name, 0, KEY_READ, &key);
224 RegCloseKey(parent);
225 if (ret)
226 return HRESULT_FROM_WIN32(ret);
228 if ((ret = RegQueryValueExW(key, name, NULL, NULL, NULL, &size)))
230 RegCloseKey(key);
231 return HRESULT_FROM_WIN32(ret);
234 data = malloc(size);
235 if ((ret = RegQueryValueExW(key, name, NULL, &type, data, &size)))
237 RegCloseKey(key);
238 free(data);
239 return HRESULT_FROM_WIN32(ret);
241 RegCloseKey(key);
243 switch (type)
245 case REG_SZ:
246 if (V_VT(var) == VT_EMPTY)
247 V_VT(var) = VT_BSTR;
248 if (V_VT(var) != VT_BSTR)
250 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
251 return E_INVALIDARG;
253 V_BSTR(var) = SysAllocStringLen(data, size / sizeof(WCHAR) - 1);
254 free(data);
255 return S_OK;
256 case REG_DWORD:
257 if (V_VT(var) == VT_EMPTY)
258 V_VT(var) = VT_I4;
259 if (V_VT(var) != VT_I4)
261 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
262 return E_INVALIDARG;
264 V_I4(var) = *(DWORD *)data;
265 free(data);
266 return S_OK;
267 case REG_BINARY:
269 SAFEARRAYBOUND bound = {.cElements = size};
270 void *array_data;
272 if (V_VT(var) == VT_EMPTY)
273 V_VT(var) = VT_ARRAY | VT_UI1;
274 if (V_VT(var) != (VT_ARRAY | VT_UI1))
276 WARN("Invalid type %s.\n", debugstr_vt(V_VT(var)));
277 return E_INVALIDARG;
280 if (!(V_ARRAY(var) = SafeArrayCreate(VT_UI1, 1, &bound)))
282 free(data);
283 return E_OUTOFMEMORY;
286 SafeArrayAccessData(V_ARRAY(var), &array_data);
287 memcpy(array_data, data, size);
288 SafeArrayUnaccessData(V_ARRAY(var));
289 free(data);
290 return S_OK;
292 default:
293 FIXME("Unhandled type %#lx.\n", type);
294 free(data);
295 return E_NOTIMPL;
299 static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *name, VARIANT *var)
301 struct moniker *moniker = impl_from_IPropertyBag(iface);
302 HKEY parent, key;
303 WCHAR path[78];
304 LONG ret;
306 TRACE("moniker %p, name %s, var %s.\n", moniker, debugstr_w(name), debugstr_variant(var));
308 switch (moniker->type)
310 case DEVICE_DMO:
311 return E_ACCESSDENIED;
313 case 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);
322 break;
324 case 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);
330 break;
332 DEFAULT_UNREACHABLE;
334 ret = RegCreateKeyExW(parent, moniker->name, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL);
335 RegCloseKey(parent);
336 if (ret)
337 return HRESULT_FROM_WIN32(ret);
339 switch (V_VT(var))
341 case VT_BSTR:
342 ret = RegSetValueExW(key, name, 0, REG_SZ, (BYTE *)V_BSTR(var),
343 (wcslen(V_BSTR(var)) + 1) * sizeof(WCHAR));
344 break;
345 case VT_I4:
346 ret = RegSetValueExW(key, name, 0, REG_DWORD, (BYTE *)&V_I4(var), sizeof(DWORD));
347 break;
348 case VT_ARRAY | VT_UI1:
350 LONG lbound, ubound;
351 void *array_data;
352 SafeArrayGetLBound(V_ARRAY(var), 1, &lbound);
353 SafeArrayGetUBound(V_ARRAY(var), 1, &ubound);
354 SafeArrayAccessData(V_ARRAY(var), &array_data);
355 ret = RegSetValueExW(key, name, 0, REG_BINARY, array_data, ubound - lbound + 1);
356 SafeArrayUnaccessData(V_ARRAY(var));
357 break;
359 default:
360 WARN("Unhandled type %s.\n", debugstr_vt(V_VT(var)));
361 return E_INVALIDARG;
364 RegCloseKey(key);
365 return S_OK;
368 static const IPropertyBagVtbl IPropertyBag_Vtbl =
370 property_bag_QueryInterface,
371 property_bag_AddRef,
372 property_bag_Release,
373 property_bag_Read,
374 property_bag_Write,
377 static inline struct moniker *impl_from_IMoniker(IMoniker *iface)
379 return CONTAINING_RECORD(iface, struct moniker, IMoniker_iface);
382 static HRESULT WINAPI moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
384 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
386 if (!ppv)
387 return E_POINTER;
389 if (IsEqualGUID(riid, &IID_IUnknown) ||
390 IsEqualGUID(riid, &IID_IPersist) ||
391 IsEqualGUID(riid, &IID_IPersistStream) ||
392 IsEqualGUID(riid, &IID_IMoniker))
394 *ppv = iface;
395 IMoniker_AddRef(iface);
396 return S_OK;
399 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
400 *ppv = NULL;
401 return E_NOINTERFACE;
404 static ULONG WINAPI moniker_AddRef(IMoniker *iface)
406 struct moniker *moniker = impl_from_IMoniker(iface);
407 ULONG refcount = InterlockedIncrement(&moniker->ref);
409 TRACE("%p increasing refcount to %lu.\n", moniker, refcount);
411 return refcount;
414 static ULONG WINAPI moniker_Release(IMoniker *iface)
416 struct moniker *This = impl_from_IMoniker(iface);
417 ULONG refcount = InterlockedDecrement(&This->ref);
419 TRACE("%p decreasing refcount to %lu.\n", This, refcount);
421 if (!refcount)
423 free(This->name);
424 free(This);
426 return refcount;
429 static HRESULT WINAPI moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
431 struct moniker *This = impl_from_IMoniker(iface);
433 TRACE("(%p)->(%p)\n", This, pClassID);
435 if (pClassID == NULL)
436 return E_INVALIDARG;
438 *pClassID = CLSID_CDeviceMoniker;
440 return S_OK;
443 static HRESULT WINAPI moniker_IsDirty(IMoniker *iface)
445 FIXME("(%p)->(): stub\n", iface);
447 return S_FALSE;
450 static HRESULT WINAPI moniker_Load(IMoniker *iface, IStream *pStm)
452 FIXME("(%p)->(%p): stub\n", iface, pStm);
454 return E_NOTIMPL;
457 static HRESULT WINAPI moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
459 FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false");
461 return STG_E_CANTSAVE;
464 static HRESULT WINAPI moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
466 FIXME("(%p)->(%p): stub\n", iface, pcbSize);
468 ZeroMemory(pcbSize, sizeof(*pcbSize));
470 return S_OK;
473 static HRESULT WINAPI moniker_BindToObject(IMoniker *iface, IBindCtx *bind_ctx,
474 IMoniker *left, REFIID iid, void **out)
476 struct moniker *moniker = impl_from_IMoniker(iface);
477 IPersistPropertyBag *persist_bag;
478 IUnknown *unk;
479 CLSID clsid;
480 VARIANT var;
481 HRESULT hr;
483 TRACE("moniker %p, bind_ctx %p, left %p, iid %s, out %p.\n",
484 moniker, bind_ctx, left, debugstr_guid(iid), out);
486 if (!out)
487 return E_POINTER;
489 *out = NULL;
491 if (moniker->type == DEVICE_DMO)
493 IDMOWrapperFilter *wrapper;
495 if (FAILED(hr = CoCreateInstance(&CLSID_DMOWrapperFilter, NULL,
496 CLSCTX_INPROC_SERVER, &IID_IDMOWrapperFilter, (void **)&wrapper)))
497 return hr;
499 if (SUCCEEDED(hr = IDMOWrapperFilter_Init(wrapper, &moniker->clsid, &moniker->class)))
501 hr = IDMOWrapperFilter_QueryInterface(wrapper, iid, out);
503 IDMOWrapperFilter_Release(wrapper);
504 return hr;
507 VariantInit(&var);
508 V_VT(&var) = VT_BSTR;
509 if (FAILED(hr = IPropertyBag_Read(&moniker->IPropertyBag_iface, L"CLSID", &var, NULL)))
510 return hr;
512 hr = CLSIDFromString(V_BSTR(&var), &clsid);
513 VariantClear(&var);
514 if (FAILED(hr))
515 return hr;
517 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_ALL, &IID_IUnknown, (void **)&unk)))
518 return hr;
520 if (SUCCEEDED(IUnknown_QueryInterface(unk, &IID_IPersistPropertyBag, (void **)&persist_bag)))
522 hr = IPersistPropertyBag_Load(persist_bag, &moniker->IPropertyBag_iface, NULL);
523 IPersistPropertyBag_Release(persist_bag);
526 if (SUCCEEDED(hr))
527 hr = IUnknown_QueryInterface(unk, iid, out);
529 IUnknown_Release(unk);
531 return hr;
534 static HRESULT WINAPI moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc,
535 IMoniker *pmkToLeft, REFIID riid, void **out)
537 struct moniker *moniker = impl_from_IMoniker(iface);
539 TRACE("moniker %p, left %p, iid %s, out %p.\n", moniker, pmkToLeft, debugstr_guid(riid), out);
541 *out = NULL;
543 if (pmkToLeft)
544 return MK_E_NOSTORAGE;
546 if (pbc != NULL)
548 static DWORD reported;
549 if (!reported)
551 FIXME("ignoring IBindCtx %p\n", pbc);
552 reported++;
556 if (IsEqualGUID(riid, &IID_IPropertyBag))
558 *out = &moniker->IPropertyBag_iface;
559 IPropertyBag_AddRef(&moniker->IPropertyBag_iface);
560 return S_OK;
563 return MK_E_NOSTORAGE;
566 static HRESULT WINAPI moniker_Reduce(IMoniker *iface, IBindCtx *pbc,
567 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
569 struct moniker *moniker = impl_from_IMoniker(iface);
571 TRACE("moniker %p, bind_ctx %p, how_far %#lx, left %p, reduced %p.\n",
572 moniker, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
574 if (ppmkToLeft)
575 *ppmkToLeft = NULL;
576 *ppmkReduced = iface;
578 return MK_S_REDUCED_TO_SELF;
581 static HRESULT WINAPI moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
582 BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
584 FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
586 /* FIXME: use CreateGenericComposite? */
587 *ppmkComposite = NULL;
589 return E_NOTIMPL;
592 static HRESULT WINAPI moniker_Enum(IMoniker *iface, BOOL fForward,
593 IEnumMoniker **ppenumMoniker)
595 FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker);
597 *ppenumMoniker = NULL;
599 return S_OK;
602 static HRESULT WINAPI moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
604 CLSID clsid;
605 LPOLESTR this_name, other_name;
606 IBindCtx *bind;
607 HRESULT res;
609 TRACE("(%p)->(%p)\n", iface, pmkOtherMoniker);
611 if (!pmkOtherMoniker)
612 return E_INVALIDARG;
614 IMoniker_GetClassID(pmkOtherMoniker, &clsid);
615 if (!IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker))
616 return S_FALSE;
618 res = CreateBindCtx(0, &bind);
619 if (FAILED(res))
620 return res;
622 res = S_FALSE;
623 if (SUCCEEDED(IMoniker_GetDisplayName(iface, bind, NULL, &this_name)) &&
624 SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker, bind, NULL, &other_name)))
626 int result = wcsicmp(this_name, other_name);
627 CoTaskMemFree(this_name);
628 CoTaskMemFree(other_name);
629 if (!result)
630 res = S_OK;
632 IBindCtx_Release(bind);
633 return res;
636 static HRESULT WINAPI moniker_Hash(IMoniker *iface, DWORD *pdwHash)
638 TRACE("(%p)->(%p)\n", iface, pdwHash);
640 *pdwHash = 0;
642 return S_OK;
645 static HRESULT WINAPI moniker_IsRunning(IMoniker *iface, IBindCtx *pbc,
646 IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
648 FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning);
650 return S_FALSE;
653 static HRESULT WINAPI moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
654 IMoniker *pmkToLeft, FILETIME *pFileTime)
656 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime);
658 pFileTime->dwLowDateTime = 0xFFFFFFFF;
659 pFileTime->dwHighDateTime = 0x7FFFFFFF;
661 return MK_E_UNAVAILABLE;
664 static HRESULT WINAPI moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
666 TRACE("(%p)->(%p)\n", iface, ppmk);
668 *ppmk = NULL;
670 return MK_E_NOINVERSE;
673 static HRESULT WINAPI moniker_CommonPrefixWith(IMoniker *iface,
674 IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix)
676 TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix);
678 *ppmkPrefix = NULL;
680 return MK_E_NOPREFIX;
683 static HRESULT WINAPI moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
684 IMoniker **ppmkRelPath)
686 TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath);
688 *ppmkRelPath = pmkOther;
690 return MK_S_HIM;
693 static HRESULT WINAPI moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
694 IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
696 struct moniker *This = impl_from_IMoniker(iface);
697 WCHAR *buffer;
699 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
701 *ppszDisplayName = NULL;
703 if (This->type == DEVICE_DMO)
705 buffer = CoTaskMemAlloc((12 + 2 * CHARS_IN_GUID + 1) * sizeof(WCHAR));
706 if (!buffer) return E_OUTOFMEMORY;
708 wcscpy(buffer, L"@device:dmo:");
709 StringFromGUID2(&This->clsid, buffer + wcslen(buffer), CHARS_IN_GUID);
710 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
712 else
714 buffer = CoTaskMemAlloc((11 + (This->has_class ? CHARS_IN_GUID : 0)
715 + wcslen(This->name) + 1) * sizeof(WCHAR));
716 if (!buffer) return E_OUTOFMEMORY;
718 if (This->type == DEVICE_FILTER)
719 wcscpy(buffer, L"@device:sw:");
720 else if (This->type == DEVICE_CODEC)
721 wcscpy(buffer, L"@device:cm:");
723 if (This->has_class)
725 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
726 wcscat(buffer, L"\\");
728 wcscat(buffer, This->name);
731 *ppszDisplayName = buffer;
732 return S_OK;
735 static HRESULT WINAPI moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
736 IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
738 FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
740 *pchEaten = 0;
741 *ppmkOut = NULL;
743 return MK_E_SYNTAX;
746 static HRESULT WINAPI moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
748 TRACE("(%p)->(%p)\n", iface, pdwMksys);
750 return S_FALSE;
753 static const IMonikerVtbl IMoniker_Vtbl =
755 moniker_QueryInterface,
756 moniker_AddRef,
757 moniker_Release,
758 moniker_GetClassID,
759 moniker_IsDirty,
760 moniker_Load,
761 moniker_Save,
762 moniker_GetSizeMax,
763 moniker_BindToObject,
764 moniker_BindToStorage,
765 moniker_Reduce,
766 moniker_ComposeWith,
767 moniker_Enum,
768 moniker_IsEqual,
769 moniker_Hash,
770 moniker_IsRunning,
771 moniker_GetTimeOfLastChange,
772 moniker_Inverse,
773 moniker_CommonPrefixWith,
774 moniker_RelativePathTo,
775 moniker_GetDisplayName,
776 moniker_ParseDisplayName,
777 moniker_IsSystemMoniker,
780 struct moniker *filter_moniker_create(const GUID *class, const WCHAR *name)
782 struct moniker *object;
784 if (!(object = calloc(1, sizeof(*object))))
785 return NULL;
787 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
788 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
789 object->ref = 1;
790 object->type = DEVICE_FILTER;
791 if (class)
792 object->class = *class;
793 object->has_class = !!class;
794 object->name = wcsdup(name);
796 return object;
799 struct moniker *codec_moniker_create(const GUID *class, const WCHAR *name)
801 struct moniker *object;
803 if (!(object = calloc(1, sizeof(*object))))
804 return NULL;
806 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
807 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
808 object->ref = 1;
809 object->type = DEVICE_CODEC;
810 if (class)
811 object->class = *class;
812 object->has_class = !!class;
813 object->name = wcsdup(name);
815 return object;
818 struct moniker *dmo_moniker_create(const GUID class, const GUID clsid)
820 struct moniker *object;
822 if (!(object = calloc(1, sizeof(*object))))
823 return NULL;
825 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
826 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
827 object->ref = 1;
828 object->type = DEVICE_DMO;
829 object->class = class;
830 object->clsid = clsid;
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 *enumerator = impl_from_IEnumMoniker(iface);
863 ULONG refcount = InterlockedIncrement(&enumerator->ref);
865 TRACE("%p increasing refcount to %lu.\n", enumerator, refcount);
867 return refcount;
870 static ULONG WINAPI enum_moniker_Release(IEnumMoniker *iface)
872 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
873 ULONG refcount = InterlockedDecrement(&This->ref);
875 TRACE("%p decreasing refcount to %lu.\n", This, refcount);
877 if (!refcount)
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 return 0;
888 return refcount;
891 static struct moniker *get_dmo_moniker(EnumMonikerImpl *enum_moniker)
893 GUID clsid;
895 if (IsEqualGUID(&enum_moniker->class, &CLSID_LegacyAmFilterCategory))
897 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
898 return dmo_moniker_create(DMOCATEGORY_AUDIO_DECODER, clsid);
899 if (enum_moniker->dmo_enum2 && IEnumDMO_Next(enum_moniker->dmo_enum2, 1, &clsid, NULL, NULL) == S_OK)
900 return dmo_moniker_create(DMOCATEGORY_VIDEO_DECODER, clsid);
902 else
904 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
905 return dmo_moniker_create(enum_moniker->class, clsid);
908 return NULL;
911 static HRESULT WINAPI enum_moniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt,
912 ULONG *pceltFetched)
914 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
915 WCHAR buffer[MAX_PATH + 1];
916 struct moniker *moniker;
917 LONG res;
918 ULONG fetched = 0;
919 HKEY hkey;
921 TRACE("enumerator %p, count %lu, monikers %p, ret_count %p.\n", This, celt, rgelt, pceltFetched);
923 while (fetched < celt)
925 /* FIXME: try PNP devices first */
927 /* try DMOs */
928 if ((moniker = get_dmo_moniker(This)))
930 /* try DirectShow filters */
931 else if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, ARRAY_SIZE(buffer))))
933 This->sw_index++;
934 if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
935 break;
937 moniker = filter_moniker_create(&This->class, buffer);
939 /* then try codecs */
940 else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, ARRAY_SIZE(buffer))))
942 This->cm_index++;
944 if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
945 break;
947 moniker = codec_moniker_create(&This->class, buffer);
949 else
950 break;
952 if (!moniker)
953 return E_OUTOFMEMORY;
955 rgelt[fetched++] = &moniker->IMoniker_iface;
958 TRACE("Returning %lu monikers.\n", fetched);
960 if (pceltFetched)
961 *pceltFetched = fetched;
963 if (fetched != celt)
964 return S_FALSE;
965 else
966 return S_OK;
969 static HRESULT WINAPI enum_moniker_Skip(IEnumMoniker *iface, ULONG celt)
971 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
973 TRACE("enumerator %p, count %lu.\n", This, celt);
975 while (celt--)
977 /* FIXME: try PNP devices first */
979 /* try DMOs */
980 if (This->dmo_enum && IEnumDMO_Skip(This->dmo_enum, 1) == S_OK)
982 else if (This->dmo_enum2 && IEnumDMO_Skip(This->dmo_enum2, 1) == S_OK)
984 /* try DirectShow filters */
985 else if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
987 This->sw_index++;
989 /* then try codecs */
990 else if (RegEnumKeyW(This->cm_key, This->cm_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
992 This->cm_index++;
994 else
995 return S_FALSE;
998 return S_OK;
1001 static HRESULT WINAPI enum_moniker_Reset(IEnumMoniker *iface)
1003 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1005 TRACE("(%p)->()\n", iface);
1007 if (This->dmo_enum)
1008 IEnumDMO_Reset(This->dmo_enum);
1009 if (This->dmo_enum2)
1010 IEnumDMO_Reset(This->dmo_enum2);
1011 This->sw_index = 0;
1012 This->cm_index = 0;
1014 return S_OK;
1017 static HRESULT WINAPI enum_moniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum)
1019 FIXME("(%p)->(%p): stub\n", iface, ppenum);
1021 return E_NOTIMPL;
1024 /**********************************************************************
1025 * IEnumMoniker_Vtbl
1027 static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
1029 enum_moniker_QueryInterface,
1030 enum_moniker_AddRef,
1031 enum_moniker_Release,
1032 enum_moniker_Next,
1033 enum_moniker_Skip,
1034 enum_moniker_Reset,
1035 enum_moniker_Clone,
1038 HRESULT enum_moniker_create(REFCLSID class, IEnumMoniker **out)
1040 EnumMonikerImpl *object;
1041 WCHAR buffer[78];
1043 if (!(object = calloc(1, sizeof(*object))))
1044 return E_OUTOFMEMORY;
1046 object->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
1047 object->ref = 1;
1048 object->class = *class;
1050 wcscpy(buffer, L"CLSID\\");
1051 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1052 wcscat(buffer, L"\\Instance");
1053 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->sw_key))
1054 object->sw_key = NULL;
1056 wcscpy(buffer, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
1057 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1058 if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->cm_key))
1059 object->cm_key = NULL;
1061 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory))
1063 if (FAILED(DMOEnum(&DMOCATEGORY_AUDIO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1064 object->dmo_enum = NULL;
1065 if (FAILED(DMOEnum(&DMOCATEGORY_VIDEO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum2)))
1066 object->dmo_enum2 = NULL;
1068 else
1070 if (FAILED(DMOEnum(class, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1071 object->dmo_enum = NULL;
1074 *out = &object->IEnumMoniker_iface;
1076 return S_OK;