ntdll: Make the open_hkcu_key() helper available globally.
[wine/zf.git] / dlls / devenum / mediacatenum.c
blobf097c580261cad27c5c83daea000805eb64a74ed
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 unsigned int count = 1, input_count, output_count, i;
141 DMO_PARTIAL_MEDIATYPE *types = NULL, *new_array;
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 %#x.\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 *This = impl_from_IMoniker(iface);
400 ULONG ref = InterlockedIncrement(&This->ref);
402 TRACE("(%p) ref=%d\n", This, ref);
404 return ref;
407 static ULONG WINAPI moniker_Release(IMoniker *iface)
409 struct moniker *This = impl_from_IMoniker(iface);
410 ULONG ref = InterlockedDecrement(&This->ref);
412 TRACE("(%p) ref=%d\n", This, ref);
414 if (ref == 0) {
415 free(This->name);
416 free(This);
417 DEVENUM_UnlockModule();
419 return ref;
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 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
564 if (ppmkToLeft)
565 *ppmkToLeft = NULL;
566 *ppmkReduced = iface;
568 return MK_S_REDUCED_TO_SELF;
571 static HRESULT WINAPI moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
572 BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
574 FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
576 /* FIXME: use CreateGenericComposite? */
577 *ppmkComposite = NULL;
579 return E_NOTIMPL;
582 static HRESULT WINAPI moniker_Enum(IMoniker *iface, BOOL fForward,
583 IEnumMoniker **ppenumMoniker)
585 FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker);
587 *ppenumMoniker = NULL;
589 return S_OK;
592 static HRESULT WINAPI moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
594 CLSID clsid;
595 LPOLESTR this_name, other_name;
596 IBindCtx *bind;
597 HRESULT res;
599 TRACE("(%p)->(%p)\n", iface, pmkOtherMoniker);
601 if (!pmkOtherMoniker)
602 return E_INVALIDARG;
604 IMoniker_GetClassID(pmkOtherMoniker, &clsid);
605 if (!IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker))
606 return S_FALSE;
608 res = CreateBindCtx(0, &bind);
609 if (FAILED(res))
610 return res;
612 res = S_FALSE;
613 if (SUCCEEDED(IMoniker_GetDisplayName(iface, bind, NULL, &this_name)) &&
614 SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker, bind, NULL, &other_name)))
616 int result = wcsicmp(this_name, other_name);
617 CoTaskMemFree(this_name);
618 CoTaskMemFree(other_name);
619 if (!result)
620 res = S_OK;
622 IBindCtx_Release(bind);
623 return res;
626 static HRESULT WINAPI moniker_Hash(IMoniker *iface, DWORD *pdwHash)
628 TRACE("(%p)->(%p)\n", iface, pdwHash);
630 *pdwHash = 0;
632 return S_OK;
635 static HRESULT WINAPI moniker_IsRunning(IMoniker *iface, IBindCtx *pbc,
636 IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
638 FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning);
640 return S_FALSE;
643 static HRESULT WINAPI moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
644 IMoniker *pmkToLeft, FILETIME *pFileTime)
646 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime);
648 pFileTime->dwLowDateTime = 0xFFFFFFFF;
649 pFileTime->dwHighDateTime = 0x7FFFFFFF;
651 return MK_E_UNAVAILABLE;
654 static HRESULT WINAPI moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
656 TRACE("(%p)->(%p)\n", iface, ppmk);
658 *ppmk = NULL;
660 return MK_E_NOINVERSE;
663 static HRESULT WINAPI moniker_CommonPrefixWith(IMoniker *iface,
664 IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix)
666 TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix);
668 *ppmkPrefix = NULL;
670 return MK_E_NOPREFIX;
673 static HRESULT WINAPI moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
674 IMoniker **ppmkRelPath)
676 TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath);
678 *ppmkRelPath = pmkOther;
680 return MK_S_HIM;
683 static HRESULT WINAPI moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
684 IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
686 struct moniker *This = impl_from_IMoniker(iface);
687 WCHAR *buffer;
689 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
691 *ppszDisplayName = NULL;
693 if (This->type == DEVICE_DMO)
695 buffer = CoTaskMemAlloc((12 + 2 * CHARS_IN_GUID + 1) * sizeof(WCHAR));
696 if (!buffer) return E_OUTOFMEMORY;
698 wcscpy(buffer, L"@device:dmo:");
699 StringFromGUID2(&This->clsid, buffer + wcslen(buffer), CHARS_IN_GUID);
700 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
702 else
704 buffer = CoTaskMemAlloc((11 + (This->has_class ? CHARS_IN_GUID : 0)
705 + wcslen(This->name) + 1) * sizeof(WCHAR));
706 if (!buffer) return E_OUTOFMEMORY;
708 if (This->type == DEVICE_FILTER)
709 wcscpy(buffer, L"@device:sw:");
710 else if (This->type == DEVICE_CODEC)
711 wcscpy(buffer, L"@device:cm:");
713 if (This->has_class)
715 StringFromGUID2(&This->class, buffer + wcslen(buffer), CHARS_IN_GUID);
716 wcscat(buffer, L"\\");
718 wcscat(buffer, This->name);
721 *ppszDisplayName = buffer;
722 return S_OK;
725 static HRESULT WINAPI moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
726 IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
728 FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
730 *pchEaten = 0;
731 *ppmkOut = NULL;
733 return MK_E_SYNTAX;
736 static HRESULT WINAPI moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
738 TRACE("(%p)->(%p)\n", iface, pdwMksys);
740 return S_FALSE;
743 static const IMonikerVtbl IMoniker_Vtbl =
745 moniker_QueryInterface,
746 moniker_AddRef,
747 moniker_Release,
748 moniker_GetClassID,
749 moniker_IsDirty,
750 moniker_Load,
751 moniker_Save,
752 moniker_GetSizeMax,
753 moniker_BindToObject,
754 moniker_BindToStorage,
755 moniker_Reduce,
756 moniker_ComposeWith,
757 moniker_Enum,
758 moniker_IsEqual,
759 moniker_Hash,
760 moniker_IsRunning,
761 moniker_GetTimeOfLastChange,
762 moniker_Inverse,
763 moniker_CommonPrefixWith,
764 moniker_RelativePathTo,
765 moniker_GetDisplayName,
766 moniker_ParseDisplayName,
767 moniker_IsSystemMoniker,
770 struct moniker *filter_moniker_create(const GUID *class, const WCHAR *name)
772 struct moniker *object;
774 if (!(object = calloc(1, sizeof(*object))))
775 return NULL;
777 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
778 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
779 object->ref = 1;
780 object->type = DEVICE_FILTER;
781 if (class)
782 object->class = *class;
783 object->has_class = !!class;
784 object->name = wcsdup(name);
786 DEVENUM_LockModule();
788 return object;
791 struct moniker *codec_moniker_create(const GUID *class, const WCHAR *name)
793 struct moniker *object;
795 if (!(object = calloc(1, sizeof(*object))))
796 return NULL;
798 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
799 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
800 object->ref = 1;
801 object->type = DEVICE_CODEC;
802 if (class)
803 object->class = *class;
804 object->has_class = !!class;
805 object->name = wcsdup(name);
807 DEVENUM_LockModule();
809 return object;
812 struct moniker *dmo_moniker_create(const GUID class, const GUID clsid)
814 struct moniker *object;
816 if (!(object = calloc(1, sizeof(*object))))
817 return NULL;
819 object->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
820 object->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
821 object->ref = 1;
822 object->type = DEVICE_DMO;
823 object->class = class;
824 object->clsid = clsid;
826 DEVENUM_LockModule();
828 return object;
831 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
833 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
836 static HRESULT WINAPI enum_moniker_QueryInterface(IEnumMoniker *iface, REFIID riid, void **ppv)
838 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
840 if (!ppv)
841 return E_POINTER;
843 if (IsEqualGUID(riid, &IID_IUnknown) ||
844 IsEqualGUID(riid, &IID_IEnumMoniker))
846 *ppv = iface;
847 IEnumMoniker_AddRef(iface);
848 return S_OK;
851 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
852 *ppv = NULL;
853 return E_NOINTERFACE;
856 static ULONG WINAPI enum_moniker_AddRef(IEnumMoniker *iface)
858 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
859 ULONG ref = InterlockedIncrement(&This->ref);
861 TRACE("(%p) ref=%d\n", This, ref);
863 return ref;
866 static ULONG WINAPI enum_moniker_Release(IEnumMoniker *iface)
868 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
869 ULONG ref = InterlockedDecrement(&This->ref);
871 TRACE("(%p) ref=%d\n", This, ref);
873 if (!ref)
875 if (This->dmo_enum)
876 IEnumDMO_Release(This->dmo_enum);
877 if (This->dmo_enum2)
878 IEnumDMO_Release(This->dmo_enum2);
879 RegCloseKey(This->sw_key);
880 RegCloseKey(This->cm_key);
881 free(This);
882 DEVENUM_UnlockModule();
883 return 0;
885 return ref;
888 static struct moniker *get_dmo_moniker(EnumMonikerImpl *enum_moniker)
890 GUID clsid;
892 if (IsEqualGUID(&enum_moniker->class, &CLSID_LegacyAmFilterCategory))
894 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
895 return dmo_moniker_create(DMOCATEGORY_AUDIO_DECODER, clsid);
896 if (enum_moniker->dmo_enum2 && IEnumDMO_Next(enum_moniker->dmo_enum2, 1, &clsid, NULL, NULL) == S_OK)
897 return dmo_moniker_create(DMOCATEGORY_VIDEO_DECODER, clsid);
899 else
901 if (enum_moniker->dmo_enum && IEnumDMO_Next(enum_moniker->dmo_enum, 1, &clsid, NULL, NULL) == S_OK)
902 return dmo_moniker_create(enum_moniker->class, clsid);
905 return NULL;
908 static HRESULT WINAPI enum_moniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt,
909 ULONG *pceltFetched)
911 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
912 WCHAR buffer[MAX_PATH + 1];
913 struct moniker *moniker;
914 LONG res;
915 ULONG fetched = 0;
916 HKEY hkey;
918 TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
920 while (fetched < celt)
922 /* FIXME: try PNP devices first */
924 /* try DMOs */
925 if ((moniker = get_dmo_moniker(This)))
927 /* try DirectShow filters */
928 else if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, ARRAY_SIZE(buffer))))
930 This->sw_index++;
931 if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
932 break;
934 moniker = filter_moniker_create(&This->class, buffer);
936 /* then try codecs */
937 else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, ARRAY_SIZE(buffer))))
939 This->cm_index++;
941 if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
942 break;
944 moniker = codec_moniker_create(&This->class, buffer);
946 else
947 break;
949 if (!moniker)
950 return E_OUTOFMEMORY;
952 rgelt[fetched++] = &moniker->IMoniker_iface;
955 TRACE("-- fetched %d\n", fetched);
957 if (pceltFetched)
958 *pceltFetched = fetched;
960 if (fetched != celt)
961 return S_FALSE;
962 else
963 return S_OK;
966 static HRESULT WINAPI enum_moniker_Skip(IEnumMoniker *iface, ULONG celt)
968 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
970 TRACE("(%p)->(%d)\n", iface, celt);
972 while (celt--)
974 /* FIXME: try PNP devices first */
976 /* try DMOs */
977 if (This->dmo_enum && IEnumDMO_Skip(This->dmo_enum, 1) == S_OK)
979 else if (This->dmo_enum2 && IEnumDMO_Skip(This->dmo_enum2, 1) == S_OK)
981 /* try DirectShow filters */
982 else if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
984 This->sw_index++;
986 /* then try codecs */
987 else if (RegEnumKeyW(This->cm_key, This->cm_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
989 This->cm_index++;
991 else
992 return S_FALSE;
995 return S_OK;
998 static HRESULT WINAPI enum_moniker_Reset(IEnumMoniker *iface)
1000 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1002 TRACE("(%p)->()\n", iface);
1004 if (This->dmo_enum)
1005 IEnumDMO_Reset(This->dmo_enum);
1006 if (This->dmo_enum2)
1007 IEnumDMO_Reset(This->dmo_enum2);
1008 This->sw_index = 0;
1009 This->cm_index = 0;
1011 return S_OK;
1014 static HRESULT WINAPI enum_moniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum)
1016 FIXME("(%p)->(%p): stub\n", iface, ppenum);
1018 return E_NOTIMPL;
1021 /**********************************************************************
1022 * IEnumMoniker_Vtbl
1024 static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
1026 enum_moniker_QueryInterface,
1027 enum_moniker_AddRef,
1028 enum_moniker_Release,
1029 enum_moniker_Next,
1030 enum_moniker_Skip,
1031 enum_moniker_Reset,
1032 enum_moniker_Clone,
1035 HRESULT enum_moniker_create(REFCLSID class, IEnumMoniker **out)
1037 EnumMonikerImpl *object;
1038 WCHAR buffer[78];
1040 if (!(object = calloc(1, sizeof(*object))))
1041 return E_OUTOFMEMORY;
1043 object->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
1044 object->ref = 1;
1045 object->class = *class;
1047 wcscpy(buffer, L"CLSID\\");
1048 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1049 wcscat(buffer, L"\\Instance");
1050 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->sw_key))
1051 object->sw_key = NULL;
1053 wcscpy(buffer, L"Software\\Microsoft\\ActiveMovie\\devenum\\");
1054 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
1055 if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &object->cm_key))
1056 object->cm_key = NULL;
1058 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory))
1060 if (FAILED(DMOEnum(&DMOCATEGORY_AUDIO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1061 object->dmo_enum = NULL;
1062 if (FAILED(DMOEnum(&DMOCATEGORY_VIDEO_DECODER, 0, 0, NULL, 0, NULL, &object->dmo_enum2)))
1063 object->dmo_enum2 = NULL;
1065 else
1067 if (FAILED(DMOEnum(class, 0, 0, NULL, 0, NULL, &object->dmo_enum)))
1068 object->dmo_enum = NULL;
1071 *out = &object->IEnumMoniker_iface;
1073 DEVENUM_LockModule();
1075 return S_OK;