winmm: Avoid explicitly casting the pointer returned from Heap(Re)Alloc.
[wine.git] / dlls / quartz / filtermapper.c
blob69755c3648e8a37b347cc66ba1124b77ddefb54f
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 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "winerror.h"
30 #include "quartz_private.h"
32 #include "ole2.h"
33 #include "olectl.h"
34 #include "strmif.h"
35 #include "uuids.h"
36 #include "initguid.h"
37 #include "wine/fil_data.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
43 struct enum_reg_filters
45 IEnumRegFilters IEnumRegFilters_iface;
46 LONG refcount;
48 unsigned int index, count;
49 REGFILTER *filters;
52 static struct enum_reg_filters *impl_from_IEnumRegFilters(IEnumRegFilters *iface)
54 return CONTAINING_RECORD(iface, struct enum_reg_filters, IEnumRegFilters_iface);
57 static HRESULT WINAPI enum_reg_filters_QueryInterface(IEnumRegFilters *iface, REFIID iid, void **out)
59 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
61 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumRegFilters))
63 IEnumRegFilters_AddRef(iface);
64 *out = iface;
65 return S_OK;
68 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
69 *out = NULL;
70 return E_NOINTERFACE;
73 static ULONG WINAPI enum_reg_filters_AddRef(IEnumRegFilters *iface)
75 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
76 ULONG refcount = InterlockedIncrement(&enumerator->refcount);
77 TRACE("%p increasing refcount to %lu.\n", enumerator, refcount);
78 return refcount;
81 static ULONG WINAPI enum_reg_filters_Release(IEnumRegFilters *iface)
83 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
84 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
85 unsigned int i;
87 TRACE("%p decreasing refcount to %lu.\n", enumerator, refcount);
88 if (!refcount)
90 for (i = 0; i < enumerator->count; ++i)
91 free(enumerator->filters[i].Name);
92 free(enumerator->filters);
93 free(enumerator);
95 return refcount;
98 static HRESULT WINAPI enum_reg_filters_Next(IEnumRegFilters *iface, ULONG count,
99 REGFILTER **filters, ULONG *ret_count)
101 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
102 unsigned int i;
104 TRACE("iface %p, count %lu, filters %p, ret_count %p.\n", iface, count, filters, ret_count);
106 for (i = 0; i < count && enumerator->index + i < enumerator->count; ++i)
108 REGFILTER *filter = &enumerator->filters[enumerator->index + i];
110 if (!(filters[i] = CoTaskMemAlloc(sizeof(REGFILTER) + (wcslen(filter->Name) + 1) * sizeof(WCHAR))))
112 while (i--)
113 CoTaskMemFree(filters[i]);
114 memset(filters, 0, count * sizeof(*filters));
115 *ret_count = 0;
116 return E_OUTOFMEMORY;
119 filters[i]->Clsid = filter->Clsid;
120 filters[i]->Name = (WCHAR *)(filters[i] + 1);
121 wcscpy(filters[i]->Name, filter->Name);
124 enumerator->index += i;
125 if (ret_count)
126 *ret_count = i;
127 return i ? S_OK : S_FALSE;
130 static HRESULT WINAPI enum_reg_filters_Skip(IEnumRegFilters *iface, ULONG count)
132 TRACE("iface %p, count %lu, unimplemented.\n", iface, count);
133 return E_NOTIMPL;
136 static HRESULT WINAPI enum_reg_filters_Reset(IEnumRegFilters *iface)
138 struct enum_reg_filters *enumerator = impl_from_IEnumRegFilters(iface);
140 TRACE("iface %p.\n", iface);
142 enumerator->index = 0;
143 return S_OK;
146 static HRESULT WINAPI enum_reg_filters_Clone(IEnumRegFilters *iface, IEnumRegFilters **out)
148 TRACE("iface %p, out %p, unimplemented.\n", iface, out);
149 return E_NOTIMPL;
152 static const IEnumRegFiltersVtbl enum_reg_filters_vtbl =
154 enum_reg_filters_QueryInterface,
155 enum_reg_filters_AddRef,
156 enum_reg_filters_Release,
157 enum_reg_filters_Next,
158 enum_reg_filters_Skip,
159 enum_reg_filters_Reset,
160 enum_reg_filters_Clone,
163 static HRESULT enum_reg_filters_create(REGFILTER *filters, unsigned int count, IEnumRegFilters **out)
165 struct enum_reg_filters *object;
166 unsigned int i;
168 *out = NULL;
170 if (!(object = calloc(1, sizeof(*object))))
171 return E_OUTOFMEMORY;
173 if (!(object->filters = malloc(count * sizeof(*object->filters))))
175 free(object);
176 return E_OUTOFMEMORY;
179 for (i = 0; i < count; ++i)
181 object->filters[i].Clsid = filters[i].Clsid;
182 if (!(object->filters[i].Name = wcsdup(filters[i].Name)))
184 while (i--)
185 free(object->filters[i].Name);
186 free(object->filters);
187 free(object);
188 return E_OUTOFMEMORY;
192 object->IEnumRegFilters_iface.lpVtbl = &enum_reg_filters_vtbl;
193 object->refcount = 1;
194 object->count = count;
196 TRACE("Created enumerator %p.\n", object);
197 *out = &object->IEnumRegFilters_iface;
198 return S_OK;
201 struct enum_moniker
203 IEnumMoniker IEnumMoniker_iface;
204 LONG refcount;
206 unsigned int index, count;
207 IMoniker **filters;
210 static struct enum_moniker *impl_from_IEnumMoniker(IEnumMoniker *iface)
212 return CONTAINING_RECORD(iface, struct enum_moniker, IEnumMoniker_iface);
215 static HRESULT WINAPI enum_moniker_QueryInterface(IEnumMoniker *iface, REFIID iid, void **out)
217 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
219 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMoniker))
221 IEnumMoniker_AddRef(iface);
222 *out = iface;
223 return S_OK;
226 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
227 *out = NULL;
228 return E_NOINTERFACE;
231 static ULONG WINAPI enum_moniker_AddRef(IEnumMoniker *iface)
233 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
234 ULONG refcount = InterlockedIncrement(&enumerator->refcount);
235 TRACE("%p increasing refcount to %lu.\n", enumerator, refcount);
236 return refcount;
239 static ULONG WINAPI enum_moniker_Release(IEnumMoniker *iface)
241 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
242 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
243 unsigned int i;
245 TRACE("%p decreasing refcount to %lu.\n", enumerator, refcount);
246 if (!refcount)
248 for (i = 0; i < enumerator->count; ++i)
249 IMoniker_Release(enumerator->filters[i]);
250 free(enumerator->filters);
251 free(enumerator);
253 return refcount;
256 static HRESULT WINAPI enum_moniker_Next(IEnumMoniker *iface, ULONG count,
257 IMoniker **filters, ULONG *ret_count)
259 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
260 unsigned int i;
262 TRACE("iface %p, count %lu, filters %p, ret_count %p.\n", iface, count, filters, ret_count);
264 for (i = 0; i < count && enumerator->index + i < enumerator->count; ++i)
265 IMoniker_AddRef(filters[i] = enumerator->filters[enumerator->index + i]);
267 enumerator->index += i;
268 if (ret_count)
269 *ret_count = i;
270 return i ? S_OK : S_FALSE;
273 static HRESULT WINAPI enum_moniker_Skip(IEnumMoniker *iface, ULONG count)
275 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
277 TRACE("iface %p, count %lu.\n", iface, count);
279 enumerator->index += count;
280 return S_OK;
283 static HRESULT WINAPI enum_moniker_Reset(IEnumMoniker *iface)
285 struct enum_moniker *enumerator = impl_from_IEnumMoniker(iface);
287 TRACE("iface %p.\n", iface);
289 enumerator->index = 0;
290 return S_OK;
293 static HRESULT WINAPI enum_moniker_Clone(IEnumMoniker *iface, IEnumMoniker **out)
295 TRACE("iface %p, out %p, unimplemented.\n", iface, out);
296 return E_NOTIMPL;
299 static const IEnumMonikerVtbl enum_moniker_vtbl =
301 enum_moniker_QueryInterface,
302 enum_moniker_AddRef,
303 enum_moniker_Release,
304 enum_moniker_Next,
305 enum_moniker_Skip,
306 enum_moniker_Reset,
307 enum_moniker_Clone,
310 static HRESULT enum_moniker_create(IMoniker **filters, unsigned int count, IEnumMoniker **out)
312 struct enum_moniker *object;
314 *out = NULL;
316 if (!(object = calloc(1, sizeof(*object))))
317 return E_OUTOFMEMORY;
319 if (!(object->filters = malloc(count * sizeof(*object->filters))))
321 free(object);
322 return E_OUTOFMEMORY;
324 memcpy(object->filters, filters, count * sizeof(*filters));
326 object->IEnumMoniker_iface.lpVtbl = &enum_moniker_vtbl;
327 object->refcount = 1;
328 object->count = count;
330 TRACE("Created enumerator %p.\n", object);
331 *out = &object->IEnumMoniker_iface;
332 return S_OK;
335 typedef struct FilterMapper3Impl
337 IUnknown IUnknown_inner;
338 IFilterMapper3 IFilterMapper3_iface;
339 IFilterMapper IFilterMapper_iface;
340 IAMFilterData IAMFilterData_iface;
341 IUnknown *outer_unk;
342 LONG ref;
343 } FilterMapper3Impl;
345 static inline FilterMapper3Impl *impl_from_IFilterMapper3( IFilterMapper3 *iface )
347 return CONTAINING_RECORD(iface, FilterMapper3Impl, IFilterMapper3_iface);
350 static inline FilterMapper3Impl *impl_from_IFilterMapper( IFilterMapper *iface )
352 return CONTAINING_RECORD(iface, FilterMapper3Impl, IFilterMapper_iface);
355 static inline FilterMapper3Impl *impl_from_IAMFilterData( IAMFilterData *iface )
357 return CONTAINING_RECORD(iface, FilterMapper3Impl, IAMFilterData_iface);
360 static inline FilterMapper3Impl *impl_from_IUnknown( IUnknown *iface )
362 return CONTAINING_RECORD(iface, FilterMapper3Impl, IUnknown_inner);
365 /* registry format for REGFILTER2 */
366 struct REG_RF
368 DWORD dwVersion;
369 DWORD dwMerit;
370 DWORD dwPins;
371 DWORD dwUnused;
374 struct REG_RFP
376 BYTE signature[4]; /* e.g. "0pi3" */
377 DWORD dwFlags;
378 DWORD dwInstances;
379 DWORD dwMediaTypes;
380 DWORD dwMediums;
381 DWORD bCategory; /* is there a category clsid? */
382 /* optional: dwOffsetCategoryClsid */
385 struct REG_TYPE
387 BYTE signature[4]; /* e.g. "0ty3" */
388 DWORD dwUnused;
389 DWORD dwOffsetMajor;
390 DWORD dwOffsetMinor;
393 struct MONIKER_MERIT
395 IMoniker * pMoniker;
396 DWORD dwMerit;
399 struct Vector
401 LPBYTE pData;
402 int capacity; /* in bytes */
403 int current; /* pointer to next free byte */
406 /* returns the position it was added at */
407 static int add_data(struct Vector *v, const void *pData, int size)
409 int index = v->current;
410 if (v->current + size > v->capacity)
412 int new_capacity = (v->capacity + size) * 2;
413 BYTE *new_data = CoTaskMemRealloc(v->pData, new_capacity);
414 if (!new_data) return -1;
415 v->capacity = new_capacity;
416 v->pData = new_data;
418 memcpy(v->pData + v->current, pData, size);
419 v->current += size;
420 return index;
423 static int find_data(const struct Vector *v, const void *pData, int size)
425 int index;
426 for (index = 0; index + size <= v->current; index++)
427 if (!memcmp(v->pData + index, pData, size))
428 return index;
429 /* not found */
430 return -1;
433 static void delete_vector(struct Vector * v)
435 CoTaskMemFree(v->pData);
436 v->current = 0;
437 v->capacity = 0;
440 /*** IUnknown (inner) methods ***/
442 static HRESULT WINAPI Inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
444 FilterMapper3Impl *This = impl_from_IUnknown(iface);
446 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
448 *ppv = NULL;
449 if (IsEqualIID(riid, &IID_IUnknown))
450 *ppv = &This->IUnknown_inner;
451 else if (IsEqualIID(riid, &IID_IFilterMapper2) || IsEqualIID(riid, &IID_IFilterMapper3))
452 *ppv = &This->IFilterMapper3_iface;
453 else if (IsEqualIID(riid, &IID_IFilterMapper))
454 *ppv = &This->IFilterMapper_iface;
455 else if (IsEqualIID(riid, &IID_IAMFilterData))
456 *ppv = &This->IAMFilterData_iface;
458 if (*ppv != NULL)
460 IUnknown_AddRef((IUnknown *)*ppv);
461 return S_OK;
464 FIXME("No interface for %s\n", debugstr_guid(riid));
465 return E_NOINTERFACE;
468 static ULONG WINAPI Inner_AddRef(IUnknown *iface)
470 FilterMapper3Impl *mapper = impl_from_IUnknown(iface);
471 ULONG refcount = InterlockedIncrement(&mapper->ref);
473 TRACE("%p increasing refcount to %lu.\n", mapper, refcount);
475 return refcount;
478 static ULONG WINAPI Inner_Release(IUnknown *iface)
480 FilterMapper3Impl *mapper = impl_from_IUnknown(iface);
481 ULONG refcount = InterlockedDecrement(&mapper->ref);
483 TRACE("%p decreasing refcount to %lu.\n", mapper, refcount);
485 if (!refcount)
487 CoTaskMemFree(mapper);
490 return refcount;
493 static const IUnknownVtbl IInner_VTable =
495 Inner_QueryInterface,
496 Inner_AddRef,
497 Inner_Release
500 static HRESULT WINAPI FilterMapper3_QueryInterface(IFilterMapper3 * iface, REFIID riid, LPVOID *ppv)
502 FilterMapper3Impl *This = impl_from_IFilterMapper3(iface);
504 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
507 static ULONG WINAPI FilterMapper3_AddRef(IFilterMapper3 * iface)
509 FilterMapper3Impl *This = impl_from_IFilterMapper3(iface);
511 return IUnknown_AddRef(This->outer_unk);
514 static ULONG WINAPI FilterMapper3_Release(IFilterMapper3 * iface)
516 FilterMapper3Impl *This = impl_from_IFilterMapper3(iface);
518 return IUnknown_Release(This->outer_unk);
521 /*** IFilterMapper3 methods ***/
523 static HRESULT WINAPI FilterMapper3_CreateCategory(IFilterMapper3 *iface,
524 REFCLSID category, DWORD merit, const WCHAR *description)
526 WCHAR guidstr[39], keypath[93];
527 HKEY key;
528 LONG ret;
530 TRACE("iface %p, category %s, merit %#lx, description %s.\n", iface,
531 debugstr_guid(category), merit, debugstr_w(description));
533 StringFromGUID2(category, guidstr, ARRAY_SIZE(guidstr));
534 wcscpy(keypath, L"CLSID\\{da4e3da0-d07d-11d0-bd50-00a0c911ce86}\\Instance\\");
535 wcscat(keypath, guidstr);
537 if ((ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
538 return HRESULT_FROM_WIN32(ret);
540 if ((ret = RegSetValueExW(key, L"FriendlyName", 0, REG_SZ,
541 (const BYTE *)description, (wcslen(description) + 1) * sizeof(WCHAR))))
543 RegCloseKey(key);
544 return HRESULT_FROM_WIN32(ret);
547 if ((ret = RegSetValueExW(key, L"CLSID", 0, REG_SZ, (const BYTE *)guidstr, sizeof(guidstr))))
549 RegCloseKey(key);
550 return HRESULT_FROM_WIN32(ret);
553 if ((ret = RegSetValueExW(key, L"Merit", 0, REG_DWORD, (const BYTE *)&merit, sizeof(DWORD))))
555 RegCloseKey(key);
556 return HRESULT_FROM_WIN32(ret);
559 RegCloseKey(key);
560 return S_OK;
563 static HRESULT WINAPI FilterMapper3_UnregisterFilter(IFilterMapper3 *iface,
564 const CLSID *category, const WCHAR *instance, REFCLSID clsid)
566 WCHAR keypath[93];
568 TRACE("iface %p, category %s, instance %s, clsid %s.\n",
569 iface, debugstr_guid(category), debugstr_w(instance), debugstr_guid(clsid));
571 if (!category)
572 category = &CLSID_LegacyAmFilterCategory;
574 wcscpy(keypath, L"CLSID\\");
575 StringFromGUID2(category, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
576 wcscat(keypath, L"\\Instance\\");
577 if (instance)
578 wcscat(keypath, instance);
579 else
580 StringFromGUID2(clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
582 return HRESULT_FROM_WIN32(RegDeleteKeyW(HKEY_CLASSES_ROOT, keypath));
585 static HRESULT FM2_WriteFilterData(const REGFILTER2 * prf2, BYTE **ppData, ULONG *pcbData)
587 int size = sizeof(struct REG_RF);
588 unsigned int i;
589 struct Vector mainStore = {NULL, 0, 0};
590 struct Vector clsidStore = {NULL, 0, 0};
591 struct REG_RF rrf;
592 HRESULT hr = S_OK;
594 rrf.dwVersion = prf2->dwVersion;
595 rrf.dwMerit = prf2->dwMerit;
596 rrf.dwPins = prf2->cPins2;
597 rrf.dwUnused = 0;
599 add_data(&mainStore, &rrf, sizeof(rrf));
601 for (i = 0; i < prf2->cPins2; i++)
603 size += sizeof(struct REG_RFP);
604 if (prf2->rgPins2[i].clsPinCategory)
605 size += sizeof(DWORD);
606 size += prf2->rgPins2[i].nMediaTypes * sizeof(struct REG_TYPE);
607 size += prf2->rgPins2[i].nMediums * sizeof(DWORD);
610 for (i = 0; i < prf2->cPins2; i++)
612 struct REG_RFP rrfp;
613 REGFILTERPINS2 rgPin2 = prf2->rgPins2[i];
614 unsigned int j;
616 rrfp.signature[0] = '0';
617 rrfp.signature[1] = 'p';
618 rrfp.signature[2] = 'i';
619 rrfp.signature[3] = '3';
620 rrfp.signature[0] += i;
621 rrfp.dwFlags = rgPin2.dwFlags;
622 rrfp.dwInstances = rgPin2.cInstances;
623 rrfp.dwMediaTypes = rgPin2.nMediaTypes;
624 rrfp.dwMediums = rgPin2.nMediums;
625 rrfp.bCategory = rgPin2.clsPinCategory ? 1 : 0;
627 add_data(&mainStore, &rrfp, sizeof(rrfp));
628 if (rrfp.bCategory)
630 DWORD index = find_data(&clsidStore, rgPin2.clsPinCategory, sizeof(CLSID));
631 if (index == -1)
632 index = add_data(&clsidStore, rgPin2.clsPinCategory, sizeof(CLSID));
633 index += size;
635 add_data(&mainStore, &index, sizeof(index));
638 for (j = 0; j < rgPin2.nMediaTypes; j++)
640 struct REG_TYPE rt;
641 const CLSID * clsMinorType = rgPin2.lpMediaType[j].clsMinorType ? rgPin2.lpMediaType[j].clsMinorType : &MEDIASUBTYPE_NULL;
642 rt.signature[0] = '0';
643 rt.signature[1] = 't';
644 rt.signature[2] = 'y';
645 rt.signature[3] = '3';
646 rt.signature[0] += j;
647 rt.dwUnused = 0;
648 rt.dwOffsetMajor = find_data(&clsidStore, rgPin2.lpMediaType[j].clsMajorType, sizeof(CLSID));
649 if (rt.dwOffsetMajor == -1)
650 rt.dwOffsetMajor = add_data(&clsidStore, rgPin2.lpMediaType[j].clsMajorType, sizeof(CLSID));
651 rt.dwOffsetMajor += size;
652 rt.dwOffsetMinor = find_data(&clsidStore, clsMinorType, sizeof(CLSID));
653 if (rt.dwOffsetMinor == -1)
654 rt.dwOffsetMinor = add_data(&clsidStore, clsMinorType, sizeof(CLSID));
655 rt.dwOffsetMinor += size;
657 add_data(&mainStore, &rt, sizeof(rt));
660 for (j = 0; j < rgPin2.nMediums; j++)
662 DWORD index = find_data(&clsidStore, rgPin2.lpMedium + j, sizeof(REGPINMEDIUM));
663 if (index == -1)
664 index = add_data(&clsidStore, rgPin2.lpMedium + j, sizeof(REGPINMEDIUM));
665 index += size;
667 add_data(&mainStore, &index, sizeof(index));
671 if (SUCCEEDED(hr))
673 *pcbData = mainStore.current + clsidStore.current;
674 *ppData = CoTaskMemAlloc(*pcbData);
675 if (!*ppData)
676 hr = E_OUTOFMEMORY;
679 if (SUCCEEDED(hr))
681 memcpy(*ppData, mainStore.pData, mainStore.current);
682 memcpy((*ppData) + mainStore.current, clsidStore.pData, clsidStore.current);
685 delete_vector(&mainStore);
686 delete_vector(&clsidStore);
687 return hr;
690 static HRESULT FM2_ReadFilterData(BYTE *pData, REGFILTER2 * prf2)
692 HRESULT hr = S_OK;
693 struct REG_RF * prrf;
694 LPBYTE pCurrent;
695 DWORD i;
696 REGFILTERPINS2 * rgPins2;
698 prrf = (struct REG_RF *)pData;
699 pCurrent = pData;
701 if (prrf->dwVersion != 2)
703 FIXME("Filter registry version %lu is not supported.\n", prrf->dwVersion);
704 ZeroMemory(prf2, sizeof(*prf2));
705 hr = E_FAIL;
708 if (SUCCEEDED(hr))
710 TRACE("dwVersion %lu, dwMerit %#lx, dwPins %lu, dwUnused %#lx.\n",
711 prrf->dwVersion, prrf->dwMerit, prrf->dwPins, prrf->dwUnused);
713 prf2->dwVersion = prrf->dwVersion;
714 prf2->dwMerit = prrf->dwMerit;
715 prf2->cPins2 = prrf->dwPins;
716 rgPins2 = CoTaskMemAlloc(prrf->dwPins * sizeof(*rgPins2));
717 prf2->rgPins2 = rgPins2;
718 pCurrent += sizeof(struct REG_RF);
720 for (i = 0; i < prrf->dwPins; i++)
722 struct REG_RFP * prrfp = (struct REG_RFP *)pCurrent;
723 REGPINTYPES * lpMediaType;
724 REGPINMEDIUM * lpMedium;
725 UINT j;
727 /* FIXME: check signature */
729 TRACE("\tsignature = %s\n", debugstr_an((const char*)prrfp->signature, 4));
731 TRACE("\tPin %lu: dwFlags %#lx, dwInstances %lu, dwMediaTypes %lu, dwMediums %lu.\n",
732 i, prrfp->dwFlags, prrfp->dwInstances, prrfp->dwMediaTypes, prrfp->dwMediums);
734 rgPins2[i].dwFlags = prrfp->dwFlags;
735 rgPins2[i].cInstances = prrfp->dwInstances;
736 rgPins2[i].nMediaTypes = prrfp->dwMediaTypes;
737 rgPins2[i].nMediums = prrfp->dwMediums;
738 pCurrent += sizeof(struct REG_RFP);
739 if (prrfp->bCategory)
741 CLSID * clsCat = CoTaskMemAlloc(sizeof(CLSID));
742 memcpy(clsCat, pData + *(DWORD*)(pCurrent), sizeof(CLSID));
743 pCurrent += sizeof(DWORD);
744 rgPins2[i].clsPinCategory = clsCat;
746 else
747 rgPins2[i].clsPinCategory = NULL;
749 if (rgPins2[i].nMediaTypes > 0)
750 lpMediaType = CoTaskMemAlloc(rgPins2[i].nMediaTypes * sizeof(*lpMediaType));
751 else
752 lpMediaType = NULL;
754 rgPins2[i].lpMediaType = lpMediaType;
756 for (j = 0; j < rgPins2[i].nMediaTypes; j++)
758 struct REG_TYPE * prt = (struct REG_TYPE *)pCurrent;
759 CLSID * clsMajor = CoTaskMemAlloc(sizeof(CLSID));
760 CLSID * clsMinor = CoTaskMemAlloc(sizeof(CLSID));
762 /* FIXME: check signature */
763 TRACE("\t\tsignature = %s\n", debugstr_an((const char*)prt->signature, 4));
765 memcpy(clsMajor, pData + prt->dwOffsetMajor, sizeof(CLSID));
766 memcpy(clsMinor, pData + prt->dwOffsetMinor, sizeof(CLSID));
768 lpMediaType[j].clsMajorType = clsMajor;
769 lpMediaType[j].clsMinorType = clsMinor;
771 pCurrent += sizeof(*prt);
774 if (rgPins2[i].nMediums > 0)
775 lpMedium = CoTaskMemAlloc(rgPins2[i].nMediums * sizeof(*lpMedium));
776 else
777 lpMedium = NULL;
779 rgPins2[i].lpMedium = lpMedium;
781 for (j = 0; j < rgPins2[i].nMediums; j++)
783 DWORD dwOffset = *(DWORD *)pCurrent;
785 memcpy(lpMedium + j, pData + dwOffset, sizeof(REGPINMEDIUM));
787 pCurrent += sizeof(dwOffset);
793 return hr;
796 static void FM2_DeleteRegFilter(REGFILTER2 * prf2)
798 UINT i;
799 for (i = 0; i < prf2->cPins2; i++)
801 UINT j;
802 CoTaskMemFree((void*)prf2->rgPins2[i].clsPinCategory);
804 for (j = 0; j < prf2->rgPins2[i].nMediaTypes; j++)
806 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMediaType[j].clsMajorType);
807 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMediaType[j].clsMinorType);
809 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMediaType);
810 CoTaskMemFree((LPVOID)prf2->rgPins2[i].lpMedium);
812 CoTaskMemFree((LPVOID)prf2->rgPins2);
815 static HRESULT WINAPI FilterMapper3_RegisterFilter(IFilterMapper3 *iface,
816 REFCLSID clsid, const WCHAR *name, IMoniker **ret_moniker,
817 const CLSID *category, const WCHAR *instance, const REGFILTER2 *prf2)
819 WCHAR *display_name, clsid_string[39];
820 IParseDisplayName *parser;
821 IPropertyBag *prop_bag;
822 ULONG filter_data_len;
823 IMoniker *moniker;
824 BYTE *filter_data;
825 VARIANT var;
826 ULONG eaten;
827 HRESULT hr;
828 size_t len;
829 REGFILTER2 regfilter2;
830 REGFILTERPINS2* pregfp2 = NULL;
832 TRACE("iface %p, clsid %s, name %s, ret_moniker %p, category %s, instance %s, prf2 %p.\n",
833 iface, debugstr_guid(clsid), debugstr_w(name), ret_moniker,
834 debugstr_guid(category), debugstr_w(instance), prf2);
836 if (prf2->dwVersion == 2)
838 regfilter2 = *prf2;
840 else if (prf2->dwVersion == 1)
842 ULONG i;
843 DWORD flags;
844 /* REGFILTER2 structure is converted from version 1 to 2. Tested on Win2k. */
845 regfilter2.dwVersion = 2;
846 regfilter2.dwMerit = prf2->dwMerit;
847 regfilter2.cPins2 = prf2->cPins;
848 pregfp2 = CoTaskMemAlloc(prf2->cPins * sizeof(REGFILTERPINS2));
849 regfilter2.rgPins2 = pregfp2;
850 for (i = 0; i < prf2->cPins; i++)
852 flags = 0;
853 if (prf2->rgPins[i].bRendered)
854 flags |= REG_PINFLAG_B_RENDERER;
855 if (prf2->rgPins[i].bOutput)
856 flags |= REG_PINFLAG_B_OUTPUT;
857 if (prf2->rgPins[i].bZero)
858 flags |= REG_PINFLAG_B_ZERO;
859 if (prf2->rgPins[i].bMany)
860 flags |= REG_PINFLAG_B_MANY;
861 pregfp2[i].dwFlags = flags;
862 pregfp2[i].cInstances = 1;
863 pregfp2[i].nMediaTypes = prf2->rgPins[i].nMediaTypes;
864 pregfp2[i].lpMediaType = prf2->rgPins[i].lpMediaType;
865 pregfp2[i].nMediums = 0;
866 pregfp2[i].lpMedium = NULL;
867 pregfp2[i].clsPinCategory = NULL;
870 else
872 FIXME("dwVersion other that 1 or 2 not supported at the moment\n");
873 return E_NOTIMPL;
876 if (ret_moniker)
877 *ret_moniker = NULL;
879 if (!category)
880 category = &CLSID_LegacyAmFilterCategory;
882 StringFromGUID2(clsid, clsid_string, ARRAY_SIZE(clsid_string));
884 len = 50 + (instance ? wcslen(instance) : 38) + 1;
885 if (!(display_name = malloc(len * sizeof(WCHAR))))
886 return E_OUTOFMEMORY;
888 wcscpy(display_name, L"@device:sw:");
889 StringFromGUID2(category, display_name + wcslen(display_name), len - wcslen(display_name));
890 wcscat(display_name, L"\\");
891 wcscat(display_name, instance ? instance : clsid_string);
893 if (FAILED(hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC,
894 &IID_IParseDisplayName, (void **)&parser)))
896 free(display_name);
897 return hr;
900 if (FAILED(hr = IParseDisplayName_ParseDisplayName(parser, NULL, display_name, &eaten, &moniker)))
902 ERR("Failed to parse display name, hr %#lx.\n", hr);
903 IParseDisplayName_Release(parser);
904 free(display_name);
905 return hr;
908 IParseDisplayName_Release(parser);
910 if (FAILED(hr = IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag)))
912 ERR("Failed to get property bag, hr %#lx.\n", hr);
913 IMoniker_Release(moniker);
914 free(display_name);
915 return hr;
918 V_VT(&var) = VT_BSTR;
919 V_BSTR(&var) = SysAllocString(name);
920 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"FriendlyName", &var)))
921 ERR("Failed to write friendly name, hr %#lx.\n", hr);
922 VariantClear(&var);
924 V_VT(&var) = VT_BSTR;
925 V_BSTR(&var) = SysAllocString(clsid_string);
926 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"CLSID", &var)))
927 ERR("Failed to write class ID, hr %#lx.\n", hr);
928 VariantClear(&var);
930 if (SUCCEEDED(FM2_WriteFilterData(&regfilter2, &filter_data, &filter_data_len)))
932 V_VT(&var) = VT_ARRAY | VT_UI1;
933 if ((V_ARRAY(&var) = SafeArrayCreateVector(VT_UI1, 0, filter_data_len)))
935 memcpy(V_ARRAY(&var)->pvData, filter_data, filter_data_len);
936 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"FilterData", &var)))
937 ERR("Failed to write filter data, hr %#lx.\n", hr);
938 VariantClear(&var);
941 CoTaskMemFree(filter_data);
944 IPropertyBag_Release(prop_bag);
945 free(display_name);
947 if (ret_moniker)
948 *ret_moniker = moniker;
949 else
950 IMoniker_Release(moniker);
952 CoTaskMemFree(pregfp2);
954 return S_OK;
957 /* internal helper function */
958 static BOOL MatchTypes(
959 BOOL bExactMatch,
960 DWORD nPinTypes,
961 const REGPINTYPES * pPinTypes,
962 DWORD nMatchTypes,
963 const GUID * pMatchTypes)
965 BOOL bMatch = FALSE;
966 DWORD j;
968 if ((nMatchTypes == 0) && (nPinTypes > 0))
969 bMatch = TRUE;
971 for (j = 0; j < nPinTypes; j++)
973 DWORD i;
974 for (i = 0; i < nMatchTypes*2; i+=2)
976 if (((!bExactMatch && IsEqualGUID(pPinTypes[j].clsMajorType, &GUID_NULL)) || IsEqualGUID(&pMatchTypes[i], &GUID_NULL) || IsEqualGUID(pPinTypes[j].clsMajorType, &pMatchTypes[i])) &&
977 ((!bExactMatch && IsEqualGUID(pPinTypes[j].clsMinorType, &GUID_NULL)) || IsEqualGUID(&pMatchTypes[i+1], &GUID_NULL) || IsEqualGUID(pPinTypes[j].clsMinorType, &pMatchTypes[i+1])))
979 bMatch = TRUE;
980 break;
984 return bMatch;
987 /* internal helper function for qsort of MONIKER_MERIT array */
988 static int __cdecl mm_compare(const void * left, const void * right)
990 const struct MONIKER_MERIT * mmLeft = left;
991 const struct MONIKER_MERIT * mmRight = right;
993 if (mmLeft->dwMerit == mmRight->dwMerit)
994 return 0;
995 if (mmLeft->dwMerit > mmRight->dwMerit)
996 return -1;
997 return 1;
1000 /* NOTES:
1001 * Exact match means whether or not to treat GUID_NULL's in filter data as wild cards
1002 * (GUID_NULL's in input to function automatically treated as wild cards)
1003 * Input/Output needed means match only on criteria if TRUE (with zero input types
1004 * meaning match any input/output pin as long as one exists), otherwise match any
1005 * filter that meets the rest of the requirements.
1007 static HRESULT WINAPI FilterMapper3_EnumMatchingFilters(
1008 IFilterMapper3 * iface,
1009 IEnumMoniker **ppEnum,
1010 DWORD dwFlags,
1011 BOOL bExactMatch,
1012 DWORD dwMerit,
1013 BOOL bInputNeeded,
1014 DWORD cInputTypes,
1015 const GUID *pInputTypes,
1016 const REGPINMEDIUM *pMedIn,
1017 const CLSID *pPinCategoryIn,
1018 BOOL bRender,
1019 BOOL bOutputNeeded,
1020 DWORD cOutputTypes,
1021 const GUID *pOutputTypes,
1022 const REGPINMEDIUM *pMedOut,
1023 const CLSID *pPinCategoryOut)
1025 ICreateDevEnum * pCreateDevEnum;
1026 IMoniker * pMonikerCat;
1027 IEnumMoniker * pEnumCat;
1028 HRESULT hr;
1029 struct Vector monikers = {NULL, 0, 0};
1031 TRACE("(%p, %#lx, %s, %#lx, %s, %lu, %p, %p, %p, %s, %s, %p, %p, %p)\n",
1032 ppEnum,
1033 dwFlags,
1034 bExactMatch ? "true" : "false",
1035 dwMerit,
1036 bInputNeeded ? "true" : "false",
1037 cInputTypes,
1038 pInputTypes,
1039 pMedIn,
1040 pPinCategoryIn,
1041 bRender ? "true" : "false",
1042 bOutputNeeded ? "true" : "false",
1043 pOutputTypes,
1044 pMedOut,
1045 pPinCategoryOut);
1047 if (dwFlags != 0)
1048 FIXME("Ignoring flags %#lx.\n", dwFlags);
1050 *ppEnum = NULL;
1052 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (LPVOID*)&pCreateDevEnum);
1053 if (FAILED(hr))
1054 return hr;
1056 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEnumCat, 0);
1057 if (FAILED(hr)) {
1058 ICreateDevEnum_Release(pCreateDevEnum);
1059 return hr;
1062 while (IEnumMoniker_Next(pEnumCat, 1, &pMonikerCat, NULL) == S_OK)
1064 IPropertyBag * pPropBagCat = NULL;
1065 VARIANT var;
1066 HRESULT hrSub; /* this is so that one buggy filter
1067 doesn't make the whole lot fail */
1069 VariantInit(&var);
1071 hrSub = IMoniker_BindToStorage(pMonikerCat, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
1073 if (SUCCEEDED(hrSub))
1074 hrSub = IPropertyBag_Read(pPropBagCat, L"Merit", &var, NULL);
1076 if (SUCCEEDED(hrSub) && (V_UI4(&var) >= dwMerit))
1078 CLSID clsidCat;
1079 IEnumMoniker * pEnum;
1080 IMoniker * pMoniker;
1082 VariantClear(&var);
1084 if (TRACE_ON(quartz))
1086 VARIANT temp;
1087 V_VT(&temp) = VT_EMPTY;
1088 IPropertyBag_Read(pPropBagCat, L"FriendlyName", &temp, NULL);
1089 TRACE("Considering category %s\n", debugstr_w(V_BSTR(&temp)));
1090 VariantClear(&temp);
1093 hrSub = IPropertyBag_Read(pPropBagCat, L"CLSID", &var, NULL);
1095 if (SUCCEEDED(hrSub))
1096 hrSub = CLSIDFromString(V_BSTR(&var), &clsidCat);
1098 if (SUCCEEDED(hrSub))
1099 hrSub = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1101 if (hrSub == S_OK)
1103 while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1105 IPropertyBag * pPropBag = NULL;
1106 VARIANT var;
1107 BYTE *pData = NULL;
1108 REGFILTER2 rf2;
1109 DWORD i;
1110 BOOL bInputMatch = !bInputNeeded;
1111 BOOL bOutputMatch = !bOutputNeeded;
1113 ZeroMemory(&rf2, sizeof(rf2));
1114 VariantInit(&var);
1116 hrSub = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBag);
1118 if (TRACE_ON(quartz))
1120 VARIANT temp;
1121 V_VT(&temp) = VT_EMPTY;
1122 IPropertyBag_Read(pPropBag, L"FriendlyName", &temp, NULL);
1123 TRACE("Considering filter %s\n", debugstr_w(V_BSTR(&temp)));
1124 VariantClear(&temp);
1127 if (SUCCEEDED(hrSub))
1129 hrSub = IPropertyBag_Read(pPropBag, L"FilterData", &var, NULL);
1132 if (SUCCEEDED(hrSub))
1133 hrSub = SafeArrayAccessData(V_ARRAY(&var), (LPVOID*)&pData);
1135 if (SUCCEEDED(hrSub))
1136 hrSub = FM2_ReadFilterData(pData, &rf2);
1138 if (pData)
1139 SafeArrayUnaccessData(V_ARRAY(&var));
1141 VariantClear(&var);
1143 /* Logic used for bInputMatch expression:
1144 * There exists some pin such that bInputNeeded implies (pin is an input and
1145 * (bRender implies pin has render flag) and major/minor types members of
1146 * pInputTypes )
1147 * bOutputMatch is similar, but without the "bRender implies ..." part
1148 * and substituting variables names containing input for output
1151 /* determine whether filter meets requirements */
1152 if (SUCCEEDED(hrSub) && (rf2.dwMerit >= dwMerit))
1154 for (i = 0; (i < rf2.cPins2) && (!bInputMatch || !bOutputMatch); i++)
1156 const REGFILTERPINS2 * rfp2 = rf2.rgPins2 + i;
1158 bInputMatch = bInputMatch || (!(rfp2->dwFlags & REG_PINFLAG_B_OUTPUT) &&
1159 (!bRender || (rfp2->dwFlags & REG_PINFLAG_B_RENDERER)) &&
1160 MatchTypes(bExactMatch, rfp2->nMediaTypes, rfp2->lpMediaType, cInputTypes, pInputTypes));
1161 bOutputMatch = bOutputMatch || ((rfp2->dwFlags & REG_PINFLAG_B_OUTPUT) &&
1162 MatchTypes(bExactMatch, rfp2->nMediaTypes, rfp2->lpMediaType, cOutputTypes, pOutputTypes));
1165 if (bInputMatch && bOutputMatch)
1167 struct MONIKER_MERIT mm = {pMoniker, rf2.dwMerit};
1168 IMoniker_AddRef(pMoniker);
1169 add_data(&monikers, &mm, sizeof(mm));
1173 FM2_DeleteRegFilter(&rf2);
1174 if (pPropBag)
1175 IPropertyBag_Release(pPropBag);
1176 IMoniker_Release(pMoniker);
1178 IEnumMoniker_Release(pEnum);
1182 VariantClear(&var);
1183 if (pPropBagCat)
1184 IPropertyBag_Release(pPropBagCat);
1185 IMoniker_Release(pMonikerCat);
1188 if (SUCCEEDED(hr))
1190 IMoniker ** ppMoniker;
1191 unsigned int i;
1192 ULONG nMonikerCount = monikers.current / sizeof(struct MONIKER_MERIT);
1194 /* sort the monikers in descending merit order */
1195 qsort(monikers.pData, nMonikerCount,
1196 sizeof(struct MONIKER_MERIT),
1197 mm_compare);
1199 /* construct an IEnumMoniker interface */
1200 ppMoniker = CoTaskMemAlloc(nMonikerCount * sizeof(IMoniker *));
1201 for (i = 0; i < nMonikerCount; i++)
1203 /* no need to AddRef here as already AddRef'd above */
1204 ppMoniker[i] = ((struct MONIKER_MERIT *)monikers.pData)[i].pMoniker;
1206 hr = enum_moniker_create(ppMoniker, nMonikerCount, ppEnum);
1207 CoTaskMemFree(ppMoniker);
1210 delete_vector(&monikers);
1211 IEnumMoniker_Release(pEnumCat);
1212 ICreateDevEnum_Release(pCreateDevEnum);
1214 return hr;
1217 static HRESULT WINAPI FilterMapper3_GetICreateDevEnum(IFilterMapper3 *iface, ICreateDevEnum **ppEnum)
1219 TRACE("(%p, %p)\n", iface, ppEnum);
1220 if (!ppEnum)
1221 return E_POINTER;
1222 return CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (void**)ppEnum);
1225 static const IFilterMapper3Vtbl fm3vtbl =
1228 FilterMapper3_QueryInterface,
1229 FilterMapper3_AddRef,
1230 FilterMapper3_Release,
1232 FilterMapper3_CreateCategory,
1233 FilterMapper3_UnregisterFilter,
1234 FilterMapper3_RegisterFilter,
1235 FilterMapper3_EnumMatchingFilters,
1236 FilterMapper3_GetICreateDevEnum
1239 /*** IUnknown methods ***/
1241 static HRESULT WINAPI FilterMapper_QueryInterface(IFilterMapper * iface, REFIID riid, LPVOID *ppv)
1243 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1245 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1247 return FilterMapper3_QueryInterface(&This->IFilterMapper3_iface, riid, ppv);
1250 static ULONG WINAPI FilterMapper_AddRef(IFilterMapper * iface)
1252 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1254 return IUnknown_AddRef(This->outer_unk);
1257 static ULONG WINAPI FilterMapper_Release(IFilterMapper * iface)
1259 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1261 return IUnknown_Release(This->outer_unk);
1264 /*** IFilterMapper methods ***/
1266 static HRESULT WINAPI FilterMapper_EnumMatchingFilters(
1267 IFilterMapper * iface,
1268 IEnumRegFilters **ppEnum,
1269 DWORD dwMerit,
1270 BOOL bInputNeeded,
1271 CLSID clsInMaj,
1272 CLSID clsInSub,
1273 BOOL bRender,
1274 BOOL bOutputNeeded,
1275 CLSID clsOutMaj,
1276 CLSID clsOutSub)
1278 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1279 GUID InputType[2];
1280 GUID OutputType[2];
1281 IEnumMoniker* ppEnumMoniker;
1282 IMoniker* IMon;
1283 ULONG nb;
1284 ULONG idx = 0, nb_mon = 0;
1285 REGFILTER* regfilters;
1286 HRESULT hr;
1288 TRACE("(%p/%p)->(%p, %#lx, %s, %s, %s, %s, %s, %s, %s)\n",
1289 This,
1290 iface,
1291 ppEnum,
1292 dwMerit,
1293 bInputNeeded ? "true" : "false",
1294 debugstr_guid(&clsInMaj),
1295 debugstr_guid(&clsInSub),
1296 bRender ? "true" : "false",
1297 bOutputNeeded ? "true" : "false",
1298 debugstr_guid(&clsOutMaj),
1299 debugstr_guid(&clsOutSub));
1301 InputType[0] = clsInMaj;
1302 InputType[1] = clsInSub;
1303 OutputType[0] = clsOutMaj;
1304 OutputType[1] = clsOutSub;
1306 *ppEnum = NULL;
1308 hr = IFilterMapper3_EnumMatchingFilters(&This->IFilterMapper3_iface, &ppEnumMoniker, 0, TRUE,
1309 dwMerit, bInputNeeded, 1, InputType, NULL, &GUID_NULL, bRender, bOutputNeeded, 1,
1310 OutputType, NULL, &GUID_NULL);
1312 if (FAILED(hr))
1313 return hr;
1315 while(IEnumMoniker_Next(ppEnumMoniker, 1, &IMon, &nb) == S_OK)
1317 IMoniker_Release(IMon);
1318 nb_mon++;
1321 if (!nb_mon)
1323 IEnumMoniker_Release(ppEnumMoniker);
1324 return enum_reg_filters_create(NULL, 0, ppEnum);
1327 regfilters = CoTaskMemAlloc(nb_mon * sizeof(REGFILTER));
1328 if (!regfilters)
1330 IEnumMoniker_Release(ppEnumMoniker);
1331 return E_OUTOFMEMORY;
1333 ZeroMemory(regfilters, nb_mon * sizeof(REGFILTER)); /* will prevent bad free of Name in case of error. */
1335 IEnumMoniker_Reset(ppEnumMoniker);
1336 while(IEnumMoniker_Next(ppEnumMoniker, 1, &IMon, &nb) == S_OK)
1338 IPropertyBag * pPropBagCat = NULL;
1339 VARIANT var;
1340 HRESULT hrSub;
1341 GUID clsid;
1342 int len;
1344 VariantInit(&var);
1346 hrSub = IMoniker_BindToStorage(IMon, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
1348 if (SUCCEEDED(hrSub))
1349 hrSub = IPropertyBag_Read(pPropBagCat, L"CLSID", &var, NULL);
1351 if (SUCCEEDED(hrSub))
1352 hrSub = CLSIDFromString(V_BSTR(&var), &clsid);
1354 VariantClear(&var);
1356 if (SUCCEEDED(hrSub))
1357 hrSub = IPropertyBag_Read(pPropBagCat, L"FriendlyName", &var, NULL);
1359 if (SUCCEEDED(hrSub))
1361 len = (wcslen(V_BSTR(&var)) + 1) * sizeof(WCHAR);
1362 if (!(regfilters[idx].Name = CoTaskMemAlloc(len*2)))
1363 hr = E_OUTOFMEMORY;
1366 if (SUCCEEDED(hrSub) && regfilters[idx].Name)
1368 memcpy(regfilters[idx].Name, V_BSTR(&var), len);
1369 regfilters[idx].Clsid = clsid;
1370 idx++;
1373 if (pPropBagCat)
1374 IPropertyBag_Release(pPropBagCat);
1375 IMoniker_Release(IMon);
1376 VariantClear(&var);
1379 if (SUCCEEDED(hr))
1381 hr = enum_reg_filters_create(regfilters, idx, ppEnum);
1384 for (idx = 0; idx < nb_mon; idx++)
1385 CoTaskMemFree(regfilters[idx].Name);
1386 CoTaskMemFree(regfilters);
1387 IEnumMoniker_Release(ppEnumMoniker);
1389 return hr;
1393 static HRESULT WINAPI FilterMapper_RegisterFilter(IFilterMapper * iface,
1394 CLSID clsid, const WCHAR *name, DWORD merit)
1396 WCHAR keypath[46], guidstr[39];
1397 HKEY key;
1398 LONG ret;
1400 TRACE("iface %p, clsid %s, name %s, merit %#lx.\n",
1401 iface, debugstr_guid(&clsid), debugstr_w(name), merit);
1403 StringFromGUID2(&clsid, guidstr, ARRAY_SIZE(guidstr));
1405 wcscpy(keypath, L"Filter\\");
1406 wcscat(keypath, guidstr);
1407 if ((ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
1408 return HRESULT_FROM_WIN32(ret);
1410 if ((ret = RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE *)name, (wcslen(name) + 1) * sizeof(WCHAR))))
1411 ERR("Failed to set filter name, error %lu.\n", ret);
1412 RegCloseKey(key);
1414 wcscpy(keypath, L"CLSID\\");
1415 wcscat(keypath, guidstr);
1416 if (!(ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
1418 if ((ret = RegSetValueExW(key, L"Merit", 0, REG_DWORD, (const BYTE *)&merit, sizeof(DWORD))))
1419 ERR("Failed to set merit, error %lu.\n", ret);
1420 RegCloseKey(key);
1422 else
1423 ERR("Failed to create CLSID key, error %lu.\n", ret);
1425 return S_OK;
1428 static HRESULT WINAPI FilterMapper_RegisterFilterInstance(IFilterMapper * iface, CLSID clsid, LPCWSTR szName, CLSID *MRId)
1430 TRACE("(%p)->(%s, %s, %p)\n", iface, debugstr_guid(&clsid), debugstr_w(szName), MRId);
1432 /* Not implemented in Windows (tested on Win2k) */
1434 return E_NOTIMPL;
1437 static HRESULT WINAPI FilterMapper_RegisterPin(IFilterMapper *iface, CLSID clsid,
1438 const WCHAR *name, BOOL rendered, BOOL output, BOOL zero, BOOL many,
1439 CLSID external_filter, const WCHAR *external_pin)
1441 WCHAR keypath[6 + 38 + 1], *pin_keypath;
1442 HKEY key, pin_key, type_key;
1443 LONG ret;
1445 TRACE("iface %p, clsid %s, name %s, rendered %d, output %d, zero %d, "
1446 "many %d, external_filter %s, external_pin %s.\n",
1447 iface, debugstr_guid(&clsid), debugstr_w(name), rendered, output,
1448 zero, many, debugstr_guid(&external_filter), debugstr_w(external_pin));
1450 wcscpy(keypath, L"CLSID\\");
1451 StringFromGUID2(&clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
1452 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_WRITE, &key)))
1453 return HRESULT_FROM_WIN32(ret);
1455 if (!(pin_keypath = malloc((5 + wcslen(name) + 1) * sizeof(WCHAR))))
1457 RegCloseKey(key);
1458 return E_OUTOFMEMORY;
1460 wcscpy(pin_keypath, L"Pins\\");
1461 wcscat(pin_keypath, name);
1463 if ((ret = RegCreateKeyExW(key, pin_keypath, 0, NULL, 0, KEY_WRITE, NULL, &pin_key, NULL)))
1465 ERR("Failed to open pin key, error %lu.\n", ret);
1466 free(pin_keypath);
1467 RegCloseKey(key);
1468 return HRESULT_FROM_WIN32(ret);
1470 free(pin_keypath);
1472 if ((ret = RegSetValueExW(pin_key, L"AllowedMany", 0, REG_DWORD, (const BYTE *)&many, sizeof(DWORD))))
1473 ERR("Failed to set AllowedMany value, error %lu.\n", ret);
1474 if ((ret = RegSetValueExW(pin_key, L"AllowedZero", 0, REG_DWORD, (const BYTE *)&zero, sizeof(DWORD))))
1475 ERR("Failed to set AllowedZero value, error %lu.\n", ret);
1476 if ((ret = RegSetValueExW(pin_key, L"Direction", 0, REG_DWORD, (const BYTE *)&output, sizeof(DWORD))))
1477 ERR("Failed to set Direction value, error %lu.\n", ret);
1478 if ((ret = RegSetValueExW(pin_key, L"IsRendered", 0, REG_DWORD, (const BYTE *)&rendered, sizeof(DWORD))))
1479 ERR("Failed to set IsRendered value, error %lu.\n", ret);
1481 if (!(ret = RegCreateKeyExW(pin_key, L"Types", 0, NULL, 0, 0, NULL, &type_key, NULL)))
1482 RegCloseKey(type_key);
1483 else
1484 ERR("Failed to create Types subkey, error %lu.\n", ret);
1486 RegCloseKey(pin_key);
1487 RegCloseKey(key);
1489 return S_OK;
1493 static HRESULT WINAPI FilterMapper_RegisterPinType(IFilterMapper *iface,
1494 CLSID clsid, const WCHAR *pin, CLSID majortype, CLSID subtype)
1496 WCHAR *keypath, type_keypath[38 + 1 + 38 + 1];
1497 HKEY key, type_key;
1498 size_t len;
1499 LONG ret;
1501 TRACE("iface %p, clsid %s, pin %s, majortype %s, subtype %s.\n", iface,
1502 debugstr_guid(&clsid), debugstr_w(pin), debugstr_guid(&majortype), debugstr_guid(&subtype));
1504 len = 6 + 38 + 6 + wcslen(pin) + 6 + 1;
1505 if (!(keypath = malloc(len * sizeof(WCHAR))))
1506 return E_OUTOFMEMORY;
1508 wcscpy(keypath, L"CLSID\\");
1509 StringFromGUID2(&clsid, keypath + wcslen(keypath), len - wcslen(keypath));
1510 wcscat(keypath, L"\\Pins\\");
1511 wcscat(keypath, pin);
1512 wcscat(keypath, L"\\Types");
1513 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_CREATE_SUB_KEY, &key)))
1515 free(keypath);
1516 return HRESULT_FROM_WIN32(ret);
1518 free(keypath);
1520 StringFromGUID2(&majortype, type_keypath, ARRAY_SIZE(type_keypath));
1521 wcscat(type_keypath, L"\\");
1522 StringFromGUID2(&subtype, type_keypath + wcslen(type_keypath), ARRAY_SIZE(type_keypath) - wcslen(type_keypath));
1523 if (!(ret = RegCreateKeyExW(key, type_keypath, 0, NULL, 0, 0, NULL, &type_key, NULL)))
1524 RegCloseKey(type_key);
1525 else
1526 ERR("Failed to create type key, error %lu.\n", ret);
1528 RegCloseKey(key);
1529 return HRESULT_FROM_WIN32(ret);
1532 static HRESULT WINAPI FilterMapper_UnregisterFilter(IFilterMapper *iface, CLSID clsid)
1534 WCHAR guidstr[39], keypath[6 + 38 + 1];
1535 LONG ret;
1536 HKEY key;
1538 TRACE("iface %p, clsid %s.\n", iface, debugstr_guid(&clsid));
1540 StringFromGUID2(&clsid, guidstr, ARRAY_SIZE(guidstr));
1542 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Filter", 0, 0, &key)))
1543 return HRESULT_FROM_WIN32(ret);
1544 if ((ret = RegDeleteKeyW(key, guidstr)))
1545 ERR("Failed to delete filter key, error %lu.\n", ret);
1546 RegCloseKey(key);
1548 wcscpy(keypath, L"CLSID\\");
1549 wcscat(keypath, guidstr);
1550 if (!(ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_WRITE, &key)))
1552 if ((ret = RegDeleteValueW(key, L"Merit")))
1553 ERR("Failed to delete Merit value, error %lu.\n", ret);
1554 if ((ret = RegDeleteTreeW(key, L"Pins")))
1555 ERR("Failed to delete Pins key, error %lu.\n", ret);
1556 RegCloseKey(key);
1558 else
1559 ERR("Failed to open CLSID key, error %lu.\n", ret);
1561 return S_OK;
1564 static HRESULT WINAPI FilterMapper_UnregisterFilterInstance(IFilterMapper * iface, CLSID MRId)
1566 TRACE("(%p)->(%s)\n", iface, debugstr_guid(&MRId));
1568 /* Not implemented in Windows (tested on Win2k) */
1570 return E_NOTIMPL;
1573 static HRESULT WINAPI FilterMapper_UnregisterPin(IFilterMapper * iface, CLSID clsid, const WCHAR *name)
1575 WCHAR keypath[6 + 38 + 5 + 1];
1576 LONG ret;
1577 HKEY key;
1579 TRACE("iface %p, clsid %s, name %s.\n", iface, debugstr_guid(&clsid), debugstr_w(name));
1581 if (!name)
1582 return E_INVALIDARG;
1584 wcscpy(keypath, L"CLSID\\");
1585 StringFromGUID2(&clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
1586 wcscat(keypath, L"\\Pins");
1587 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, 0, &key)))
1588 return HRESULT_FROM_WIN32(ret);
1590 if ((ret = RegDeleteTreeW(key, name)))
1591 ERR("Failed to delete subkey, error %lu.\n", ret);
1593 RegCloseKey(key);
1595 return S_OK;
1598 static const IFilterMapperVtbl fmvtbl =
1601 FilterMapper_QueryInterface,
1602 FilterMapper_AddRef,
1603 FilterMapper_Release,
1605 FilterMapper_RegisterFilter,
1606 FilterMapper_RegisterFilterInstance,
1607 FilterMapper_RegisterPin,
1608 FilterMapper_RegisterPinType,
1609 FilterMapper_UnregisterFilter,
1610 FilterMapper_UnregisterFilterInstance,
1611 FilterMapper_UnregisterPin,
1612 FilterMapper_EnumMatchingFilters
1616 /*** IUnknown methods ***/
1617 static HRESULT WINAPI AMFilterData_QueryInterface(IAMFilterData * iface, REFIID riid, LPVOID *ppv)
1619 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1621 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1624 static ULONG WINAPI AMFilterData_AddRef(IAMFilterData * iface)
1626 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1628 return IUnknown_AddRef(This->outer_unk);
1631 static ULONG WINAPI AMFilterData_Release(IAMFilterData * iface)
1633 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1635 return IUnknown_Release(This->outer_unk);
1638 /*** IAMFilterData methods ***/
1639 static HRESULT WINAPI AMFilterData_ParseFilterData(IAMFilterData* iface,
1640 BYTE *pData, ULONG cb,
1641 BYTE **ppRegFilter2)
1643 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1644 HRESULT hr = S_OK;
1645 static REGFILTER2 *prf2;
1647 TRACE("mapper %p, data %p, size %lu, parsed_data %p.\n", This, pData, cb, ppRegFilter2);
1649 prf2 = CoTaskMemAlloc(sizeof(*prf2));
1650 if (!prf2)
1651 return E_OUTOFMEMORY;
1652 *ppRegFilter2 = (BYTE *)&prf2;
1654 hr = FM2_ReadFilterData(pData, prf2);
1655 if (FAILED(hr))
1657 CoTaskMemFree(prf2);
1658 *ppRegFilter2 = NULL;
1661 return hr;
1664 static HRESULT WINAPI AMFilterData_CreateFilterData(IAMFilterData* iface,
1665 REGFILTER2 *prf2,
1666 BYTE **pRegFilterData,
1667 ULONG *pcb)
1669 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1671 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, prf2, pRegFilterData, pcb);
1673 return FM2_WriteFilterData(prf2, pRegFilterData, pcb);
1676 static const IAMFilterDataVtbl AMFilterDataVtbl = {
1677 AMFilterData_QueryInterface,
1678 AMFilterData_AddRef,
1679 AMFilterData_Release,
1680 AMFilterData_ParseFilterData,
1681 AMFilterData_CreateFilterData
1684 HRESULT filter_mapper_create(IUnknown *pUnkOuter, IUnknown **out)
1686 FilterMapper3Impl * pFM2impl;
1688 pFM2impl = CoTaskMemAlloc(sizeof(*pFM2impl));
1689 if (!pFM2impl)
1690 return E_OUTOFMEMORY;
1692 pFM2impl->IUnknown_inner.lpVtbl = &IInner_VTable;
1693 pFM2impl->IFilterMapper3_iface.lpVtbl = &fm3vtbl;
1694 pFM2impl->IFilterMapper_iface.lpVtbl = &fmvtbl;
1695 pFM2impl->IAMFilterData_iface.lpVtbl = &AMFilterDataVtbl;
1696 pFM2impl->ref = 1;
1698 if (pUnkOuter)
1699 pFM2impl->outer_unk = pUnkOuter;
1700 else
1701 pFM2impl->outer_unk = &pFM2impl->IUnknown_inner;
1703 TRACE("Created filter mapper %p.\n", pFM2impl);
1704 *out = &pFM2impl->IUnknown_inner;
1705 return S_OK;