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"
28 DEFINE_GUID(GUID_NULL
,0,0,0,0,0,0,0,0,0,0,0);
30 /* Helper function, checks if filter with given name was enumerated. */
31 static BOOL
enum_find_filter(const WCHAR
*wszFilterName
, IEnumMoniker
*pEnum
)
33 IMoniker
*pMoniker
= NULL
;
37 static const WCHAR wszFriendlyName
[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
39 while(!found
&& IEnumMoniker_Next(pEnum
, 1, &pMoniker
, &nb
) == S_OK
)
41 IPropertyBag
* pPropBagCat
= NULL
;
46 hr
= IMoniker_BindToStorage(pMoniker
, NULL
, NULL
, &IID_IPropertyBag
, (LPVOID
*)&pPropBagCat
);
47 ok(SUCCEEDED(hr
), "IMoniker_BindToStorage failed with %x\n", hr
);
48 if (FAILED(hr
) || !pPropBagCat
)
51 IMoniker_Release(pMoniker
);
55 hr
= IPropertyBag_Read(pPropBagCat
, wszFriendlyName
, &var
, NULL
);
56 ok(SUCCEEDED(hr
), "IPropertyBag_Read failed with %x\n", hr
);
60 CHAR val1
[512], val2
[512];
62 WideCharToMultiByte(CP_ACP
, 0, V_UNION(&var
, bstrVal
), -1, val1
, sizeof(val1
), 0, 0);
63 WideCharToMultiByte(CP_ACP
, 0, wszFilterName
, -1, val2
, sizeof(val2
), 0, 0);
64 if (!lstrcmpA(val1
, val2
)) found
= TRUE
;
67 IPropertyBag_Release(pPropBagCat
);
68 IMoniker_Release(pMoniker
);
75 static void test_fm2_enummatchingfilters(void)
77 IFilterMapper2
*pMapper
= NULL
;
80 REGFILTERPINS2 rgPins2
[2];
81 REGPINTYPES rgPinType
;
82 static const WCHAR wszFilterName1
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '1', 0 };
83 static const WCHAR wszFilterName2
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '2', 0 };
86 IEnumMoniker
*pEnum
= NULL
;
89 ZeroMemory(&rgf2
, sizeof(rgf2
));
91 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
92 &IID_IFilterMapper2
, (LPVOID
*)&pMapper
);
93 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
94 if (FAILED(hr
)) goto out
;
96 hr
= CoCreateGuid(&clsidFilter1
);
97 ok(hr
== S_OK
, "CoCreateGuid failed with %x\n", hr
);
98 hr
= CoCreateGuid(&clsidFilter2
);
99 ok(hr
== S_OK
, "CoCreateGuid failed with %x\n", hr
);
101 /* Test that a test renderer filter is returned when enumerating filters with bRender=FALSE */
103 rgf2
.dwMerit
= MERIT_UNLIKELY
;
104 S1(U(rgf2
)).cPins2
= 1;
105 S1(U(rgf2
)).rgPins2
= rgPins2
;
107 rgPins2
[0].dwFlags
= REG_PINFLAG_B_RENDERER
;
108 rgPins2
[0].cInstances
= 1;
109 rgPins2
[0].nMediaTypes
= 1;
110 rgPins2
[0].lpMediaType
= &rgPinType
;
111 rgPins2
[0].nMediums
= 0;
112 rgPins2
[0].lpMedium
= NULL
;
113 rgPins2
[0].clsPinCategory
= NULL
;
115 rgPinType
.clsMajorType
= &GUID_NULL
;
116 rgPinType
.clsMinorType
= &GUID_NULL
;
118 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter1
, wszFilterName1
, NULL
,
119 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
120 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
122 rgPins2
[0].dwFlags
= 0;
124 rgPins2
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
125 rgPins2
[1].cInstances
= 1;
126 rgPins2
[1].nMediaTypes
= 1;
127 rgPins2
[1].lpMediaType
= &rgPinType
;
128 rgPins2
[1].nMediums
= 0;
129 rgPins2
[1].lpMedium
= NULL
;
130 rgPins2
[1].clsPinCategory
= NULL
;
132 S1(U(rgf2
)).cPins2
= 2;
134 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter2
, wszFilterName2
, NULL
,
135 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
136 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
138 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
139 0, NULL
, NULL
, &GUID_NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
140 ok(hr
== S_OK
, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr
);
141 if (SUCCEEDED(hr
) && pEnum
)
143 found
= enum_find_filter(wszFilterName1
, pEnum
);
144 ok(found
, "EnumMatchingFilters failed to return the test filter 1\n");
147 if (pEnum
) IEnumMoniker_Release(pEnum
);
150 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
151 0, NULL
, NULL
, &GUID_NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
152 ok(hr
== S_OK
, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr
);
153 if (SUCCEEDED(hr
) && pEnum
)
155 found
= enum_find_filter(wszFilterName2
, pEnum
);
156 ok(found
, "EnumMatchingFilters failed to return the test filter 2\n");
159 if (pEnum
) IEnumMoniker_Release(pEnum
);
162 /* Non renderer must not be returned with bRender=TRUE */
164 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
165 0, NULL
, NULL
, &GUID_NULL
, TRUE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
166 ok(hr
== S_OK
, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr
);
168 if (SUCCEEDED(hr
) && pEnum
)
170 found
= enum_find_filter(wszFilterName1
, pEnum
);
171 ok(found
, "EnumMatchingFilters failed to return the test filter 1\n");
174 if (pEnum
) IEnumMoniker_Release(pEnum
);
177 hr
= IFilterMapper2_EnumMatchingFilters(pMapper
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
178 0, NULL
, NULL
, &GUID_NULL
, TRUE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
179 ok(hr
== S_OK
, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr
);
181 if (SUCCEEDED(hr
) && pEnum
)
183 found
= enum_find_filter(wszFilterName2
, pEnum
);
184 ok(!found
, "EnumMatchingFilters should not return the test filter 2\n");
187 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
,
189 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
191 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
,
193 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
197 if (pEnum
) IEnumMoniker_Release(pEnum
);
198 if (pMapper
) IFilterMapper2_Release(pMapper
);
201 static void test_legacy_filter_registration(void)
203 IFilterMapper2
*pMapper2
= NULL
;
204 IFilterMapper
*pMapper
= NULL
;
206 static const WCHAR wszFilterName
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 0 };
207 static const CHAR szFilterName
[] = "Testfilter";
208 static const WCHAR wszPinName
[] = {'P', 'i', 'n', '1', 0 };
210 WCHAR wszRegKey
[MAX_PATH
];
211 CHAR szRegKey
[MAX_PATH
];
212 static const WCHAR wszClsid
[] = {'C','L','S','I','D', 0};
213 static const CHAR szClsid
[] = "CLSID";
214 static const WCHAR wszSlash
[] = {'\\', 0};
217 IEnumMoniker
*pEnum
= NULL
;
219 IEnumRegFilters
*pRegEnum
= NULL
;
221 /* Test if legacy filter registration scheme works (filter is added to HKCR\Filter). IFilterMapper_RegisterFilter
222 * registers in this way. Filters so registered must then be accessible through both IFilterMapper_EnumMatchingFilters
223 * and IFilterMapper2_EnumMatchingFilters. */
224 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
225 &IID_IFilterMapper2
, (LPVOID
*)&pMapper2
);
226 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
227 if (FAILED(hr
)) goto out
;
229 hr
= IFilterMapper2_QueryInterface(pMapper2
, &IID_IFilterMapper
, (LPVOID
)&pMapper
);
230 ok(hr
== S_OK
, "IFilterMapper2_QueryInterface failed with %x\n", hr
);
231 if (FAILED(hr
)) goto out
;
233 /* Register a test filter. */
234 hr
= CoCreateGuid(&clsidFilter
);
235 ok(hr
== S_OK
, "CoCreateGuid failed with %x\n", hr
);
237 lstrcpyW(wszRegKey
, wszClsid
);
238 lstrcatW(wszRegKey
, wszSlash
);
239 lRet
= StringFromGUID2(&clsidFilter
, wszRegKey
+ lstrlenW(wszRegKey
), MAX_PATH
- lstrlenW(wszRegKey
));
240 ok(lRet
> 0, "StringFromGUID2 failed\n");
242 WideCharToMultiByte(CP_ACP
, 0, wszRegKey
, -1, szRegKey
, sizeof(szRegKey
), 0, 0);
244 /* Register---- functions need a filter class key to write pin and pin media type data to. Create a bogus
245 * class key for it. */
246 lRet
= RegCreateKeyExA(HKEY_CLASSES_ROOT
, szRegKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &hKey
, NULL
);
247 ok(lRet
== ERROR_SUCCESS
, "RegCreateKeyExA failed with %x\n", HRESULT_FROM_WIN32(lRet
));
249 /* Set default value - this is interpreted as "friendly name" later. */
250 lRet
= RegSetValueExA(hKey
, NULL
, 0, REG_SZ
, (LPBYTE
)szFilterName
, lstrlenA(szFilterName
) + 1);
251 ok(lRet
== ERROR_SUCCESS
, "RegSetValueExA failed with %x\n", HRESULT_FROM_WIN32(lRet
));
253 if (hKey
) RegCloseKey(hKey
);
256 hr
= IFilterMapper_RegisterFilter(pMapper
, clsidFilter
, wszFilterName
, MERIT_UNLIKELY
);
257 ok(hr
== S_OK
, "IFilterMapper_RegisterFilter failed with %x\n", hr
);
259 hr
= IFilterMapper_RegisterPin(pMapper
, clsidFilter
, wszPinName
, TRUE
, FALSE
, FALSE
, FALSE
, GUID_NULL
, NULL
);
260 ok(hr
== S_OK
, "IFilterMapper_RegisterPin failed with %x\n", hr
);
262 hr
= IFilterMapper_RegisterPinType(pMapper
, clsidFilter
, wszPinName
, GUID_NULL
, GUID_NULL
);
263 ok(hr
== S_OK
, "IFilterMapper_RegisterPinType failed with %x\n", hr
);
265 hr
= IFilterMapper2_EnumMatchingFilters(pMapper2
, &pEnum
, 0, TRUE
, MERIT_UNLIKELY
, TRUE
,
266 0, NULL
, NULL
, &GUID_NULL
, FALSE
, FALSE
, 0, NULL
, NULL
, &GUID_NULL
);
267 ok(hr
== S_OK
, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr
);
268 if (SUCCEEDED(hr
) && pEnum
)
270 found
= enum_find_filter(wszFilterName
, pEnum
);
271 ok(found
, "IFilterMapper2_EnumMatchingFilters failed to return the test filter\n");
274 if (pEnum
) IEnumMoniker_Release(pEnum
);
278 hr
= IFilterMapper_EnumMatchingFilters(pMapper
, &pRegEnum
, MERIT_UNLIKELY
, TRUE
, GUID_NULL
, GUID_NULL
,
279 FALSE
, FALSE
, GUID_NULL
, GUID_NULL
);
280 ok(hr
== S_OK
, "IFilterMapper_EnumMatchingFilters failed with %x\n", hr
);
281 if (SUCCEEDED(hr
) && pRegEnum
)
286 while(!found
&& IEnumRegFilters_Next(pRegEnum
, 1, &prgf
, &cFetched
) == S_OK
)
290 WideCharToMultiByte(CP_ACP
, 0, prgf
->Name
, -1, val
, sizeof(val
), 0, 0);
291 if (!lstrcmpA(val
, szFilterName
)) found
= TRUE
;
296 IEnumRegFilters_Release(pRegEnum
);
298 ok(found
, "IFilterMapper_EnumMatchingFilters failed to return the test filter\n");
300 hr
= IFilterMapper_UnregisterFilter(pMapper
, clsidFilter
);
301 ok(hr
== S_OK
, "FilterMapper_UnregisterFilter failed with %x\n", hr
);
303 lRet
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, szClsid
, 0, KEY_WRITE
| DELETE
, &hKey
);
304 ok(lRet
== ERROR_SUCCESS
, "RegOpenKeyExA failed with %x\n", HRESULT_FROM_WIN32(lRet
));
306 lRet
= StringFromGUID2(&clsidFilter
, wszRegKey
, MAX_PATH
);
307 ok(lRet
> 0, "StringFromGUID2 failed\n");
308 WideCharToMultiByte(CP_ACP
, 0, wszRegKey
, -1, szRegKey
, sizeof(szRegKey
), 0, 0);
310 lRet
= RegDeleteKeyA(hKey
, szRegKey
);
311 ok(lRet
== ERROR_SUCCESS
, "RegDeleteKeyA failed with %x\n", HRESULT_FROM_WIN32(lRet
));
313 if (hKey
) RegCloseKey(hKey
);
318 if (pMapper
) IFilterMapper_Release(pMapper
);
319 if (pMapper2
) IFilterMapper2_Release(pMapper2
);
322 static ULONG
getRefcount(IUnknown
*iface
)
324 IUnknown_AddRef(iface
);
325 return IUnknown_Release(iface
);
328 static void test_ifiltermapper_from_filtergraph(void)
330 IFilterGraph2
* pgraph2
= NULL
;
331 IFilterMapper2
*pMapper2
= NULL
;
332 IFilterGraph
*filtergraph
= NULL
;
336 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
337 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
338 if (!pgraph2
) goto out
;
340 hr
= IFilterGraph2_QueryInterface(pgraph2
, &IID_IFilterMapper2
, (LPVOID
*)&pMapper2
);
341 ok(hr
== S_OK
, "IFilterGraph2_QueryInterface failed with %08x\n", hr
);
342 if (!pMapper2
) goto out
;
344 refcount
= getRefcount((IUnknown
*)pgraph2
);
345 ok(refcount
== 2, "unexpected reference count: %u\n", refcount
);
346 refcount
= getRefcount((IUnknown
*)pMapper2
);
347 ok(refcount
== 2, "unexpected reference count: %u\n", refcount
);
349 IFilterMapper2_AddRef(pMapper2
);
350 refcount
= getRefcount((IUnknown
*)pgraph2
);
351 ok(refcount
== 3, "unexpected reference count: %u\n", refcount
);
352 refcount
= getRefcount((IUnknown
*)pMapper2
);
353 ok(refcount
== 3, "unexpected reference count: %u\n", refcount
);
354 IFilterMapper2_Release(pMapper2
);
356 hr
= IFilterMapper2_QueryInterface(pMapper2
, &IID_IFilterGraph
, (LPVOID
*)&filtergraph
);
357 ok(hr
== S_OK
, "IFilterMapper2_QueryInterface failed with %08x\n", hr
);
358 if (!filtergraph
) goto out
;
360 IFilterMapper2_Release(pMapper2
);
362 IFilterGraph_Release(filtergraph
);
365 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterMapper2
, (LPVOID
*)&pMapper2
);
366 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
367 if (!pMapper2
) goto out
;
369 hr
= IFilterMapper2_QueryInterface(pMapper2
, &IID_IFilterGraph
, (LPVOID
*)&filtergraph
);
370 ok(hr
== E_NOINTERFACE
, "IFilterMapper2_QueryInterface unexpected result: %08x\n", hr
);
374 if (pMapper2
) IFilterMapper2_Release(pMapper2
);
375 if (filtergraph
) IFilterGraph_Release(filtergraph
);
376 if (pgraph2
) IFilterGraph2_Release(pgraph2
);
379 static void test_register_filter_with_null_clsMinorType(void)
381 IFilterMapper2
*pMapper
= NULL
;
384 REGFILTERPINS rgPins
;
385 REGFILTERPINS2 rgPins2
;
386 REGPINTYPES rgPinType
;
387 static WCHAR wszPinName
[] = {'P', 'i', 'n', 0 };
388 static const WCHAR wszFilterName1
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '1', 0 };
389 static const WCHAR wszFilterName2
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '2', 0 };
393 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
394 &IID_IFilterMapper2
, (LPVOID
*)&pMapper
);
395 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
396 if (FAILED(hr
)) goto out
;
398 hr
= CoCreateGuid(&clsidFilter1
);
399 ok(hr
== S_OK
, "CoCreateGuid failed with %x\n", hr
);
400 hr
= CoCreateGuid(&clsidFilter2
);
401 ok(hr
== S_OK
, "CoCreateGuid failed with %x\n", hr
);
403 rgPinType
.clsMajorType
= &GUID_NULL
;
404 /* Make sure quartz accepts it without crashing */
405 rgPinType
.clsMinorType
= NULL
;
407 /* Test with pin descript version 1 */
408 ZeroMemory(&rgf2
, sizeof(rgf2
));
410 rgf2
.dwMerit
= MERIT_UNLIKELY
;
411 S(U(rgf2
)).cPins
= 1;
412 S(U(rgf2
)).rgPins
= &rgPins
;
414 rgPins
.strName
= wszPinName
;
415 rgPins
.bRendered
= 1;
419 rgPins
.clsConnectsToFilter
= NULL
;
420 rgPins
.strConnectsToPin
= NULL
;
421 rgPins
.nMediaTypes
= 1;
422 rgPins
.lpMediaType
= &rgPinType
;
424 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter1
, wszFilterName1
, NULL
,
425 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
426 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
428 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
, &clsidFilter1
);
429 ok(hr
== S_OK
, "FilterMapper_UnregisterFilter failed with %x\n", hr
);
431 /* Test with pin descript version 2 */
432 ZeroMemory(&rgf2
, sizeof(rgf2
));
434 rgf2
.dwMerit
= MERIT_UNLIKELY
;
435 S1(U(rgf2
)).cPins2
= 1;
436 S1(U(rgf2
)).rgPins2
= &rgPins2
;
438 rgPins2
.dwFlags
= REG_PINFLAG_B_RENDERER
;
439 rgPins2
.cInstances
= 1;
440 rgPins2
.nMediaTypes
= 1;
441 rgPins2
.lpMediaType
= &rgPinType
;
442 rgPins2
.nMediums
= 0;
443 rgPins2
.lpMedium
= NULL
;
444 rgPins2
.clsPinCategory
= NULL
;
446 hr
= IFilterMapper2_RegisterFilter(pMapper
, &clsidFilter2
, wszFilterName2
, NULL
,
447 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
448 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
450 hr
= IFilterMapper2_UnregisterFilter(pMapper
, &CLSID_LegacyAmFilterCategory
, NULL
, &clsidFilter2
);
451 ok(hr
== S_OK
, "FilterMapper_UnregisterFilter failed with %x\n", hr
);
455 if (pMapper
) IFilterMapper2_Release(pMapper
);
459 START_TEST(filtermapper
)
463 test_fm2_enummatchingfilters();
464 test_legacy_filter_registration();
465 test_ifiltermapper_from_filtergraph();
466 test_register_filter_with_null_clsMinorType();