2 * Copyright 2009 Maarten Lankhorst
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/debug.h"
28 #include "wine/list.h"
32 #include "mmdeviceapi.h"
35 #include "audioclient.h"
36 #include "endpointvolume.h"
37 #include "audiopolicy.h"
38 #include "spatialaudioclient.h"
40 #include "mmdevapi_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi
);
45 DEFINE_GUID(GUID_NULL
,0,0,0,0,0,0,0,0,0,0,0);
47 static HKEY key_render
;
48 static HKEY key_capture
;
50 typedef struct MMDevPropStoreImpl
52 IPropertyStore IPropertyStore_iface
;
58 typedef struct MMDevEnumImpl
60 IMMDeviceEnumerator IMMDeviceEnumerator_iface
;
64 static MMDevice
*MMDevice_def_rec
, *MMDevice_def_play
;
65 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
;
66 static const IMMDeviceCollectionVtbl MMDevColVtbl
;
67 static const IMMDeviceVtbl MMDeviceVtbl
;
68 static const IPropertyStoreVtbl MMDevPropVtbl
;
69 static const IMMEndpointVtbl MMEndpointVtbl
;
71 static MMDevEnumImpl enumerator
;
72 static struct list device_list
= LIST_INIT(device_list
);
73 static IMMDevice info_device
;
75 typedef struct MMDevColImpl
77 IMMDeviceCollection IMMDeviceCollection_iface
;
83 typedef struct IPropertyBagImpl
{
84 IPropertyBag IPropertyBag_iface
;
88 static const IPropertyBagVtbl PB_Vtbl
;
90 typedef struct IConnectorImpl
{
91 IConnector IConnector_iface
;
95 typedef struct IDeviceTopologyImpl
{
96 IDeviceTopology IDeviceTopology_iface
;
98 } IDeviceTopologyImpl
;
100 static HRESULT
MMDevPropStore_Create(MMDevice
*This
, DWORD access
, IPropertyStore
**ppv
);
102 static inline MMDevPropStore
*impl_from_IPropertyStore(IPropertyStore
*iface
)
104 return CONTAINING_RECORD(iface
, MMDevPropStore
, IPropertyStore_iface
);
107 static inline MMDevEnumImpl
*impl_from_IMMDeviceEnumerator(IMMDeviceEnumerator
*iface
)
109 return CONTAINING_RECORD(iface
, MMDevEnumImpl
, IMMDeviceEnumerator_iface
);
112 static inline MMDevColImpl
*impl_from_IMMDeviceCollection(IMMDeviceCollection
*iface
)
114 return CONTAINING_RECORD(iface
, MMDevColImpl
, IMMDeviceCollection_iface
);
117 static inline IPropertyBagImpl
*impl_from_IPropertyBag(IPropertyBag
*iface
)
119 return CONTAINING_RECORD(iface
, IPropertyBagImpl
, IPropertyBag_iface
);
122 static HRESULT
DeviceTopology_Create(IMMDevice
*device
, IDeviceTopology
**ppv
);
124 static inline IConnectorImpl
*impl_from_IConnector(IConnector
*iface
)
126 return CONTAINING_RECORD(iface
, IConnectorImpl
, IConnector_iface
);
129 static inline IDeviceTopologyImpl
*impl_from_IDeviceTopology(IDeviceTopology
*iface
)
131 return CONTAINING_RECORD(iface
, IDeviceTopologyImpl
, IDeviceTopology_iface
);
134 static const WCHAR propkey_formatW
[] = L
"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X},%d";
136 static HRESULT
MMDevPropStore_OpenPropKey(const GUID
*guid
, DWORD flow
, HKEY
*propkey
)
141 StringFromGUID2(guid
, buffer
, 39);
142 if ((ret
= RegOpenKeyExW(flow
== eRender
? key_render
: key_capture
, buffer
, 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, &key
)) != ERROR_SUCCESS
)
144 WARN("Opening key %s failed with %lu\n", debugstr_w(buffer
), ret
);
147 ret
= RegOpenKeyExW(key
, L
"Properties", 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, propkey
);
149 if (ret
!= ERROR_SUCCESS
)
151 WARN("Opening key Properties failed with %lu\n", ret
);
157 static HRESULT
MMDevice_GetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
160 const GUID
*id
= &key
->fmtid
;
166 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
169 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
170 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
171 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
172 ret
= RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_ANY
, &type
, NULL
, &size
);
173 if (ret
!= ERROR_SUCCESS
)
175 WARN("Reading %s returned %ld\n", debugstr_w(buffer
), ret
);
186 pv
->pwszVal
= CoTaskMemAlloc(size
);
190 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_SZ
, NULL
, (BYTE
*)pv
->pwszVal
, &size
);
196 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_DWORD
, NULL
, (BYTE
*)&pv
->ulVal
, &size
);
202 pv
->blob
.cbSize
= size
;
203 pv
->blob
.pBlobData
= CoTaskMemAlloc(size
);
204 if (!pv
->blob
.pBlobData
)
207 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_BINARY
, NULL
, (BYTE
*)pv
->blob
.pBlobData
, &size
);
211 ERR("Unknown/unhandled type: %lu\n", type
);
212 PropVariantClear(pv
);
219 static HRESULT
MMDevice_SetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
222 const GUID
*id
= &key
->fmtid
;
227 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
230 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
231 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
232 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
237 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_DWORD
, (const BYTE
*)&pv
->ulVal
, sizeof(DWORD
));
242 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_BINARY
, pv
->blob
.pBlobData
, pv
->blob
.cbSize
);
243 TRACE("Blob %p %lu\n", pv
->blob
.pBlobData
, pv
->blob
.cbSize
);
249 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_SZ
, (const BYTE
*)pv
->pwszVal
, sizeof(WCHAR
)*(1+lstrlenW(pv
->pwszVal
)));
254 FIXME("Unhandled type %u\n", pv
->vt
);
259 TRACE("Writing %s returned %lu\n", debugstr_w(buffer
), ret
);
263 static HRESULT
set_driver_prop_value(GUID
*id
, const EDataFlow flow
, const PROPERTYKEY
*prop
)
265 struct get_prop_value_params params
;
268 unsigned int size
= 0;
270 TRACE("%s, (%s,%lu)\n", wine_dbgstr_guid(id
), wine_dbgstr_guid(&prop
->fmtid
), prop
->pid
);
272 if (!drvs
.pget_device_name_from_guid(id
, &dev_name
, ¶ms
.flow
))
275 params
.device
= dev_name
;
279 params
.buffer
= NULL
;
280 params
.buffer_size
= &size
;
283 __wine_unix_call(drvs
.module_unixlib
, get_prop_value
, ¶ms
);
285 if (params
.result
!= E_NOT_SUFFICIENT_BUFFER
)
288 CoTaskMemFree(params
.buffer
);
289 params
.buffer
= CoTaskMemAlloc(*params
.buffer_size
);
290 if (!params
.buffer
) {
292 return E_OUTOFMEMORY
;
296 if (FAILED(params
.result
))
297 CoTaskMemFree(params
.buffer
);
301 if (SUCCEEDED(params
.result
)) {
302 MMDevice_SetPropValue(id
, flow
, prop
, &pv
);
303 PropVariantClear(&pv
);
306 return params
.result
;
309 struct product_name_overrides
312 const WCHAR
*product
;
315 static const struct product_name_overrides product_name_overrides
[] =
317 /* Sony controllers */
318 { .id
= L
"VID_054C&PID_0CE6", .product
= L
"Wireless Controller" },
319 { .id
= L
"VID_054C&PID_0DF2", .product
= L
"Wireless Controller" },
322 static const WCHAR
*find_product_name_override(const WCHAR
*device_id
)
324 const WCHAR
*match_id
= wcschr( device_id
, '\\' ) + 1;
327 for (i
= 0; i
< ARRAY_SIZE(product_name_overrides
); ++i
)
328 if (!wcsnicmp( product_name_overrides
[i
].id
, match_id
, 17 ))
329 return product_name_overrides
[i
].product
;
334 /* Creates or updates the state of a device
335 * If GUID is null, a random guid will be assigned
336 * and the device will be created
338 static MMDevice
*MMDevice_Create(const WCHAR
*name
, GUID
*id
, EDataFlow flow
, DWORD state
, BOOL setdefault
)
341 MMDevice
*device
, *cur
= NULL
;
344 static const PROPERTYKEY deviceinterface_key
= {
345 {0x233164c8, 0x1b2c, 0x4c7d, {0xbc, 0x68, 0xb6, 0x71, 0x68, 0x7a, 0x25, 0x67}}, 1
348 static const PROPERTYKEY devicepath_key
= {
349 {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2
352 LIST_FOR_EACH_ENTRY(device
, &device_list
, MMDevice
, entry
)
354 if (device
->flow
== flow
&& IsEqualGUID(&device
->devguid
, id
)){
361 /* No device found, allocate new one */
362 cur
= calloc(1, sizeof(*cur
));
366 cur
->IMMDevice_iface
.lpVtbl
= &MMDeviceVtbl
;
367 cur
->IMMEndpoint_iface
.lpVtbl
= &MMEndpointVtbl
;
369 InitializeCriticalSectionEx(&cur
->crst
, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO
);
370 cur
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": MMDevice.crst");
372 list_add_tail(&device_list
, &cur
->entry
);
373 }else if(cur
->ref
> 0)
374 WARN("Modifying an MMDevice with postitive reference count!\n");
377 cur
->drv_id
= wcsdup(name
);
383 StringFromGUID2(&cur
->devguid
, guidstr
, ARRAY_SIZE(guidstr
));
390 if (RegCreateKeyExW(root
, guidstr
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
|KEY_WOW64_64KEY
, NULL
, &key
, NULL
) == ERROR_SUCCESS
)
393 RegSetValueExW(key
, L
"DeviceState", 0, REG_DWORD
, (const BYTE
*)&state
, sizeof(DWORD
));
394 if (!RegCreateKeyExW(key
, L
"Properties", 0, NULL
, 0, KEY_WRITE
|KEY_READ
|KEY_WOW64_64KEY
, NULL
, &keyprop
, NULL
))
399 pv
.pwszVal
= cur
->drv_id
;
401 if (SUCCEEDED(set_driver_prop_value(id
, flow
, &devicepath_key
))) {
404 PropVariantInit(&pv2
);
406 if (SUCCEEDED(MMDevice_GetPropValue(id
, flow
, &devicepath_key
, &pv2
)) && pv2
.vt
== VT_LPWSTR
) {
407 const WCHAR
*override
;
408 if ((override
= find_product_name_override(pv2
.pwszVal
)) != NULL
)
409 pv
.pwszVal
= (WCHAR
*) override
;
412 PropVariantClear(&pv2
);
415 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
);
416 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_DeviceInterface_FriendlyName
, &pv
);
417 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_DeviceDesc
, &pv
);
419 pv
.pwszVal
= guidstr
;
420 MMDevice_SetPropValue(id
, flow
, &deviceinterface_key
, &pv
);
422 if (FAILED(set_driver_prop_value(id
, flow
, &PKEY_AudioEndpoint_FormFactor
)))
425 pv
.ulVal
= (flow
== eCapture
) ? Microphone
: Speakers
;
427 MMDevice_SetPropValue(id
, flow
, &PKEY_AudioEndpoint_FormFactor
, &pv
);
430 if (flow
!= eCapture
)
434 PropVariantInit(&pv2
);
436 /* make read-write by not overwriting if already set */
437 if (FAILED(MMDevice_GetPropValue(id
, flow
, &PKEY_AudioEndpoint_PhysicalSpeakers
, &pv2
)) || pv2
.vt
!= VT_UI4
)
438 set_driver_prop_value(id
, flow
, &PKEY_AudioEndpoint_PhysicalSpeakers
);
440 PropVariantClear(&pv2
);
443 RegCloseKey(keyprop
);
451 MMDevice_def_play
= cur
;
453 MMDevice_def_rec
= cur
;
458 HRESULT
load_devices_from_reg(void)
465 ret
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
466 L
"Software\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio", 0, NULL
, 0,
467 KEY_WRITE
|KEY_READ
|KEY_WOW64_64KEY
, NULL
, &root
, NULL
);
468 if (ret
== ERROR_SUCCESS
)
469 ret
= RegCreateKeyExW(root
, L
"Capture", 0, NULL
, 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, NULL
, &key_capture
, NULL
);
470 if (ret
== ERROR_SUCCESS
)
471 ret
= RegCreateKeyExW(root
, L
"Render", 0, NULL
, 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, NULL
, &key_render
, NULL
);
475 if (ret
!= ERROR_SUCCESS
)
477 RegCloseKey(key_capture
);
478 key_render
= key_capture
= NULL
;
479 WARN("Couldn't create key: %lu\n", ret
);
487 PROPVARIANT pv
= { VT_EMPTY
};
489 len
= ARRAY_SIZE(guidvalue
);
490 ret
= RegEnumKeyExW(cur
, i
++, guidvalue
, &len
, NULL
, NULL
, NULL
, NULL
);
491 if (ret
== ERROR_NO_MORE_ITEMS
)
493 if (cur
== key_capture
)
502 if (ret
!= ERROR_SUCCESS
)
504 if (SUCCEEDED(CLSIDFromString(guidvalue
, &guid
))
505 && SUCCEEDED(MMDevice_GetPropValue(&guid
, curflow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
))
506 && pv
.vt
== VT_LPWSTR
)
508 MMDevice_Create(pv
.pwszVal
, &guid
, curflow
,
509 DEVICE_STATE_NOTPRESENT
, FALSE
);
510 CoTaskMemFree(pv
.pwszVal
);
517 static HRESULT
set_format(MMDevice
*dev
)
520 IAudioClient
*client
;
522 PROPVARIANT pv
= { VT_EMPTY
};
524 hr
= AudioClient_Create(&dev
->devguid
, &dev
->IMMDevice_iface
, &client
);
528 hr
= IAudioClient_GetMixFormat(client
, &fmt
);
530 IAudioClient_Release(client
);
534 IAudioClient_Release(client
);
537 pv
.blob
.cbSize
= sizeof(WAVEFORMATEX
) + fmt
->cbSize
;
538 pv
.blob
.pBlobData
= (BYTE
*)fmt
;
539 MMDevice_SetPropValue(&dev
->devguid
, dev
->flow
,
540 &PKEY_AudioEngine_DeviceFormat
, &pv
);
541 MMDevice_SetPropValue(&dev
->devguid
, dev
->flow
,
542 &PKEY_AudioEngine_OEMFormat
, &pv
);
548 HRESULT
load_driver_devices(EDataFlow flow
)
550 struct get_endpoint_ids_params params
;
555 params
.endpoints
= NULL
;
557 free(params
.endpoints
);
558 params
.endpoints
= malloc(params
.size
);
559 __wine_unix_call(drvs
.module_unixlib
, get_endpoint_ids
, ¶ms
);
560 } while (params
.result
== HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
));
562 if (FAILED(params
.result
))
565 for (i
= 0; i
< params
.num
; i
++) {
568 const WCHAR
*name
= (WCHAR
*)((char *)params
.endpoints
+ params
.endpoints
[i
].name
);
569 const char *dev_name
= (char *)params
.endpoints
+ params
.endpoints
[i
].device
;
571 drvs
.pget_device_guid(flow
, dev_name
, &guid
);
573 dev
= MMDevice_Create(name
, &guid
, flow
, DEVICE_STATE_ACTIVE
, params
.default_idx
== i
);
578 free(params
.endpoints
);
580 return params
.result
;
583 static void MMDevice_Destroy(MMDevice
*This
)
585 TRACE("Freeing %s\n", debugstr_w(This
->drv_id
));
586 list_remove(&This
->entry
);
587 This
->crst
.DebugInfo
->Spare
[0] = 0;
588 DeleteCriticalSection(&This
->crst
);
593 static inline MMDevice
*impl_from_IMMDevice(IMMDevice
*iface
)
595 return CONTAINING_RECORD(iface
, MMDevice
, IMMDevice_iface
);
598 static HRESULT WINAPI
MMDevice_QueryInterface(IMMDevice
*iface
, REFIID riid
, void **ppv
)
600 MMDevice
*This
= impl_from_IMMDevice(iface
);
601 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
606 if (IsEqualIID(riid
, &IID_IUnknown
)
607 || IsEqualIID(riid
, &IID_IMMDevice
))
608 *ppv
= &This
->IMMDevice_iface
;
609 else if (IsEqualIID(riid
, &IID_IMMEndpoint
))
610 *ppv
= &This
->IMMEndpoint_iface
;
613 IUnknown_AddRef((IUnknown
*)*ppv
);
616 WARN("Unknown interface %s\n", debugstr_guid(riid
));
617 return E_NOINTERFACE
;
620 static ULONG WINAPI
MMDevice_AddRef(IMMDevice
*iface
)
622 MMDevice
*This
= impl_from_IMMDevice(iface
);
625 ref
= InterlockedIncrement(&This
->ref
);
626 TRACE("Refcount now %li\n", ref
);
630 static ULONG WINAPI
MMDevice_Release(IMMDevice
*iface
)
632 MMDevice
*This
= impl_from_IMMDevice(iface
);
635 ref
= InterlockedDecrement(&This
->ref
);
636 TRACE("Refcount now %li\n", ref
);
640 static HRESULT WINAPI
MMDevice_Activate(IMMDevice
*iface
, REFIID riid
, DWORD clsctx
, PROPVARIANT
*params
, void **ppv
)
642 HRESULT hr
= E_NOINTERFACE
;
643 MMDevice
*This
= impl_from_IMMDevice(iface
);
645 TRACE("(%p)->(%s, %lx, %p, %p)\n", iface
, debugstr_guid(riid
), clsctx
, params
, ppv
);
650 if (IsEqualIID(riid
, &IID_IAudioClient
) ||
651 IsEqualIID(riid
, &IID_IAudioClient2
) ||
652 IsEqualIID(riid
, &IID_IAudioClient3
)){
653 hr
= AudioClient_Create(&This
->devguid
, iface
, (IAudioClient
**)ppv
);
654 }else if (IsEqualIID(riid
, &IID_IAudioEndpointVolume
) ||
655 IsEqualIID(riid
, &IID_IAudioEndpointVolumeEx
))
656 hr
= AudioEndpointVolume_Create(This
, (IAudioEndpointVolumeEx
**)ppv
);
657 else if (IsEqualIID(riid
, &IID_IAudioSessionManager
)
658 || IsEqualIID(riid
, &IID_IAudioSessionManager2
))
660 hr
= AudioSessionManager_Create(iface
, (IAudioSessionManager2
**)ppv
);
662 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
664 if (This
->flow
== eRender
)
665 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, clsctx
, riid
, ppv
);
667 ERR("Not supported for recording?\n");
670 IPersistPropertyBag
*ppb
;
671 hr
= IUnknown_QueryInterface((IUnknown
*)*ppv
, &IID_IPersistPropertyBag
, (void **)&ppb
);
674 /* ::Load cannot assume the interface stays alive after the function returns,
675 * so just create the interface on the stack, saves a lot of complicated code */
676 IPropertyBagImpl bag
= { { &PB_Vtbl
} };
677 bag
.devguid
= This
->devguid
;
678 hr
= IPersistPropertyBag_Load(ppb
, &bag
.IPropertyBag_iface
, NULL
);
679 IPersistPropertyBag_Release(ppb
);
681 IBaseFilter_Release((IBaseFilter
*)*ppv
);
685 FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n");
690 else if (IsEqualIID(riid
, &IID_IDeviceTopology
))
692 hr
= DeviceTopology_Create(iface
, (IDeviceTopology
**)ppv
);
694 else if (IsEqualIID(riid
, &IID_IDirectSound
)
695 || IsEqualIID(riid
, &IID_IDirectSound8
))
697 if (This
->flow
== eRender
)
698 hr
= CoCreateInstance(&CLSID_DirectSound8
, NULL
, clsctx
, riid
, ppv
);
701 hr
= IDirectSound_Initialize((IDirectSound
*)*ppv
, &This
->devguid
);
703 IDirectSound_Release((IDirectSound
*)*ppv
);
706 else if (IsEqualIID(riid
, &IID_IDirectSoundCapture
))
708 if (This
->flow
== eCapture
)
709 hr
= CoCreateInstance(&CLSID_DirectSoundCapture8
, NULL
, clsctx
, riid
, ppv
);
712 hr
= IDirectSoundCapture_Initialize((IDirectSoundCapture
*)*ppv
, &This
->devguid
);
714 IDirectSoundCapture_Release((IDirectSoundCapture
*)*ppv
);
717 else if (IsEqualIID(riid
, &IID_ISpatialAudioClient
))
719 hr
= SpatialAudioClient_Create(iface
, (ISpatialAudioClient
**)ppv
);
722 ERR("Invalid/unknown iid %s\n", debugstr_guid(riid
));
727 TRACE("Returning %08lx\n", hr
);
731 static HRESULT WINAPI
MMDevice_OpenPropertyStore(IMMDevice
*iface
, DWORD access
, IPropertyStore
**ppv
)
733 MMDevice
*This
= impl_from_IMMDevice(iface
);
734 TRACE("(%p)->(%lx,%p)\n", This
, access
, ppv
);
738 return MMDevPropStore_Create(This
, access
, ppv
);
741 static HRESULT WINAPI
MMDevice_GetId(IMMDevice
*iface
, WCHAR
**itemid
)
743 MMDevice
*This
= impl_from_IMMDevice(iface
);
745 GUID
*id
= &This
->devguid
;
747 TRACE("(%p)->(%p)\n", This
, itemid
);
750 *itemid
= str
= CoTaskMemAlloc(56 * sizeof(WCHAR
));
752 return E_OUTOFMEMORY
;
753 wsprintfW(str
, L
"{0.0.%u.00000000}.{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
754 This
->flow
, id
->Data1
, id
->Data2
, id
->Data3
,
755 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
756 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7]);
757 TRACE("returning %s\n", wine_dbgstr_w(str
));
761 static HRESULT WINAPI
MMDevice_GetState(IMMDevice
*iface
, DWORD
*state
)
763 MMDevice
*This
= impl_from_IMMDevice(iface
);
764 TRACE("(%p)->(%p)\n", iface
, state
);
768 *state
= This
->state
;
772 static const IMMDeviceVtbl MMDeviceVtbl
=
774 MMDevice_QueryInterface
,
778 MMDevice_OpenPropertyStore
,
783 static inline MMDevice
*impl_from_IMMEndpoint(IMMEndpoint
*iface
)
785 return CONTAINING_RECORD(iface
, MMDevice
, IMMEndpoint_iface
);
788 static HRESULT WINAPI
MMEndpoint_QueryInterface(IMMEndpoint
*iface
, REFIID riid
, void **ppv
)
790 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
791 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
792 return IMMDevice_QueryInterface(&This
->IMMDevice_iface
, riid
, ppv
);
795 static ULONG WINAPI
MMEndpoint_AddRef(IMMEndpoint
*iface
)
797 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
798 TRACE("(%p)\n", This
);
799 return IMMDevice_AddRef(&This
->IMMDevice_iface
);
802 static ULONG WINAPI
MMEndpoint_Release(IMMEndpoint
*iface
)
804 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
805 TRACE("(%p)\n", This
);
806 return IMMDevice_Release(&This
->IMMDevice_iface
);
809 static HRESULT WINAPI
MMEndpoint_GetDataFlow(IMMEndpoint
*iface
, EDataFlow
*flow
)
811 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
812 TRACE("(%p)->(%p)\n", This
, flow
);
819 static const IMMEndpointVtbl MMEndpointVtbl
=
821 MMEndpoint_QueryInterface
,
824 MMEndpoint_GetDataFlow
827 static HRESULT
MMDevCol_Create(IMMDeviceCollection
**ppv
, EDataFlow flow
, DWORD state
)
833 This
= malloc(sizeof(*This
));
836 return E_OUTOFMEMORY
;
837 This
->IMMDeviceCollection_iface
.lpVtbl
= &MMDevColVtbl
;
839 This
->devices
= NULL
;
840 This
->devices_count
= 0;
841 *ppv
= &This
->IMMDeviceCollection_iface
;
843 LIST_FOR_EACH_ENTRY(cur
, &device_list
, MMDevice
, entry
)
845 if ((cur
->flow
== flow
|| flow
== eAll
) && (cur
->state
& state
))
846 This
->devices_count
++;
849 if (This
->devices_count
)
851 This
->devices
= malloc(This
->devices_count
* sizeof(IMMDevice
*));
852 if (!This
->devices_count
)
853 return E_OUTOFMEMORY
;
855 LIST_FOR_EACH_ENTRY(cur
, &device_list
, MMDevice
, entry
)
857 if ((cur
->flow
== flow
|| flow
== eAll
) && (cur
->state
& state
))
859 This
->devices
[i
] = &cur
->IMMDevice_iface
;
860 IMMDevice_AddRef(This
->devices
[i
]);
869 static void MMDevCol_Destroy(MMDevColImpl
*This
)
872 for (i
= 0; i
< This
->devices_count
; i
++)
873 IMMDevice_Release(This
->devices
[i
]);
879 static HRESULT WINAPI
MMDevCol_QueryInterface(IMMDeviceCollection
*iface
, REFIID riid
, void **ppv
)
881 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
882 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
886 if (IsEqualIID(riid
, &IID_IUnknown
)
887 || IsEqualIID(riid
, &IID_IMMDeviceCollection
))
888 *ppv
= &This
->IMMDeviceCollection_iface
;
892 return E_NOINTERFACE
;
893 IUnknown_AddRef((IUnknown
*)*ppv
);
897 static ULONG WINAPI
MMDevCol_AddRef(IMMDeviceCollection
*iface
)
899 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
900 LONG ref
= InterlockedIncrement(&This
->ref
);
901 TRACE("Refcount now %li\n", ref
);
905 static ULONG WINAPI
MMDevCol_Release(IMMDeviceCollection
*iface
)
907 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
908 LONG ref
= InterlockedDecrement(&This
->ref
);
909 TRACE("Refcount now %li\n", ref
);
911 MMDevCol_Destroy(This
);
915 static HRESULT WINAPI
MMDevCol_GetCount(IMMDeviceCollection
*iface
, UINT
*numdevs
)
917 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
919 TRACE("(%p)->(%p)\n", This
, numdevs
);
923 *numdevs
= This
->devices_count
;
927 static HRESULT WINAPI
MMDevCol_Item(IMMDeviceCollection
*iface
, UINT n
, IMMDevice
**dev
)
929 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
931 TRACE("(%p)->(%u, %p)\n", This
, n
, dev
);
935 if (n
>= This
->devices_count
)
937 WARN("Could not obtain item %u\n", n
);
942 *dev
= This
->devices
[n
];
943 IMMDevice_AddRef(*dev
);
947 static const IMMDeviceCollectionVtbl MMDevColVtbl
=
949 MMDevCol_QueryInterface
,
956 HRESULT
MMDevEnum_Create(REFIID riid
, void **ppv
)
958 return IMMDeviceEnumerator_QueryInterface(&enumerator
.IMMDeviceEnumerator_iface
, riid
, ppv
);
961 void MMDevEnum_Free(void)
963 MMDevice
*device
, *next
;
964 LIST_FOR_EACH_ENTRY_SAFE(device
, next
, &device_list
, MMDevice
, entry
)
965 MMDevice_Destroy(device
);
966 RegCloseKey(key_render
);
967 RegCloseKey(key_capture
);
968 key_render
= key_capture
= NULL
;
971 static HRESULT WINAPI
MMDevEnum_QueryInterface(IMMDeviceEnumerator
*iface
, REFIID riid
, void **ppv
)
973 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
974 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
978 if (IsEqualIID(riid
, &IID_IUnknown
)
979 || IsEqualIID(riid
, &IID_IMMDeviceEnumerator
))
980 *ppv
= &This
->IMMDeviceEnumerator_iface
;
984 return E_NOINTERFACE
;
985 IUnknown_AddRef((IUnknown
*)*ppv
);
989 static ULONG WINAPI
MMDevEnum_AddRef(IMMDeviceEnumerator
*iface
)
991 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
992 LONG ref
= InterlockedIncrement(&This
->ref
);
993 TRACE("Refcount now %li\n", ref
);
997 static ULONG WINAPI
MMDevEnum_Release(IMMDeviceEnumerator
*iface
)
999 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1000 LONG ref
= InterlockedDecrement(&This
->ref
);
1001 TRACE("Refcount now %li\n", ref
);
1005 static HRESULT WINAPI
MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator
*iface
, EDataFlow flow
, DWORD mask
, IMMDeviceCollection
**devices
)
1007 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1008 TRACE("(%p)->(%u,%lu,%p)\n", This
, flow
, mask
, devices
);
1012 if (flow
>= EDataFlow_enum_count
)
1013 return E_INVALIDARG
;
1014 if (mask
& ~DEVICE_STATEMASK_ALL
)
1015 return E_INVALIDARG
;
1016 return MMDevCol_Create(devices
, flow
, mask
);
1019 static HRESULT WINAPI
MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator
*iface
, EDataFlow flow
, ERole role
, IMMDevice
**device
)
1021 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1026 TRACE("(%p)->(%u,%u,%p)\n", This
, flow
, role
, device
);
1031 if((flow
!= eRender
&& flow
!= eCapture
) ||
1032 (role
!= eConsole
&& role
!= eMultimedia
&& role
!= eCommunications
)){
1033 WARN("Unknown flow (%u) or role (%u)\n", flow
, role
);
1034 return E_INVALIDARG
;
1039 if(!drvs
.module_name
[0])
1042 lstrcpyW(reg_key
, drv_keyW
);
1043 lstrcatW(reg_key
, L
"\\");
1044 lstrcatW(reg_key
, drvs
.module_name
);
1046 if(RegOpenKeyW(HKEY_CURRENT_USER
, reg_key
, &key
) == ERROR_SUCCESS
){
1047 const WCHAR
*reg_x_name
, *reg_vx_name
;
1049 DWORD size
= sizeof(def_id
), state
;
1051 if(flow
== eRender
){
1052 reg_x_name
= L
"DefaultOutput";
1053 reg_vx_name
= L
"DefaultVoiceOutput";
1055 reg_x_name
= L
"DefaultInput";
1056 reg_vx_name
= L
"DefaultVoiceInput";
1059 if(role
== eCommunications
&&
1060 RegQueryValueExW(key
, reg_vx_name
, 0, NULL
,
1061 (BYTE
*)def_id
, &size
) == ERROR_SUCCESS
){
1062 hr
= IMMDeviceEnumerator_GetDevice(iface
, def_id
, device
);
1064 if(SUCCEEDED(IMMDevice_GetState(*device
, &state
)) &&
1065 state
== DEVICE_STATE_ACTIVE
){
1071 TRACE("Unable to find voice device %s\n", wine_dbgstr_w(def_id
));
1074 if(RegQueryValueExW(key
, reg_x_name
, 0, NULL
,
1075 (BYTE
*)def_id
, &size
) == ERROR_SUCCESS
){
1076 hr
= IMMDeviceEnumerator_GetDevice(iface
, def_id
, device
);
1078 if(SUCCEEDED(IMMDevice_GetState(*device
, &state
)) &&
1079 state
== DEVICE_STATE_ACTIVE
){
1085 TRACE("Unable to find device %s\n", wine_dbgstr_w(def_id
));
1091 if (flow
== eRender
)
1092 *device
= &MMDevice_def_play
->IMMDevice_iface
;
1094 *device
= &MMDevice_def_rec
->IMMDevice_iface
;
1098 IMMDevice_AddRef(*device
);
1102 static HRESULT WINAPI
MMDevEnum_GetDevice(IMMDeviceEnumerator
*iface
, const WCHAR
*name
, IMMDevice
**device
)
1104 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1106 IMMDevice
*dev
= NULL
;
1108 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(name
), device
);
1110 if(!name
|| !device
)
1113 if(!lstrcmpW(name
, L
"Wine info device")){
1114 *device
= &info_device
;
1118 LIST_FOR_EACH_ENTRY(impl
, &device_list
, MMDevice
, entry
)
1122 dev
= &impl
->IMMDevice_iface
;
1123 hr
= IMMDevice_GetId(dev
, &str
);
1126 WARN("GetId failed: %08lx\n", hr
);
1130 if (str
&& !lstrcmpW(str
, name
))
1133 IMMDevice_AddRef(dev
);
1139 TRACE("Could not find device %s\n", debugstr_w(name
));
1140 return E_INVALIDARG
;
1143 struct NotificationClientWrapper
{
1144 IMMNotificationClient
*client
;
1148 static struct list g_notif_clients
= LIST_INIT(g_notif_clients
);
1149 static HANDLE g_notif_thread
;
1151 static CRITICAL_SECTION g_notif_lock
;
1152 static CRITICAL_SECTION_DEBUG g_notif_lock_debug
=
1154 0, 0, &g_notif_lock
,
1155 { &g_notif_lock_debug
.ProcessLocksList
, &g_notif_lock_debug
.ProcessLocksList
},
1156 0, 0, { (DWORD_PTR
)(__FILE__
": g_notif_lock") }
1158 static CRITICAL_SECTION g_notif_lock
= { &g_notif_lock_debug
, -1, 0, 0, 0, 0 };
1160 static void notify_clients(EDataFlow flow
, ERole role
, const WCHAR
*id
)
1162 struct NotificationClientWrapper
*wrapper
;
1163 LIST_FOR_EACH_ENTRY(wrapper
, &g_notif_clients
,
1164 struct NotificationClientWrapper
, entry
)
1165 IMMNotificationClient_OnDefaultDeviceChanged(wrapper
->client
, flow
,
1168 /* Windows 7 treats changes to eConsole as changes to eMultimedia */
1169 if(role
== eConsole
)
1170 notify_clients(flow
, eMultimedia
, id
);
1173 static BOOL
notify_if_changed(EDataFlow flow
, ERole role
, HKEY key
,
1174 const WCHAR
*val_name
, WCHAR
*old_val
, IMMDevice
*def_dev
)
1176 WCHAR new_val
[64], *id
;
1180 size
= sizeof(new_val
);
1181 if(RegQueryValueExW(key
, val_name
, 0, NULL
,
1182 (BYTE
*)new_val
, &size
) != ERROR_SUCCESS
){
1183 if(old_val
[0] != 0){
1184 /* set by user -> system default */
1186 hr
= IMMDevice_GetId(def_dev
, &id
);
1188 ERR("GetId failed: %08lx\n", hr
);
1194 notify_clients(flow
, role
, id
);
1201 /* system default -> system default, noop */
1205 if(!lstrcmpW(old_val
, new_val
)){
1206 /* set by user -> same value */
1210 if(new_val
[0] != 0){
1211 /* set by user -> different value */
1212 notify_clients(flow
, role
, new_val
);
1213 memcpy(old_val
, new_val
, sizeof(new_val
));
1217 /* set by user -> system default */
1219 hr
= IMMDevice_GetId(def_dev
, &id
);
1221 ERR("GetId failed: %08lx\n", hr
);
1227 notify_clients(flow
, role
, id
);
1234 static DWORD WINAPI
notif_thread_proc(void *user
)
1238 WCHAR out_name
[64], vout_name
[64], in_name
[64], vin_name
[64];
1241 SetThreadDescription(GetCurrentThread(), L
"wine_mmdevapi_notification");
1243 lstrcpyW(reg_key
, drv_keyW
);
1244 lstrcatW(reg_key
, L
"\\");
1245 lstrcatW(reg_key
, drvs
.module_name
);
1247 if(RegCreateKeyExW(HKEY_CURRENT_USER
, reg_key
, 0, NULL
, 0,
1248 MAXIMUM_ALLOWED
, NULL
, &key
, NULL
) != ERROR_SUCCESS
){
1249 ERR("RegCreateKeyEx failed: %lu\n", GetLastError());
1253 size
= sizeof(out_name
);
1254 if(RegQueryValueExW(key
, L
"DefaultOutput", 0, NULL
, (BYTE
*)out_name
, &size
) != ERROR_SUCCESS
)
1257 size
= sizeof(vout_name
);
1258 if(RegQueryValueExW(key
, L
"DefaultVoiceOutput", 0, NULL
, (BYTE
*)vout_name
, &size
) != ERROR_SUCCESS
)
1261 size
= sizeof(in_name
);
1262 if(RegQueryValueExW(key
, L
"DefaultInput", 0, NULL
, (BYTE
*)in_name
, &size
) != ERROR_SUCCESS
)
1265 size
= sizeof(vin_name
);
1266 if(RegQueryValueExW(key
, L
"DefaultVoiceInput", 0, NULL
, (BYTE
*)vin_name
, &size
) != ERROR_SUCCESS
)
1270 if(RegNotifyChangeKeyValue(key
, FALSE
, REG_NOTIFY_CHANGE_LAST_SET
,
1271 NULL
, FALSE
) != ERROR_SUCCESS
){
1272 ERR("RegNotifyChangeKeyValue failed: %lu\n", GetLastError());
1274 g_notif_thread
= NULL
;
1278 EnterCriticalSection(&g_notif_lock
);
1280 notify_if_changed(eRender
, eConsole
, key
, L
"DefaultOutput",
1281 out_name
, &MMDevice_def_play
->IMMDevice_iface
);
1282 notify_if_changed(eRender
, eCommunications
, key
, L
"DefaultVoiceOutput",
1283 vout_name
, &MMDevice_def_play
->IMMDevice_iface
);
1284 notify_if_changed(eCapture
, eConsole
, key
, L
"DefaultInput",
1285 in_name
, &MMDevice_def_rec
->IMMDevice_iface
);
1286 notify_if_changed(eCapture
, eCommunications
, key
, L
"DefaultVoiceInput",
1287 vin_name
, &MMDevice_def_rec
->IMMDevice_iface
);
1289 LeaveCriticalSection(&g_notif_lock
);
1294 g_notif_thread
= NULL
;
1299 static HRESULT WINAPI
MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
1301 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1302 struct NotificationClientWrapper
*wrapper
;
1304 TRACE("(%p)->(%p)\n", This
, client
);
1309 wrapper
= malloc(sizeof(*wrapper
));
1311 return E_OUTOFMEMORY
;
1313 wrapper
->client
= client
;
1315 EnterCriticalSection(&g_notif_lock
);
1317 list_add_tail(&g_notif_clients
, &wrapper
->entry
);
1319 if(!g_notif_thread
){
1320 g_notif_thread
= CreateThread(NULL
, 0, notif_thread_proc
, NULL
, 0, NULL
);
1322 ERR("CreateThread failed: %lu\n", GetLastError());
1325 LeaveCriticalSection(&g_notif_lock
);
1330 static HRESULT WINAPI
MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
1332 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1333 struct NotificationClientWrapper
*wrapper
;
1335 TRACE("(%p)->(%p)\n", This
, client
);
1340 EnterCriticalSection(&g_notif_lock
);
1342 LIST_FOR_EACH_ENTRY(wrapper
, &g_notif_clients
, struct NotificationClientWrapper
, entry
){
1343 if(wrapper
->client
== client
){
1344 list_remove(&wrapper
->entry
);
1346 LeaveCriticalSection(&g_notif_lock
);
1351 LeaveCriticalSection(&g_notif_lock
);
1356 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
=
1358 MMDevEnum_QueryInterface
,
1361 MMDevEnum_EnumAudioEndpoints
,
1362 MMDevEnum_GetDefaultAudioEndpoint
,
1363 MMDevEnum_GetDevice
,
1364 MMDevEnum_RegisterEndpointNotificationCallback
,
1365 MMDevEnum_UnregisterEndpointNotificationCallback
1368 static MMDevEnumImpl enumerator
=
1374 static HRESULT
MMDevPropStore_Create(MMDevice
*parent
, DWORD access
, IPropertyStore
**ppv
)
1376 MMDevPropStore
*This
;
1377 if (access
!= STGM_READ
1378 && access
!= STGM_WRITE
1379 && access
!= STGM_READWRITE
)
1381 WARN("Invalid access %08lx\n", access
);
1382 return E_INVALIDARG
;
1384 This
= malloc(sizeof(*This
));
1385 *ppv
= &This
->IPropertyStore_iface
;
1387 return E_OUTOFMEMORY
;
1388 This
->IPropertyStore_iface
.lpVtbl
= &MMDevPropVtbl
;
1390 This
->parent
= parent
;
1391 This
->access
= access
;
1395 static void MMDevPropStore_Destroy(MMDevPropStore
*This
)
1400 static HRESULT WINAPI
MMDevPropStore_QueryInterface(IPropertyStore
*iface
, REFIID riid
, void **ppv
)
1402 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1403 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1407 if (IsEqualIID(riid
, &IID_IUnknown
)
1408 || IsEqualIID(riid
, &IID_IPropertyStore
))
1409 *ppv
= &This
->IPropertyStore_iface
;
1413 return E_NOINTERFACE
;
1414 IUnknown_AddRef((IUnknown
*)*ppv
);
1418 static ULONG WINAPI
MMDevPropStore_AddRef(IPropertyStore
*iface
)
1420 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1421 LONG ref
= InterlockedIncrement(&This
->ref
);
1422 TRACE("Refcount now %li\n", ref
);
1426 static ULONG WINAPI
MMDevPropStore_Release(IPropertyStore
*iface
)
1428 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1429 LONG ref
= InterlockedDecrement(&This
->ref
);
1430 TRACE("Refcount now %li\n", ref
);
1432 MMDevPropStore_Destroy(This
);
1436 static HRESULT WINAPI
MMDevPropStore_GetCount(IPropertyStore
*iface
, DWORD
*nprops
)
1438 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1444 TRACE("(%p)->(%p)\n", iface
, nprops
);
1447 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
1452 DWORD len
= ARRAY_SIZE(buffer
);
1453 if (RegEnumValueW(propkey
, i
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
1457 RegCloseKey(propkey
);
1458 TRACE("Returning %li\n", i
);
1463 static HRESULT WINAPI
MMDevPropStore_GetAt(IPropertyStore
*iface
, DWORD prop
, PROPERTYKEY
*key
)
1465 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1467 DWORD len
= ARRAY_SIZE(buffer
);
1471 TRACE("(%p)->(%lu,%p)\n", iface
, prop
, key
);
1475 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
1479 if (RegEnumValueW(propkey
, prop
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
1482 WARN("GetAt %lu failed\n", prop
);
1483 return E_INVALIDARG
;
1485 RegCloseKey(propkey
);
1487 CLSIDFromString(buffer
, &key
->fmtid
);
1488 key
->pid
= wcstol(&buffer
[39], NULL
, 10);
1492 static HRESULT WINAPI
MMDevPropStore_GetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
1494 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1496 TRACE("(%p)->(\"%s,%lu\", %p)\n", This
, key
? debugstr_guid(&key
->fmtid
) : NULL
, key
? key
->pid
: 0, pv
);
1500 if (This
->access
!= STGM_READ
1501 && This
->access
!= STGM_READWRITE
)
1502 return STG_E_ACCESSDENIED
;
1505 if (IsEqualPropertyKey(*key
, PKEY_AudioEndpoint_GUID
))
1508 pv
->pwszVal
= CoTaskMemAlloc(39 * sizeof(WCHAR
));
1510 return E_OUTOFMEMORY
;
1511 StringFromGUID2(&This
->parent
->devguid
, pv
->pwszVal
, 39);
1515 hres
= MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1519 if (WARN_ON(mmdevapi
))
1521 if ((IsEqualPropertyKey(*key
, DEVPKEY_Device_FriendlyName
) ||
1522 IsEqualPropertyKey(*key
, DEVPKEY_DeviceInterface_FriendlyName
) ||
1523 IsEqualPropertyKey(*key
, DEVPKEY_Device_DeviceDesc
)) &&
1524 pv
->vt
== VT_LPWSTR
&& wcslen(pv
->pwszVal
) > 62)
1525 WARN("Returned name exceeds length limit of some broken apps/libs, might crash: %s\n", debugstr_w(pv
->pwszVal
));
1530 static HRESULT WINAPI
MMDevPropStore_SetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
1532 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1533 TRACE("(%p)->(\"%s,%lu\", %p)\n", This
, key
? debugstr_guid(&key
->fmtid
) : NULL
, key
? key
->pid
: 0, pv
);
1538 if (This
->access
!= STGM_WRITE
1539 && This
->access
!= STGM_READWRITE
)
1540 return STG_E_ACCESSDENIED
;
1541 return MMDevice_SetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1544 static HRESULT WINAPI
MMDevPropStore_Commit(IPropertyStore
*iface
)
1546 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1547 TRACE("(%p)\n", iface
);
1549 if (This
->access
!= STGM_WRITE
1550 && This
->access
!= STGM_READWRITE
)
1551 return STG_E_ACCESSDENIED
;
1553 /* Does nothing - for mmdevapi, the propstore values are written on SetValue,
1559 static const IPropertyStoreVtbl MMDevPropVtbl
=
1561 MMDevPropStore_QueryInterface
,
1562 MMDevPropStore_AddRef
,
1563 MMDevPropStore_Release
,
1564 MMDevPropStore_GetCount
,
1565 MMDevPropStore_GetAt
,
1566 MMDevPropStore_GetValue
,
1567 MMDevPropStore_SetValue
,
1568 MMDevPropStore_Commit
1572 /* Property bag for IBaseFilter activation */
1573 static HRESULT WINAPI
PB_QueryInterface(IPropertyBag
*iface
, REFIID riid
, void **ppv
)
1575 ERR("Should not be called\n");
1577 return E_NOINTERFACE
;
1580 static ULONG WINAPI
PB_AddRef(IPropertyBag
*iface
)
1582 ERR("Should not be called\n");
1586 static ULONG WINAPI
PB_Release(IPropertyBag
*iface
)
1588 ERR("Should not be called\n");
1592 static HRESULT WINAPI
PB_Read(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
, IErrorLog
*log
)
1594 IPropertyBagImpl
*This
= impl_from_IPropertyBag(iface
);
1595 TRACE("Trying to read %s, type %u\n", debugstr_w(name
), var
->vt
);
1596 if (!lstrcmpW(name
, L
"DSGuid"))
1599 StringFromGUID2(&This
->devguid
, guidstr
,ARRAY_SIZE(guidstr
));
1601 var
->bstrVal
= SysAllocString(guidstr
);
1604 ERR("Unknown property '%s' queried\n", debugstr_w(name
));
1608 static HRESULT WINAPI
PB_Write(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
)
1610 ERR("Should not be called\n");
1614 static const IPropertyBagVtbl PB_Vtbl
=
1623 static ULONG WINAPI
info_device_ps_AddRef(IPropertyStore
*iface
)
1628 static ULONG WINAPI
info_device_ps_Release(IPropertyStore
*iface
)
1633 static HRESULT WINAPI
info_device_ps_GetValue(IPropertyStore
*iface
,
1634 REFPROPERTYKEY key
, PROPVARIANT
*pv
)
1636 TRACE("(static)->(\"%s,%lu\", %p)\n", debugstr_guid(&key
->fmtid
), key
? key
->pid
: 0, pv
);
1641 if (IsEqualPropertyKey(*key
, DEVPKEY_Device_Driver
))
1643 INT size
= (lstrlenW(drvs
.module_name
) + 1) * sizeof(WCHAR
);
1645 pv
->pwszVal
= CoTaskMemAlloc(size
);
1647 return E_OUTOFMEMORY
;
1648 memcpy(pv
->pwszVal
, drvs
.module_name
, size
);
1652 return E_INVALIDARG
;
1655 static const IPropertyStoreVtbl info_device_ps_Vtbl
=
1658 info_device_ps_AddRef
,
1659 info_device_ps_Release
,
1662 info_device_ps_GetValue
,
1667 static IPropertyStore info_device_ps
= {
1668 &info_device_ps_Vtbl
1671 static ULONG WINAPI
info_device_AddRef(IMMDevice
*iface
)
1676 static ULONG WINAPI
info_device_Release(IMMDevice
*iface
)
1681 static HRESULT WINAPI
info_device_OpenPropertyStore(IMMDevice
*iface
,
1682 DWORD access
, IPropertyStore
**ppv
)
1684 TRACE("(static)->(%lx, %p)\n", access
, ppv
);
1685 *ppv
= &info_device_ps
;
1689 static const IMMDeviceVtbl info_device_Vtbl
=
1693 info_device_Release
,
1695 info_device_OpenPropertyStore
,
1700 static IMMDevice info_device
= {
1704 static HRESULT WINAPI
Connector_QueryInterface(IConnector
*iface
, REFIID riid
, void **ppv
)
1706 IConnectorImpl
*This
= impl_from_IConnector(iface
);
1707 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1712 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1713 IsEqualIID(riid
, &IID_IConnector
))
1714 *ppv
= &This
->IConnector_iface
;
1717 return E_NOINTERFACE
;
1720 IUnknown_AddRef((IUnknown
*)*ppv
);
1725 static ULONG WINAPI
Connector_AddRef(IConnector
*iface
)
1727 IConnectorImpl
*This
= impl_from_IConnector(iface
);
1728 ULONG ref
= InterlockedIncrement(&This
->ref
);
1729 TRACE("(%p) new ref %lu\n", This
, ref
);
1733 static ULONG WINAPI
Connector_Release(IConnector
*iface
)
1735 IConnectorImpl
*This
= impl_from_IConnector(iface
);
1736 ULONG ref
= InterlockedDecrement(&This
->ref
);
1737 TRACE("(%p) new ref %lu\n", This
, ref
);
1740 HeapFree(GetProcessHeap(), 0, This
);
1745 static HRESULT WINAPI
Connector_GetType(
1747 ConnectorType
*pType
)
1749 FIXME("(%p) - partial stub\n", This
);
1750 *pType
= Physical_Internal
;
1754 static HRESULT WINAPI
Connector_GetDataFlow(
1758 FIXME("(%p) - stub\n", This
);
1762 static HRESULT WINAPI
Connector_ConnectTo(
1764 IConnector
*pConnectTo
)
1766 FIXME("(%p) - stub\n", This
);
1770 static HRESULT WINAPI
Connector_Disconnect(
1773 FIXME("(%p) - stub\n", This
);
1777 static HRESULT WINAPI
Connector_IsConnected(
1781 FIXME("(%p) - stub\n", This
);
1785 static HRESULT WINAPI
Connector_GetConnectedTo(
1787 IConnector
**ppConTo
)
1789 FIXME("(%p) - stub\n", This
);
1793 static HRESULT WINAPI
Connector_GetConnectorIdConnectedTo(
1795 LPWSTR
*ppwstrConnectorId
)
1797 FIXME("(%p) - stub\n", This
);
1801 static HRESULT WINAPI
Connector_GetDeviceIdConnectedTo(
1803 LPWSTR
*ppwstrDeviceId
)
1805 FIXME("(%p) - stub\n", This
);
1809 static const IConnectorVtbl Connector_Vtbl
=
1811 Connector_QueryInterface
,
1815 Connector_GetDataFlow
,
1816 Connector_ConnectTo
,
1817 Connector_Disconnect
,
1818 Connector_IsConnected
,
1819 Connector_GetConnectedTo
,
1820 Connector_GetConnectorIdConnectedTo
,
1821 Connector_GetDeviceIdConnectedTo
,
1824 HRESULT
Connector_Create(IConnector
**ppv
)
1826 IConnectorImpl
*This
;
1828 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
1830 return E_OUTOFMEMORY
;
1832 This
->IConnector_iface
.lpVtbl
= &Connector_Vtbl
;
1835 *ppv
= &This
->IConnector_iface
;
1840 static HRESULT WINAPI
DT_QueryInterface(IDeviceTopology
*iface
, REFIID riid
, void **ppv
)
1842 IDeviceTopologyImpl
*This
= impl_from_IDeviceTopology(iface
);
1843 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1848 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1849 IsEqualIID(riid
, &IID_IDeviceTopology
))
1850 *ppv
= &This
->IDeviceTopology_iface
;
1853 return E_NOINTERFACE
;
1856 IUnknown_AddRef((IUnknown
*)*ppv
);
1861 static ULONG WINAPI
DT_AddRef(IDeviceTopology
*iface
)
1863 IDeviceTopologyImpl
*This
= impl_from_IDeviceTopology(iface
);
1864 ULONG ref
= InterlockedIncrement(&This
->ref
);
1865 TRACE("(%p) new ref %lu\n", This
, ref
);
1869 static ULONG WINAPI
DT_Release(IDeviceTopology
*iface
)
1871 IDeviceTopologyImpl
*This
= impl_from_IDeviceTopology(iface
);
1872 ULONG ref
= InterlockedDecrement(&This
->ref
);
1873 TRACE("(%p) new ref %lu\n", This
, ref
);
1876 HeapFree(GetProcessHeap(), 0, This
);
1881 static HRESULT WINAPI
DT_GetConnectorCount(IDeviceTopology
*This
,
1884 FIXME("(%p)->(%p) - partial stub\n", This
, pCount
);
1893 static HRESULT WINAPI
DT_GetConnector(IDeviceTopology
*This
,
1895 IConnector
**ppConnector
)
1897 FIXME("(%p)->(%u, %p) - partial stub\n", This
, nIndex
, ppConnector
);
1901 return Connector_Create(ppConnector
);
1904 return E_INVALIDARG
;
1907 static HRESULT WINAPI
DT_GetSubunitCount(IDeviceTopology
*This
,
1910 FIXME("(%p)->(%p) - stub\n", This
, pCount
);
1914 static HRESULT WINAPI
DT_GetSubunit(IDeviceTopology
*This
,
1916 ISubUnit
**ppConnector
)
1918 FIXME("(%p)->(%u, %p) - stub\n", This
, nIndex
, ppConnector
);
1922 static HRESULT WINAPI
DT_GetPartById(IDeviceTopology
*This
,
1926 FIXME("(%p)->(%u, %p) - stub\n", This
, nId
, ppPart
);
1930 static HRESULT WINAPI
DT_GetDeviceId(IDeviceTopology
*This
,
1931 LPWSTR
*ppwstrDeviceId
)
1933 FIXME("(%p)->(%p) - stub\n", This
, ppwstrDeviceId
);
1937 static HRESULT WINAPI
DT_GetSignalPath(IDeviceTopology
*This
,
1940 BOOL bRejectMixedPaths
,
1941 IPartsList
**ppParts
)
1943 FIXME("(%p)->(%p, %p, %s, %p) - stub\n",
1944 This
, pIPartFrom
, pIPartTo
, bRejectMixedPaths
? "TRUE" : "FALSE", ppParts
);
1948 static const IDeviceTopologyVtbl DeviceTopology_Vtbl
=
1953 DT_GetConnectorCount
,
1962 static HRESULT
DeviceTopology_Create(IMMDevice
*device
, IDeviceTopology
**ppv
)
1964 IDeviceTopologyImpl
*This
;
1966 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
1968 return E_OUTOFMEMORY
;
1970 This
->IDeviceTopology_iface
.lpVtbl
= &DeviceTopology_Vtbl
;
1973 *ppv
= &This
->IDeviceTopology_iface
;