quartz: Always return S_FALSE from DllCanUnloadNow().
[wine.git] / dlls / quartz / filtermapper.c
blob230273891d45f350ef8393c1fa7e6fec4e9bf803
1 /*
2 * IFilterMapper & IFilterMapper3 Implementations
4 * Copyright 2003 Robert Shearman
5 * Copyright 2004 Christian Costa
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
32 #include "quartz_private.h"
34 #include "ole2.h"
35 #include "olectl.h"
36 #include "strmif.h"
37 #include "uuids.h"
38 #include "initguid.h"
39 #include "wine/fil_data.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45 struct enum_reg_filters
47 IEnumRegFilters IEnumRegFilters_iface;
48 LONG refcount;
50 unsigned int index, count;
51 REGFILTER *filters;
54 static struct enum_reg_filters *impl_from_IEnumRegFilters(IEnumRegFilters *iface)
56 return CONTAINING_RECORD(iface, struct enum_reg_filters, IEnumRegFilters_iface);
59 static HRESULT WINAPI enum_reg_filters_QueryInterface(IEnumRegFilters *iface, REFIID iid, void **out)
61 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
63 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumRegFilters))
65 IEnumRegFilters_AddRef(iface);
66 *out = iface;
67 return S_OK;
70 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
71 *out = NULL;
72 return E_NOINTERFACE;
75 static ULONG WINAPI enum_reg_filters_AddRef(IEnumRegFilters *iface)
77 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
78 ULONG refcount = InterlockedIncrement(&enumerator->refcount);
79 TRACE("%p increasing refcount to %u.\n", enumerator, refcount);
80 return refcount;
83 static ULONG WINAPI enum_reg_filters_Release(IEnumRegFilters *iface)
85 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
86 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
87 unsigned int i;
89 TRACE("%p decreasing refcount to %u.\n", enumerator, refcount);
90 if (!refcount)
92 for (i = 0; i < enumerator->count; ++i)
93 free(enumerator->filters[i].Name);
94 free(enumerator->filters);
95 free(enumerator);
97 return refcount;
100 static HRESULT WINAPI enum_reg_filters_Next(IEnumRegFilters *iface, ULONG count,
101 REGFILTER **filters, ULONG *ret_count)
103 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
104 unsigned int i;
106 TRACE("iface %p, count %u, filters %p, ret_count %p.\n", iface, count, filters, ret_count);
108 for (i = 0; i < count && enumerator->index + i < enumerator->count; ++i)
110 REGFILTER *filter = &enumerator->filters[enumerator->index + i];
112 if (!(filters[i] = CoTaskMemAlloc(sizeof(REGFILTER) + (wcslen(filter->Name) + 1) * sizeof(WCHAR))))
114 while (i--)
115 CoTaskMemFree(filters[i]);
116 memset(filters, 0, count * sizeof(*filters));
117 *ret_count = 0;
118 return E_OUTOFMEMORY;
121 filters[i]->Clsid = filter->Clsid;
122 filters[i]->Name = (WCHAR *)(filters[i] + 1);
123 wcscpy(filters[i]->Name, filter->Name);
126 enumerator->index += i;
127 if (ret_count)
128 *ret_count = i;
129 return i ? S_OK : S_FALSE;
132 static HRESULT WINAPI enum_reg_filters_Skip(IEnumRegFilters *iface, ULONG count)
134 TRACE("iface %p, count %u, unimplemented.\n", iface, count);
135 return E_NOTIMPL;
138 static HRESULT WINAPI enum_reg_filters_Reset(IEnumRegFilters *iface)
140 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
142 TRACE("iface %p.\n", iface);
144 enumerator->index = 0;
145 return S_OK;
148 static HRESULT WINAPI enum_reg_filters_Clone(IEnumRegFilters *iface, IEnumRegFilters **out)
150 TRACE("iface %p, out %p, unimplemented.\n", iface, out);
151 return E_NOTIMPL;
154 static const IEnumRegFiltersVtbl enum_reg_filters_vtbl =
156 enum_reg_filters_QueryInterface,
157 enum_reg_filters_AddRef,
158 enum_reg_filters_Release,
159 enum_reg_filters_Next,
160 enum_reg_filters_Skip,
161 enum_reg_filters_Reset,
162 enum_reg_filters_Clone,
165 static HRESULT enum_reg_filters_create(REGFILTER *filters, unsigned int count, IEnumRegFilters **out)
167 struct enum_reg_filters *object;
168 unsigned int i;
170 *out = NULL;
172 if (!(object = calloc(1, sizeof(*object))))
173 return E_OUTOFMEMORY;
175 if (!(object->filters = malloc(count * sizeof(*object->filters))))
177 free(object);
178 return E_OUTOFMEMORY;
181 for (i = 0; i < count; ++i)
183 object->filters[i].Clsid = filters[i].Clsid;
184 if (!(object->filters[i].Name = wcsdup(filters[i].Name)))
186 while (i--)
187 free(object->filters[i].Name);
188 free(object->filters);
189 free(object);
190 return E_OUTOFMEMORY;
194 object->IEnumRegFilters_iface.lpVtbl = &enum_reg_filters_vtbl;
195 object->refcount = 1;
196 object->count = count;
198 TRACE("Created enumerator %p.\n", object);
199 *out = &object->IEnumRegFilters_iface;
200 return S_OK;
203 struct enum_moniker
205 IEnumMoniker IEnumMoniker_iface;
206 LONG refcount;
208 unsigned int index, count;
209 IMoniker **filters;
212 static struct enum_moniker *impl_from_IEnumMoniker(IEnumMoniker *iface)
214 return CONTAINING_RECORD(iface, struct enum_moniker, IEnumMoniker_iface);
217 static HRESULT WINAPI enum_moniker_QueryInterface(IEnumMoniker *iface, REFIID iid, void **out)
219 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
221 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMoniker))
223 IEnumMoniker_AddRef(iface);
224 *out = iface;
225 return S_OK;
228 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
229 *out = NULL;
230 return E_NOINTERFACE;
233 static ULONG WINAPI enum_moniker_AddRef(IEnumMoniker *iface)
235 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
236 ULONG refcount = InterlockedIncrement(&enumerator->refcount);
237 TRACE("%p increasing refcount to %u.\n", enumerator, refcount);
238 return refcount;
241 static ULONG WINAPI enum_moniker_Release(IEnumMoniker *iface)
243 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
244 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
245 unsigned int i;
247 TRACE("%p decreasing refcount to %u.\n", enumerator, refcount);
248 if (!refcount)
250 for (i = 0; i < enumerator->count; ++i)
251 IMoniker_Release(enumerator->filters[i]);
252 free(enumerator->filters);
253 free(enumerator);
255 return refcount;
258 static HRESULT WINAPI enum_moniker_Next(IEnumMoniker *iface, ULONG count,
259 IMoniker **filters, ULONG *ret_count)
261 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
262 unsigned int i;
264 TRACE("iface %p, count %u, filters %p, ret_count %p.\n", iface, count, filters, ret_count);
266 for (i = 0; i < count && enumerator->index + i < enumerator->count; ++i)
267 IMoniker_AddRef(filters[i] = enumerator->filters[enumerator->index + i]);
269 enumerator->index += i;
270 if (ret_count)
271 *ret_count = i;
272 return i ? S_OK : S_FALSE;
275 static HRESULT WINAPI enum_moniker_Skip(IEnumMoniker *iface, ULONG count)
277 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
279 TRACE("iface %p, count %u.\n", iface, count);
281 enumerator->index += count;
282 return S_OK;
285 static HRESULT WINAPI enum_moniker_Reset(IEnumMoniker *iface)
287 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
289 TRACE("iface %p.\n", iface);
291 enumerator->index = 0;
292 return S_OK;
295 static HRESULT WINAPI enum_moniker_Clone(IEnumMoniker *iface, IEnumMoniker **out)
297 TRACE("iface %p, out %p, unimplemented.\n", iface, out);
298 return E_NOTIMPL;
301 static const IEnumMonikerVtbl enum_moniker_vtbl =
303 enum_moniker_QueryInterface,
304 enum_moniker_AddRef,
305 enum_moniker_Release,
306 enum_moniker_Next,
307 enum_moniker_Skip,
308 enum_moniker_Reset,
309 enum_moniker_Clone,
312 static HRESULT enum_moniker_create(IMoniker **filters, unsigned int count, IEnumMoniker **out)
314 struct enum_moniker *object;
316 *out = NULL;
318 if (!(object = calloc(1, sizeof(*object))))
319 return E_OUTOFMEMORY;
321 if (!(object->filters = malloc(count * sizeof(*object->filters))))
323 free(object);
324 return E_OUTOFMEMORY;
326 memcpy(object->filters, filters, count * sizeof(*filters));
328 object->IEnumMoniker_iface.lpVtbl = &enum_moniker_vtbl;
329 object->refcount = 1;
330 object->count = count;
332 TRACE("Created enumerator %p.\n", object);
333 *out = &object->IEnumMoniker_iface;
334 return S_OK;
337 typedef struct FilterMapper3Impl
339 IUnknown IUnknown_inner;
340 IFilterMapper3 IFilterMapper3_iface;
341 IFilterMapper IFilterMapper_iface;
342 IAMFilterData IAMFilterData_iface;
343 IUnknown *outer_unk;
344 LONG ref;
345 } FilterMapper3Impl;
347 static inline FilterMapper3Impl *impl_from_IFilterMapper3( IFilterMapper3 *iface )
349 return CONTAINING_RECORD(iface, FilterMapper3Impl, IFilterMapper3_iface);
352 static inline FilterMapper3Impl *impl_from_IFilterMapper( IFilterMapper *iface )
354 return CONTAINING_RECORD(iface, FilterMapper3Impl, IFilterMapper_iface);
357 static inline FilterMapper3Impl *impl_from_IAMFilterData( IAMFilterData *iface )
359 return CONTAINING_RECORD(iface, FilterMapper3Impl, IAMFilterData_iface);
362 static inline FilterMapper3Impl *impl_from_IUnknown( IUnknown *iface )
364 return CONTAINING_RECORD(iface, FilterMapper3Impl, IUnknown_inner);
367 /* registry format for REGFILTER2 */
368 struct REG_RF
370 DWORD dwVersion;
371 DWORD dwMerit;
372 DWORD dwPins;
373 DWORD dwUnused;
376 struct REG_RFP
378 BYTE signature[4]; /* e.g. "0pi3" */
379 DWORD dwFlags;
380 DWORD dwInstances;
381 DWORD dwMediaTypes;
382 DWORD dwMediums;
383 DWORD bCategory; /* is there a category clsid? */
384 /* optional: dwOffsetCategoryClsid */
387 struct REG_TYPE
389 BYTE signature[4]; /* e.g. "0ty3" */
390 DWORD dwUnused;
391 DWORD dwOffsetMajor;
392 DWORD dwOffsetMinor;
395 struct MONIKER_MERIT
397 IMoniker * pMoniker;
398 DWORD dwMerit;
401 struct Vector
403 LPBYTE pData;
404 int capacity; /* in bytes */
405 int current; /* pointer to next free byte */
408 /* returns the position it was added at */
409 static int add_data(struct Vector *v, const void *pData, int size)
411 int index = v->current;
412 if (v->current + size > v->capacity)
414 int new_capacity = (v->capacity + size) * 2;
415 BYTE *new_data = CoTaskMemRealloc(v->pData, new_capacity);
416 if (!new_data) return -1;
417 v->capacity = new_capacity;
418 v->pData = new_data;
420 memcpy(v->pData + v->current, pData, size);
421 v->current += size;
422 return index;
425 static int find_data(const struct Vector *v, const void *pData, int size)
427 int index;
428 for (index = 0; index < v->current; index++)
429 if (!memcmp(v->pData + index, pData, size))
430 return index;
431 /* not found */
432 return -1;
435 static void delete_vector(struct Vector * v)
437 CoTaskMemFree(v->pData);
438 v->current = 0;
439 v->capacity = 0;
442 /*** IUnknown (inner) methods ***/
444 static HRESULT WINAPI Inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
446 FilterMapper3Impl *This = impl_from_IUnknown(iface);
448 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
450 *ppv = NULL;
451 if (IsEqualIID(riid, &IID_IUnknown))
452 *ppv = &This->IUnknown_inner;
453 else if (IsEqualIID(riid, &IID_IFilterMapper2) || IsEqualIID(riid, &IID_IFilterMapper3))
454 *ppv = &This->IFilterMapper3_iface;
455 else if (IsEqualIID(riid, &IID_IFilterMapper))
456 *ppv = &This->IFilterMapper_iface;
457 else if (IsEqualIID(riid, &IID_IAMFilterData))
458 *ppv = &This->IAMFilterData_iface;
460 if (*ppv != NULL)
462 IUnknown_AddRef((IUnknown *)*ppv);
463 return S_OK;
466 FIXME("No interface for %s\n", debugstr_guid(riid));
467 return E_NOINTERFACE;
470 static ULONG WINAPI Inner_AddRef(IUnknown *iface)
472 FilterMapper3Impl *This = impl_from_IUnknown(iface);
473 ULONG ref = InterlockedIncrement(&This->ref);
475 TRACE("(%p)->(): new ref = %d\n", This, ref);
477 return ref;
480 static ULONG WINAPI Inner_Release(IUnknown *iface)
482 FilterMapper3Impl *This = impl_from_IUnknown(iface);
483 ULONG ref = InterlockedDecrement(&This->ref);
485 TRACE("(%p)->(): new ref = %d\n", This, ref);
487 if (ref == 0)
489 CoTaskMemFree(This);
492 return ref;
495 static const IUnknownVtbl IInner_VTable =
497 Inner_QueryInterface,
498 Inner_AddRef,
499 Inner_Release
502 static HRESULT WINAPI FilterMapper3_QueryInterface(IFilterMapper3 * iface, REFIID riid, LPVOID *ppv)
504 FilterMapper3Impl *This = impl_from_IFilterMapper3(iface);
506 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
509 static ULONG WINAPI FilterMapper3_AddRef(IFilterMapper3 * iface)
511 FilterMapper3Impl *This = impl_from_IFilterMapper3(iface);
513 return IUnknown_AddRef(This->outer_unk);
516 static ULONG WINAPI FilterMapper3_Release(IFilterMapper3 * iface)
518 FilterMapper3Impl *This = impl_from_IFilterMapper3(iface);
520 return IUnknown_Release(This->outer_unk);
523 /*** IFilterMapper3 methods ***/
525 static HRESULT WINAPI FilterMapper3_CreateCategory(IFilterMapper3 *iface,
526 REFCLSID category, DWORD merit, const WCHAR *description)
528 WCHAR guidstr[39], keypath[93];
529 HKEY key;
530 LONG ret;
532 TRACE("iface %p, category %s, merit %#x, description %s.\n", iface,
533 debugstr_guid(category), merit, debugstr_w(description));
535 StringFromGUID2(category, guidstr, ARRAY_SIZE(guidstr));
536 wcscpy(keypath, L"CLSID\\{da4e3da0-d07d-11d0-bd50-00a0c911ce86}\\Instance\\");
537 wcscat(keypath, guidstr);
539 if ((ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
540 return HRESULT_FROM_WIN32(ret);
542 if ((ret = RegSetValueExW(key, L"FriendlyName", 0, REG_SZ,
543 (const BYTE *)description, (wcslen(description) + 1) * sizeof(WCHAR))))
545 RegCloseKey(key);
546 return HRESULT_FROM_WIN32(ret);
549 if ((ret = RegSetValueExW(key, L"CLSID", 0, REG_SZ, (const BYTE *)guidstr, sizeof(guidstr))))
551 RegCloseKey(key);
552 return HRESULT_FROM_WIN32(ret);
555 if ((ret = RegSetValueExW(key, L"Merit", 0, REG_DWORD, (const BYTE *)&merit, sizeof(DWORD))))
557 RegCloseKey(key);
558 return HRESULT_FROM_WIN32(ret);
561 RegCloseKey(key);
562 return S_OK;
565 static HRESULT WINAPI FilterMapper3_UnregisterFilter(IFilterMapper3 *iface,
566 const CLSID *category, const WCHAR *instance, REFCLSID clsid)
568 WCHAR keypath[93];
570 TRACE("iface %p, category %s, instance %s, clsid %s.\n",
571 iface, debugstr_guid(category), debugstr_w(instance), debugstr_guid(clsid));
573 if (!category)
574 category = &CLSID_LegacyAmFilterCategory;
576 wcscpy(keypath, L"CLSID\\");
577 StringFromGUID2(category, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
578 wcscat(keypath, L"\\Instance\\");
579 if (instance)
580 wcscat(keypath, instance);
581 else
582 StringFromGUID2(clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
584 return HRESULT_FROM_WIN32(RegDeleteKeyW(HKEY_CLASSES_ROOT, keypath));
587 static HRESULT FM2_WriteFilterData(const REGFILTER2 * prf2, BYTE **ppData, ULONG *pcbData)
589 int size = sizeof(struct REG_RF);
590 unsigned int i;
591 struct Vector mainStore = {NULL, 0, 0};
592 struct Vector clsidStore = {NULL, 0, 0};
593 struct REG_RF rrf;
594 HRESULT hr = S_OK;
596 rrf.dwVersion = prf2->dwVersion;
597 rrf.dwMerit = prf2->dwMerit;
598 rrf.dwPins = prf2->cPins2;
599 rrf.dwUnused = 0;
601 add_data(&mainStore, &rrf, sizeof(rrf));
603 for (i = 0; i < prf2->cPins2; i++)
605 size += sizeof(struct REG_RFP);
606 if (prf2->rgPins2[i].clsPinCategory)
607 size += sizeof(DWORD);
608 size += prf2->rgPins2[i].nMediaTypes * sizeof(struct REG_TYPE);
609 size += prf2->rgPins2[i].nMediums * sizeof(DWORD);
612 for (i = 0; i < prf2->cPins2; i++)
614 struct REG_RFP rrfp;
615 REGFILTERPINS2 rgPin2 = prf2->rgPins2[i];
616 unsigned int j;
618 rrfp.signature[0] = '0';
619 rrfp.signature[1] = 'p';
620 rrfp.signature[2] = 'i';
621 rrfp.signature[3] = '3';
622 rrfp.signature[0] += i;
623 rrfp.dwFlags = rgPin2.dwFlags;
624 rrfp.dwInstances = rgPin2.cInstances;
625 rrfp.dwMediaTypes = rgPin2.nMediaTypes;
626 rrfp.dwMediums = rgPin2.nMediums;
627 rrfp.bCategory = rgPin2.clsPinCategory ? 1 : 0;
629 add_data(&mainStore, &rrfp, sizeof(rrfp));
630 if (rrfp.bCategory)
632 DWORD index = find_data(&clsidStore, rgPin2.clsPinCategory, sizeof(CLSID));
633 if (index == -1)
634 index = add_data(&clsidStore, rgPin2.clsPinCategory, sizeof(CLSID));
635 index += size;
637 add_data(&mainStore, &index, sizeof(index));
640 for (j = 0; j < rgPin2.nMediaTypes; j++)
642 struct REG_TYPE rt;
643 const CLSID * clsMinorType = rgPin2.lpMediaType[j].clsMinorType ? rgPin2.lpMediaType[j].clsMinorType : &MEDIASUBTYPE_NULL;
644 rt.signature[0] = '0';
645 rt.signature[1] = 't';
646 rt.signature[2] = 'y';
647 rt.signature[3] = '3';
648 rt.signature[0] += j;
649 rt.dwUnused = 0;
650 rt.dwOffsetMajor = find_data(&clsidStore, rgPin2.lpMediaType[j].clsMajorType, sizeof(CLSID));
651 if (rt.dwOffsetMajor == -1)
652 rt.dwOffsetMajor = add_data(&clsidStore, rgPin2.lpMediaType[j].clsMajorType, sizeof(CLSID));
653 rt.dwOffsetMajor += size;
654 rt.dwOffsetMinor = find_data(&clsidStore, clsMinorType, sizeof(CLSID));
655 if (rt.dwOffsetMinor == -1)
656 rt.dwOffsetMinor = add_data(&clsidStore, clsMinorType, sizeof(CLSID));
657 rt.dwOffsetMinor += size;
659 add_data(&mainStore, &rt, sizeof(rt));
662 for (j = 0; j < rgPin2.nMediums; j++)
664 DWORD index = find_data(&clsidStore, rgPin2.lpMedium + j, sizeof(REGPINMEDIUM));
665 if (index == -1)
666 index = add_data(&clsidStore, rgPin2.lpMedium + j, sizeof(REGPINMEDIUM));
667 index += size;
669 add_data(&mainStore, &index, sizeof(index));
673 if (SUCCEEDED(hr))
675 *pcbData = mainStore.current + clsidStore.current;
676 *ppData = CoTaskMemAlloc(*pcbData);
677 if (!*ppData)
678 hr = E_OUTOFMEMORY;
681 if (SUCCEEDED(hr))
683 memcpy(*ppData, mainStore.pData, mainStore.current);
684 memcpy((*ppData) + mainStore.current, clsidStore.pData, clsidStore.current);
687 delete_vector(&mainStore);
688 delete_vector(&clsidStore);
689 return hr;
692 static HRESULT FM2_ReadFilterData(BYTE *pData, REGFILTER2 * prf2)
694 HRESULT hr = S_OK;
695 struct REG_RF * prrf;
696 LPBYTE pCurrent;
697 DWORD i;
698 REGFILTERPINS2 * rgPins2;
700 prrf = (struct REG_RF *)pData;
701 pCurrent = pData;
703 if (prrf->dwVersion != 2)
705 FIXME("Filter registry version %d not supported\n", prrf->dwVersion);
706 ZeroMemory(prf2, sizeof(*prf2));
707 hr = E_FAIL;
710 if (SUCCEEDED(hr))
712 TRACE("version = %d, merit = %x, #pins = %d, unused = %x\n",
713 prrf->dwVersion, prrf->dwMerit, prrf->dwPins, prrf->dwUnused);
715 prf2->dwVersion = prrf->dwVersion;
716 prf2->dwMerit = prrf->dwMerit;
717 prf2->cPins2 = prrf->dwPins;
718 rgPins2 = CoTaskMemAlloc(prrf->dwPins * sizeof(*rgPins2));
719 prf2->rgPins2 = rgPins2;
720 pCurrent += sizeof(struct REG_RF);
722 for (i = 0; i < prrf->dwPins; i++)
724 struct REG_RFP * prrfp = (struct REG_RFP *)pCurrent;
725 REGPINTYPES * lpMediaType;
726 REGPINMEDIUM * lpMedium;
727 UINT j;
729 /* FIXME: check signature */
731 TRACE("\tsignature = %s\n", debugstr_an((const char*)prrfp->signature, 4));
733 TRACE("\tpin[%d]: flags = %x, instances = %d, media types = %d, mediums = %d\n",
734 i, prrfp->dwFlags, prrfp->dwInstances, prrfp->dwMediaTypes, prrfp->dwMediums);
736 rgPins2[i].dwFlags = prrfp->dwFlags;
737 rgPins2[i].cInstances = prrfp->dwInstances;
738 rgPins2[i].nMediaTypes = prrfp->dwMediaTypes;
739 rgPins2[i].nMediums = prrfp->dwMediums;
740 pCurrent += sizeof(struct REG_RFP);
741 if (prrfp->bCategory)
743 CLSID * clsCat = CoTaskMemAlloc(sizeof(CLSID));
744 memcpy(clsCat, pData + *(DWORD*)(pCurrent), sizeof(CLSID));
745 pCurrent += sizeof(DWORD);
746 rgPins2[i].clsPinCategory = clsCat;
748 else
749 rgPins2[i].clsPinCategory = NULL;
751 if (rgPins2[i].nMediaTypes > 0)
752 lpMediaType = CoTaskMemAlloc(rgPins2[i].nMediaTypes * sizeof(*lpMediaType));
753 else
754 lpMediaType = NULL;
756 rgPins2[i].lpMediaType = lpMediaType;
758 for (j = 0; j < rgPins2[i].nMediaTypes; j++)
760 struct REG_TYPE * prt = (struct REG_TYPE *)pCurrent;
761 CLSID * clsMajor = CoTaskMemAlloc(sizeof(CLSID));
762 CLSID * clsMinor = CoTaskMemAlloc(sizeof(CLSID));
764 /* FIXME: check signature */
765 TRACE("\t\tsignature = %s\n", debugstr_an((const char*)prt->signature, 4));
767 memcpy(clsMajor, pData + prt->dwOffsetMajor, sizeof(CLSID));
768 memcpy(clsMinor, pData + prt->dwOffsetMinor, sizeof(CLSID));
770 lpMediaType[j].clsMajorType = clsMajor;
771 lpMediaType[j].clsMinorType = clsMinor;
773 pCurrent += sizeof(*prt);
776 if (rgPins2[i].nMediums > 0)
777 lpMedium = CoTaskMemAlloc(rgPins2[i].nMediums * sizeof(*lpMedium));
778 else
779 lpMedium = NULL;
781 rgPins2[i].lpMedium = lpMedium;
783 for (j = 0; j < rgPins2[i].nMediums; j++)
785 DWORD dwOffset = *(DWORD *)pCurrent;
787 memcpy(lpMedium + j, pData + dwOffset, sizeof(REGPINMEDIUM));
789 pCurrent += sizeof(dwOffset);
795 return hr;
798 static void FM2_DeleteRegFilter(REGFILTER2 * prf2)
800 UINT i;
801 for (i = 0; i < prf2->cPins2; i++)
803 UINT j;
804 CoTaskMemFree((void*)prf2->rgPins2[i].clsPinCategory);
806 for (j = 0; j < prf2->rgPins2[i].nMediaTypes; j++)
808 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMediaType[j].clsMajorType);
809 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMediaType[j].clsMinorType);
811 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMediaType);
812 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMedium);
814 CoTaskMemFree((LPVOID)prf2->rgPins2);
817 static HRESULT WINAPI FilterMapper3_RegisterFilter(IFilterMapper3 *iface,
818 REFCLSID clsid, const WCHAR *name, IMoniker **ret_moniker,
819 const CLSID *category, const WCHAR *instance, const REGFILTER2 *prf2)
821 WCHAR *display_name, clsid_string[39];
822 IParseDisplayName *parser;
823 IPropertyBag *prop_bag;
824 ULONG filter_data_len;
825 IMoniker *moniker;
826 BYTE *filter_data;
827 VARIANT var;
828 ULONG eaten;
829 HRESULT hr;
830 size_t len;
831 REGFILTER2 regfilter2;
832 REGFILTERPINS2* pregfp2 = NULL;
834 TRACE("iface %p, clsid %s, name %s, ret_moniker %p, category %s, instance %s, prf2 %p.\n",
835 iface, debugstr_guid(clsid), debugstr_w(name), ret_moniker,
836 debugstr_guid(category), debugstr_w(instance), prf2);
838 if (prf2->dwVersion == 2)
840 regfilter2 = *prf2;
842 else if (prf2->dwVersion == 1)
844 ULONG i;
845 DWORD flags;
846 /* REGFILTER2 structure is converted from version 1 to 2. Tested on Win2k. */
847 regfilter2.dwVersion = 2;
848 regfilter2.dwMerit = prf2->dwMerit;
849 regfilter2.cPins2 = prf2->cPins;
850 pregfp2 = CoTaskMemAlloc(prf2->cPins * sizeof(REGFILTERPINS2));
851 regfilter2.rgPins2 = pregfp2;
852 for (i = 0; i < prf2->cPins; i++)
854 flags = 0;
855 if (prf2->rgPins[i].bRendered)
856 flags |= REG_PINFLAG_B_RENDERER;
857 if (prf2->rgPins[i].bOutput)
858 flags |= REG_PINFLAG_B_OUTPUT;
859 if (prf2->rgPins[i].bZero)
860 flags |= REG_PINFLAG_B_ZERO;
861 if (prf2->rgPins[i].bMany)
862 flags |= REG_PINFLAG_B_MANY;
863 pregfp2[i].dwFlags = flags;
864 pregfp2[i].cInstances = 1;
865 pregfp2[i].nMediaTypes = prf2->rgPins[i].nMediaTypes;
866 pregfp2[i].lpMediaType = prf2->rgPins[i].lpMediaType;
867 pregfp2[i].nMediums = 0;
868 pregfp2[i].lpMedium = NULL;
869 pregfp2[i].clsPinCategory = NULL;
872 else
874 FIXME("dwVersion other that 1 or 2 not supported at the moment\n");
875 return E_NOTIMPL;
878 if (ret_moniker)
879 *ret_moniker = NULL;
881 if (!category)
882 category = &CLSID_LegacyAmFilterCategory;
884 StringFromGUID2(clsid, clsid_string, ARRAY_SIZE(clsid_string));
886 len = 50 + (instance ? wcslen(instance) : 38) + 1;
887 if (!(display_name = malloc(len * sizeof(WCHAR))))
888 return E_OUTOFMEMORY;
890 wcscpy(display_name, L"@device:sw:");
891 StringFromGUID2(category, display_name + wcslen(display_name), len - wcslen(display_name));
892 wcscat(display_name, L"\\");
893 wcscat(display_name, instance ? instance : clsid_string);
895 if (FAILED(hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC,
896 &IID_IParseDisplayName, (void **)&parser)))
897 return hr;
899 if (FAILED(hr = IParseDisplayName_ParseDisplayName(parser, NULL, display_name, &eaten, &moniker)))
901 ERR("Failed to parse display name, hr %#x.\n", hr);
902 IParseDisplayName_Release(parser);
903 return hr;
906 IParseDisplayName_Release(parser);
908 if (FAILED(hr = IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag)))
910 ERR("Failed to get property bag, hr %#x.\n", hr);
911 IMoniker_Release(moniker);
912 return hr;
915 V_VT(&var) = VT_BSTR;
916 V_BSTR(&var) = SysAllocString(name);
917 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"FriendlyName", &var)))
918 ERR("Failed to write friendly name, hr %#x.\n", hr);
919 VariantClear(&var);
921 V_VT(&var) = VT_BSTR;
922 V_BSTR(&var) = SysAllocString(clsid_string);
923 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"CLSID", &var)))
924 ERR("Failed to write class ID, hr %#x.\n", hr);
925 VariantClear(&var);
927 if (SUCCEEDED(FM2_WriteFilterData(&regfilter2, &filter_data, &filter_data_len)))
929 V_VT(&var) = VT_ARRAY | VT_UI1;
930 if ((V_ARRAY(&var) = SafeArrayCreateVector(VT_UI1, 0, filter_data_len)))
932 memcpy(V_ARRAY(&var)->pvData, filter_data, filter_data_len);
933 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"FilterData", &var)))
934 ERR("Failed to write filter data, hr %#x.\n", hr);
935 VariantClear(&var);
938 CoTaskMemFree(filter_data);
941 IPropertyBag_Release(prop_bag);
942 free(display_name);
944 if (ret_moniker)
945 *ret_moniker = moniker;
946 else
947 IMoniker_Release(moniker);
949 CoTaskMemFree(pregfp2);
951 return S_OK;
954 /* internal helper function */
955 static BOOL MatchTypes(
956 BOOL bExactMatch,
957 DWORD nPinTypes,
958 const REGPINTYPES * pPinTypes,
959 DWORD nMatchTypes,
960 const GUID * pMatchTypes)
962 BOOL bMatch = FALSE;
963 DWORD j;
965 if ((nMatchTypes == 0) && (nPinTypes > 0))
966 bMatch = TRUE;
968 for (j = 0; j < nPinTypes; j++)
970 DWORD i;
971 for (i = 0; i < nMatchTypes*2; i+=2)
973 if (((!bExactMatch && IsEqualGUID(pPinTypes[j].clsMajorType, &GUID_NULL)) || IsEqualGUID(&pMatchTypes[i], &GUID_NULL) || IsEqualGUID(pPinTypes[j].clsMajorType, &pMatchTypes[i])) &&
974 ((!bExactMatch && IsEqualGUID(pPinTypes[j].clsMinorType, &GUID_NULL)) || IsEqualGUID(&pMatchTypes[i+1], &GUID_NULL) || IsEqualGUID(pPinTypes[j].clsMinorType, &pMatchTypes[i+1])))
976 bMatch = TRUE;
977 break;
981 return bMatch;
984 /* internal helper function for qsort of MONIKER_MERIT array */
985 static int __cdecl mm_compare(const void * left, const void * right)
987 const struct MONIKER_MERIT * mmLeft = left;
988 const struct MONIKER_MERIT * mmRight = right;
990 if (mmLeft->dwMerit == mmRight->dwMerit)
991 return 0;
992 if (mmLeft->dwMerit > mmRight->dwMerit)
993 return -1;
994 return 1;
997 /* NOTES:
998 * Exact match means whether or not to treat GUID_NULL's in filter data as wild cards
999 * (GUID_NULL's in input to function automatically treated as wild cards)
1000 * Input/Output needed means match only on criteria if TRUE (with zero input types
1001 * meaning match any input/output pin as long as one exists), otherwise match any
1002 * filter that meets the rest of the requirements.
1004 static HRESULT WINAPI FilterMapper3_EnumMatchingFilters(
1005 IFilterMapper3 * iface,
1006 IEnumMoniker **ppEnum,
1007 DWORD dwFlags,
1008 BOOL bExactMatch,
1009 DWORD dwMerit,
1010 BOOL bInputNeeded,
1011 DWORD cInputTypes,
1012 const GUID *pInputTypes,
1013 const REGPINMEDIUM *pMedIn,
1014 const CLSID *pPinCategoryIn,
1015 BOOL bRender,
1016 BOOL bOutputNeeded,
1017 DWORD cOutputTypes,
1018 const GUID *pOutputTypes,
1019 const REGPINMEDIUM *pMedOut,
1020 const CLSID *pPinCategoryOut)
1022 ICreateDevEnum * pCreateDevEnum;
1023 IMoniker * pMonikerCat;
1024 IEnumMoniker * pEnumCat;
1025 HRESULT hr;
1026 struct Vector monikers = {NULL, 0, 0};
1028 TRACE("(%p, %x, %s, %x, %s, %d, %p, %p, %p, %s, %s, %p, %p, %p)\n",
1029 ppEnum,
1030 dwFlags,
1031 bExactMatch ? "true" : "false",
1032 dwMerit,
1033 bInputNeeded ? "true" : "false",
1034 cInputTypes,
1035 pInputTypes,
1036 pMedIn,
1037 pPinCategoryIn,
1038 bRender ? "true" : "false",
1039 bOutputNeeded ? "true" : "false",
1040 pOutputTypes,
1041 pMedOut,
1042 pPinCategoryOut);
1044 if (dwFlags != 0)
1046 FIXME("dwFlags = %x not implemented\n", dwFlags);
1049 *ppEnum = NULL;
1051 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (LPVOID*)&pCreateDevEnum);
1052 if (FAILED(hr))
1053 return hr;
1055 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEnumCat, 0);
1056 if (FAILED(hr)) {
1057 ICreateDevEnum_Release(pCreateDevEnum);
1058 return hr;
1061 while (IEnumMoniker_Next(pEnumCat, 1, &pMonikerCat, NULL) == S_OK)
1063 IPropertyBag * pPropBagCat = NULL;
1064 VARIANT var;
1065 HRESULT hrSub; /* this is so that one buggy filter
1066 doesn't make the whole lot fail */
1068 VariantInit(&var);
1070 hrSub = IMoniker_BindToStorage(pMonikerCat, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
1072 if (SUCCEEDED(hrSub))
1073 hrSub = IPropertyBag_Read(pPropBagCat, L"Merit", &var, NULL);
1075 if (SUCCEEDED(hrSub) && (V_UI4(&var) >= dwMerit))
1077 CLSID clsidCat;
1078 IEnumMoniker * pEnum;
1079 IMoniker * pMoniker;
1081 VariantClear(&var);
1083 if (TRACE_ON(quartz))
1085 VARIANT temp;
1086 V_VT(&temp) = VT_EMPTY;
1087 IPropertyBag_Read(pPropBagCat, L"FriendlyName", &temp, NULL);
1088 TRACE("Considering category %s\n", debugstr_w(V_BSTR(&temp)));
1089 VariantClear(&temp);
1092 hrSub = IPropertyBag_Read(pPropBagCat, L"CLSID", &var, NULL);
1094 if (SUCCEEDED(hrSub))
1095 hrSub = CLSIDFromString(V_BSTR(&var), &clsidCat);
1097 if (SUCCEEDED(hrSub))
1098 hrSub = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1100 if (hrSub == S_OK)
1102 while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1104 IPropertyBag * pPropBag = NULL;
1105 VARIANT var;
1106 BYTE *pData = NULL;
1107 REGFILTER2 rf2;
1108 DWORD i;
1109 BOOL bInputMatch = !bInputNeeded;
1110 BOOL bOutputMatch = !bOutputNeeded;
1112 ZeroMemory(&rf2, sizeof(rf2));
1113 VariantInit(&var);
1115 hrSub = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBag);
1117 if (TRACE_ON(quartz))
1119 VARIANT temp;
1120 V_VT(&temp) = VT_EMPTY;
1121 IPropertyBag_Read(pPropBag, L"FriendlyName", &temp, NULL);
1122 TRACE("Considering filter %s\n", debugstr_w(V_BSTR(&temp)));
1123 VariantClear(&temp);
1126 if (SUCCEEDED(hrSub))
1128 hrSub = IPropertyBag_Read(pPropBag, L"FilterData", &var, NULL);
1131 if (SUCCEEDED(hrSub))
1132 hrSub = SafeArrayAccessData(V_ARRAY(&var), (LPVOID*)&pData);
1134 if (SUCCEEDED(hrSub))
1135 hrSub = FM2_ReadFilterData(pData, &rf2);
1137 if (pData)
1138 SafeArrayUnaccessData(V_ARRAY(&var));
1140 VariantClear(&var);
1142 /* Logic used for bInputMatch expression:
1143 * There exists some pin such that bInputNeeded implies (pin is an input and
1144 * (bRender implies pin has render flag) and major/minor types members of
1145 * pInputTypes )
1146 * bOutputMatch is similar, but without the "bRender implies ..." part
1147 * and substituting variables names containing input for output
1150 /* determine whether filter meets requirements */
1151 if (SUCCEEDED(hrSub) && (rf2.dwMerit >= dwMerit))
1153 for (i = 0; (i < rf2.cPins2) && (!bInputMatch || !bOutputMatch); i++)
1155 const REGFILTERPINS2 * rfp2 = rf2.rgPins2 + i;
1157 bInputMatch = bInputMatch || (!(rfp2->dwFlags & REG_PINFLAG_B_OUTPUT) &&
1158 (!bRender || (rfp2->dwFlags & REG_PINFLAG_B_RENDERER)) &&
1159 MatchTypes(bExactMatch, rfp2->nMediaTypes, rfp2->lpMediaType, cInputTypes, pInputTypes));
1160 bOutputMatch = bOutputMatch || ((rfp2->dwFlags & REG_PINFLAG_B_OUTPUT) &&
1161 MatchTypes(bExactMatch, rfp2->nMediaTypes, rfp2->lpMediaType, cOutputTypes, pOutputTypes));
1164 if (bInputMatch && bOutputMatch)
1166 struct MONIKER_MERIT mm = {pMoniker, rf2.dwMerit};
1167 IMoniker_AddRef(pMoniker);
1168 add_data(&monikers, &mm, sizeof(mm));
1172 FM2_DeleteRegFilter(&rf2);
1173 if (pPropBag)
1174 IPropertyBag_Release(pPropBag);
1175 IMoniker_Release(pMoniker);
1177 IEnumMoniker_Release(pEnum);
1181 VariantClear(&var);
1182 if (pPropBagCat)
1183 IPropertyBag_Release(pPropBagCat);
1184 IMoniker_Release(pMonikerCat);
1187 if (SUCCEEDED(hr))
1189 IMoniker ** ppMoniker;
1190 unsigned int i;
1191 ULONG nMonikerCount = monikers.current / sizeof(struct MONIKER_MERIT);
1193 /* sort the monikers in descending merit order */
1194 qsort(monikers.pData, nMonikerCount,
1195 sizeof(struct MONIKER_MERIT),
1196 mm_compare);
1198 /* construct an IEnumMoniker interface */
1199 ppMoniker = CoTaskMemAlloc(nMonikerCount * sizeof(IMoniker *));
1200 for (i = 0; i < nMonikerCount; i++)
1202 /* no need to AddRef here as already AddRef'd above */
1203 ppMoniker[i] = ((struct MONIKER_MERIT *)monikers.pData)[i].pMoniker;
1205 hr = enum_moniker_create(ppMoniker, nMonikerCount, ppEnum);
1206 CoTaskMemFree(ppMoniker);
1209 delete_vector(&monikers);
1210 IEnumMoniker_Release(pEnumCat);
1211 ICreateDevEnum_Release(pCreateDevEnum);
1213 return hr;
1216 static HRESULT WINAPI FilterMapper3_GetICreateDevEnum(IFilterMapper3 *iface, ICreateDevEnum **ppEnum)
1218 TRACE("(%p, %p)\n", iface, ppEnum);
1219 if (!ppEnum)
1220 return E_POINTER;
1221 return CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (void**)ppEnum);
1224 static const IFilterMapper3Vtbl fm3vtbl =
1227 FilterMapper3_QueryInterface,
1228 FilterMapper3_AddRef,
1229 FilterMapper3_Release,
1231 FilterMapper3_CreateCategory,
1232 FilterMapper3_UnregisterFilter,
1233 FilterMapper3_RegisterFilter,
1234 FilterMapper3_EnumMatchingFilters,
1235 FilterMapper3_GetICreateDevEnum
1238 /*** IUnknown methods ***/
1240 static HRESULT WINAPI FilterMapper_QueryInterface(IFilterMapper * iface, REFIID riid, LPVOID *ppv)
1242 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1244 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1246 return FilterMapper3_QueryInterface(&This->IFilterMapper3_iface, riid, ppv);
1249 static ULONG WINAPI FilterMapper_AddRef(IFilterMapper * iface)
1251 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1253 return IUnknown_AddRef(This->outer_unk);
1256 static ULONG WINAPI FilterMapper_Release(IFilterMapper * iface)
1258 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1260 return IUnknown_Release(This->outer_unk);
1263 /*** IFilterMapper methods ***/
1265 static HRESULT WINAPI FilterMapper_EnumMatchingFilters(
1266 IFilterMapper * iface,
1267 IEnumRegFilters **ppEnum,
1268 DWORD dwMerit,
1269 BOOL bInputNeeded,
1270 CLSID clsInMaj,
1271 CLSID clsInSub,
1272 BOOL bRender,
1273 BOOL bOutputNeeded,
1274 CLSID clsOutMaj,
1275 CLSID clsOutSub)
1277 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1278 GUID InputType[2];
1279 GUID OutputType[2];
1280 IEnumMoniker* ppEnumMoniker;
1281 IMoniker* IMon;
1282 ULONG nb;
1283 ULONG idx = 0, nb_mon = 0;
1284 REGFILTER* regfilters;
1285 HRESULT hr;
1287 TRACE("(%p/%p)->(%p, %x, %s, %s, %s, %s, %s, %s, %s)\n",
1288 This,
1289 iface,
1290 ppEnum,
1291 dwMerit,
1292 bInputNeeded ? "true" : "false",
1293 debugstr_guid(&clsInMaj),
1294 debugstr_guid(&clsInSub),
1295 bRender ? "true" : "false",
1296 bOutputNeeded ? "true" : "false",
1297 debugstr_guid(&clsOutMaj),
1298 debugstr_guid(&clsOutSub));
1300 InputType[0] = clsInMaj;
1301 InputType[1] = clsInSub;
1302 OutputType[0] = clsOutMaj;
1303 OutputType[1] = clsOutSub;
1305 *ppEnum = NULL;
1307 hr = IFilterMapper3_EnumMatchingFilters(&This->IFilterMapper3_iface, &ppEnumMoniker, 0, TRUE,
1308 dwMerit, bInputNeeded, 1, InputType, NULL, &GUID_NULL, bRender, bOutputNeeded, 1,
1309 OutputType, NULL, &GUID_NULL);
1311 if (FAILED(hr))
1312 return hr;
1314 while(IEnumMoniker_Next(ppEnumMoniker, 1, &IMon, &nb) == S_OK)
1316 IMoniker_Release(IMon);
1317 nb_mon++;
1320 if (!nb_mon)
1322 IEnumMoniker_Release(ppEnumMoniker);
1323 return enum_reg_filters_create(NULL, 0, ppEnum);
1326 regfilters = CoTaskMemAlloc(nb_mon * sizeof(REGFILTER));
1327 if (!regfilters)
1329 IEnumMoniker_Release(ppEnumMoniker);
1330 return E_OUTOFMEMORY;
1332 ZeroMemory(regfilters, nb_mon * sizeof(REGFILTER)); /* will prevent bad free of Name in case of error. */
1334 IEnumMoniker_Reset(ppEnumMoniker);
1335 while(IEnumMoniker_Next(ppEnumMoniker, 1, &IMon, &nb) == S_OK)
1337 IPropertyBag * pPropBagCat = NULL;
1338 VARIANT var;
1339 HRESULT hrSub;
1340 GUID clsid;
1341 int len;
1343 VariantInit(&var);
1345 hrSub = IMoniker_BindToStorage(IMon, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
1347 if (SUCCEEDED(hrSub))
1348 hrSub = IPropertyBag_Read(pPropBagCat, L"CLSID", &var, NULL);
1350 if (SUCCEEDED(hrSub))
1351 hrSub = CLSIDFromString(V_BSTR(&var), &clsid);
1353 VariantClear(&var);
1355 if (SUCCEEDED(hrSub))
1356 hrSub = IPropertyBag_Read(pPropBagCat, L"FriendlyName", &var, NULL);
1358 if (SUCCEEDED(hrSub))
1360 len = (wcslen(V_BSTR(&var)) + 1) * sizeof(WCHAR);
1361 if (!(regfilters[idx].Name = CoTaskMemAlloc(len*2)))
1362 hr = E_OUTOFMEMORY;
1365 if (SUCCEEDED(hrSub) && regfilters[idx].Name)
1367 memcpy(regfilters[idx].Name, V_BSTR(&var), len);
1368 regfilters[idx].Clsid = clsid;
1369 idx++;
1372 if (pPropBagCat)
1373 IPropertyBag_Release(pPropBagCat);
1374 IMoniker_Release(IMon);
1375 VariantClear(&var);
1378 if (SUCCEEDED(hr))
1380 hr = enum_reg_filters_create(regfilters, idx, ppEnum);
1383 for (idx = 0; idx < nb_mon; idx++)
1384 CoTaskMemFree(regfilters[idx].Name);
1385 CoTaskMemFree(regfilters);
1386 IEnumMoniker_Release(ppEnumMoniker);
1388 return hr;
1392 static HRESULT WINAPI FilterMapper_RegisterFilter(IFilterMapper * iface,
1393 CLSID clsid, const WCHAR *name, DWORD merit)
1395 WCHAR keypath[46], guidstr[39];
1396 HKEY key;
1397 LONG ret;
1399 TRACE("iface %p, clsid %s, name %s, merit %#x.\n",
1400 iface, debugstr_guid(&clsid), debugstr_w(name), merit);
1402 StringFromGUID2(&clsid, guidstr, ARRAY_SIZE(guidstr));
1404 wcscpy(keypath, L"Filter\\");
1405 wcscat(keypath, guidstr);
1406 if ((ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
1407 return HRESULT_FROM_WIN32(ret);
1409 if ((ret = RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE *)name, (wcslen(name) + 1) * sizeof(WCHAR))))
1410 ERR("Failed to set filter name, error %u.\n", ret);
1411 RegCloseKey(key);
1413 wcscpy(keypath, L"CLSID\\");
1414 wcscat(keypath, guidstr);
1415 if (!(ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
1417 if ((ret = RegSetValueExW(key, L"Merit", 0, REG_DWORD, (const BYTE *)&merit, sizeof(DWORD))))
1418 ERR("Failed to set merit, error %u.\n", ret);
1419 RegCloseKey(key);
1421 else
1422 ERR("Failed to create CLSID key, error %u.\n", ret);
1424 return S_OK;
1427 static HRESULT WINAPI FilterMapper_RegisterFilterInstance(IFilterMapper * iface, CLSID clsid, LPCWSTR szName, CLSID *MRId)
1429 TRACE("(%p)->(%s, %s, %p)\n", iface, debugstr_guid(&clsid), debugstr_w(szName), MRId);
1431 /* Not implemented in Windows (tested on Win2k) */
1433 return E_NOTIMPL;
1436 static HRESULT WINAPI FilterMapper_RegisterPin(IFilterMapper *iface, CLSID clsid,
1437 const WCHAR *name, BOOL rendered, BOOL output, BOOL zero, BOOL many,
1438 CLSID external_filter, const WCHAR *external_pin)
1440 WCHAR keypath[6 + 38 + 1], *pin_keypath;
1441 HKEY key, pin_key, type_key;
1442 LONG ret;
1444 TRACE("iface %p, clsid %s, name %s, rendered %d, output %d, zero %d, "
1445 "many %d, external_filter %s, external_pin %s.\n",
1446 iface, debugstr_guid(&clsid), debugstr_w(name), rendered, output,
1447 zero, many, debugstr_guid(&external_filter), debugstr_w(external_pin));
1449 wcscpy(keypath, L"CLSID\\");
1450 StringFromGUID2(&clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
1451 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_WRITE, &key)))
1452 return HRESULT_FROM_WIN32(ret);
1454 if (!(pin_keypath = malloc((5 + wcslen(name) + 1) * sizeof(WCHAR))))
1456 RegCloseKey(key);
1457 return E_OUTOFMEMORY;
1459 wcscpy(pin_keypath, L"Pins\\");
1460 wcscat(pin_keypath, name);
1462 if ((ret = RegCreateKeyExW(key, pin_keypath, 0, NULL, 0, KEY_WRITE, NULL, &pin_key, NULL)))
1464 ERR("Failed to open pin key, error %u.\n", ret);
1465 free(pin_keypath);
1466 RegCloseKey(key);
1467 return HRESULT_FROM_WIN32(ret);
1469 free(pin_keypath);
1471 if ((ret = RegSetValueExW(pin_key, L"AllowedMany", 0, REG_DWORD, (const BYTE *)&many, sizeof(DWORD))))
1472 ERR("Failed to set AllowedMany value, error %u.\n", ret);
1473 if ((ret = RegSetValueExW(pin_key, L"AllowedZero", 0, REG_DWORD, (const BYTE *)&zero, sizeof(DWORD))))
1474 ERR("Failed to set AllowedZero value, error %u.\n", ret);
1475 if ((ret = RegSetValueExW(pin_key, L"Direction", 0, REG_DWORD, (const BYTE *)&output, sizeof(DWORD))))
1476 ERR("Failed to set Direction value, error %u.\n", ret);
1477 if ((ret = RegSetValueExW(pin_key, L"IsRendered", 0, REG_DWORD, (const BYTE *)&rendered, sizeof(DWORD))))
1478 ERR("Failed to set IsRendered value, error %u.\n", ret);
1480 if (!(ret = RegCreateKeyExW(pin_key, L"Types", 0, NULL, 0, 0, NULL, &type_key, NULL)))
1481 RegCloseKey(type_key);
1482 else
1483 ERR("Failed to create Types subkey, error %u.\n", ret);
1485 RegCloseKey(pin_key);
1486 RegCloseKey(key);
1488 return S_OK;
1492 static HRESULT WINAPI FilterMapper_RegisterPinType(IFilterMapper *iface,
1493 CLSID clsid, const WCHAR *pin, CLSID majortype, CLSID subtype)
1495 WCHAR *keypath, type_keypath[38 + 1 + 38 + 1];
1496 HKEY key, type_key;
1497 size_t len;
1498 LONG ret;
1500 TRACE("iface %p, clsid %s, pin %s, majortype %s, subtype %s.\n", iface,
1501 debugstr_guid(&clsid), debugstr_w(pin), debugstr_guid(&majortype), debugstr_guid(&subtype));
1503 len = 6 + 38 + 6 + wcslen(pin) + 6 + 1;
1504 if (!(keypath = malloc(len * sizeof(WCHAR))))
1505 return E_OUTOFMEMORY;
1507 wcscpy(keypath, L"CLSID\\");
1508 StringFromGUID2(&clsid, keypath + wcslen(keypath), len - wcslen(keypath));
1509 wcscat(keypath, L"\\Pins\\");
1510 wcscat(keypath, pin);
1511 wcscat(keypath, L"\\Types");
1512 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_CREATE_SUB_KEY, &key)))
1514 free(keypath);
1515 return HRESULT_FROM_WIN32(ret);
1517 free(keypath);
1519 StringFromGUID2(&majortype, type_keypath, ARRAY_SIZE(type_keypath));
1520 wcscat(type_keypath, L"\\");
1521 StringFromGUID2(&subtype, type_keypath + wcslen(type_keypath), ARRAY_SIZE(type_keypath) - wcslen(type_keypath));
1522 if (!(ret = RegCreateKeyExW(key, type_keypath, 0, NULL, 0, 0, NULL, &type_key, NULL)))
1523 RegCloseKey(type_key);
1524 else
1525 ERR("Failed to create type key, error %u.\n", ret);
1527 RegCloseKey(key);
1528 return HRESULT_FROM_WIN32(ret);
1531 static HRESULT WINAPI FilterMapper_UnregisterFilter(IFilterMapper *iface, CLSID clsid)
1533 WCHAR guidstr[39], keypath[6 + 38 + 1];
1534 LONG ret;
1535 HKEY key;
1537 TRACE("iface %p, clsid %s.\n", iface, debugstr_guid(&clsid));
1539 StringFromGUID2(&clsid, guidstr, ARRAY_SIZE(guidstr));
1541 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Filter", 0, 0, &key)))
1542 return HRESULT_FROM_WIN32(ret);
1543 if ((ret = RegDeleteKeyW(key, guidstr)))
1544 ERR("Failed to delete filter key, error %u.\n", ret);
1545 RegCloseKey(key);
1547 wcscpy(keypath, L"CLSID\\");
1548 wcscat(keypath, guidstr);
1549 if (!(ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_WRITE, &key)))
1551 if ((ret = RegDeleteValueW(key, L"Merit")))
1552 ERR("Failed to delete Merit value, error %u.\n", ret);
1553 if ((ret = RegDeleteTreeW(key, L"Pins")))
1554 ERR("Failed to delete Pins key, error %u.\n", ret);
1555 RegCloseKey(key);
1557 else
1558 ERR("Failed to open CLSID key, error %u.\n", ret);
1560 return S_OK;
1563 static HRESULT WINAPI FilterMapper_UnregisterFilterInstance(IFilterMapper * iface, CLSID MRId)
1565 TRACE("(%p)->(%s)\n", iface, debugstr_guid(&MRId));
1567 /* Not implemented in Windows (tested on Win2k) */
1569 return E_NOTIMPL;
1572 static HRESULT WINAPI FilterMapper_UnregisterPin(IFilterMapper * iface, CLSID clsid, const WCHAR *name)
1574 WCHAR keypath[6 + 38 + 5 + 1];
1575 LONG ret;
1576 HKEY key;
1578 TRACE("iface %p, clsid %s, name %s.\n", iface, debugstr_guid(&clsid), debugstr_w(name));
1580 if (!name)
1581 return E_INVALIDARG;
1583 wcscpy(keypath, L"CLSID\\");
1584 StringFromGUID2(&clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
1585 wcscat(keypath, L"\\Pins");
1586 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, 0, &key)))
1587 return HRESULT_FROM_WIN32(ret);
1589 if ((ret = RegDeleteTreeW(key, name)))
1590 ERR("Failed to delete subkey, error %u.\n", ret);
1592 RegCloseKey(key);
1594 return S_OK;
1597 static const IFilterMapperVtbl fmvtbl =
1600 FilterMapper_QueryInterface,
1601 FilterMapper_AddRef,
1602 FilterMapper_Release,
1604 FilterMapper_RegisterFilter,
1605 FilterMapper_RegisterFilterInstance,
1606 FilterMapper_RegisterPin,
1607 FilterMapper_RegisterPinType,
1608 FilterMapper_UnregisterFilter,
1609 FilterMapper_UnregisterFilterInstance,
1610 FilterMapper_UnregisterPin,
1611 FilterMapper_EnumMatchingFilters
1615 /*** IUnknown methods ***/
1616 static HRESULT WINAPI AMFilterData_QueryInterface(IAMFilterData * iface, REFIID riid, LPVOID *ppv)
1618 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1620 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1623 static ULONG WINAPI AMFilterData_AddRef(IAMFilterData * iface)
1625 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1627 return IUnknown_AddRef(This->outer_unk);
1630 static ULONG WINAPI AMFilterData_Release(IAMFilterData * iface)
1632 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1634 return IUnknown_Release(This->outer_unk);
1637 /*** IAMFilterData methods ***/
1638 static HRESULT WINAPI AMFilterData_ParseFilterData(IAMFilterData* iface,
1639 BYTE *pData, ULONG cb,
1640 BYTE **ppRegFilter2)
1642 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1643 HRESULT hr = S_OK;
1644 static REGFILTER2 *prf2;
1646 TRACE("(%p/%p)->(%p, %d, %p)\n", This, iface, pData, cb, ppRegFilter2);
1648 prf2 = CoTaskMemAlloc(sizeof(*prf2));
1649 if (!prf2)
1650 return E_OUTOFMEMORY;
1651 *ppRegFilter2 = (BYTE *)&prf2;
1653 hr = FM2_ReadFilterData(pData, prf2);
1654 if (FAILED(hr))
1656 CoTaskMemFree(prf2);
1657 *ppRegFilter2 = NULL;
1660 return hr;
1663 static HRESULT WINAPI AMFilterData_CreateFilterData(IAMFilterData* iface,
1664 REGFILTER2 *prf2,
1665 BYTE **pRegFilterData,
1666 ULONG *pcb)
1668 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1670 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, prf2, pRegFilterData, pcb);
1672 return FM2_WriteFilterData(prf2, pRegFilterData, pcb);
1675 static const IAMFilterDataVtbl AMFilterDataVtbl = {
1676 AMFilterData_QueryInterface,
1677 AMFilterData_AddRef,
1678 AMFilterData_Release,
1679 AMFilterData_ParseFilterData,
1680 AMFilterData_CreateFilterData
1683 HRESULT filter_mapper_create(IUnknown *pUnkOuter, IUnknown **out)
1685 FilterMapper3Impl * pFM2impl;
1687 pFM2impl = CoTaskMemAlloc(sizeof(*pFM2impl));
1688 if (!pFM2impl)
1689 return E_OUTOFMEMORY;
1691 pFM2impl->IUnknown_inner.lpVtbl = &IInner_VTable;
1692 pFM2impl->IFilterMapper3_iface.lpVtbl = &fm3vtbl;
1693 pFM2impl->IFilterMapper_iface.lpVtbl = &fmvtbl;
1694 pFM2impl->IAMFilterData_iface.lpVtbl = &AMFilterDataVtbl;
1695 pFM2impl->ref = 1;
1697 if (pUnkOuter)
1698 pFM2impl->outer_unk = pUnkOuter;
1699 else
1700 pFM2impl->outer_unk = &pFM2impl->IUnknown_inner;
1702 TRACE("Created filter mapper %p.\n", pFM2impl);
1703 *out = &pFM2impl->IUnknown_inner;
1704 return S_OK;