devenum: Register waveIn devices as codec devices.
[wine.git] / dlls / devenum / tests / devenum.c
blob3f66237131ec84f68fbd012ccb3ba2a4fc6a8e6d
1 /*
2 * Some unit tests for devenum
4 * Copyright (C) 2012 Christian Costa
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
21 #define COBJMACROS
23 #include <stdio.h>
25 #include "wine/test.h"
26 #include "initguid.h"
27 #include "ole2.h"
28 #include "strmif.h"
29 #include "uuids.h"
30 #include "vfwmsgs.h"
31 #include "mmsystem.h"
32 #include "dsound.h"
33 #include "mmddk.h"
35 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
37 static const WCHAR friendly_name[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
38 static const WCHAR fcc_handlerW[] = {'F','c','c','H','a','n','d','l','e','r',0};
39 static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':',0};
40 static const WCHAR clsidW[] = {'C','L','S','I','D',0};
41 static const WCHAR waveW[] = {'w','a','v','e',':',0};
42 static const WCHAR mrleW[] = {'m','r','l','e',0};
43 static const WCHAR swW[] = {'s','w',':',0};
44 static const WCHAR cmW[] = {'c','m',':',0};
45 static const WCHAR backslashW[] = {'\\',0};
47 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
49 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
50 return NULL;
53 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
55 if (n <= 0) return 0;
56 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
57 return *str1 - *str2;
60 static void test_devenum(IBindCtx *bind_ctx)
62 IEnumMoniker *enum_cat, *enum_moniker;
63 ICreateDevEnum* create_devenum;
64 IPropertyBag *prop_bag;
65 IMoniker *moniker;
66 BOOL have_mrle = FALSE;
67 GUID cat_guid, clsid;
68 VARIANT var;
69 HRESULT hr;
71 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
72 &IID_ICreateDevEnum, (LPVOID*)&create_devenum);
73 ok(hr == S_OK, "Failed to create devenum: %#x\n", hr);
75 hr = ICreateDevEnum_CreateClassEnumerator(create_devenum, &CLSID_ActiveMovieCategories, &enum_cat, 0);
76 ok(hr == S_OK, "Failed to enum categories: %#x\n", hr);
78 while (IEnumMoniker_Next(enum_cat, 1, &moniker, NULL) == S_OK)
80 hr = IMoniker_BindToStorage(moniker, bind_ctx, NULL, &IID_IPropertyBag, (void **)&prop_bag);
81 ok(hr == S_OK, "IMoniker_BindToStorage failed: %#x\n", hr);
83 VariantInit(&var);
84 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
85 ok(hr == S_OK, "Failed to read FriendlyName: %#x\n", hr);
87 if (winetest_debug > 1)
88 trace("%s:\n", wine_dbgstr_w(V_BSTR(&var)));
90 VariantClear(&var);
91 hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL);
92 ok(hr == S_OK, "Failed to read CLSID: %#x\n", hr);
94 hr = CLSIDFromString(V_BSTR(&var), &cat_guid);
95 ok(hr == S_OK, "got %#x\n", hr);
97 IPropertyBag_Release(prop_bag);
98 IMoniker_Release(moniker);
100 hr = ICreateDevEnum_CreateClassEnumerator(create_devenum, &cat_guid, &enum_moniker, 0);
101 ok(SUCCEEDED(hr), "Failed to enum devices: %#x\n", hr);
103 if (hr == S_OK)
105 while (IEnumMoniker_Next(enum_moniker, 1, &moniker, NULL) == S_OK)
107 hr = IMoniker_GetClassID(moniker, NULL);
108 ok(hr == E_INVALIDARG, "IMoniker_GetClassID should failed %x\n", hr);
110 hr = IMoniker_GetClassID(moniker, &clsid);
111 ok(hr == S_OK, "IMoniker_GetClassID failed with error %x\n", hr);
112 ok(IsEqualGUID(&clsid, &CLSID_CDeviceMoniker),
113 "Expected CLSID_CDeviceMoniker got %s\n", wine_dbgstr_guid(&clsid));
115 VariantInit(&var);
116 hr = IMoniker_BindToStorage(moniker, bind_ctx, NULL, &IID_IPropertyBag, (LPVOID*)&prop_bag);
117 ok(hr == S_OK, "IMoniker_BindToStorage failed with error %x\n", hr);
119 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
120 ok(hr == S_OK, "IPropertyBag_Read failed: %#x\n", hr);
122 if (winetest_debug > 1)
123 trace(" %s\n", wine_dbgstr_w(V_BSTR(&var)));
125 if (IsEqualGUID(&CLSID_VideoCompressorCategory, &cat_guid)) {
126 /* Test well known compressor to ensure that we really enumerate codecs */
127 hr = IPropertyBag_Read(prop_bag, fcc_handlerW, &var, NULL);
128 if (SUCCEEDED(hr)) {
129 ok(V_VT(&var) == VT_BSTR, "V_VT(var) = %d\n", V_VT(&var));
130 if(!lstrcmpW(V_BSTR(&var), mrleW))
131 have_mrle = TRUE;
132 VariantClear(&var);
136 IPropertyBag_Release(prop_bag);
137 IMoniker_Release(moniker);
139 IEnumMoniker_Release(enum_moniker);
143 ICreateDevEnum_Release(create_devenum);
145 /* 64-bit windows are missing mrle codec */
146 if(sizeof(void*) == 4)
147 ok(have_mrle, "mrle codec not found\n");
149 static void test_moniker_isequal(void)
151 HRESULT res;
152 ICreateDevEnum *create_devenum = NULL;
153 IEnumMoniker *enum_moniker0 = NULL, *enum_moniker1 = NULL;
154 IMoniker *moniker0 = NULL, *moniker1 = NULL;
156 res = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
157 &IID_ICreateDevEnum, (LPVOID*)&create_devenum);
158 if (FAILED(res))
160 skip("Cannot create SystemDeviceEnum object (%x)\n", res);
161 return;
164 res = ICreateDevEnum_CreateClassEnumerator(create_devenum, &CLSID_LegacyAmFilterCategory, &enum_moniker0, 0);
165 ok(SUCCEEDED(res), "Cannot create enum moniker (res = %x)\n", res);
166 if (SUCCEEDED(res))
168 if (IEnumMoniker_Next(enum_moniker0, 1, &moniker0, NULL) == S_OK &&
169 IEnumMoniker_Next(enum_moniker0, 1, &moniker1, NULL) == S_OK)
171 res = IMoniker_IsEqual(moniker0, moniker1);
172 ok(res == S_FALSE, "IMoniker_IsEqual should fail (res = %x)\n", res);
174 res = IMoniker_IsEqual(moniker1, moniker0);
175 ok(res == S_FALSE, "IMoniker_IsEqual should fail (res = %x)\n", res);
177 IMoniker_Release(moniker0);
178 IMoniker_Release(moniker1);
180 else
181 skip("Cannot get moniker for testing.\n");
183 IEnumMoniker_Release(enum_moniker0);
185 res = ICreateDevEnum_CreateClassEnumerator(create_devenum, &CLSID_LegacyAmFilterCategory, &enum_moniker0, 0);
186 ok(SUCCEEDED(res), "Cannot create enum moniker (res = %x)\n", res);
187 res = ICreateDevEnum_CreateClassEnumerator(create_devenum, &CLSID_AudioRendererCategory, &enum_moniker1, 0);
188 ok(SUCCEEDED(res), "Cannot create enum moniker (res = %x)\n", res);
189 if (SUCCEEDED(res))
191 if (IEnumMoniker_Next(enum_moniker0, 1, &moniker0, NULL) == S_OK &&
192 IEnumMoniker_Next(enum_moniker1, 1, &moniker1, NULL) == S_OK)
194 res = IMoniker_IsEqual(moniker0, moniker1);
195 ok(res == S_FALSE, "IMoniker_IsEqual should failed (res = %x)\n", res);
197 res = IMoniker_IsEqual(moniker1, moniker0);
198 ok(res == S_FALSE, "IMoniker_IsEqual should failed (res = %x)\n", res);
200 IMoniker_Release(moniker0);
201 IMoniker_Release(moniker1);
203 else
204 skip("Cannot get moniker for testing.\n");
206 IEnumMoniker_Release(enum_moniker0);
207 IEnumMoniker_Release(enum_moniker1);
209 res = ICreateDevEnum_CreateClassEnumerator(create_devenum, &CLSID_LegacyAmFilterCategory, &enum_moniker0, 0);
210 ok(SUCCEEDED(res), "Cannot create enum moniker (res = %x)\n", res);
211 res = ICreateDevEnum_CreateClassEnumerator(create_devenum, &CLSID_LegacyAmFilterCategory, &enum_moniker1, 0);
212 ok(SUCCEEDED(res), "Cannot create enum moniker (res = %x)\n", res);
213 if (SUCCEEDED(res))
215 if (IEnumMoniker_Next(enum_moniker0, 1, &moniker0, NULL) == S_OK &&
216 IEnumMoniker_Next(enum_moniker1, 1, &moniker1, NULL) == S_OK)
218 res = IMoniker_IsEqual(moniker0, moniker1);
219 ok(res == S_OK, "IMoniker_IsEqual failed (res = %x)\n", res);
221 res = IMoniker_IsEqual(moniker1, moniker0);
222 ok(res == S_OK, "IMoniker_IsEqual failed (res = %x)\n", res);
224 IMoniker_Release(moniker0);
225 IMoniker_Release(moniker1);
227 else
228 skip("Cannot get moniker for testing.\n");
230 IEnumMoniker_Release(enum_moniker0);
231 IEnumMoniker_Release(enum_moniker1);
233 ICreateDevEnum_Release(create_devenum);
235 return;
238 static BOOL find_moniker(const GUID *class, IMoniker *needle)
240 ICreateDevEnum *devenum;
241 IEnumMoniker *enum_mon;
242 IMoniker *mon;
243 BOOL found = FALSE;
245 CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (void **)&devenum);
246 ICreateDevEnum_CreateClassEnumerator(devenum, class, &enum_mon, 0);
247 while (!found && IEnumMoniker_Next(enum_mon, 1, &mon, NULL) == S_OK)
249 if (IMoniker_IsEqual(mon, needle) == S_OK)
250 found = TRUE;
252 IMoniker_Release(mon);
255 IEnumMoniker_Release(enum_mon);
256 ICreateDevEnum_Release(devenum);
257 return found;
260 DEFINE_GUID(CLSID_TestFilter, 0xdeadbeef,0xcf51,0x43e6,0xb6,0xc5,0x29,0x9e,0xa8,0xb6,0xb5,0x91);
262 static void test_register_filter(void)
264 static const WCHAR name[] = {'d','e','v','e','n','u','m',' ','t','e','s','t',0};
265 IFilterMapper2 *mapper2;
266 IMoniker *mon = NULL;
267 REGFILTER2 rgf2 = {0};
268 HRESULT hr;
270 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2, (void **)&mapper2);
271 ok(hr == S_OK, "Failed to create FilterMapper2: %#x\n", hr);
273 rgf2.dwVersion = 2;
274 rgf2.dwMerit = MERIT_UNLIKELY;
275 S2(U(rgf2)).cPins2 = 0;
277 hr = IFilterMapper2_RegisterFilter(mapper2, &CLSID_TestFilter, name, &mon, NULL, NULL, &rgf2);
278 if (hr == E_ACCESSDENIED)
280 skip("Not enough permissions to register filters\n");
281 IFilterMapper2_Release(mapper2);
282 return;
284 ok(hr == S_OK, "RegisterFilter failed: %#x\n", hr);
286 ok(find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should be registered\n");
288 hr = IFilterMapper2_UnregisterFilter(mapper2, NULL, NULL, &CLSID_TestFilter);
289 ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr);
291 ok(!find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should not be registered\n");
292 IMoniker_Release(mon);
294 mon = NULL;
295 hr = IFilterMapper2_RegisterFilter(mapper2, &CLSID_TestFilter, name, &mon, &CLSID_AudioRendererCategory, NULL, &rgf2);
296 ok(hr == S_OK, "RegisterFilter failed: %#x\n", hr);
298 ok(find_moniker(&CLSID_AudioRendererCategory, mon), "filter should be registered\n");
300 hr = IFilterMapper2_UnregisterFilter(mapper2, &CLSID_AudioRendererCategory, NULL, &CLSID_TestFilter);
301 ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr);
303 ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n");
304 IMoniker_Release(mon);
306 IFilterMapper2_Release(mapper2);
309 static IMoniker *check_display_name_(int line, IParseDisplayName *parser, WCHAR *buffer)
311 IMoniker *mon;
312 ULONG eaten;
313 HRESULT hr;
314 WCHAR *str;
316 hr = IParseDisplayName_ParseDisplayName(parser, NULL, buffer, &eaten, &mon);
317 ok_(__FILE__, line)(hr == S_OK, "ParseDisplayName failed: %#x\n", hr);
319 hr = IMoniker_GetDisplayName(mon, NULL, NULL, &str);
320 ok_(__FILE__, line)(hr == S_OK, "GetDisplayName failed: %#x\n", hr);
321 ok_(__FILE__, line)(!lstrcmpW(str, buffer), "got %s\n", wine_dbgstr_w(str));
323 CoTaskMemFree(str);
325 return mon;
327 #define check_display_name(parser, buffer) check_display_name_(__LINE__, parser, buffer)
329 static void test_directshow_filter(void)
331 static const WCHAR instanceW[] = {'\\','I','n','s','t','a','n','c','e',0};
332 static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0};
333 static WCHAR testW[] = {'\\','t','e','s','t',0};
334 IParseDisplayName *parser;
335 IPropertyBag *prop_bag;
336 IMoniker *mon;
337 WCHAR buffer[200];
338 LRESULT res;
339 VARIANT var;
340 HRESULT hr;
342 /* Test ParseDisplayName and GetDisplayName */
343 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
344 ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
346 lstrcpyW(buffer, deviceW);
347 lstrcatW(buffer, swW);
348 StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
349 lstrcatW(buffer, testW);
350 mon = check_display_name(parser, buffer);
352 /* Test writing and reading from the property bag */
353 ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n");
355 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
356 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
358 VariantInit(&var);
359 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
360 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr);
362 /* writing causes the key to be created */
363 V_VT(&var) = VT_BSTR;
364 V_BSTR(&var) = SysAllocString(testW);
365 hr = IPropertyBag_Write(prop_bag, friendly_name, &var);
366 if (hr != E_ACCESSDENIED)
368 ok(hr == S_OK, "Write failed: %#x\n", hr);
370 ok(find_moniker(&CLSID_AudioRendererCategory, mon), "filter should be registered\n");
372 VariantClear(&var);
373 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
374 ok(hr == S_OK, "Read failed: %#x\n", hr);
375 ok(!lstrcmpW(V_BSTR(&var), testW), "got %s\n", wine_dbgstr_w(V_BSTR(&var)));
377 IMoniker_Release(mon);
379 /* devenum doesn't give us a way to unregister—we have to do that manually */
380 lstrcpyW(buffer, clsidW);
381 StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
382 lstrcatW(buffer, instanceW);
383 lstrcatW(buffer, testW);
384 res = RegDeleteKeyW(HKEY_CLASSES_ROOT, buffer);
385 ok(!res, "RegDeleteKey failed: %lu\n", res);
388 VariantClear(&var);
389 IPropertyBag_Release(prop_bag);
391 /* name can be anything */
393 lstrcpyW(buffer, deviceW);
394 lstrcatW(buffer, swW);
395 lstrcatW(buffer, testW+1);
396 mon = check_display_name(parser, buffer);
398 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
399 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
401 VariantClear(&var);
402 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
403 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr);
405 V_VT(&var) = VT_BSTR;
406 V_BSTR(&var) = SysAllocString(testW);
407 hr = IPropertyBag_Write(prop_bag, friendly_name, &var);
408 if (hr != E_ACCESSDENIED)
410 ok(hr == S_OK, "Write failed: %#x\n", hr);
412 VariantClear(&var);
413 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
414 ok(hr == S_OK, "Read failed: %#x\n", hr);
415 ok(!lstrcmpW(V_BSTR(&var), testW), "got %s\n", wine_dbgstr_w(V_BSTR(&var)));
417 IMoniker_Release(mon);
419 /* vista+ stores it inside the Instance key */
420 RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID\\test\\Instance");
422 res = RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID\\test");
423 ok(!res, "RegDeleteKey failed: %lu\n", res);
426 VariantClear(&var);
427 IPropertyBag_Release(prop_bag);
428 IParseDisplayName_Release(parser);
431 static void test_codec(void)
433 static WCHAR testW[] = {'\\','t','e','s','t',0};
434 IParseDisplayName *parser;
435 IPropertyBag *prop_bag;
436 IMoniker *mon;
437 WCHAR buffer[200];
438 VARIANT var;
439 HRESULT hr;
441 /* Test ParseDisplayName and GetDisplayName */
442 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
443 ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
445 lstrcpyW(buffer, deviceW);
446 lstrcatW(buffer, cmW);
447 StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
448 lstrcatW(buffer, testW);
449 mon = check_display_name(parser, buffer);
451 /* Test writing and reading from the property bag */
452 ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "codec should not be registered\n");
454 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
455 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
457 VariantInit(&var);
458 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
459 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr);
461 V_VT(&var) = VT_BSTR;
462 V_BSTR(&var) = SysAllocString(testW);
463 hr = IPropertyBag_Write(prop_bag, friendly_name, &var);
464 ok(hr == S_OK, "Write failed: %#x\n", hr);
466 VariantClear(&var);
467 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
468 ok(hr == S_OK, "Read failed: %#x\n", hr);
469 ok(!lstrcmpW(V_BSTR(&var), testW), "got %s\n", wine_dbgstr_w(V_BSTR(&var)));
471 /* unlike DirectShow filters, these are automatically generated, so
472 * enumerating them will destroy the key */
473 ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "codec should not be registered\n");
475 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
476 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr);
478 IPropertyBag_Release(prop_bag);
479 IMoniker_Release(mon);
481 IParseDisplayName_Release(parser);
484 static void test_legacy_filter(void)
486 static const WCHAR nameW[] = {'t','e','s','t',0};
487 IParseDisplayName *parser;
488 IPropertyBag *prop_bag;
489 IFilterMapper *mapper;
490 IMoniker *mon;
491 WCHAR buffer[200];
492 VARIANT var;
493 HRESULT hr;
495 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
496 ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
498 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper, (void **)&mapper);
499 ok(hr == S_OK, "Failed to create FilterMapper: %#x\n", hr);
501 hr = IFilterMapper_RegisterFilter(mapper, CLSID_TestFilter, nameW, 0xdeadbeef);
502 if (hr == VFW_E_BAD_KEY)
504 win_skip("not enough permissions to register filters\n");
505 goto end;
507 ok(hr == S_OK, "RegisterFilter failed: %#x\n", hr);
509 lstrcpyW(buffer, deviceW);
510 lstrcatW(buffer, cmW);
511 StringFromGUID2(&CLSID_LegacyAmFilterCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
512 lstrcatW(buffer, backslashW);
513 StringFromGUID2(&CLSID_TestFilter, buffer + lstrlenW(buffer), CHARS_IN_GUID);
515 mon = check_display_name(parser, buffer);
516 ok(find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should be registered\n");
518 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
519 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
521 VariantInit(&var);
522 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
523 ok(hr == S_OK, "Read failed: %#x\n", hr);
525 StringFromGUID2(&CLSID_TestFilter, buffer, CHARS_IN_GUID);
526 ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
527 wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
529 VariantClear(&var);
530 hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL);
531 ok(hr == S_OK, "Read failed: %#x\n", hr);
532 ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
533 wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
535 IPropertyBag_Release(prop_bag);
537 hr = IFilterMapper_UnregisterFilter(mapper, CLSID_TestFilter);
538 ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr);
540 ok(!find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should not be registered\n");
541 IMoniker_Release(mon);
543 end:
544 IFilterMapper_Release(mapper);
545 IParseDisplayName_Release(parser);
548 static BOOL CALLBACK test_dsound(GUID *guid, const WCHAR *desc, const WCHAR *module, void *context)
550 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','D','i','r','e','c','t','S','o','u','n','d',' ','D','e','v','i','c','e',0};
551 static const WCHAR directsoundW[] = {'D','i','r','e','c','t','S','o','u','n','d',':',' ',0};
552 static const WCHAR dsguidW[] = {'D','S','G','u','i','d',0};
553 IParseDisplayName *parser;
554 IPropertyBag *prop_bag;
555 IMoniker *mon;
556 WCHAR buffer[200];
557 WCHAR name[200];
558 VARIANT var;
559 HRESULT hr;
561 if (guid)
563 lstrcpyW(name, directsoundW);
564 lstrcatW(name, desc);
566 else
568 lstrcpyW(name, defaultW);
569 guid = (GUID *)&GUID_NULL;
572 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
573 ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
575 lstrcpyW(buffer, deviceW);
576 lstrcatW(buffer, cmW);
577 StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
578 lstrcatW(buffer, backslashW);
579 lstrcatW(buffer, name);
581 mon = check_display_name(parser, buffer);
583 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
584 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
586 VariantInit(&var);
587 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
588 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
590 /* Win8+ uses the GUID instead of the device name */
591 IPropertyBag_Release(prop_bag);
592 IMoniker_Release(mon);
594 lstrcpyW(buffer, deviceW);
595 lstrcatW(buffer, cmW);
596 StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
597 lstrcatW(buffer, backslashW);
598 lstrcatW(buffer, directsoundW);
599 StringFromGUID2(guid, buffer + lstrlenW(buffer) - 1, CHARS_IN_GUID);
601 mon = check_display_name(parser, buffer);
603 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
604 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
606 VariantInit(&var);
607 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
609 ok(hr == S_OK, "Read failed: %#x\n", hr);
611 ok(!lstrcmpW(name, V_BSTR(&var)), "expected %s, got %s\n",
612 wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&var)));
614 VariantClear(&var);
615 hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL);
616 ok(hr == S_OK, "Read failed: %#x\n", hr);
618 StringFromGUID2(&CLSID_DSoundRender, buffer, CHARS_IN_GUID);
619 ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
620 wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
622 VariantClear(&var);
623 hr = IPropertyBag_Read(prop_bag, dsguidW, &var, NULL);
624 ok(hr == S_OK, "Read failed: %#x\n", hr);
626 StringFromGUID2(guid, buffer, CHARS_IN_GUID);
627 ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
628 wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
630 IPropertyBag_Release(prop_bag);
631 IMoniker_Release(mon);
632 IParseDisplayName_Release(parser);
633 return TRUE;
636 static void test_waveout(void)
638 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','W','a','v','e','O','u','t',' ','D','e','v','i','c','e',0};
639 static const WCHAR waveoutidW[] = {'W','a','v','e','O','u','t','I','d',0};
640 IParseDisplayName *parser;
641 IPropertyBag *prop_bag;
642 IMoniker *mon;
643 WCHAR endpoint[200];
644 WAVEOUTCAPSW caps;
645 WCHAR buffer[200];
646 const WCHAR *name;
647 MMRESULT mmr;
648 int count, i;
649 VARIANT var;
650 HRESULT hr;
652 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
653 ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
655 count = waveOutGetNumDevs();
657 for (i = -1; i < count; i++)
659 waveOutGetDevCapsW(i, &caps, sizeof(caps));
661 if (i == -1) /* WAVE_MAPPER */
662 name = defaultW;
663 else
664 name = caps.szPname;
666 lstrcpyW(buffer, deviceW);
667 lstrcatW(buffer, cmW);
668 StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
669 lstrcatW(buffer, backslashW);
670 lstrcatW(buffer, name);
672 mon = check_display_name(parser, buffer);
674 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
675 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
677 VariantInit(&var);
678 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
679 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
681 IPropertyBag_Release(prop_bag);
682 IMoniker_Release(mon);
684 /* Win8+ uses the endpoint GUID instead of the device name */
685 mmr = waveOutMessage((HWAVEOUT)(DWORD_PTR) i, DRV_QUERYFUNCTIONINSTANCEID,
686 (DWORD_PTR) endpoint, sizeof(endpoint));
687 ok(!mmr, "waveOutMessage failed: %u\n", mmr);
689 lstrcpyW(buffer, deviceW);
690 lstrcatW(buffer, cmW);
691 StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
692 lstrcatW(buffer, backslashW);
693 lstrcatW(buffer, waveW);
694 lstrcatW(buffer, strchrW(endpoint, '}') + 2);
696 mon = check_display_name(parser, buffer);
698 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
699 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
701 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
703 ok(hr == S_OK, "Read failed: %#x\n", hr);
705 ok(!strncmpW(name, V_BSTR(&var), lstrlenW(name)), "expected %s, got %s\n",
706 wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&var)));
708 VariantClear(&var);
709 hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL);
710 ok(hr == S_OK, "Read failed: %#x\n", hr);
712 StringFromGUID2(&CLSID_AudioRender, buffer, CHARS_IN_GUID);
713 ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
714 wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
716 VariantClear(&var);
717 hr = IPropertyBag_Read(prop_bag, waveoutidW, &var, NULL);
718 ok(hr == S_OK, "Read failed: %#x\n", hr);
720 ok(V_I4(&var) == i, "expected %d, got %d\n", i, V_I4(&var));
722 IPropertyBag_Release(prop_bag);
723 IMoniker_Release(mon);
726 IParseDisplayName_Release(parser);
729 static void test_wavein(void)
731 static const WCHAR waveinidW[] = {'W','a','v','e','I','n','I','d',0};
732 IParseDisplayName *parser;
733 IPropertyBag *prop_bag;
734 IMoniker *mon;
735 WCHAR endpoint[200];
736 WCHAR buffer[200];
737 WAVEINCAPSW caps;
738 MMRESULT mmr;
739 int count, i;
740 VARIANT var;
741 HRESULT hr;
743 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
744 ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
746 count = waveInGetNumDevs();
748 for (i = 0; i < count; i++)
750 waveInGetDevCapsW(i, &caps, sizeof(caps));
752 lstrcpyW(buffer, deviceW);
753 lstrcatW(buffer, cmW);
754 StringFromGUID2(&CLSID_AudioInputDeviceCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
755 lstrcatW(buffer, backslashW);
756 lstrcatW(buffer, caps.szPname);
758 mon = check_display_name(parser, buffer);
760 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
761 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
763 VariantInit(&var);
764 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
765 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
767 IPropertyBag_Release(prop_bag);
768 IMoniker_Release(mon);
770 /* Win8+ uses the endpoint GUID instead of the device name */
771 mmr = waveInMessage((HWAVEIN)(DWORD_PTR) i, DRV_QUERYFUNCTIONINSTANCEID,
772 (DWORD_PTR) endpoint, sizeof(endpoint));
773 ok(!mmr, "waveInMessage failed: %u\n", mmr);
775 lstrcpyW(buffer, deviceW);
776 lstrcatW(buffer, cmW);
777 StringFromGUID2(&CLSID_AudioInputDeviceCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
778 lstrcatW(buffer, backslashW);
779 lstrcatW(buffer, waveW);
780 lstrcatW(buffer, strchrW(endpoint, '}') + 2);
782 mon = check_display_name(parser, buffer);
784 hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
785 ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
787 hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
789 ok(hr == S_OK, "Read failed: %#x\n", hr);
791 ok(!strncmpW(caps.szPname, V_BSTR(&var), lstrlenW(caps.szPname)), "expected %s, got %s\n",
792 wine_dbgstr_w(caps.szPname), wine_dbgstr_w(V_BSTR(&var)));
794 VariantClear(&var);
795 hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL);
796 ok(hr == S_OK, "Read failed: %#x\n", hr);
798 StringFromGUID2(&CLSID_AudioRecord, buffer, CHARS_IN_GUID);
799 ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
800 wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
802 VariantClear(&var);
803 hr = IPropertyBag_Read(prop_bag, waveinidW, &var, NULL);
804 ok(hr == S_OK, "Read failed: %#x\n", hr);
806 ok(V_I4(&var) == i, "expected %d, got %d\n", i, V_I4(&var));
808 IPropertyBag_Release(prop_bag);
809 IMoniker_Release(mon);
812 IParseDisplayName_Release(parser);
815 START_TEST(devenum)
817 IBindCtx *bind_ctx = NULL;
818 HRESULT hr;
820 CoInitialize(NULL);
822 test_devenum(NULL);
824 /* IBindCtx is allowed in IMoniker_BindToStorage (IMediaCatMoniker_BindToStorage) */
825 hr = CreateBindCtx(0, &bind_ctx);
826 ok(hr == S_OK, "Cannot create BindCtx: (res = 0x%x)\n", hr);
827 if (bind_ctx) {
828 test_devenum(bind_ctx);
829 IBindCtx_Release(bind_ctx);
832 test_moniker_isequal();
833 test_register_filter();
834 test_directshow_filter();
835 test_codec();
837 test_legacy_filter();
838 hr = DirectSoundEnumerateW(test_dsound, NULL);
839 ok(hr == S_OK, "got %#x\n", hr);
840 test_waveout();
841 test_wavein();
843 CoUninitialize();