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
23 #define NONAMELESSUNION
29 #include "wine/debug.h"
30 #include "wine/list.h"
31 #include "wine/unicode.h"
35 #include "mmdeviceapi.h"
38 #include "audioclient.h"
39 #include "endpointvolume.h"
40 #include "audiopolicy.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi
);
47 static const WCHAR software_mmdevapi
[] =
48 { 'S','o','f','t','w','a','r','e','\\',
49 'M','i','c','r','o','s','o','f','t','\\',
50 'W','i','n','d','o','w','s','\\',
51 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
52 'M','M','D','e','v','i','c','e','s','\\',
53 'A','u','d','i','o',0};
54 static const WCHAR reg_render
[] =
55 { 'R','e','n','d','e','r',0 };
56 static const WCHAR reg_capture
[] =
57 { 'C','a','p','t','u','r','e',0 };
58 static const WCHAR reg_devicestate
[] =
59 { 'D','e','v','i','c','e','S','t','a','t','e',0 };
60 static const WCHAR reg_properties
[] =
61 { 'P','r','o','p','e','r','t','i','e','s',0 };
62 static const WCHAR slashW
[] = {'\\',0};
63 static const WCHAR reg_out_nameW
[] = {'D','e','f','a','u','l','t','O','u','t','p','u','t',0};
64 static const WCHAR reg_vout_nameW
[] = {'D','e','f','a','u','l','t','V','o','i','c','e','O','u','t','p','u','t',0};
65 static const WCHAR reg_in_nameW
[] = {'D','e','f','a','u','l','t','I','n','p','u','t',0};
66 static const WCHAR reg_vin_nameW
[] = {'D','e','f','a','u','l','t','V','o','i','c','e','I','n','p','u','t',0};
68 static HKEY key_render
;
69 static HKEY key_capture
;
71 typedef struct MMDevPropStoreImpl
73 IPropertyStore IPropertyStore_iface
;
79 typedef struct MMDevEnumImpl
81 IMMDeviceEnumerator IMMDeviceEnumerator_iface
;
85 static MMDevEnumImpl
*MMDevEnumerator
;
86 static MMDevice
**MMDevice_head
;
87 static MMDevice
*MMDevice_def_rec
, *MMDevice_def_play
;
88 static DWORD MMDevice_count
;
89 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
;
90 static const IMMDeviceCollectionVtbl MMDevColVtbl
;
91 static const IMMDeviceVtbl MMDeviceVtbl
;
92 static const IPropertyStoreVtbl MMDevPropVtbl
;
93 static const IMMEndpointVtbl MMEndpointVtbl
;
95 static IMMDevice info_device
;
97 typedef struct MMDevColImpl
99 IMMDeviceCollection IMMDeviceCollection_iface
;
105 typedef struct IPropertyBagImpl
{
106 IPropertyBag IPropertyBag_iface
;
110 static const IPropertyBagVtbl PB_Vtbl
;
112 static HRESULT
MMDevPropStore_Create(MMDevice
*This
, DWORD access
, IPropertyStore
**ppv
);
114 static inline MMDevPropStore
*impl_from_IPropertyStore(IPropertyStore
*iface
)
116 return CONTAINING_RECORD(iface
, MMDevPropStore
, IPropertyStore_iface
);
119 static inline MMDevEnumImpl
*impl_from_IMMDeviceEnumerator(IMMDeviceEnumerator
*iface
)
121 return CONTAINING_RECORD(iface
, MMDevEnumImpl
, IMMDeviceEnumerator_iface
);
124 static inline MMDevColImpl
*impl_from_IMMDeviceCollection(IMMDeviceCollection
*iface
)
126 return CONTAINING_RECORD(iface
, MMDevColImpl
, IMMDeviceCollection_iface
);
129 static inline IPropertyBagImpl
*impl_from_IPropertyBag(IPropertyBag
*iface
)
131 return CONTAINING_RECORD(iface
, IPropertyBagImpl
, IPropertyBag_iface
);
134 static const WCHAR propkey_formatW
[] = {
135 '{','%','0','8','X','-','%','0','4','X','-',
136 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
137 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
138 '%','0','2','X','%','0','2','X','}',',','%','d',0 };
140 static HRESULT
MMDevPropStore_OpenPropKey(const GUID
*guid
, DWORD flow
, HKEY
*propkey
)
145 StringFromGUID2(guid
, buffer
, 39);
146 if ((ret
= RegOpenKeyExW(flow
== eRender
? key_render
: key_capture
, buffer
, 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, &key
)) != ERROR_SUCCESS
)
148 WARN("Opening key %s failed with %u\n", debugstr_w(buffer
), ret
);
151 ret
= RegOpenKeyExW(key
, reg_properties
, 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, propkey
);
153 if (ret
!= ERROR_SUCCESS
)
155 WARN("Opening key %s failed with %u\n", debugstr_w(reg_properties
), ret
);
161 static HRESULT
MMDevice_GetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
164 const GUID
*id
= &key
->fmtid
;
170 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
173 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
174 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
175 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
176 ret
= RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_ANY
, &type
, NULL
, &size
);
177 if (ret
!= ERROR_SUCCESS
)
179 WARN("Reading %s returned %d\n", debugstr_w(buffer
), ret
);
181 PropVariantClear(pv
);
190 pv
->u
.pwszVal
= CoTaskMemAlloc(size
);
194 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_SZ
, NULL
, (BYTE
*)pv
->u
.pwszVal
, &size
);
200 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_DWORD
, NULL
, (BYTE
*)&pv
->u
.ulVal
, &size
);
206 pv
->u
.blob
.cbSize
= size
;
207 pv
->u
.blob
.pBlobData
= CoTaskMemAlloc(size
);
208 if (!pv
->u
.blob
.pBlobData
)
211 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_BINARY
, NULL
, (BYTE
*)pv
->u
.blob
.pBlobData
, &size
);
215 ERR("Unknown/unhandled type: %u\n", type
);
216 PropVariantClear(pv
);
223 static HRESULT
MMDevice_SetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
226 const GUID
*id
= &key
->fmtid
;
231 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
234 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
235 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
236 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
241 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_DWORD
, (const BYTE
*)&pv
->u
.ulVal
, sizeof(DWORD
));
246 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_BINARY
, pv
->u
.blob
.pBlobData
, pv
->u
.blob
.cbSize
);
247 TRACE("Blob %p %u\n", pv
->u
.blob
.pBlobData
, pv
->u
.blob
.cbSize
);
253 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_SZ
, (const BYTE
*)pv
->u
.pwszVal
, sizeof(WCHAR
)*(1+lstrlenW(pv
->u
.pwszVal
)));
258 FIXME("Unhandled type %u\n", pv
->vt
);
263 TRACE("Writing %s returned %u\n", debugstr_w(buffer
), ret
);
267 static HRESULT
set_driver_prop_value(GUID
*id
, const EDataFlow flow
, const PROPERTYKEY
*prop
)
272 if (!drvs
.pGetPropValue
)
275 hr
= drvs
.pGetPropValue(id
, prop
, &pv
);
279 MMDevice_SetPropValue(id
, flow
, prop
, &pv
);
280 PropVariantClear(&pv
);
286 /* Creates or updates the state of a device
287 * If GUID is null, a random guid will be assigned
288 * and the device will be created
290 static MMDevice
*MMDevice_Create(WCHAR
*name
, GUID
*id
, EDataFlow flow
, DWORD state
, BOOL setdefault
)
293 MMDevice
*cur
= NULL
;
297 static const PROPERTYKEY deviceinterface_key
= {
298 {0x233164c8, 0x1b2c, 0x4c7d, {0xbc, 0x68, 0xb6, 0x71, 0x68, 0x7a, 0x25, 0x67}}, 1
301 static const PROPERTYKEY devicepath_key
= {
302 {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2
305 for (i
= 0; i
< MMDevice_count
; ++i
)
307 MMDevice
*device
= MMDevice_head
[i
];
308 if (device
->flow
== flow
&& IsEqualGUID(&device
->devguid
, id
)){
315 /* No device found, allocate new one */
316 cur
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*cur
));
320 cur
->IMMDevice_iface
.lpVtbl
= &MMDeviceVtbl
;
321 cur
->IMMEndpoint_iface
.lpVtbl
= &MMEndpointVtbl
;
323 InitializeCriticalSection(&cur
->crst
);
324 cur
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": MMDevice.crst");
327 MMDevice_head
= HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head
));
329 MMDevice_head
= HeapReAlloc(GetProcessHeap(), 0, MMDevice_head
, sizeof(*MMDevice_head
)*(1+MMDevice_count
));
330 MMDevice_head
[MMDevice_count
++] = cur
;
331 }else if(cur
->ref
> 0)
332 WARN("Modifying an MMDevice with postitive reference count!\n");
334 HeapFree(GetProcessHeap(), 0, cur
->drv_id
);
341 StringFromGUID2(&cur
->devguid
, guidstr
, sizeof(guidstr
)/sizeof(*guidstr
));
348 if (RegCreateKeyExW(root
, guidstr
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
|KEY_WOW64_64KEY
, NULL
, &key
, NULL
) == ERROR_SUCCESS
)
351 RegSetValueExW(key
, reg_devicestate
, 0, REG_DWORD
, (const BYTE
*)&state
, sizeof(DWORD
));
352 if (!RegCreateKeyExW(key
, reg_properties
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
|KEY_WOW64_64KEY
, NULL
, &keyprop
, NULL
))
358 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
);
359 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_DeviceInterface_FriendlyName
, &pv
);
360 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_DeviceDesc
, &pv
);
362 pv
.u
.pwszVal
= guidstr
;
363 MMDevice_SetPropValue(id
, flow
, &deviceinterface_key
, &pv
);
365 set_driver_prop_value(id
, flow
, &devicepath_key
);
367 if (FAILED(set_driver_prop_value(id
, flow
, &PKEY_AudioEndpoint_FormFactor
)))
370 pv
.u
.ulVal
= (flow
== eCapture
) ? Microphone
: Speakers
;
372 MMDevice_SetPropValue(id
, flow
, &PKEY_AudioEndpoint_FormFactor
, &pv
);
375 if (flow
!= eCapture
)
379 PropVariantInit(&pv2
);
381 /* make read-write by not overwriting if already set */
382 if (FAILED(MMDevice_GetPropValue(id
, flow
, &PKEY_AudioEndpoint_PhysicalSpeakers
, &pv2
)) || pv2
.vt
!= VT_UI4
)
383 set_driver_prop_value(id
, flow
, &PKEY_AudioEndpoint_PhysicalSpeakers
);
385 PropVariantClear(&pv2
);
388 RegCloseKey(keyprop
);
396 MMDevice_def_play
= cur
;
398 MMDevice_def_rec
= cur
;
403 static HRESULT
load_devices_from_reg(void)
410 ret
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, software_mmdevapi
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
|KEY_WOW64_64KEY
, NULL
, &root
, NULL
);
411 if (ret
== ERROR_SUCCESS
)
412 ret
= RegCreateKeyExW(root
, reg_capture
, 0, NULL
, 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, NULL
, &key_capture
, NULL
);
413 if (ret
== ERROR_SUCCESS
)
414 ret
= RegCreateKeyExW(root
, reg_render
, 0, NULL
, 0, KEY_READ
|KEY_WRITE
|KEY_WOW64_64KEY
, NULL
, &key_render
, NULL
);
418 if (ret
!= ERROR_SUCCESS
)
420 RegCloseKey(key_capture
);
421 key_render
= key_capture
= NULL
;
422 WARN("Couldn't create key: %u\n", ret
);
430 PROPVARIANT pv
= { VT_EMPTY
};
432 len
= sizeof(guidvalue
)/sizeof(guidvalue
[0]);
433 ret
= RegEnumKeyExW(cur
, i
++, guidvalue
, &len
, NULL
, NULL
, NULL
, NULL
);
434 if (ret
== ERROR_NO_MORE_ITEMS
)
436 if (cur
== key_capture
)
445 if (ret
!= ERROR_SUCCESS
)
447 if (SUCCEEDED(CLSIDFromString(guidvalue
, &guid
))
448 && SUCCEEDED(MMDevice_GetPropValue(&guid
, curflow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
))
449 && pv
.vt
== VT_LPWSTR
)
451 DWORD size_bytes
= (strlenW(pv
.u
.pwszVal
) + 1) * sizeof(WCHAR
);
452 WCHAR
*name
= HeapAlloc(GetProcessHeap(), 0, size_bytes
);
453 memcpy(name
, pv
.u
.pwszVal
, size_bytes
);
454 MMDevice_Create(name
, &guid
, curflow
,
455 DEVICE_STATE_NOTPRESENT
, FALSE
);
456 CoTaskMemFree(pv
.u
.pwszVal
);
463 static HRESULT
set_format(MMDevice
*dev
)
466 IAudioClient
*client
;
468 PROPVARIANT pv
= { VT_EMPTY
};
470 hr
= drvs
.pGetAudioEndpoint(&dev
->devguid
, &dev
->IMMDevice_iface
, &client
);
474 hr
= IAudioClient_GetMixFormat(client
, &fmt
);
476 IAudioClient_Release(client
);
480 IAudioClient_Release(client
);
483 pv
.u
.blob
.cbSize
= sizeof(WAVEFORMATEX
) + fmt
->cbSize
;
484 pv
.u
.blob
.pBlobData
= (BYTE
*)fmt
;
485 MMDevice_SetPropValue(&dev
->devguid
, dev
->flow
,
486 &PKEY_AudioEngine_DeviceFormat
, &pv
);
487 MMDevice_SetPropValue(&dev
->devguid
, dev
->flow
,
488 &PKEY_AudioEngine_OEMFormat
, &pv
);
494 static HRESULT
load_driver_devices(EDataFlow flow
)
501 if(!drvs
.pGetEndpointIDs
)
504 hr
= drvs
.pGetEndpointIDs(flow
, &ids
, &guids
, &num
, &def
);
508 for(i
= 0; i
< num
; ++i
){
510 dev
= MMDevice_Create(ids
[i
], &guids
[i
], flow
, DEVICE_STATE_ACTIVE
,
515 HeapFree(GetProcessHeap(), 0, guids
);
516 HeapFree(GetProcessHeap(), 0, ids
);
521 static void MMDevice_Destroy(MMDevice
*This
)
524 TRACE("Freeing %s\n", debugstr_w(This
->drv_id
));
525 /* Since this function is called at destruction time, reordering of the list is unimportant */
526 for (i
= 0; i
< MMDevice_count
; ++i
)
528 if (MMDevice_head
[i
] == This
)
530 MMDevice_head
[i
] = MMDevice_head
[--MMDevice_count
];
534 This
->crst
.DebugInfo
->Spare
[0] = 0;
535 DeleteCriticalSection(&This
->crst
);
536 HeapFree(GetProcessHeap(), 0, This
->drv_id
);
537 HeapFree(GetProcessHeap(), 0, This
);
540 static inline MMDevice
*impl_from_IMMDevice(IMMDevice
*iface
)
542 return CONTAINING_RECORD(iface
, MMDevice
, IMMDevice_iface
);
545 static HRESULT WINAPI
MMDevice_QueryInterface(IMMDevice
*iface
, REFIID riid
, void **ppv
)
547 MMDevice
*This
= impl_from_IMMDevice(iface
);
548 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
553 if (IsEqualIID(riid
, &IID_IUnknown
)
554 || IsEqualIID(riid
, &IID_IMMDevice
))
555 *ppv
= &This
->IMMDevice_iface
;
556 else if (IsEqualIID(riid
, &IID_IMMEndpoint
))
557 *ppv
= &This
->IMMEndpoint_iface
;
560 IUnknown_AddRef((IUnknown
*)*ppv
);
563 WARN("Unknown interface %s\n", debugstr_guid(riid
));
564 return E_NOINTERFACE
;
567 static ULONG WINAPI
MMDevice_AddRef(IMMDevice
*iface
)
569 MMDevice
*This
= impl_from_IMMDevice(iface
);
572 ref
= InterlockedIncrement(&This
->ref
);
573 TRACE("Refcount now %i\n", ref
);
577 static ULONG WINAPI
MMDevice_Release(IMMDevice
*iface
)
579 MMDevice
*This
= impl_from_IMMDevice(iface
);
582 ref
= InterlockedDecrement(&This
->ref
);
583 TRACE("Refcount now %i\n", ref
);
587 static HRESULT WINAPI
MMDevice_Activate(IMMDevice
*iface
, REFIID riid
, DWORD clsctx
, PROPVARIANT
*params
, void **ppv
)
589 HRESULT hr
= E_NOINTERFACE
;
590 MMDevice
*This
= impl_from_IMMDevice(iface
);
592 TRACE("(%p)->(%s, %x, %p, %p)\n", iface
, debugstr_guid(riid
), clsctx
, params
, ppv
);
597 if (IsEqualIID(riid
, &IID_IAudioClient
)){
598 hr
= drvs
.pGetAudioEndpoint(&This
->devguid
, iface
, (IAudioClient
**)ppv
);
599 }else if (IsEqualIID(riid
, &IID_IAudioEndpointVolume
) ||
600 IsEqualIID(riid
, &IID_IAudioEndpointVolumeEx
))
601 hr
= AudioEndpointVolume_Create(This
, (IAudioEndpointVolumeEx
**)ppv
);
602 else if (IsEqualIID(riid
, &IID_IAudioSessionManager
)
603 || IsEqualIID(riid
, &IID_IAudioSessionManager2
))
605 hr
= drvs
.pGetAudioSessionManager(iface
, (IAudioSessionManager2
**)ppv
);
607 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
609 if (This
->flow
== eRender
)
610 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, clsctx
, riid
, ppv
);
612 ERR("Not supported for recording?\n");
615 IPersistPropertyBag
*ppb
;
616 hr
= IUnknown_QueryInterface((IUnknown
*)*ppv
, &IID_IPersistPropertyBag
, (void **)&ppb
);
619 /* ::Load cannot assume the interface stays alive after the function returns,
620 * so just create the interface on the stack, saves a lot of complicated code */
621 IPropertyBagImpl bag
= { { &PB_Vtbl
} };
622 bag
.devguid
= This
->devguid
;
623 hr
= IPersistPropertyBag_Load(ppb
, &bag
.IPropertyBag_iface
, NULL
);
624 IPersistPropertyBag_Release(ppb
);
626 IBaseFilter_Release((IBaseFilter
*)*ppv
);
630 FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n");
635 else if (IsEqualIID(riid
, &IID_IDeviceTopology
))
637 FIXME("IID_IDeviceTopology unsupported\n");
639 else if (IsEqualIID(riid
, &IID_IDirectSound
)
640 || IsEqualIID(riid
, &IID_IDirectSound8
))
642 if (This
->flow
== eRender
)
643 hr
= CoCreateInstance(&CLSID_DirectSound8
, NULL
, clsctx
, riid
, ppv
);
646 hr
= IDirectSound_Initialize((IDirectSound
*)*ppv
, &This
->devguid
);
648 IDirectSound_Release((IDirectSound
*)*ppv
);
651 else if (IsEqualIID(riid
, &IID_IDirectSoundCapture
))
653 if (This
->flow
== eCapture
)
654 hr
= CoCreateInstance(&CLSID_DirectSoundCapture8
, NULL
, clsctx
, riid
, ppv
);
657 hr
= IDirectSoundCapture_Initialize((IDirectSoundCapture
*)*ppv
, &This
->devguid
);
659 IDirectSoundCapture_Release((IDirectSoundCapture
*)*ppv
);
663 ERR("Invalid/unknown iid %s\n", debugstr_guid(riid
));
668 TRACE("Returning %08x\n", hr
);
672 static HRESULT WINAPI
MMDevice_OpenPropertyStore(IMMDevice
*iface
, DWORD access
, IPropertyStore
**ppv
)
674 MMDevice
*This
= impl_from_IMMDevice(iface
);
675 TRACE("(%p)->(%x,%p)\n", This
, access
, ppv
);
679 return MMDevPropStore_Create(This
, access
, ppv
);
682 static HRESULT WINAPI
MMDevice_GetId(IMMDevice
*iface
, WCHAR
**itemid
)
684 MMDevice
*This
= impl_from_IMMDevice(iface
);
686 GUID
*id
= &This
->devguid
;
687 static const WCHAR formatW
[] = { '{','0','.','0','.','%','u','.','0','0','0','0','0','0','0','0','}','.',
688 '{','%','0','8','X','-','%','0','4','X','-',
689 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
690 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
691 '%','0','2','X','%','0','2','X','}',0 };
693 TRACE("(%p)->(%p)\n", This
, itemid
);
696 *itemid
= str
= CoTaskMemAlloc(56 * sizeof(WCHAR
));
698 return E_OUTOFMEMORY
;
699 wsprintfW( str
, formatW
, This
->flow
, id
->Data1
, id
->Data2
, id
->Data3
,
700 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
701 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
702 TRACE("returning %s\n", wine_dbgstr_w(str
));
706 static HRESULT WINAPI
MMDevice_GetState(IMMDevice
*iface
, DWORD
*state
)
708 MMDevice
*This
= impl_from_IMMDevice(iface
);
709 TRACE("(%p)->(%p)\n", iface
, state
);
713 *state
= This
->state
;
717 static const IMMDeviceVtbl MMDeviceVtbl
=
719 MMDevice_QueryInterface
,
723 MMDevice_OpenPropertyStore
,
728 static inline MMDevice
*impl_from_IMMEndpoint(IMMEndpoint
*iface
)
730 return CONTAINING_RECORD(iface
, MMDevice
, IMMEndpoint_iface
);
733 static HRESULT WINAPI
MMEndpoint_QueryInterface(IMMEndpoint
*iface
, REFIID riid
, void **ppv
)
735 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
736 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
737 return IMMDevice_QueryInterface(&This
->IMMDevice_iface
, riid
, ppv
);
740 static ULONG WINAPI
MMEndpoint_AddRef(IMMEndpoint
*iface
)
742 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
743 TRACE("(%p)\n", This
);
744 return IMMDevice_AddRef(&This
->IMMDevice_iface
);
747 static ULONG WINAPI
MMEndpoint_Release(IMMEndpoint
*iface
)
749 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
750 TRACE("(%p)\n", This
);
751 return IMMDevice_Release(&This
->IMMDevice_iface
);
754 static HRESULT WINAPI
MMEndpoint_GetDataFlow(IMMEndpoint
*iface
, EDataFlow
*flow
)
756 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
757 TRACE("(%p)->(%p)\n", This
, flow
);
764 static const IMMEndpointVtbl MMEndpointVtbl
=
766 MMEndpoint_QueryInterface
,
769 MMEndpoint_GetDataFlow
772 static HRESULT
MMDevCol_Create(IMMDeviceCollection
**ppv
, EDataFlow flow
, DWORD state
)
776 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
779 return E_OUTOFMEMORY
;
780 This
->IMMDeviceCollection_iface
.lpVtbl
= &MMDevColVtbl
;
784 *ppv
= &This
->IMMDeviceCollection_iface
;
788 static void MMDevCol_Destroy(MMDevColImpl
*This
)
790 HeapFree(GetProcessHeap(), 0, This
);
793 static HRESULT WINAPI
MMDevCol_QueryInterface(IMMDeviceCollection
*iface
, REFIID riid
, void **ppv
)
795 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
796 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
800 if (IsEqualIID(riid
, &IID_IUnknown
)
801 || IsEqualIID(riid
, &IID_IMMDeviceCollection
))
802 *ppv
= &This
->IMMDeviceCollection_iface
;
806 return E_NOINTERFACE
;
807 IUnknown_AddRef((IUnknown
*)*ppv
);
811 static ULONG WINAPI
MMDevCol_AddRef(IMMDeviceCollection
*iface
)
813 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
814 LONG ref
= InterlockedIncrement(&This
->ref
);
815 TRACE("Refcount now %i\n", ref
);
819 static ULONG WINAPI
MMDevCol_Release(IMMDeviceCollection
*iface
)
821 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
822 LONG ref
= InterlockedDecrement(&This
->ref
);
823 TRACE("Refcount now %i\n", ref
);
825 MMDevCol_Destroy(This
);
829 static HRESULT WINAPI
MMDevCol_GetCount(IMMDeviceCollection
*iface
, UINT
*numdevs
)
831 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
834 TRACE("(%p)->(%p)\n", This
, numdevs
);
839 for (i
= 0; i
< MMDevice_count
; ++i
)
841 MMDevice
*cur
= MMDevice_head
[i
];
842 if ((cur
->flow
== This
->flow
|| This
->flow
== eAll
)
843 && (cur
->state
& This
->state
))
849 static HRESULT WINAPI
MMDevCol_Item(IMMDeviceCollection
*iface
, UINT n
, IMMDevice
**dev
)
851 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
854 TRACE("(%p)->(%u, %p)\n", This
, n
, dev
);
858 for (j
= 0; j
< MMDevice_count
; ++j
)
860 MMDevice
*cur
= MMDevice_head
[j
];
861 if ((cur
->flow
== This
->flow
|| This
->flow
== eAll
)
862 && (cur
->state
& This
->state
)
865 *dev
= &cur
->IMMDevice_iface
;
866 IMMDevice_AddRef(*dev
);
870 WARN("Could not obtain item %u\n", n
);
875 static const IMMDeviceCollectionVtbl MMDevColVtbl
=
877 MMDevCol_QueryInterface
,
884 HRESULT
MMDevEnum_Create(REFIID riid
, void **ppv
)
886 MMDevEnumImpl
*This
= MMDevEnumerator
;
890 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
893 return E_OUTOFMEMORY
;
895 This
->IMMDeviceEnumerator_iface
.lpVtbl
= &MMDevEnumVtbl
;
896 MMDevEnumerator
= This
;
898 load_devices_from_reg();
899 load_driver_devices(eRender
);
900 load_driver_devices(eCapture
);
902 return IMMDeviceEnumerator_QueryInterface(&This
->IMMDeviceEnumerator_iface
, riid
, ppv
);
905 void MMDevEnum_Free(void)
907 while (MMDevice_count
)
908 MMDevice_Destroy(MMDevice_head
[0]);
909 RegCloseKey(key_render
);
910 RegCloseKey(key_capture
);
911 key_render
= key_capture
= NULL
;
912 HeapFree(GetProcessHeap(), 0, MMDevEnumerator
);
913 MMDevEnumerator
= NULL
;
916 static HRESULT WINAPI
MMDevEnum_QueryInterface(IMMDeviceEnumerator
*iface
, REFIID riid
, void **ppv
)
918 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
919 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
923 if (IsEqualIID(riid
, &IID_IUnknown
)
924 || IsEqualIID(riid
, &IID_IMMDeviceEnumerator
))
925 *ppv
= &This
->IMMDeviceEnumerator_iface
;
929 return E_NOINTERFACE
;
930 IUnknown_AddRef((IUnknown
*)*ppv
);
934 static ULONG WINAPI
MMDevEnum_AddRef(IMMDeviceEnumerator
*iface
)
936 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
937 LONG ref
= InterlockedIncrement(&This
->ref
);
938 TRACE("Refcount now %i\n", ref
);
942 static ULONG WINAPI
MMDevEnum_Release(IMMDeviceEnumerator
*iface
)
944 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
945 LONG ref
= InterlockedDecrement(&This
->ref
);
948 TRACE("Refcount now %i\n", ref
);
952 static HRESULT WINAPI
MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator
*iface
, EDataFlow flow
, DWORD mask
, IMMDeviceCollection
**devices
)
954 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
955 TRACE("(%p)->(%u,%u,%p)\n", This
, flow
, mask
, devices
);
959 if (flow
>= EDataFlow_enum_count
)
961 if (mask
& ~DEVICE_STATEMASK_ALL
)
963 return MMDevCol_Create(devices
, flow
, mask
);
966 static HRESULT WINAPI
MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator
*iface
, EDataFlow flow
, ERole role
, IMMDevice
**device
)
968 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
973 TRACE("(%p)->(%u,%u,%p)\n", This
, flow
, role
, device
);
978 if((flow
!= eRender
&& flow
!= eCapture
) ||
979 (role
!= eConsole
&& role
!= eMultimedia
&& role
!= eCommunications
)){
980 WARN("Unknown flow (%u) or role (%u)\n", flow
, role
);
986 if(!drvs
.module_name
[0])
989 lstrcpyW(reg_key
, drv_keyW
);
990 lstrcatW(reg_key
, slashW
);
991 lstrcatW(reg_key
, drvs
.module_name
);
993 if(RegOpenKeyW(HKEY_CURRENT_USER
, reg_key
, &key
) == ERROR_SUCCESS
){
994 const WCHAR
*reg_x_name
, *reg_vx_name
;
996 DWORD size
= sizeof(def_id
), state
;
999 reg_x_name
= reg_out_nameW
;
1000 reg_vx_name
= reg_vout_nameW
;
1002 reg_x_name
= reg_in_nameW
;
1003 reg_vx_name
= reg_vin_nameW
;
1006 if(role
== eCommunications
&&
1007 RegQueryValueExW(key
, reg_vx_name
, 0, NULL
,
1008 (BYTE
*)def_id
, &size
) == ERROR_SUCCESS
){
1009 hr
= IMMDeviceEnumerator_GetDevice(iface
, def_id
, device
);
1011 if(SUCCEEDED(IMMDevice_GetState(*device
, &state
)) &&
1012 state
== DEVICE_STATE_ACTIVE
){
1018 TRACE("Unable to find voice device %s\n", wine_dbgstr_w(def_id
));
1021 if(RegQueryValueExW(key
, reg_x_name
, 0, NULL
,
1022 (BYTE
*)def_id
, &size
) == ERROR_SUCCESS
){
1023 hr
= IMMDeviceEnumerator_GetDevice(iface
, def_id
, device
);
1025 if(SUCCEEDED(IMMDevice_GetState(*device
, &state
)) &&
1026 state
== DEVICE_STATE_ACTIVE
){
1032 TRACE("Unable to find device %s\n", wine_dbgstr_w(def_id
));
1038 if (flow
== eRender
)
1039 *device
= &MMDevice_def_play
->IMMDevice_iface
;
1041 *device
= &MMDevice_def_rec
->IMMDevice_iface
;
1045 IMMDevice_AddRef(*device
);
1049 static HRESULT WINAPI
MMDevEnum_GetDevice(IMMDeviceEnumerator
*iface
, const WCHAR
*name
, IMMDevice
**device
)
1051 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1053 IMMDevice
*dev
= NULL
;
1055 static const WCHAR wine_info_deviceW
[] = {'W','i','n','e',' ',
1056 'i','n','f','o',' ','d','e','v','i','c','e',0};
1058 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(name
), device
);
1060 if(!name
|| !device
)
1063 if(!lstrcmpW(name
, wine_info_deviceW
)){
1064 *device
= &info_device
;
1068 for (i
= 0; i
< MMDevice_count
; ++i
)
1072 dev
= &MMDevice_head
[i
]->IMMDevice_iface
;
1073 hr
= IMMDevice_GetId(dev
, &str
);
1076 WARN("GetId failed: %08x\n", hr
);
1080 if (str
&& !lstrcmpW(str
, name
))
1083 IMMDevice_AddRef(dev
);
1089 TRACE("Could not find device %s\n", debugstr_w(name
));
1090 return E_INVALIDARG
;
1093 struct NotificationClientWrapper
{
1094 IMMNotificationClient
*client
;
1098 static struct list g_notif_clients
= LIST_INIT(g_notif_clients
);
1099 static HANDLE g_notif_thread
;
1101 static CRITICAL_SECTION g_notif_lock
;
1102 static CRITICAL_SECTION_DEBUG g_notif_lock_debug
=
1104 0, 0, &g_notif_lock
,
1105 { &g_notif_lock_debug
.ProcessLocksList
, &g_notif_lock_debug
.ProcessLocksList
},
1106 0, 0, { (DWORD_PTR
)(__FILE__
": g_notif_lock") }
1108 static CRITICAL_SECTION g_notif_lock
= { &g_notif_lock_debug
, -1, 0, 0, 0, 0 };
1110 static void notify_clients(EDataFlow flow
, ERole role
, const WCHAR
*id
)
1112 struct NotificationClientWrapper
*wrapper
;
1113 LIST_FOR_EACH_ENTRY(wrapper
, &g_notif_clients
,
1114 struct NotificationClientWrapper
, entry
)
1115 IMMNotificationClient_OnDefaultDeviceChanged(wrapper
->client
, flow
,
1118 /* Windows 7 treats changes to eConsole as changes to eMultimedia */
1119 if(role
== eConsole
)
1120 notify_clients(flow
, eMultimedia
, id
);
1123 static BOOL
notify_if_changed(EDataFlow flow
, ERole role
, HKEY key
,
1124 const WCHAR
*val_name
, WCHAR
*old_val
, IMMDevice
*def_dev
)
1126 WCHAR new_val
[64], *id
;
1130 size
= sizeof(new_val
);
1131 if(RegQueryValueExW(key
, val_name
, 0, NULL
,
1132 (BYTE
*)new_val
, &size
) != ERROR_SUCCESS
){
1133 if(old_val
[0] != 0){
1134 /* set by user -> system default */
1136 hr
= IMMDevice_GetId(def_dev
, &id
);
1138 ERR("GetId failed: %08x\n", hr
);
1144 notify_clients(flow
, role
, id
);
1151 /* system default -> system default, noop */
1155 if(!lstrcmpW(old_val
, new_val
)){
1156 /* set by user -> same value */
1160 if(new_val
[0] != 0){
1161 /* set by user -> different value */
1162 notify_clients(flow
, role
, new_val
);
1163 memcpy(old_val
, new_val
, sizeof(new_val
));
1167 /* set by user -> system default */
1169 hr
= IMMDevice_GetId(def_dev
, &id
);
1171 ERR("GetId failed: %08x\n", hr
);
1177 notify_clients(flow
, role
, id
);
1184 static DWORD WINAPI
notif_thread_proc(void *user
)
1188 WCHAR out_name
[64], vout_name
[64], in_name
[64], vin_name
[64];
1191 lstrcpyW(reg_key
, drv_keyW
);
1192 lstrcatW(reg_key
, slashW
);
1193 lstrcatW(reg_key
, drvs
.module_name
);
1195 if(RegCreateKeyExW(HKEY_CURRENT_USER
, reg_key
, 0, NULL
, 0,
1196 MAXIMUM_ALLOWED
, NULL
, &key
, NULL
) != ERROR_SUCCESS
){
1197 ERR("RegCreateKeyEx failed: %u\n", GetLastError());
1201 size
= sizeof(out_name
);
1202 if(RegQueryValueExW(key
, reg_out_nameW
, 0, NULL
,
1203 (BYTE
*)out_name
, &size
) != ERROR_SUCCESS
)
1206 size
= sizeof(vout_name
);
1207 if(RegQueryValueExW(key
, reg_vout_nameW
, 0, NULL
,
1208 (BYTE
*)vout_name
, &size
) != ERROR_SUCCESS
)
1211 size
= sizeof(in_name
);
1212 if(RegQueryValueExW(key
, reg_in_nameW
, 0, NULL
,
1213 (BYTE
*)in_name
, &size
) != ERROR_SUCCESS
)
1216 size
= sizeof(vin_name
);
1217 if(RegQueryValueExW(key
, reg_vin_nameW
, 0, NULL
,
1218 (BYTE
*)vin_name
, &size
) != ERROR_SUCCESS
)
1222 if(RegNotifyChangeKeyValue(key
, FALSE
, REG_NOTIFY_CHANGE_LAST_SET
,
1223 NULL
, FALSE
) != ERROR_SUCCESS
){
1224 ERR("RegNotifyChangeKeyValue failed: %u\n", GetLastError());
1226 g_notif_thread
= NULL
;
1230 EnterCriticalSection(&g_notif_lock
);
1232 notify_if_changed(eRender
, eConsole
, key
, reg_out_nameW
,
1233 out_name
, &MMDevice_def_play
->IMMDevice_iface
);
1234 notify_if_changed(eRender
, eCommunications
, key
, reg_vout_nameW
,
1235 vout_name
, &MMDevice_def_play
->IMMDevice_iface
);
1236 notify_if_changed(eCapture
, eConsole
, key
, reg_in_nameW
,
1237 in_name
, &MMDevice_def_rec
->IMMDevice_iface
);
1238 notify_if_changed(eCapture
, eCommunications
, key
, reg_vin_nameW
,
1239 vin_name
, &MMDevice_def_rec
->IMMDevice_iface
);
1241 LeaveCriticalSection(&g_notif_lock
);
1246 g_notif_thread
= NULL
;
1251 static HRESULT WINAPI
MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
1253 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1254 struct NotificationClientWrapper
*wrapper
;
1256 TRACE("(%p)->(%p)\n", This
, client
);
1261 wrapper
= HeapAlloc(GetProcessHeap(), 0, sizeof(*wrapper
));
1263 return E_OUTOFMEMORY
;
1265 wrapper
->client
= client
;
1267 EnterCriticalSection(&g_notif_lock
);
1269 list_add_tail(&g_notif_clients
, &wrapper
->entry
);
1271 if(!g_notif_thread
){
1272 g_notif_thread
= CreateThread(NULL
, 0, notif_thread_proc
, NULL
, 0, NULL
);
1274 ERR("CreateThread failed: %u\n", GetLastError());
1277 LeaveCriticalSection(&g_notif_lock
);
1282 static HRESULT WINAPI
MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
1284 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1285 struct NotificationClientWrapper
*wrapper
;
1287 TRACE("(%p)->(%p)\n", This
, client
);
1292 EnterCriticalSection(&g_notif_lock
);
1294 LIST_FOR_EACH_ENTRY(wrapper
, &g_notif_clients
, struct NotificationClientWrapper
, entry
){
1295 if(wrapper
->client
== client
){
1296 list_remove(&wrapper
->entry
);
1297 HeapFree(GetProcessHeap(), 0, wrapper
);
1298 LeaveCriticalSection(&g_notif_lock
);
1303 LeaveCriticalSection(&g_notif_lock
);
1308 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
=
1310 MMDevEnum_QueryInterface
,
1313 MMDevEnum_EnumAudioEndpoints
,
1314 MMDevEnum_GetDefaultAudioEndpoint
,
1315 MMDevEnum_GetDevice
,
1316 MMDevEnum_RegisterEndpointNotificationCallback
,
1317 MMDevEnum_UnregisterEndpointNotificationCallback
1320 static HRESULT
MMDevPropStore_Create(MMDevice
*parent
, DWORD access
, IPropertyStore
**ppv
)
1322 MMDevPropStore
*This
;
1323 if (access
!= STGM_READ
1324 && access
!= STGM_WRITE
1325 && access
!= STGM_READWRITE
)
1327 WARN("Invalid access %08x\n", access
);
1328 return E_INVALIDARG
;
1330 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1331 *ppv
= &This
->IPropertyStore_iface
;
1333 return E_OUTOFMEMORY
;
1334 This
->IPropertyStore_iface
.lpVtbl
= &MMDevPropVtbl
;
1336 This
->parent
= parent
;
1337 This
->access
= access
;
1341 static void MMDevPropStore_Destroy(MMDevPropStore
*This
)
1343 HeapFree(GetProcessHeap(), 0, This
);
1346 static HRESULT WINAPI
MMDevPropStore_QueryInterface(IPropertyStore
*iface
, REFIID riid
, void **ppv
)
1348 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1349 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1353 if (IsEqualIID(riid
, &IID_IUnknown
)
1354 || IsEqualIID(riid
, &IID_IPropertyStore
))
1355 *ppv
= &This
->IPropertyStore_iface
;
1359 return E_NOINTERFACE
;
1360 IUnknown_AddRef((IUnknown
*)*ppv
);
1364 static ULONG WINAPI
MMDevPropStore_AddRef(IPropertyStore
*iface
)
1366 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1367 LONG ref
= InterlockedIncrement(&This
->ref
);
1368 TRACE("Refcount now %i\n", ref
);
1372 static ULONG WINAPI
MMDevPropStore_Release(IPropertyStore
*iface
)
1374 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1375 LONG ref
= InterlockedDecrement(&This
->ref
);
1376 TRACE("Refcount now %i\n", ref
);
1378 MMDevPropStore_Destroy(This
);
1382 static HRESULT WINAPI
MMDevPropStore_GetCount(IPropertyStore
*iface
, DWORD
*nprops
)
1384 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1390 TRACE("(%p)->(%p)\n", iface
, nprops
);
1393 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
1398 DWORD len
= sizeof(buffer
)/sizeof(*buffer
);
1399 if (RegEnumValueW(propkey
, i
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
1403 RegCloseKey(propkey
);
1404 TRACE("Returning %i\n", i
);
1409 static HRESULT WINAPI
MMDevPropStore_GetAt(IPropertyStore
*iface
, DWORD prop
, PROPERTYKEY
*key
)
1411 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1413 DWORD len
= sizeof(buffer
)/sizeof(*buffer
);
1417 TRACE("(%p)->(%u,%p)\n", iface
, prop
, key
);
1421 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
1425 if (RegEnumValueW(propkey
, prop
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
1428 WARN("GetAt %u failed\n", prop
);
1429 return E_INVALIDARG
;
1431 RegCloseKey(propkey
);
1433 CLSIDFromString(buffer
, &key
->fmtid
);
1434 key
->pid
= atoiW(&buffer
[39]);
1438 static HRESULT WINAPI
MMDevPropStore_GetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
1440 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1441 TRACE("(%p)->(\"%s,%u\", %p)\n", This
, key
? debugstr_guid(&key
->fmtid
) : NULL
, key
? key
->pid
: 0, pv
);
1445 if (This
->access
!= STGM_READ
1446 && This
->access
!= STGM_READWRITE
)
1447 return STG_E_ACCESSDENIED
;
1450 if (IsEqualPropertyKey(*key
, PKEY_AudioEndpoint_GUID
))
1453 pv
->u
.pwszVal
= CoTaskMemAlloc(39 * sizeof(WCHAR
));
1455 return E_OUTOFMEMORY
;
1456 StringFromGUID2(&This
->parent
->devguid
, pv
->u
.pwszVal
, 39);
1460 return MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1463 static HRESULT WINAPI
MMDevPropStore_SetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
1465 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1466 TRACE("(%p)->(\"%s,%u\", %p)\n", This
, key
? debugstr_guid(&key
->fmtid
) : NULL
, key
? key
->pid
: 0, pv
);
1471 if (This
->access
!= STGM_WRITE
1472 && This
->access
!= STGM_READWRITE
)
1473 return STG_E_ACCESSDENIED
;
1474 return MMDevice_SetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1477 static HRESULT WINAPI
MMDevPropStore_Commit(IPropertyStore
*iface
)
1479 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1480 TRACE("(%p)\n", iface
);
1482 if (This
->access
!= STGM_WRITE
1483 && This
->access
!= STGM_READWRITE
)
1484 return STG_E_ACCESSDENIED
;
1486 /* Does nothing - for mmdevapi, the propstore values are written on SetValue,
1492 static const IPropertyStoreVtbl MMDevPropVtbl
=
1494 MMDevPropStore_QueryInterface
,
1495 MMDevPropStore_AddRef
,
1496 MMDevPropStore_Release
,
1497 MMDevPropStore_GetCount
,
1498 MMDevPropStore_GetAt
,
1499 MMDevPropStore_GetValue
,
1500 MMDevPropStore_SetValue
,
1501 MMDevPropStore_Commit
1505 /* Property bag for IBaseFilter activation */
1506 static HRESULT WINAPI
PB_QueryInterface(IPropertyBag
*iface
, REFIID riid
, void **ppv
)
1508 ERR("Should not be called\n");
1510 return E_NOINTERFACE
;
1513 static ULONG WINAPI
PB_AddRef(IPropertyBag
*iface
)
1515 ERR("Should not be called\n");
1519 static ULONG WINAPI
PB_Release(IPropertyBag
*iface
)
1521 ERR("Should not be called\n");
1525 static HRESULT WINAPI
PB_Read(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
, IErrorLog
*log
)
1527 static const WCHAR dsguid
[] = { 'D','S','G','u','i','d', 0 };
1528 IPropertyBagImpl
*This
= impl_from_IPropertyBag(iface
);
1529 TRACE("Trying to read %s, type %u\n", debugstr_w(name
), var
->n1
.n2
.vt
);
1530 if (!lstrcmpW(name
, dsguid
))
1533 StringFromGUID2(&This
->devguid
, guidstr
,sizeof(guidstr
)/sizeof(*guidstr
));
1534 var
->n1
.n2
.vt
= VT_BSTR
;
1535 var
->n1
.n2
.n3
.bstrVal
= SysAllocString(guidstr
);
1538 ERR("Unknown property '%s' queried\n", debugstr_w(name
));
1542 static HRESULT WINAPI
PB_Write(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
)
1544 ERR("Should not be called\n");
1548 static const IPropertyBagVtbl PB_Vtbl
=
1557 static ULONG WINAPI
info_device_ps_AddRef(IPropertyStore
*iface
)
1562 static ULONG WINAPI
info_device_ps_Release(IPropertyStore
*iface
)
1567 static HRESULT WINAPI
info_device_ps_GetValue(IPropertyStore
*iface
,
1568 REFPROPERTYKEY key
, PROPVARIANT
*pv
)
1570 TRACE("(static)->(\"%s,%u\", %p)\n", debugstr_guid(&key
->fmtid
), key
? key
->pid
: 0, pv
);
1575 if (IsEqualPropertyKey(*key
, DEVPKEY_Device_Driver
))
1577 INT size
= (lstrlenW(drvs
.module_name
) + 1) * sizeof(WCHAR
);
1579 pv
->u
.pwszVal
= CoTaskMemAlloc(size
);
1581 return E_OUTOFMEMORY
;
1582 memcpy(pv
->u
.pwszVal
, drvs
.module_name
, size
);
1586 return E_INVALIDARG
;
1589 static const IPropertyStoreVtbl info_device_ps_Vtbl
=
1592 info_device_ps_AddRef
,
1593 info_device_ps_Release
,
1596 info_device_ps_GetValue
,
1601 static IPropertyStore info_device_ps
= {
1602 &info_device_ps_Vtbl
1605 static ULONG WINAPI
info_device_AddRef(IMMDevice
*iface
)
1610 static ULONG WINAPI
info_device_Release(IMMDevice
*iface
)
1615 static HRESULT WINAPI
info_device_OpenPropertyStore(IMMDevice
*iface
,
1616 DWORD access
, IPropertyStore
**ppv
)
1618 TRACE("(static)->(%x, %p)\n", access
, ppv
);
1619 *ppv
= &info_device_ps
;
1623 static const IMMDeviceVtbl info_device_Vtbl
=
1627 info_device_Release
,
1629 info_device_OpenPropertyStore
,
1634 static IMMDevice info_device
= {