quartz: Avoid reading past the end of a buffer (Valgrind).
[wine.git] / dlls / quartz / filtermapper.c
blobdd7c6c4187216a296c7cf069651234eed7087623
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 %lu.\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 %lu.\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 %lu, 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 %lu, 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 %lu.\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 %lu.\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 %lu, 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 %lu.\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 + size <= 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 *mapper = impl_from_IUnknown(iface);
473 ULONG refcount = InterlockedIncrement(&mapper->ref);
475 TRACE("%p increasing refcount to %lu.\n", mapper, refcount);
477 return refcount;
480 static ULONG WINAPI Inner_Release(IUnknown *iface)
482 FilterMapper3Impl *mapper = impl_from_IUnknown(iface);
483 ULONG refcount = InterlockedDecrement(&mapper->ref);
485 TRACE("%p decreasing refcount to %lu.\n", mapper, refcount);
487 if (!refcount)
489 CoTaskMemFree(mapper);
492 return refcount;
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 %#lx, 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 %lu is not supported.\n", prrf->dwVersion);
706 ZeroMemory(prf2, sizeof(*prf2));
707 hr = E_FAIL;
710 if (SUCCEEDED(hr))
712 TRACE("dwVersion %lu, dwMerit %#lx, dwPins %lu, dwUnused %#lx.\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 %lu: dwFlags %#lx, dwInstances %lu, dwMediaTypes %lu, dwMediums %lu.\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)))
898 free(display_name);
899 return hr;
902 if (FAILED(hr = IParseDisplayName_ParseDisplayName(parser, NULL, display_name, &eaten, &moniker)))
904 ERR("Failed to parse display name, hr %#lx.\n", hr);
905 IParseDisplayName_Release(parser);
906 free(display_name);
907 return hr;
910 IParseDisplayName_Release(parser);
912 if (FAILED(hr = IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag)))
914 ERR("Failed to get property bag, hr %#lx.\n", hr);
915 IMoniker_Release(moniker);
916 free(display_name);
917 return hr;
920 V_VT(&var) = VT_BSTR;
921 V_BSTR(&var) = SysAllocString(name);
922 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"FriendlyName", &var)))
923 ERR("Failed to write friendly name, hr %#lx.\n", hr);
924 VariantClear(&var);
926 V_VT(&var) = VT_BSTR;
927 V_BSTR(&var) = SysAllocString(clsid_string);
928 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"CLSID", &var)))
929 ERR("Failed to write class ID, hr %#lx.\n", hr);
930 VariantClear(&var);
932 if (SUCCEEDED(FM2_WriteFilterData(&regfilter2, &filter_data, &filter_data_len)))
934 V_VT(&var) = VT_ARRAY | VT_UI1;
935 if ((V_ARRAY(&var) = SafeArrayCreateVector(VT_UI1, 0, filter_data_len)))
937 memcpy(V_ARRAY(&var)->pvData, filter_data, filter_data_len);
938 if (FAILED(hr = IPropertyBag_Write(prop_bag, L"FilterData", &var)))
939 ERR("Failed to write filter data, hr %#lx.\n", hr);
940 VariantClear(&var);
943 CoTaskMemFree(filter_data);
946 IPropertyBag_Release(prop_bag);
947 free(display_name);
949 if (ret_moniker)
950 *ret_moniker = moniker;
951 else
952 IMoniker_Release(moniker);
954 CoTaskMemFree(pregfp2);
956 return S_OK;
959 /* internal helper function */
960 static BOOL MatchTypes(
961 BOOL bExactMatch,
962 DWORD nPinTypes,
963 const REGPINTYPES * pPinTypes,
964 DWORD nMatchTypes,
965 const GUID * pMatchTypes)
967 BOOL bMatch = FALSE;
968 DWORD j;
970 if ((nMatchTypes == 0) && (nPinTypes > 0))
971 bMatch = TRUE;
973 for (j = 0; j < nPinTypes; j++)
975 DWORD i;
976 for (i = 0; i < nMatchTypes*2; i+=2)
978 if (((!bExactMatch && IsEqualGUID(pPinTypes[j].clsMajorType, &GUID_NULL)) || IsEqualGUID(&pMatchTypes[i], &GUID_NULL) || IsEqualGUID(pPinTypes[j].clsMajorType, &pMatchTypes[i])) &&
979 ((!bExactMatch && IsEqualGUID(pPinTypes[j].clsMinorType, &GUID_NULL)) || IsEqualGUID(&pMatchTypes[i+1], &GUID_NULL) || IsEqualGUID(pPinTypes[j].clsMinorType, &pMatchTypes[i+1])))
981 bMatch = TRUE;
982 break;
986 return bMatch;
989 /* internal helper function for qsort of MONIKER_MERIT array */
990 static int __cdecl mm_compare(const void * left, const void * right)
992 const struct MONIKER_MERIT * mmLeft = left;
993 const struct MONIKER_MERIT * mmRight = right;
995 if (mmLeft->dwMerit == mmRight->dwMerit)
996 return 0;
997 if (mmLeft->dwMerit > mmRight->dwMerit)
998 return -1;
999 return 1;
1002 /* NOTES:
1003 * Exact match means whether or not to treat GUID_NULL's in filter data as wild cards
1004 * (GUID_NULL's in input to function automatically treated as wild cards)
1005 * Input/Output needed means match only on criteria if TRUE (with zero input types
1006 * meaning match any input/output pin as long as one exists), otherwise match any
1007 * filter that meets the rest of the requirements.
1009 static HRESULT WINAPI FilterMapper3_EnumMatchingFilters(
1010 IFilterMapper3 * iface,
1011 IEnumMoniker **ppEnum,
1012 DWORD dwFlags,
1013 BOOL bExactMatch,
1014 DWORD dwMerit,
1015 BOOL bInputNeeded,
1016 DWORD cInputTypes,
1017 const GUID *pInputTypes,
1018 const REGPINMEDIUM *pMedIn,
1019 const CLSID *pPinCategoryIn,
1020 BOOL bRender,
1021 BOOL bOutputNeeded,
1022 DWORD cOutputTypes,
1023 const GUID *pOutputTypes,
1024 const REGPINMEDIUM *pMedOut,
1025 const CLSID *pPinCategoryOut)
1027 ICreateDevEnum * pCreateDevEnum;
1028 IMoniker * pMonikerCat;
1029 IEnumMoniker * pEnumCat;
1030 HRESULT hr;
1031 struct Vector monikers = {NULL, 0, 0};
1033 TRACE("(%p, %#lx, %s, %#lx, %s, %lu, %p, %p, %p, %s, %s, %p, %p, %p)\n",
1034 ppEnum,
1035 dwFlags,
1036 bExactMatch ? "true" : "false",
1037 dwMerit,
1038 bInputNeeded ? "true" : "false",
1039 cInputTypes,
1040 pInputTypes,
1041 pMedIn,
1042 pPinCategoryIn,
1043 bRender ? "true" : "false",
1044 bOutputNeeded ? "true" : "false",
1045 pOutputTypes,
1046 pMedOut,
1047 pPinCategoryOut);
1049 if (dwFlags != 0)
1050 FIXME("Ignoring flags %#lx.\n", dwFlags);
1052 *ppEnum = NULL;
1054 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (LPVOID*)&pCreateDevEnum);
1055 if (FAILED(hr))
1056 return hr;
1058 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEnumCat, 0);
1059 if (FAILED(hr)) {
1060 ICreateDevEnum_Release(pCreateDevEnum);
1061 return hr;
1064 while (IEnumMoniker_Next(pEnumCat, 1, &pMonikerCat, NULL) == S_OK)
1066 IPropertyBag * pPropBagCat = NULL;
1067 VARIANT var;
1068 HRESULT hrSub; /* this is so that one buggy filter
1069 doesn't make the whole lot fail */
1071 VariantInit(&var);
1073 hrSub = IMoniker_BindToStorage(pMonikerCat, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
1075 if (SUCCEEDED(hrSub))
1076 hrSub = IPropertyBag_Read(pPropBagCat, L"Merit", &var, NULL);
1078 if (SUCCEEDED(hrSub) && (V_UI4(&var) >= dwMerit))
1080 CLSID clsidCat;
1081 IEnumMoniker * pEnum;
1082 IMoniker * pMoniker;
1084 VariantClear(&var);
1086 if (TRACE_ON(quartz))
1088 VARIANT temp;
1089 V_VT(&temp) = VT_EMPTY;
1090 IPropertyBag_Read(pPropBagCat, L"FriendlyName", &temp, NULL);
1091 TRACE("Considering category %s\n", debugstr_w(V_BSTR(&temp)));
1092 VariantClear(&temp);
1095 hrSub = IPropertyBag_Read(pPropBagCat, L"CLSID", &var, NULL);
1097 if (SUCCEEDED(hrSub))
1098 hrSub = CLSIDFromString(V_BSTR(&var), &clsidCat);
1100 if (SUCCEEDED(hrSub))
1101 hrSub = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1103 if (hrSub == S_OK)
1105 while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1107 IPropertyBag * pPropBag = NULL;
1108 VARIANT var;
1109 BYTE *pData = NULL;
1110 REGFILTER2 rf2;
1111 DWORD i;
1112 BOOL bInputMatch = !bInputNeeded;
1113 BOOL bOutputMatch = !bOutputNeeded;
1115 ZeroMemory(&rf2, sizeof(rf2));
1116 VariantInit(&var);
1118 hrSub = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBag);
1120 if (TRACE_ON(quartz))
1122 VARIANT temp;
1123 V_VT(&temp) = VT_EMPTY;
1124 IPropertyBag_Read(pPropBag, L"FriendlyName", &temp, NULL);
1125 TRACE("Considering filter %s\n", debugstr_w(V_BSTR(&temp)));
1126 VariantClear(&temp);
1129 if (SUCCEEDED(hrSub))
1131 hrSub = IPropertyBag_Read(pPropBag, L"FilterData", &var, NULL);
1134 if (SUCCEEDED(hrSub))
1135 hrSub = SafeArrayAccessData(V_ARRAY(&var), (LPVOID*)&pData);
1137 if (SUCCEEDED(hrSub))
1138 hrSub = FM2_ReadFilterData(pData, &rf2);
1140 if (pData)
1141 SafeArrayUnaccessData(V_ARRAY(&var));
1143 VariantClear(&var);
1145 /* Logic used for bInputMatch expression:
1146 * There exists some pin such that bInputNeeded implies (pin is an input and
1147 * (bRender implies pin has render flag) and major/minor types members of
1148 * pInputTypes )
1149 * bOutputMatch is similar, but without the "bRender implies ..." part
1150 * and substituting variables names containing input for output
1153 /* determine whether filter meets requirements */
1154 if (SUCCEEDED(hrSub) && (rf2.dwMerit >= dwMerit))
1156 for (i = 0; (i < rf2.cPins2) && (!bInputMatch || !bOutputMatch); i++)
1158 const REGFILTERPINS2 * rfp2 = rf2.rgPins2 + i;
1160 bInputMatch = bInputMatch || (!(rfp2->dwFlags & REG_PINFLAG_B_OUTPUT) &&
1161 (!bRender || (rfp2->dwFlags & REG_PINFLAG_B_RENDERER)) &&
1162 MatchTypes(bExactMatch, rfp2->nMediaTypes, rfp2->lpMediaType, cInputTypes, pInputTypes));
1163 bOutputMatch = bOutputMatch || ((rfp2->dwFlags & REG_PINFLAG_B_OUTPUT) &&
1164 MatchTypes(bExactMatch, rfp2->nMediaTypes, rfp2->lpMediaType, cOutputTypes, pOutputTypes));
1167 if (bInputMatch && bOutputMatch)
1169 struct MONIKER_MERIT mm = {pMoniker, rf2.dwMerit};
1170 IMoniker_AddRef(pMoniker);
1171 add_data(&monikers, &mm, sizeof(mm));
1175 FM2_DeleteRegFilter(&rf2);
1176 if (pPropBag)
1177 IPropertyBag_Release(pPropBag);
1178 IMoniker_Release(pMoniker);
1180 IEnumMoniker_Release(pEnum);
1184 VariantClear(&var);
1185 if (pPropBagCat)
1186 IPropertyBag_Release(pPropBagCat);
1187 IMoniker_Release(pMonikerCat);
1190 if (SUCCEEDED(hr))
1192 IMoniker ** ppMoniker;
1193 unsigned int i;
1194 ULONG nMonikerCount = monikers.current / sizeof(struct MONIKER_MERIT);
1196 /* sort the monikers in descending merit order */
1197 qsort(monikers.pData, nMonikerCount,
1198 sizeof(struct MONIKER_MERIT),
1199 mm_compare);
1201 /* construct an IEnumMoniker interface */
1202 ppMoniker = CoTaskMemAlloc(nMonikerCount * sizeof(IMoniker *));
1203 for (i = 0; i < nMonikerCount; i++)
1205 /* no need to AddRef here as already AddRef'd above */
1206 ppMoniker[i] = ((struct MONIKER_MERIT *)monikers.pData)[i].pMoniker;
1208 hr = enum_moniker_create(ppMoniker, nMonikerCount, ppEnum);
1209 CoTaskMemFree(ppMoniker);
1212 delete_vector(&monikers);
1213 IEnumMoniker_Release(pEnumCat);
1214 ICreateDevEnum_Release(pCreateDevEnum);
1216 return hr;
1219 static HRESULT WINAPI FilterMapper3_GetICreateDevEnum(IFilterMapper3 *iface, ICreateDevEnum **ppEnum)
1221 TRACE("(%p, %p)\n", iface, ppEnum);
1222 if (!ppEnum)
1223 return E_POINTER;
1224 return CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (void**)ppEnum);
1227 static const IFilterMapper3Vtbl fm3vtbl =
1230 FilterMapper3_QueryInterface,
1231 FilterMapper3_AddRef,
1232 FilterMapper3_Release,
1234 FilterMapper3_CreateCategory,
1235 FilterMapper3_UnregisterFilter,
1236 FilterMapper3_RegisterFilter,
1237 FilterMapper3_EnumMatchingFilters,
1238 FilterMapper3_GetICreateDevEnum
1241 /*** IUnknown methods ***/
1243 static HRESULT WINAPI FilterMapper_QueryInterface(IFilterMapper * iface, REFIID riid, LPVOID *ppv)
1245 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1247 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1249 return FilterMapper3_QueryInterface(&This->IFilterMapper3_iface, riid, ppv);
1252 static ULONG WINAPI FilterMapper_AddRef(IFilterMapper * iface)
1254 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1256 return IUnknown_AddRef(This->outer_unk);
1259 static ULONG WINAPI FilterMapper_Release(IFilterMapper * iface)
1261 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1263 return IUnknown_Release(This->outer_unk);
1266 /*** IFilterMapper methods ***/
1268 static HRESULT WINAPI FilterMapper_EnumMatchingFilters(
1269 IFilterMapper * iface,
1270 IEnumRegFilters **ppEnum,
1271 DWORD dwMerit,
1272 BOOL bInputNeeded,
1273 CLSID clsInMaj,
1274 CLSID clsInSub,
1275 BOOL bRender,
1276 BOOL bOutputNeeded,
1277 CLSID clsOutMaj,
1278 CLSID clsOutSub)
1280 FilterMapper3Impl *This = impl_from_IFilterMapper(iface);
1281 GUID InputType[2];
1282 GUID OutputType[2];
1283 IEnumMoniker* ppEnumMoniker;
1284 IMoniker* IMon;
1285 ULONG nb;
1286 ULONG idx = 0, nb_mon = 0;
1287 REGFILTER* regfilters;
1288 HRESULT hr;
1290 TRACE("(%p/%p)->(%p, %#lx, %s, %s, %s, %s, %s, %s, %s)\n",
1291 This,
1292 iface,
1293 ppEnum,
1294 dwMerit,
1295 bInputNeeded ? "true" : "false",
1296 debugstr_guid(&clsInMaj),
1297 debugstr_guid(&clsInSub),
1298 bRender ? "true" : "false",
1299 bOutputNeeded ? "true" : "false",
1300 debugstr_guid(&clsOutMaj),
1301 debugstr_guid(&clsOutSub));
1303 InputType[0] = clsInMaj;
1304 InputType[1] = clsInSub;
1305 OutputType[0] = clsOutMaj;
1306 OutputType[1] = clsOutSub;
1308 *ppEnum = NULL;
1310 hr = IFilterMapper3_EnumMatchingFilters(&This->IFilterMapper3_iface, &ppEnumMoniker, 0, TRUE,
1311 dwMerit, bInputNeeded, 1, InputType, NULL, &GUID_NULL, bRender, bOutputNeeded, 1,
1312 OutputType, NULL, &GUID_NULL);
1314 if (FAILED(hr))
1315 return hr;
1317 while(IEnumMoniker_Next(ppEnumMoniker, 1, &IMon, &nb) == S_OK)
1319 IMoniker_Release(IMon);
1320 nb_mon++;
1323 if (!nb_mon)
1325 IEnumMoniker_Release(ppEnumMoniker);
1326 return enum_reg_filters_create(NULL, 0, ppEnum);
1329 regfilters = CoTaskMemAlloc(nb_mon * sizeof(REGFILTER));
1330 if (!regfilters)
1332 IEnumMoniker_Release(ppEnumMoniker);
1333 return E_OUTOFMEMORY;
1335 ZeroMemory(regfilters, nb_mon * sizeof(REGFILTER)); /* will prevent bad free of Name in case of error. */
1337 IEnumMoniker_Reset(ppEnumMoniker);
1338 while(IEnumMoniker_Next(ppEnumMoniker, 1, &IMon, &nb) == S_OK)
1340 IPropertyBag * pPropBagCat = NULL;
1341 VARIANT var;
1342 HRESULT hrSub;
1343 GUID clsid;
1344 int len;
1346 VariantInit(&var);
1348 hrSub = IMoniker_BindToStorage(IMon, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
1350 if (SUCCEEDED(hrSub))
1351 hrSub = IPropertyBag_Read(pPropBagCat, L"CLSID", &var, NULL);
1353 if (SUCCEEDED(hrSub))
1354 hrSub = CLSIDFromString(V_BSTR(&var), &clsid);
1356 VariantClear(&var);
1358 if (SUCCEEDED(hrSub))
1359 hrSub = IPropertyBag_Read(pPropBagCat, L"FriendlyName", &var, NULL);
1361 if (SUCCEEDED(hrSub))
1363 len = (wcslen(V_BSTR(&var)) + 1) * sizeof(WCHAR);
1364 if (!(regfilters[idx].Name = CoTaskMemAlloc(len*2)))
1365 hr = E_OUTOFMEMORY;
1368 if (SUCCEEDED(hrSub) && regfilters[idx].Name)
1370 memcpy(regfilters[idx].Name, V_BSTR(&var), len);
1371 regfilters[idx].Clsid = clsid;
1372 idx++;
1375 if (pPropBagCat)
1376 IPropertyBag_Release(pPropBagCat);
1377 IMoniker_Release(IMon);
1378 VariantClear(&var);
1381 if (SUCCEEDED(hr))
1383 hr = enum_reg_filters_create(regfilters, idx, ppEnum);
1386 for (idx = 0; idx < nb_mon; idx++)
1387 CoTaskMemFree(regfilters[idx].Name);
1388 CoTaskMemFree(regfilters);
1389 IEnumMoniker_Release(ppEnumMoniker);
1391 return hr;
1395 static HRESULT WINAPI FilterMapper_RegisterFilter(IFilterMapper * iface,
1396 CLSID clsid, const WCHAR *name, DWORD merit)
1398 WCHAR keypath[46], guidstr[39];
1399 HKEY key;
1400 LONG ret;
1402 TRACE("iface %p, clsid %s, name %s, merit %#lx.\n",
1403 iface, debugstr_guid(&clsid), debugstr_w(name), merit);
1405 StringFromGUID2(&clsid, guidstr, ARRAY_SIZE(guidstr));
1407 wcscpy(keypath, L"Filter\\");
1408 wcscat(keypath, guidstr);
1409 if ((ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
1410 return HRESULT_FROM_WIN32(ret);
1412 if ((ret = RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE *)name, (wcslen(name) + 1) * sizeof(WCHAR))))
1413 ERR("Failed to set filter name, error %lu.\n", ret);
1414 RegCloseKey(key);
1416 wcscpy(keypath, L"CLSID\\");
1417 wcscat(keypath, guidstr);
1418 if (!(ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, keypath, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL)))
1420 if ((ret = RegSetValueExW(key, L"Merit", 0, REG_DWORD, (const BYTE *)&merit, sizeof(DWORD))))
1421 ERR("Failed to set merit, error %lu.\n", ret);
1422 RegCloseKey(key);
1424 else
1425 ERR("Failed to create CLSID key, error %lu.\n", ret);
1427 return S_OK;
1430 static HRESULT WINAPI FilterMapper_RegisterFilterInstance(IFilterMapper * iface, CLSID clsid, LPCWSTR szName, CLSID *MRId)
1432 TRACE("(%p)->(%s, %s, %p)\n", iface, debugstr_guid(&clsid), debugstr_w(szName), MRId);
1434 /* Not implemented in Windows (tested on Win2k) */
1436 return E_NOTIMPL;
1439 static HRESULT WINAPI FilterMapper_RegisterPin(IFilterMapper *iface, CLSID clsid,
1440 const WCHAR *name, BOOL rendered, BOOL output, BOOL zero, BOOL many,
1441 CLSID external_filter, const WCHAR *external_pin)
1443 WCHAR keypath[6 + 38 + 1], *pin_keypath;
1444 HKEY key, pin_key, type_key;
1445 LONG ret;
1447 TRACE("iface %p, clsid %s, name %s, rendered %d, output %d, zero %d, "
1448 "many %d, external_filter %s, external_pin %s.\n",
1449 iface, debugstr_guid(&clsid), debugstr_w(name), rendered, output,
1450 zero, many, debugstr_guid(&external_filter), debugstr_w(external_pin));
1452 wcscpy(keypath, L"CLSID\\");
1453 StringFromGUID2(&clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
1454 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_WRITE, &key)))
1455 return HRESULT_FROM_WIN32(ret);
1457 if (!(pin_keypath = malloc((5 + wcslen(name) + 1) * sizeof(WCHAR))))
1459 RegCloseKey(key);
1460 return E_OUTOFMEMORY;
1462 wcscpy(pin_keypath, L"Pins\\");
1463 wcscat(pin_keypath, name);
1465 if ((ret = RegCreateKeyExW(key, pin_keypath, 0, NULL, 0, KEY_WRITE, NULL, &pin_key, NULL)))
1467 ERR("Failed to open pin key, error %lu.\n", ret);
1468 free(pin_keypath);
1469 RegCloseKey(key);
1470 return HRESULT_FROM_WIN32(ret);
1472 free(pin_keypath);
1474 if ((ret = RegSetValueExW(pin_key, L"AllowedMany", 0, REG_DWORD, (const BYTE *)&many, sizeof(DWORD))))
1475 ERR("Failed to set AllowedMany value, error %lu.\n", ret);
1476 if ((ret = RegSetValueExW(pin_key, L"AllowedZero", 0, REG_DWORD, (const BYTE *)&zero, sizeof(DWORD))))
1477 ERR("Failed to set AllowedZero value, error %lu.\n", ret);
1478 if ((ret = RegSetValueExW(pin_key, L"Direction", 0, REG_DWORD, (const BYTE *)&output, sizeof(DWORD))))
1479 ERR("Failed to set Direction value, error %lu.\n", ret);
1480 if ((ret = RegSetValueExW(pin_key, L"IsRendered", 0, REG_DWORD, (const BYTE *)&rendered, sizeof(DWORD))))
1481 ERR("Failed to set IsRendered value, error %lu.\n", ret);
1483 if (!(ret = RegCreateKeyExW(pin_key, L"Types", 0, NULL, 0, 0, NULL, &type_key, NULL)))
1484 RegCloseKey(type_key);
1485 else
1486 ERR("Failed to create Types subkey, error %lu.\n", ret);
1488 RegCloseKey(pin_key);
1489 RegCloseKey(key);
1491 return S_OK;
1495 static HRESULT WINAPI FilterMapper_RegisterPinType(IFilterMapper *iface,
1496 CLSID clsid, const WCHAR *pin, CLSID majortype, CLSID subtype)
1498 WCHAR *keypath, type_keypath[38 + 1 + 38 + 1];
1499 HKEY key, type_key;
1500 size_t len;
1501 LONG ret;
1503 TRACE("iface %p, clsid %s, pin %s, majortype %s, subtype %s.\n", iface,
1504 debugstr_guid(&clsid), debugstr_w(pin), debugstr_guid(&majortype), debugstr_guid(&subtype));
1506 len = 6 + 38 + 6 + wcslen(pin) + 6 + 1;
1507 if (!(keypath = malloc(len * sizeof(WCHAR))))
1508 return E_OUTOFMEMORY;
1510 wcscpy(keypath, L"CLSID\\");
1511 StringFromGUID2(&clsid, keypath + wcslen(keypath), len - wcslen(keypath));
1512 wcscat(keypath, L"\\Pins\\");
1513 wcscat(keypath, pin);
1514 wcscat(keypath, L"\\Types");
1515 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_CREATE_SUB_KEY, &key)))
1517 free(keypath);
1518 return HRESULT_FROM_WIN32(ret);
1520 free(keypath);
1522 StringFromGUID2(&majortype, type_keypath, ARRAY_SIZE(type_keypath));
1523 wcscat(type_keypath, L"\\");
1524 StringFromGUID2(&subtype, type_keypath + wcslen(type_keypath), ARRAY_SIZE(type_keypath) - wcslen(type_keypath));
1525 if (!(ret = RegCreateKeyExW(key, type_keypath, 0, NULL, 0, 0, NULL, &type_key, NULL)))
1526 RegCloseKey(type_key);
1527 else
1528 ERR("Failed to create type key, error %lu.\n", ret);
1530 RegCloseKey(key);
1531 return HRESULT_FROM_WIN32(ret);
1534 static HRESULT WINAPI FilterMapper_UnregisterFilter(IFilterMapper *iface, CLSID clsid)
1536 WCHAR guidstr[39], keypath[6 + 38 + 1];
1537 LONG ret;
1538 HKEY key;
1540 TRACE("iface %p, clsid %s.\n", iface, debugstr_guid(&clsid));
1542 StringFromGUID2(&clsid, guidstr, ARRAY_SIZE(guidstr));
1544 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Filter", 0, 0, &key)))
1545 return HRESULT_FROM_WIN32(ret);
1546 if ((ret = RegDeleteKeyW(key, guidstr)))
1547 ERR("Failed to delete filter key, error %lu.\n", ret);
1548 RegCloseKey(key);
1550 wcscpy(keypath, L"CLSID\\");
1551 wcscat(keypath, guidstr);
1552 if (!(ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, KEY_WRITE, &key)))
1554 if ((ret = RegDeleteValueW(key, L"Merit")))
1555 ERR("Failed to delete Merit value, error %lu.\n", ret);
1556 if ((ret = RegDeleteTreeW(key, L"Pins")))
1557 ERR("Failed to delete Pins key, error %lu.\n", ret);
1558 RegCloseKey(key);
1560 else
1561 ERR("Failed to open CLSID key, error %lu.\n", ret);
1563 return S_OK;
1566 static HRESULT WINAPI FilterMapper_UnregisterFilterInstance(IFilterMapper * iface, CLSID MRId)
1568 TRACE("(%p)->(%s)\n", iface, debugstr_guid(&MRId));
1570 /* Not implemented in Windows (tested on Win2k) */
1572 return E_NOTIMPL;
1575 static HRESULT WINAPI FilterMapper_UnregisterPin(IFilterMapper * iface, CLSID clsid, const WCHAR *name)
1577 WCHAR keypath[6 + 38 + 5 + 1];
1578 LONG ret;
1579 HKEY key;
1581 TRACE("iface %p, clsid %s, name %s.\n", iface, debugstr_guid(&clsid), debugstr_w(name));
1583 if (!name)
1584 return E_INVALIDARG;
1586 wcscpy(keypath, L"CLSID\\");
1587 StringFromGUID2(&clsid, keypath + wcslen(keypath), ARRAY_SIZE(keypath) - wcslen(keypath));
1588 wcscat(keypath, L"\\Pins");
1589 if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, keypath, 0, 0, &key)))
1590 return HRESULT_FROM_WIN32(ret);
1592 if ((ret = RegDeleteTreeW(key, name)))
1593 ERR("Failed to delete subkey, error %lu.\n", ret);
1595 RegCloseKey(key);
1597 return S_OK;
1600 static const IFilterMapperVtbl fmvtbl =
1603 FilterMapper_QueryInterface,
1604 FilterMapper_AddRef,
1605 FilterMapper_Release,
1607 FilterMapper_RegisterFilter,
1608 FilterMapper_RegisterFilterInstance,
1609 FilterMapper_RegisterPin,
1610 FilterMapper_RegisterPinType,
1611 FilterMapper_UnregisterFilter,
1612 FilterMapper_UnregisterFilterInstance,
1613 FilterMapper_UnregisterPin,
1614 FilterMapper_EnumMatchingFilters
1618 /*** IUnknown methods ***/
1619 static HRESULT WINAPI AMFilterData_QueryInterface(IAMFilterData * iface, REFIID riid, LPVOID *ppv)
1621 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1623 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1626 static ULONG WINAPI AMFilterData_AddRef(IAMFilterData * iface)
1628 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1630 return IUnknown_AddRef(This->outer_unk);
1633 static ULONG WINAPI AMFilterData_Release(IAMFilterData * iface)
1635 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1637 return IUnknown_Release(This->outer_unk);
1640 /*** IAMFilterData methods ***/
1641 static HRESULT WINAPI AMFilterData_ParseFilterData(IAMFilterData* iface,
1642 BYTE *pData, ULONG cb,
1643 BYTE **ppRegFilter2)
1645 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1646 HRESULT hr = S_OK;
1647 static REGFILTER2 *prf2;
1649 TRACE("mapper %p, data %p, size %lu, parsed_data %p.\n", This, pData, cb, ppRegFilter2);
1651 prf2 = CoTaskMemAlloc(sizeof(*prf2));
1652 if (!prf2)
1653 return E_OUTOFMEMORY;
1654 *ppRegFilter2 = (BYTE *)&prf2;
1656 hr = FM2_ReadFilterData(pData, prf2);
1657 if (FAILED(hr))
1659 CoTaskMemFree(prf2);
1660 *ppRegFilter2 = NULL;
1663 return hr;
1666 static HRESULT WINAPI AMFilterData_CreateFilterData(IAMFilterData* iface,
1667 REGFILTER2 *prf2,
1668 BYTE **pRegFilterData,
1669 ULONG *pcb)
1671 FilterMapper3Impl *This = impl_from_IAMFilterData(iface);
1673 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, prf2, pRegFilterData, pcb);
1675 return FM2_WriteFilterData(prf2, pRegFilterData, pcb);
1678 static const IAMFilterDataVtbl AMFilterDataVtbl = {
1679 AMFilterData_QueryInterface,
1680 AMFilterData_AddRef,
1681 AMFilterData_Release,
1682 AMFilterData_ParseFilterData,
1683 AMFilterData_CreateFilterData
1686 HRESULT filter_mapper_create(IUnknown *pUnkOuter, IUnknown **out)
1688 FilterMapper3Impl * pFM2impl;
1690 pFM2impl = CoTaskMemAlloc(sizeof(*pFM2impl));
1691 if (!pFM2impl)
1692 return E_OUTOFMEMORY;
1694 pFM2impl->IUnknown_inner.lpVtbl = &IInner_VTable;
1695 pFM2impl->IFilterMapper3_iface.lpVtbl = &fm3vtbl;
1696 pFM2impl->IFilterMapper_iface.lpVtbl = &fmvtbl;
1697 pFM2impl->IAMFilterData_iface.lpVtbl = &AMFilterDataVtbl;
1698 pFM2impl->ref = 1;
1700 if (pUnkOuter)
1701 pFM2impl->outer_unk = pUnkOuter;
1702 else
1703 pFM2impl->outer_unk = &pFM2impl->IUnknown_inner;
1705 TRACE("Created filter mapper %p.\n", pFM2impl);
1706 *out = &pFM2impl->IUnknown_inner;
1707 return S_OK;