2 * Filtermapper unit tests for Quartz
4 * Copyright (C) 2008 Alexander Dorofeyev
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/test.h"
29 #include "wine/fil_data.h"
31 static const GUID testclsid
= {0x77777777};
33 static IFilterMapper3
*create_mapper(void)
37 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterMapper3
, (void **)&ret
);
38 ok(hr
== S_OK
, "Failed to create filter mapper, hr %#lx.\n", hr
);
42 static ULONG
get_refcount(void *iface
)
44 IUnknown
*unknown
= iface
;
45 IUnknown_AddRef(unknown
);
46 return IUnknown_Release(unknown
);
49 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
50 static void check_interface_(unsigned int line
, void *iface_ptr
, REFIID iid
, BOOL supported
)
52 IUnknown
*iface
= iface_ptr
;
53 HRESULT hr
, expected_hr
;
56 expected_hr
= supported
? S_OK
: E_NOINTERFACE
;
58 hr
= IUnknown_QueryInterface(iface
, iid
, (void **)&unk
);
59 ok_(__FILE__
, line
)(hr
== expected_hr
, "Got hr %#lx, expected %#lx.\n", hr
, expected_hr
);
61 IUnknown_Release(unk
);
64 static void test_interfaces(void)
66 IFilterMapper3
*mapper
= create_mapper();
68 check_interface(mapper
, &IID_IAMFilterData
, TRUE
);
69 check_interface(mapper
, &IID_IFilterMapper
, TRUE
);
70 check_interface(mapper
, &IID_IFilterMapper2
, TRUE
);
71 check_interface(mapper
, &IID_IFilterMapper3
, TRUE
);
72 check_interface(mapper
, &IID_IUnknown
, TRUE
);
74 check_interface(mapper
, &IID_IFilterGraph
, FALSE
);
76 IFilterMapper3_Release(mapper
);
79 /* Helper function, checks if filter with given name was enumerated. */
80 static BOOL
enum_find_filter(const WCHAR
*wszFilterName
, IEnumMoniker
*pEnum
)
82 IMoniker
*pMoniker
= NULL
;
87 while(!found
&& IEnumMoniker_Next(pEnum
, 1, &pMoniker
, &nb
) == S_OK
)
89 IPropertyBag
* pPropBagCat
= NULL
;
94 hr
= IMoniker_BindToStorage(pMoniker
, NULL
, NULL
, &IID_IPropertyBag
, (LPVOID
*)&pPropBagCat
);
95 ok(SUCCEEDED(hr
), "Got hr %#lx.\n", hr
);
97 hr
= IPropertyBag_Read(pPropBagCat
, L
"FriendlyName", &var
, NULL
);
98 ok(SUCCEEDED(hr
), "Got hr %#lx.\n", hr
);
100 if (!wcscmp(V_BSTR(&var
), wszFilterName
))
103 IPropertyBag_Release(pPropBagCat
);
104 IMoniker_Release(pMoniker
);
111 static void test_fm2_enummatchingfilters(void)
113 IEnumRegFilters
*enum_reg
;
114 IFilterMapper2
*pMapper
= NULL
;
115 IFilterMapper
*mapper
;
118 REGFILTERPINS2 rgPins2
[2];
119 REGPINTYPES rgPinType
;
122 IEnumMoniker
*pEnum
= NULL
;
123 BOOL found
, registered
= TRUE
;
124 REGFILTER
*regfilter
;
127 ZeroMemory(&rgf2
, sizeof(rgf2
));
129 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
130 &IID_IFilterMapper2
, (LPVOID
*)&pMapper
);
131 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
132 if (FAILED(hr
)) goto out
;
134 hr
= CoCreateGuid(&clsidFilter1
);
135 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
136 hr
= CoCreateGuid(&clsidFilter2
);
137 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
139 /* Test that a test renderer filter is returned when enumerating filters with bRender=FALSE */
141 rgf2
.dwMerit
= MERIT_UNLIKELY
;
142 S2(U(rgf2
)).cPins2
= 1;
143 S2(U(rgf2
)).rgPins2
= rgPins2
;
145 rgPins2
[0].dwFlags
= REG_PINFLAG_B_RENDERER
;
146 rgPins2
[0].cInstances
= 1;
147 rgPins2
[0].nMediaTypes
= 1;
148 rgPins2
[0].lpMediaType
= &rgPinType
;
149 rgPins2
[0].nMediums
= 0;
150 rgPins2
[0].lpMedium
= NULL
;
151 rgPins2
[0].clsPinCategory
= NULL
;
153 rgPinType
.clsMajorType
= &GUID_NULL
;
154 rgPinType
.clsMinorType
= &GUID_NULL
;
156 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter1
, L
"Testfilter1", NULL
,
157 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
158 if (hr
== E_ACCESSDENIED
)
161 skip("Not authorized to register filters\n");
165 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
167 rgPins2
[0].dwFlags
= 0;
169 rgPins2
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
170 rgPins2
[1].cInstances
= 1;
171 rgPins2
[1].nMediaTypes
= 1;
172 rgPins2
[1].lpMediaType
= &rgPinType
;
173 rgPins2
[1].nMediums
= 0;
174 rgPins2
[1].lpMedium
= NULL
;
175 rgPins2
[1].clsPinCategory
= NULL
;
177 S2(U(rgf2
)).cPins2
= 2;
179 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter2
, L
"Testfilter2", NULL
,
180 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
181 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
183 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
184 0, NULL
, NULL
, &GUID_NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
185 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
186 if (SUCCEEDED(hr
) && pEnum
)
188 found
= enum_find_filter(L
"Testfilter1", pEnum
);
189 ok(found
, "EnumMatchingFilters failed to return the test filter 1\n");
192 if (pEnum
) IEnumMoniker_Release(pEnum
);
195 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
196 0, NULL
, NULL
, &GUID_NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
197 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
198 if (SUCCEEDED(hr
) && pEnum
)
200 found
= enum_find_filter(L
"Testfilter2", pEnum
);
201 ok(found
, "EnumMatchingFilters failed to return the test filter 2\n");
204 if (pEnum
) IEnumMoniker_Release(pEnum
);
207 /* Non renderer must not be returned with bRender=TRUE */
209 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
210 0, NULL
, NULL
, &GUID_NULL
, TRUE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
211 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
213 if (SUCCEEDED(hr
) && pEnum
)
215 found
= enum_find_filter(L
"Testfilter1", pEnum
);
216 ok(found
, "EnumMatchingFilters failed to return the test filter 1\n");
219 hr
= IFilterMapper2_QueryInterface(pMapper
, &IID_IFilterMapper
, (void **)&mapper
);
220 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
223 hr
= IFilterMapper_EnumMatchingFilters(mapper
, &enum_reg
, MERIT_UNLIKELY
,
224 FALSE
, GUID_NULL
, GUID_NULL
, FALSE
, FALSE
, GUID_NULL
, GUID_NULL
);
225 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
226 while (!found
&& IEnumRegFilters_Next(enum_reg
, 1, ®filter
, &count
) == S_OK
)
228 if (!wcscmp(regfilter
->Name
, L
"Testfilter1") && IsEqualGUID(&clsidFilter1
, ®filter
->Clsid
))
231 IEnumRegFilters_Release(enum_reg
);
232 ok(found
, "IFilterMapper didn't find filter\n");
234 IFilterMapper_Release(mapper
);
237 if (pEnum
) IEnumMoniker_Release(pEnum
);
240 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
241 0, NULL
, NULL
, &GUID_NULL
, TRUE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
242 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
244 if (SUCCEEDED(hr
) && pEnum
)
246 found
= enum_find_filter(L
"Testfilter2", pEnum
);
247 ok(!found
, "EnumMatchingFilters should not return the test filter 2\n");
252 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
,
254 ok(SUCCEEDED(hr
), "Got hr %#lx.\n", hr
);
256 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
,
258 ok(SUCCEEDED(hr
), "Got hr %#lx.\n", hr
);
263 if (pEnum
) IEnumMoniker_Release(pEnum
);
264 ref
= IFilterMapper2_Release(pMapper
);
265 ok(!ref
, "Got outstanding refcount %ld.\n", ref
);
268 static void test_legacy_filter_registration(void)
270 IEnumRegFilters
*enum_reg
;
271 IEnumMoniker
*enum_mon
;
272 IFilterMapper2
*mapper2
;
273 IFilterMapper
*mapper
;
274 REGFILTER
*regfilter
;
275 WCHAR clsidstring
[40];
284 /* Register* functions need a filter class key to write pin and pin media
285 * type data to. Create a bogus class key for it. */
286 CoCreateGuid(&clsid
);
287 StringFromGUID2(&clsid
, clsidstring
, ARRAY_SIZE(clsidstring
));
288 wcscpy(key_name
, L
"CLSID\\");
289 wcscat(key_name
, clsidstring
);
290 ret
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, key_name
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hkey
, NULL
);
291 if (ret
== ERROR_ACCESS_DENIED
)
293 skip("Not authorized to register filters\n");
297 /* Test if legacy filter registration scheme works (filter is added to HKCR\Filter). IFilterMapper_RegisterFilter
298 * registers in this way. Filters so registered must then be accessible through both IFilterMapper_EnumMatchingFilters
299 * and IFilterMapper2_EnumMatchingFilters. */
300 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterMapper2
, (void **)&mapper2
);
301 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
303 hr
= IFilterMapper2_QueryInterface(mapper2
, &IID_IFilterMapper
, (void **)&mapper
);
304 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
306 /* Set default value - this is interpreted as "friendly name" later. */
307 RegSetValueExW(hkey
, NULL
, 0, REG_SZ
, (const BYTE
*)L
"Testfilter", sizeof(L
"Testfilter"));
310 hr
= IFilterMapper_RegisterFilter(mapper
, clsid
, L
"Testfilter", MERIT_UNLIKELY
);
311 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
313 hr
= IFilterMapper_RegisterPin(mapper
, clsid
, L
"Pin1", TRUE
, FALSE
, FALSE
, FALSE
, GUID_NULL
, NULL
);
314 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
316 hr
= IFilterMapper_RegisterPinType(mapper
, clsid
, L
"Pin1", GUID_NULL
, GUID_NULL
);
317 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
319 hr
= IFilterMapper2_EnumMatchingFilters(mapper2
, &enum_mon
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
320 0, NULL
, NULL
, &GUID_NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
321 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
322 ok(enum_find_filter(L
"Testfilter", enum_mon
), "IFilterMapper2 didn't find filter\n");
323 IEnumMoniker_Release(enum_mon
);
326 hr
= IFilterMapper_EnumMatchingFilters(mapper
, &enum_reg
, MERIT_UNLIKELY
, TRUE
, GUID_NULL
, GUID_NULL
,
327 FALSE
, FALSE
, GUID_NULL
, GUID_NULL
);
328 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
329 while(!found
&& IEnumRegFilters_Next(enum_reg
, 1, ®filter
, &count
) == S_OK
)
331 if (!wcscmp(regfilter
->Name
, L
"Testfilter") && IsEqualGUID(&clsid
, ®filter
->Clsid
))
334 IEnumRegFilters_Release(enum_reg
);
335 ok(found
, "IFilterMapper didn't find filter\n");
337 hr
= IFilterMapper_UnregisterFilter(mapper
, clsid
);
338 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
340 hr
= IFilterMapper2_EnumMatchingFilters(mapper2
, &enum_mon
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
341 0, NULL
, NULL
, &GUID_NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
342 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
343 ok(!enum_find_filter(L
"Testfilter", enum_mon
), "IFilterMapper2 shouldn't find filter\n");
344 IEnumMoniker_Release(enum_mon
);
347 hr
= IFilterMapper_EnumMatchingFilters(mapper
, &enum_reg
, MERIT_UNLIKELY
, TRUE
, GUID_NULL
, GUID_NULL
,
348 FALSE
, FALSE
, GUID_NULL
, GUID_NULL
);
349 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
350 while(!found
&& IEnumRegFilters_Next(enum_reg
, 1, ®filter
, &count
) == S_OK
)
352 if (!wcscmp(regfilter
->Name
, L
"Testfilter") && IsEqualGUID(&clsid
, ®filter
->Clsid
))
355 IEnumRegFilters_Release(enum_reg
);
356 ok(!found
, "IFilterMapper shouldn't find filter\n");
358 ret
= RegDeleteKeyW(HKEY_CLASSES_ROOT
, key_name
);
359 ok(!ret
, "RegDeleteKeyA failed: %Iu\n", ret
);
361 hr
= IFilterMapper_RegisterFilter(mapper
, clsid
, L
"Testfilter", MERIT_UNLIKELY
);
362 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
364 hr
= IFilterMapper_UnregisterFilter(mapper
, clsid
);
365 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
367 IFilterMapper_Release(mapper
);
368 IFilterMapper2_Release(mapper2
);
371 static void test_register_filter_with_null_clsMinorType(void)
373 static WCHAR wszPinName
[] = L
"Pin";
374 IFilterMapper2
*pMapper
= NULL
;
377 REGFILTERPINS rgPins
;
378 REGFILTERPINS2 rgPins2
;
379 REGPINTYPES rgPinType
;
383 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
384 &IID_IFilterMapper2
, (LPVOID
*)&pMapper
);
385 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
386 if (FAILED(hr
)) goto out
;
388 hr
= CoCreateGuid(&clsidFilter1
);
389 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
390 hr
= CoCreateGuid(&clsidFilter2
);
391 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
393 rgPinType
.clsMajorType
= &GUID_NULL
;
394 /* Make sure quartz accepts it without crashing */
395 rgPinType
.clsMinorType
= NULL
;
397 /* Test with pin descript version 1 */
398 ZeroMemory(&rgf2
, sizeof(rgf2
));
400 rgf2
.dwMerit
= MERIT_UNLIKELY
;
401 S1(U(rgf2
)).cPins
= 1;
402 S1(U(rgf2
)).rgPins
= &rgPins
;
404 rgPins
.strName
= wszPinName
;
405 rgPins
.bRendered
= 1;
409 rgPins
.clsConnectsToFilter
= NULL
;
410 rgPins
.strConnectsToPin
= NULL
;
411 rgPins
.nMediaTypes
= 1;
412 rgPins
.lpMediaType
= &rgPinType
;
414 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter1
, L
"Testfilter1", NULL
,
415 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
416 if (hr
== E_ACCESSDENIED
)
418 skip("Not authorized to register filters\n");
421 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
423 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
, &clsidFilter1
);
424 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
426 /* Test with pin descript version 2 */
427 ZeroMemory(&rgf2
, sizeof(rgf2
));
429 rgf2
.dwMerit
= MERIT_UNLIKELY
;
430 S2(U(rgf2
)).cPins2
= 1;
431 S2(U(rgf2
)).rgPins2
= &rgPins2
;
433 rgPins2
.dwFlags
= REG_PINFLAG_B_RENDERER
;
434 rgPins2
.cInstances
= 1;
435 rgPins2
.nMediaTypes
= 1;
436 rgPins2
.lpMediaType
= &rgPinType
;
437 rgPins2
.nMediums
= 0;
438 rgPins2
.lpMedium
= NULL
;
439 rgPins2
.clsPinCategory
= NULL
;
441 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter2
, L
"Testfilter2", NULL
,
442 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
443 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
445 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
, &clsidFilter2
);
446 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
450 if (pMapper
) IFilterMapper2_Release(pMapper
);
453 static void test_parse_filter_data(void)
455 static const BYTE data_block
[] = {
456 0x02,0x00,0x00,0x00,0xff,0xff,0x5f,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x70,0x69,0x33,
457 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
458 0x30,0x74,0x79,0x33,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x31,0x70,0x69,0x33,
459 0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
460 0x30,0x74,0x79,0x33,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x76,0x69,0x64,0x73,
461 0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
462 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
464 BYTE
*prgbRegFilter2
= NULL
;
465 REGFILTER2
*pRegFilter
= NULL
;
466 IFilterMapper2
*pMapper
= NULL
;
467 SAFEARRAYBOUND saBound
;
468 SAFEARRAY
*psa
= NULL
;
469 LPBYTE pbSAData
= NULL
;
472 IAMFilterData
*pData
= NULL
;
474 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
475 &IID_IFilterMapper2
, (LPVOID
*)&pMapper
);
476 ok((hr
== S_OK
|| broken(hr
!= S_OK
)), "Got hr %#lx.\n", hr
);
477 if (FAILED(hr
)) goto out
;
479 hr
= IFilterMapper2_QueryInterface(pMapper
, &IID_IAMFilterData
, (LPVOID
*)&pData
);
480 ok((hr
== S_OK
|| broken(hr
!= S_OK
)), "Unable to find IID_IAMFilterData interface\n");
481 if (FAILED(hr
)) goto out
;
484 saBound
.cElements
= sizeof(data_block
);
485 psa
= SafeArrayCreate(VT_UI1
, 1, &saBound
);
486 ok(psa
!= NULL
, "Unable to create safe array\n");
488 hr
= SafeArrayAccessData(psa
, (LPVOID
*)&pbSAData
);
489 ok(hr
== S_OK
, "Unable to access array data\n");
490 if (FAILED(hr
)) goto out
;
491 memcpy(pbSAData
, data_block
, sizeof(data_block
));
493 hr
= IAMFilterData_ParseFilterData(pData
, pbSAData
, sizeof(data_block
), &prgbRegFilter2
);
494 /* We cannot do anything here. prgbRegFilter2 is very unstable */
495 /* Pre Vista, this is a stack pointer so anything that changes the stack invalidats it */
496 /* Post Vista, it is a static pointer in the data section of the module */
497 pRegFilter
=((REGFILTER2
**)prgbRegFilter2
)[0];
498 ok (hr
==S_OK
,"Failed to Parse filter Data\n");
500 ok(IsBadReadPtr(prgbRegFilter2
,sizeof(REGFILTER2
*))==0,"Bad read pointer returned\n");
501 ok(IsBadReadPtr(pRegFilter
,sizeof(REGFILTER2
))==0,"Bad read pointer for FilterData\n");
502 ok(pRegFilter
->dwMerit
== 0x5fffff,"Incorrect merit returned\n");
505 CoTaskMemFree(pRegFilter
);
508 SafeArrayUnaccessData(psa
);
509 SafeArrayDestroy(psa
);
512 IAMFilterData_Release(pData
);
514 IFilterMapper2_Release(pMapper
);
517 static const GUID test_iid
= {0x33333333};
518 static LONG outer_ref
= 1;
520 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID iid
, void **out
)
522 if (IsEqualGUID(iid
, &IID_IUnknown
)
523 || IsEqualGUID(iid
, &IID_IFilterMapper3
)
524 || IsEqualGUID(iid
, &test_iid
))
526 *out
= (IUnknown
*)0xdeadbeef;
529 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid
));
530 return E_NOINTERFACE
;
533 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
535 return InterlockedIncrement(&outer_ref
);
538 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
540 return InterlockedDecrement(&outer_ref
);
543 static const IUnknownVtbl outer_vtbl
=
545 outer_QueryInterface
,
550 static IUnknown test_outer
= {&outer_vtbl
};
552 static void test_aggregation(void)
554 IFilterMapper3
*mapper
, *mapper2
;
555 IUnknown
*unk
, *unk2
;
559 mapper
= (IFilterMapper3
*)0xdeadbeef;
560 hr
= CoCreateInstance(&CLSID_FilterMapper2
, &test_outer
, CLSCTX_INPROC_SERVER
,
561 &IID_IFilterMapper3
, (void **)&mapper
);
562 ok(hr
== E_NOINTERFACE
, "Got hr %#lx.\n", hr
);
563 ok(!mapper
, "Got interface %p.\n", mapper
);
565 hr
= CoCreateInstance(&CLSID_FilterMapper2
, &test_outer
, CLSCTX_INPROC_SERVER
,
566 &IID_IUnknown
, (void **)&unk
);
567 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
568 ok(outer_ref
== 1, "Got unexpected refcount %ld.\n", outer_ref
);
569 ok(unk
!= &test_outer
, "Returned IUnknown should not be outer IUnknown.\n");
570 ref
= get_refcount(unk
);
571 ok(ref
== 1, "Got unexpected refcount %ld.\n", ref
);
573 ref
= IUnknown_AddRef(unk
);
574 ok(ref
== 2, "Got unexpected refcount %ld.\n", ref
);
575 ok(outer_ref
== 1, "Got unexpected refcount %ld.\n", outer_ref
);
577 ref
= IUnknown_Release(unk
);
578 ok(ref
== 1, "Got unexpected refcount %ld.\n", ref
);
579 ok(outer_ref
== 1, "Got unexpected refcount %ld.\n", outer_ref
);
581 hr
= IUnknown_QueryInterface(unk
, &IID_IUnknown
, (void **)&unk2
);
582 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
583 ok(unk2
== unk
, "Got unexpected IUnknown %p.\n", unk2
);
584 IUnknown_Release(unk2
);
586 hr
= IUnknown_QueryInterface(unk
, &IID_IFilterMapper3
, (void **)&mapper
);
587 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
589 hr
= IFilterMapper3_QueryInterface(mapper
, &IID_IUnknown
, (void **)&unk2
);
590 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
591 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
593 hr
= IFilterMapper3_QueryInterface(mapper
, &IID_IFilterMapper3
, (void **)&mapper2
);
594 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
595 ok(mapper2
== (IFilterMapper3
*)0xdeadbeef, "Got unexpected IFilterMapper3 %p.\n", mapper2
);
597 hr
= IUnknown_QueryInterface(unk
, &test_iid
, (void **)&unk2
);
598 ok(hr
== E_NOINTERFACE
, "Got hr %#lx.\n", hr
);
599 ok(!unk2
, "Got unexpected IUnknown %p.\n", unk2
);
601 hr
= IFilterMapper3_QueryInterface(mapper
, &test_iid
, (void **)&unk2
);
602 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
603 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
605 IFilterMapper3_Release(mapper
);
606 ref
= IUnknown_Release(unk
);
607 ok(!ref
, "Got unexpected refcount %ld.\n", ref
);
608 ok(outer_ref
== 1, "Got unexpected refcount %ld.\n", outer_ref
);
611 static void test_dmo(void)
613 DMO_PARTIAL_MEDIATYPE mt
= {MEDIATYPE_Audio
, MEDIASUBTYPE_PCM
};
614 IEnumMoniker
*enumerator
;
615 IFilterMapper3
*mapper
;
622 hr
= DMORegister(L
"dmo test", &testclsid
, &DMOCATEGORY_AUDIO_DECODER
, 0, 1, &mt
, 1, &mt
);
625 skip("Not enough permissions to register DMOs.\n");
628 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
630 mapper
= create_mapper();
632 hr
= IFilterMapper3_EnumMatchingFilters(mapper
, &enumerator
, 0, FALSE
, 0,
633 FALSE
, 0, NULL
, NULL
, NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, NULL
);
634 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
637 while (IEnumMoniker_Next(enumerator
, 1, &moniker
, NULL
) == S_OK
)
639 hr
= IMoniker_GetDisplayName(moniker
, NULL
, NULL
, &name
);
640 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
642 if (!wcscmp(name
, L
"@device:dmo:{77777777-0000-0000-0000-000000000000}{57F2DB8B-E6BB-4513-9D43-DCD2A6593125}"))
646 IMoniker_Release(moniker
);
648 IEnumMoniker_Release(enumerator
);
649 ok(found
, "DMO should be enumerated.\n");
651 /* DMOs are enumerated by IFilterMapper in Windows 7 and higher. */
653 ref
= IFilterMapper3_Release(mapper
);
654 ok(!ref
, "Got outstanding refcount %ld.\n", ref
);
656 hr
= DMOUnregister(&testclsid
, &DMOCATEGORY_AUDIO_DECODER
);
657 ok(hr
== S_OK
, "Got hr %#lx.\n", hr
);
660 START_TEST(filtermapper
)
665 test_fm2_enummatchingfilters();
666 test_legacy_filter_registration();
667 test_register_filter_with_null_clsMinorType();
668 test_parse_filter_data();