mshtml: IHTMLDocument2 iface handling clean up.
[wine.git] / dlls / mmdevapi / devenum.c
blobe53566a7e7153dd424fdc1f775bd6c25291a09c8
1 /*
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
19 #include "config.h"
21 #include <stdarg.h>
23 #ifdef HAVE_AL_AL_H
24 #include <AL/al.h>
25 #include <AL/alc.h>
26 #elif defined(HAVE_OPENAL_AL_H)
27 #include <OpenAL/al.h>
28 #include <OpenAL/alc.h>
29 #endif
31 #define NONAMELESSUNION
32 #define COBJMACROS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winnls.h"
36 #include "winreg.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
40 #include "ole2.h"
41 #include "mmdeviceapi.h"
42 #include "dshow.h"
43 #include "dsound.h"
44 #include "audioclient.h"
45 #include "endpointvolume.h"
46 #include "audiopolicy.h"
48 #include "mmdevapi.h"
49 #include "devpkey.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
53 static const WCHAR software_mmdevapi[] =
54 { 'S','o','f','t','w','a','r','e','\\',
55 'M','i','c','r','o','s','o','f','t','\\',
56 'W','i','n','d','o','w','s','\\',
57 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
58 'M','M','D','e','v','i','c','e','s','\\',
59 'A','u','d','i','o',0};
60 static const WCHAR reg_render[] =
61 { 'R','e','n','d','e','r',0 };
62 static const WCHAR reg_capture[] =
63 { 'C','a','p','t','u','r','e',0 };
64 static const WCHAR reg_devicestate[] =
65 { 'D','e','v','i','c','e','S','t','a','t','e',0 };
66 static const WCHAR reg_properties[] =
67 { 'P','r','o','p','e','r','t','i','e','s',0 };
69 static HKEY key_render;
70 static HKEY key_capture;
72 typedef struct MMDevPropStoreImpl
74 IPropertyStore IPropertyStore_iface;
75 LONG ref;
76 MMDevice *parent;
77 DWORD access;
78 } MMDevPropStore;
80 typedef struct MMDevEnumImpl
82 IMMDeviceEnumerator IMMDeviceEnumerator_iface;
83 LONG ref;
84 } MMDevEnumImpl;
86 static MMDevEnumImpl *MMDevEnumerator;
87 static MMDevice **MMDevice_head;
88 static MMDevice *MMDevice_def_rec, *MMDevice_def_play;
89 static DWORD MMDevice_count;
90 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl;
91 static const IMMDeviceCollectionVtbl MMDevColVtbl;
92 static const IMMDeviceVtbl MMDeviceVtbl;
93 static const IPropertyStoreVtbl MMDevPropVtbl;
94 static const IMMEndpointVtbl MMEndpointVtbl;
96 typedef struct MMDevColImpl
98 IMMDeviceCollection IMMDeviceCollection_iface;
99 LONG ref;
100 EDataFlow flow;
101 DWORD state;
102 } MMDevColImpl;
104 typedef struct IPropertyBagImpl {
105 IPropertyBag IPropertyBag_iface;
106 GUID devguid;
107 } IPropertyBagImpl;
109 static const IPropertyBagVtbl PB_Vtbl;
111 static HRESULT MMDevPropStore_Create(MMDevice *This, DWORD access, IPropertyStore **ppv);
113 static inline MMDevPropStore *impl_from_IPropertyStore(IPropertyStore *iface)
115 return CONTAINING_RECORD(iface, MMDevPropStore, IPropertyStore_iface);
118 static inline MMDevEnumImpl *impl_from_IMMDeviceEnumerator(IMMDeviceEnumerator *iface)
120 return CONTAINING_RECORD(iface, MMDevEnumImpl, IMMDeviceEnumerator_iface);
123 static inline MMDevColImpl *impl_from_IMMDeviceCollection(IMMDeviceCollection *iface)
125 return CONTAINING_RECORD(iface, MMDevColImpl, IMMDeviceCollection_iface);
128 static inline IPropertyBagImpl *impl_from_IPropertyBag(IPropertyBag *iface)
130 return CONTAINING_RECORD(iface, IPropertyBagImpl, IPropertyBag_iface);
133 /* Creates or updates the state of a device
134 * If GUID is null, a random guid will be assigned
135 * and the device will be created
137 static void MMDevice_Create(MMDevice **dev, WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault)
139 HKEY key, root;
140 MMDevice *cur;
141 WCHAR guidstr[39];
142 DWORD i;
144 for (i = 0; i < MMDevice_count; ++i)
146 cur = MMDevice_head[i];
147 if (cur->flow == flow && !lstrcmpW(cur->alname, name))
149 LONG ret;
150 /* Same device, update state */
151 cur->state = state;
152 StringFromGUID2(&cur->devguid, guidstr, sizeof(guidstr)/sizeof(*guidstr));
153 ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, guidstr, 0, KEY_WRITE, &key);
154 if (ret == ERROR_SUCCESS)
156 RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD));
157 RegCloseKey(key);
159 goto done;
163 /* No device found, allocate new one */
164 cur = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur));
165 if (!cur)
166 return;
167 cur->alname = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1)*sizeof(WCHAR));
168 if (!cur->alname)
170 HeapFree(GetProcessHeap(), 0, cur);
171 return;
173 lstrcpyW(cur->alname, name);
174 cur->lpVtbl = &MMDeviceVtbl;
175 cur->lpEndpointVtbl = &MMEndpointVtbl;
176 cur->ref = 0;
177 InitializeCriticalSection(&cur->crst);
178 cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst");
179 cur->flow = flow;
180 cur->state = state;
181 cur->device = NULL;
182 if (!id)
184 id = &cur->devguid;
185 CoCreateGuid(id);
187 cur->devguid = *id;
188 StringFromGUID2(id, guidstr, sizeof(guidstr)/sizeof(*guidstr));
189 if (flow == eRender)
190 root = key_render;
191 else
192 root = key_capture;
193 if (!RegCreateKeyExW(root, guidstr, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &key, NULL))
195 HKEY keyprop;
196 RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD));
197 if (!RegCreateKeyExW(key, reg_properties, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &keyprop, NULL))
199 PROPVARIANT pv;
200 pv.vt = VT_LPWSTR;
201 pv.u.pwszVal = name;
202 MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv);
203 MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv);
204 RegCloseKey(keyprop);
206 RegCloseKey(key);
208 if (!MMDevice_head)
209 MMDevice_head = HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head));
210 else
211 MMDevice_head = HeapReAlloc(GetProcessHeap(), 0, MMDevice_head, sizeof(*MMDevice_head)*(1+MMDevice_count));
212 MMDevice_head[MMDevice_count++] = cur;
214 done:
215 if (setdefault)
217 if (flow == eRender)
218 MMDevice_def_play = cur;
219 else
220 MMDevice_def_rec = cur;
222 if (dev)
223 *dev = cur;
226 static void MMDevice_Destroy(MMDevice *This)
228 DWORD i;
229 TRACE("Freeing %s\n", debugstr_w(This->alname));
230 /* Since this function is called at destruction time, reordering of the list is unimportant */
231 for (i = 0; i < MMDevice_count; ++i)
233 if (MMDevice_head[i] == This)
235 MMDevice_head[i] = MMDevice_head[--MMDevice_count];
236 break;
239 #ifdef HAVE_OPENAL
240 if (This->device)
241 palcCloseDevice(This->device);
242 #endif
243 This->crst.DebugInfo->Spare[0] = 0;
244 DeleteCriticalSection(&This->crst);
245 HeapFree(GetProcessHeap(), 0, This->alname);
246 HeapFree(GetProcessHeap(), 0, This);
249 static HRESULT WINAPI MMDevice_QueryInterface(IMMDevice *iface, REFIID riid, void **ppv)
251 MMDevice *This = (MMDevice *)iface;
252 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ppv);
254 if (!ppv)
255 return E_POINTER;
256 *ppv = NULL;
257 if (IsEqualIID(riid, &IID_IUnknown)
258 || IsEqualIID(riid, &IID_IMMDevice))
259 *ppv = This;
260 else if (IsEqualIID(riid, &IID_IMMEndpoint))
261 *ppv = &This->lpEndpointVtbl;
262 if (*ppv)
264 IUnknown_AddRef((IUnknown*)*ppv);
265 return S_OK;
267 WARN("Unknown interface %s\n", debugstr_guid(riid));
268 return E_NOINTERFACE;
271 static ULONG WINAPI MMDevice_AddRef(IMMDevice *iface)
273 MMDevice *This = (MMDevice *)iface;
274 LONG ref;
276 ref = InterlockedIncrement(&This->ref);
277 TRACE("Refcount now %i\n", ref);
278 return ref;
281 static ULONG WINAPI MMDevice_Release(IMMDevice *iface)
283 MMDevice *This = (MMDevice *)iface;
284 LONG ref;
286 ref = InterlockedDecrement(&This->ref);
287 TRACE("Refcount now %i\n", ref);
288 return ref;
291 static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD clsctx, PROPVARIANT *params, void **ppv)
293 HRESULT hr = E_NOINTERFACE;
295 #ifdef HAVE_OPENAL
296 MMDevice *This = (MMDevice *)iface;
298 TRACE("(%p)->(%p,%x,%p,%p)\n", iface, riid, clsctx, params, ppv);
300 if (!ppv)
301 return E_POINTER;
303 if (!openal_loaded)
305 WARN("OpenAL is still not loaded\n");
306 hr = AUDCLNT_E_SERVICE_NOT_RUNNING;
308 else if (IsEqualIID(riid, &IID_IAudioClient))
309 hr = AudioClient_Create(This, (IAudioClient**)ppv);
310 else if (IsEqualIID(riid, &IID_IAudioEndpointVolume))
311 hr = AudioEndpointVolume_Create(This, (IAudioEndpointVolume**)ppv);
312 else if (IsEqualIID(riid, &IID_IAudioSessionManager)
313 || IsEqualIID(riid, &IID_IAudioSessionManager2))
315 FIXME("IID_IAudioSessionManager unsupported\n");
317 else if (IsEqualIID(riid, &IID_IBaseFilter))
319 if (This->flow == eRender)
320 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, clsctx, riid, ppv);
321 else
322 ERR("Not supported for recording?\n");
323 if (SUCCEEDED(hr))
325 IPersistPropertyBag *ppb;
326 hr = IUnknown_QueryInterface((IUnknown*)*ppv, &IID_IPersistPropertyBag, (void*)&ppb);
327 if (SUCCEEDED(hr))
329 /* ::Load cannot assume the interface stays alive after the function returns,
330 * so just create the interface on the stack, saves a lot of complicated code */
331 IPropertyBagImpl bag = { { &PB_Vtbl }, This->devguid };
332 hr = IPersistPropertyBag_Load(ppb, &bag.IPropertyBag_iface, NULL);
333 IPersistPropertyBag_Release(ppb);
334 if (FAILED(hr))
335 IBaseFilter_Release((IBaseFilter*)*ppv);
337 else
339 FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n");
340 hr = S_OK;
344 else if (IsEqualIID(riid, &IID_IDeviceTopology))
346 FIXME("IID_IDeviceTopology unsupported\n");
348 else if (IsEqualIID(riid, &IID_IDirectSound)
349 || IsEqualIID(riid, &IID_IDirectSound8))
351 if (This->flow == eRender)
352 hr = CoCreateInstance(&CLSID_DirectSound8, NULL, clsctx, riid, ppv);
353 if (SUCCEEDED(hr))
355 hr = IDirectSound_Initialize((IDirectSound*)*ppv, &This->devguid);
356 if (FAILED(hr))
357 IDirectSound_Release((IDirectSound*)*ppv);
360 else if (IsEqualIID(riid, &IID_IDirectSoundCapture)
361 || IsEqualIID(riid, &IID_IDirectSoundCapture8))
363 if (This->flow == eCapture)
364 hr = CoCreateInstance(&CLSID_DirectSoundCapture8, NULL, clsctx, riid, ppv);
365 if (SUCCEEDED(hr))
367 hr = IDirectSoundCapture_Initialize((IDirectSoundCapture*)*ppv, &This->devguid);
368 if (FAILED(hr))
369 IDirectSoundCapture_Release((IDirectSoundCapture*)*ppv);
372 else
373 ERR("Invalid/unknown iid %s\n", debugstr_guid(riid));
374 #else
375 if (!ppv) return E_POINTER;
376 hr = AUDCLNT_E_SERVICE_NOT_RUNNING;
377 #endif
379 if (FAILED(hr))
380 *ppv = NULL;
382 TRACE("Returning %08x\n", hr);
383 return hr;
386 static HRESULT WINAPI MMDevice_OpenPropertyStore(IMMDevice *iface, DWORD access, IPropertyStore **ppv)
388 MMDevice *This = (MMDevice *)iface;
389 TRACE("(%p)->(%x,%p)\n", This, access, ppv);
391 if (!ppv)
392 return E_POINTER;
393 return MMDevPropStore_Create(This, access, ppv);
396 static HRESULT WINAPI MMDevice_GetId(IMMDevice *iface, WCHAR **itemid)
398 MMDevice *This = (MMDevice *)iface;
399 WCHAR *str;
400 GUID *id = &This->devguid;
401 static const WCHAR formatW[] = { '{','0','.','0','.','0','.','0','0','0','0','0','0','0','0','}','.',
402 '{','%','0','8','X','-','%','0','4','X','-',
403 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
404 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
405 '%','0','2','X','%','0','2','X','}',0 };
407 TRACE("(%p)->(%p)\n", This, itemid);
408 if (!itemid)
409 return E_POINTER;
410 *itemid = str = CoTaskMemAlloc(56 * sizeof(WCHAR));
411 if (!str)
412 return E_OUTOFMEMORY;
413 wsprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
414 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
415 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
416 return S_OK;
419 static HRESULT WINAPI MMDevice_GetState(IMMDevice *iface, DWORD *state)
421 MMDevice *This = (MMDevice *)iface;
422 TRACE("(%p)->(%p)\n", iface, state);
424 if (!state)
425 return E_POINTER;
426 *state = This->state;
427 return S_OK;
430 static const IMMDeviceVtbl MMDeviceVtbl =
432 MMDevice_QueryInterface,
433 MMDevice_AddRef,
434 MMDevice_Release,
435 MMDevice_Activate,
436 MMDevice_OpenPropertyStore,
437 MMDevice_GetId,
438 MMDevice_GetState
441 static MMDevice *get_this_from_endpoint(IMMEndpoint *iface)
443 return (MMDevice*)((char*)iface - offsetof(MMDevice,lpEndpointVtbl));
446 static HRESULT WINAPI MMEndpoint_QueryInterface(IMMEndpoint *iface, REFIID riid, void **ppv)
448 MMDevice *This = get_this_from_endpoint(iface);
449 return IMMDevice_QueryInterface((IMMDevice*)This, riid, ppv);
452 static ULONG WINAPI MMEndpoint_AddRef(IMMEndpoint *iface)
454 MMDevice *This = get_this_from_endpoint(iface);
455 return IMMDevice_AddRef((IMMDevice*)This);
458 static ULONG WINAPI MMEndpoint_Release(IMMEndpoint *iface)
460 MMDevice *This = get_this_from_endpoint(iface);
461 return IMMDevice_Release((IMMDevice*)This);
464 static HRESULT WINAPI MMEndpoint_GetDataFlow(IMMEndpoint *iface, EDataFlow *flow)
466 MMDevice *This = get_this_from_endpoint(iface);
467 if (!flow)
468 return E_POINTER;
469 *flow = This->flow;
470 return S_OK;
473 static const IMMEndpointVtbl MMEndpointVtbl =
475 MMEndpoint_QueryInterface,
476 MMEndpoint_AddRef,
477 MMEndpoint_Release,
478 MMEndpoint_GetDataFlow
481 static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state)
483 MMDevColImpl *This;
485 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
486 *ppv = NULL;
487 if (!This)
488 return E_OUTOFMEMORY;
489 This->IMMDeviceCollection_iface.lpVtbl = &MMDevColVtbl;
490 This->ref = 1;
491 This->flow = flow;
492 This->state = state;
493 *ppv = &This->IMMDeviceCollection_iface;
494 return S_OK;
497 static void MMDevCol_Destroy(MMDevColImpl *This)
499 HeapFree(GetProcessHeap(), 0, This);
502 static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv)
504 MMDevColImpl *This = impl_from_IMMDeviceCollection(iface);
506 if (!ppv)
507 return E_POINTER;
508 if (IsEqualIID(riid, &IID_IUnknown)
509 || IsEqualIID(riid, &IID_IMMDeviceCollection))
510 *ppv = This;
511 else
512 *ppv = NULL;
513 if (!*ppv)
514 return E_NOINTERFACE;
515 IUnknown_AddRef((IUnknown*)*ppv);
516 return S_OK;
519 static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface)
521 MMDevColImpl *This = impl_from_IMMDeviceCollection(iface);
522 LONG ref = InterlockedIncrement(&This->ref);
523 TRACE("Refcount now %i\n", ref);
524 return ref;
527 static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface)
529 MMDevColImpl *This = impl_from_IMMDeviceCollection(iface);
530 LONG ref = InterlockedDecrement(&This->ref);
531 TRACE("Refcount now %i\n", ref);
532 if (!ref)
533 MMDevCol_Destroy(This);
534 return ref;
537 static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs)
539 MMDevColImpl *This = impl_from_IMMDeviceCollection(iface);
540 DWORD i;
542 TRACE("(%p)->(%p)\n", This, numdevs);
543 if (!numdevs)
544 return E_POINTER;
546 *numdevs = 0;
547 for (i = 0; i < MMDevice_count; ++i)
549 MMDevice *cur = MMDevice_head[i];
550 if ((cur->flow == This->flow || This->flow == eAll)
551 && (cur->state & This->state))
552 ++(*numdevs);
554 return S_OK;
557 static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT n, IMMDevice **dev)
559 MMDevColImpl *This = impl_from_IMMDeviceCollection(iface);
560 DWORD i = 0, j = 0;
562 TRACE("(%p)->(%u, %p)\n", This, n, dev);
563 if (!dev)
564 return E_POINTER;
566 for (j = 0; j < MMDevice_count; ++j)
568 MMDevice *cur = MMDevice_head[j];
569 if ((cur->flow == This->flow || This->flow == eAll)
570 && (cur->state & This->state)
571 && i++ == n)
573 *dev = (IMMDevice *)cur;
574 IMMDevice_AddRef(*dev);
575 return S_OK;
578 WARN("Could not obtain item %u\n", n);
579 *dev = NULL;
580 return E_INVALIDARG;
583 static const IMMDeviceCollectionVtbl MMDevColVtbl =
585 MMDevCol_QueryInterface,
586 MMDevCol_AddRef,
587 MMDevCol_Release,
588 MMDevCol_GetCount,
589 MMDevCol_Item
592 static const WCHAR propkey_formatW[] = {
593 '{','%','0','8','X','-','%','0','4','X','-',
594 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
595 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
596 '%','0','2','X','%','0','2','X','}',',','%','d',0 };
598 static HRESULT MMDevPropStore_OpenPropKey(const GUID *guid, DWORD flow, HKEY *propkey)
600 WCHAR buffer[39];
601 LONG ret;
602 HKEY key;
603 StringFromGUID2(guid, buffer, 39);
604 if ((ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, buffer, 0, KEY_READ|KEY_WRITE, &key)) != ERROR_SUCCESS)
606 WARN("Opening key %s failed with %u\n", debugstr_w(buffer), ret);
607 return E_FAIL;
609 ret = RegOpenKeyExW(key, reg_properties, 0, KEY_READ|KEY_WRITE, propkey);
610 RegCloseKey(key);
611 if (ret != ERROR_SUCCESS)
613 WARN("Opening key %s failed with %u\n", debugstr_w(reg_properties), ret);
614 return E_FAIL;
616 return S_OK;
619 HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv)
621 WCHAR buffer[80];
622 const GUID *id = &key->fmtid;
623 DWORD type, size;
624 HRESULT hr = S_OK;
625 HKEY regkey;
626 LONG ret;
628 hr = MMDevPropStore_OpenPropKey(devguid, flow, &regkey);
629 if (FAILED(hr))
630 return hr;
631 wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3,
632 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
633 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid );
634 ret = RegGetValueW(regkey, NULL, buffer, RRF_RT_ANY, &type, NULL, &size);
635 if (ret != ERROR_SUCCESS)
637 WARN("Reading %s returned %d\n", debugstr_w(buffer), ret);
638 RegCloseKey(regkey);
639 PropVariantClear(pv);
640 return S_OK;
643 switch (type)
645 case REG_SZ:
647 pv->vt = VT_LPWSTR;
648 pv->u.pwszVal = CoTaskMemAlloc(size);
649 if (!pv->u.pwszVal)
650 hr = E_OUTOFMEMORY;
651 else
652 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_SZ, NULL, (BYTE*)pv->u.pwszVal, &size);
653 break;
655 case REG_DWORD:
657 pv->vt = VT_UI4;
658 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_DWORD, NULL, (BYTE*)&pv->u.ulVal, &size);
659 break;
661 case REG_BINARY:
663 pv->vt = VT_BLOB;
664 pv->u.blob.cbSize = size;
665 pv->u.blob.pBlobData = CoTaskMemAlloc(size);
666 if (!pv->u.blob.pBlobData)
667 hr = E_OUTOFMEMORY;
668 else
669 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, (BYTE*)pv->u.blob.pBlobData, &size);
670 break;
672 default:
673 ERR("Unknown/unhandled type: %u\n", type);
674 PropVariantClear(pv);
675 break;
677 RegCloseKey(regkey);
678 return hr;
681 HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, REFPROPVARIANT pv)
683 WCHAR buffer[80];
684 const GUID *id = &key->fmtid;
685 HRESULT hr;
686 HKEY regkey;
687 LONG ret;
689 hr = MMDevPropStore_OpenPropKey(devguid, flow, &regkey);
690 if (FAILED(hr))
691 return hr;
692 wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3,
693 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
694 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid );
695 switch (pv->vt)
697 case VT_UI4:
699 ret = RegSetValueExW(regkey, buffer, 0, REG_DWORD, (const BYTE*)&pv->u.ulVal, sizeof(DWORD));
700 break;
702 case VT_BLOB:
704 ret = RegSetValueExW(regkey, buffer, 0, REG_BINARY, pv->u.blob.pBlobData, pv->u.blob.cbSize);
705 TRACE("Blob %p %u\n", pv->u.blob.pBlobData, pv->u.blob.cbSize);
707 break;
709 case VT_LPWSTR:
711 ret = RegSetValueExW(regkey, buffer, 0, REG_SZ, (const BYTE*)pv->u.pwszVal, sizeof(WCHAR)*(1+lstrlenW(pv->u.pwszVal)));
712 break;
714 default:
715 ret = 0;
716 FIXME("Unhandled type %u\n", pv->vt);
717 hr = E_INVALIDARG;
718 break;
720 RegCloseKey(regkey);
721 TRACE("Writing %s returned %u\n", debugstr_w(buffer), ret);
722 return hr;
725 #ifdef HAVE_OPENAL
727 static void openal_setformat(MMDevice *This, DWORD freq)
729 HRESULT hr;
730 PROPVARIANT pv = { VT_EMPTY };
732 hr = MMDevice_GetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
733 if (SUCCEEDED(hr) && pv.vt == VT_BLOB)
735 WAVEFORMATEX *pwfx;
736 pwfx = (WAVEFORMATEX*)pv.u.blob.pBlobData;
737 if (pwfx->nSamplesPerSec != freq)
739 pwfx->nSamplesPerSec = freq;
740 pwfx->nAvgBytesPerSec = freq * pwfx->nBlockAlign;
741 MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
743 CoTaskMemFree(pwfx);
745 else
747 WAVEFORMATEXTENSIBLE wfxe;
749 wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
750 wfxe.Format.nChannels = 2;
751 wfxe.Format.wBitsPerSample = 32;
752 wfxe.Format.nBlockAlign = wfxe.Format.nChannels * wfxe.Format.wBitsPerSample/8;
753 wfxe.Format.nSamplesPerSec = freq;
754 wfxe.Format.nAvgBytesPerSec = wfxe.Format.nSamplesPerSec * wfxe.Format.nBlockAlign;
755 wfxe.Format.cbSize = sizeof(wfxe)-sizeof(WAVEFORMATEX);
756 wfxe.Samples.wValidBitsPerSample = 32;
757 wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
758 wfxe.dwChannelMask = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT;
760 pv.vt = VT_BLOB;
761 pv.u.blob.cbSize = sizeof(wfxe);
762 pv.u.blob.pBlobData = (BYTE*)&wfxe;
763 MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
764 MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_OEMFormat, &pv);
768 static int blacklist_pulse;
770 static int blacklist(const char *dev) {
771 #ifdef __linux__
772 if (!strncmp(dev, "OSS ", 4))
773 return 1;
774 #endif
775 if (blacklist_pulse && !strncmp(dev, "PulseAudio ", 11))
776 return 1;
777 if (!strncmp(dev, "ALSA ", 5) && strstr(dev, "hw:"))
778 return 1;
779 if (!strncmp(dev, "PortAudio ", 10))
780 return 1;
781 return 0;
784 static void pulse_fixup(const char *devstr, const char **defstr, int render) {
785 static int warned;
786 int default_pulse;
788 if (render && !blacklist_pulse && !local_contexts)
789 blacklist_pulse = 1;
791 if (!blacklist_pulse || !devstr || !*devstr)
792 return;
794 default_pulse = !strncmp(*defstr, "PulseAudio ", 11);
796 while (*devstr && !strncmp(devstr, "PulseAudio ", 11))
797 devstr += strlen(devstr) + 1;
799 /* Could still be a newer version, so check for 1.11 if more devices are enabled */
800 if (render && *devstr) {
801 ALCdevice *dev = palcOpenDevice(devstr);
802 ALCcontext *ctx = palcCreateContext(dev, NULL);
803 if (ctx) {
804 const char *ver;
806 setALContext(ctx);
807 ver = palGetString(AL_VERSION);
808 popALContext();
809 palcDestroyContext(ctx);
811 if (!strcmp(ver, "1.1 ALSOFT 1.11.753")) {
812 blacklist_pulse = 0;
813 palcCloseDevice(dev);
814 return;
817 if (dev)
818 palcCloseDevice(dev);
821 if (!warned++) {
822 ERR("Disabling pulseaudio because of old openal version\n");
823 ERR("Please upgrade to openal-soft v1.12 or newer\n");
825 TRACE("New default: %s\n", devstr);
826 if (default_pulse)
827 *defstr = devstr;
830 static void openal_scanrender(void)
832 WCHAR name[MAX_PATH];
833 ALCdevice *dev;
834 const ALCchar *devstr, *defaultstr;
835 int defblacklisted;
836 EnterCriticalSection(&openal_crst);
837 if (palcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) {
838 defaultstr = palcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
839 devstr = palcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
840 } else {
841 defaultstr = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
842 devstr = palcGetString(NULL, ALC_DEVICE_SPECIFIER);
844 pulse_fixup(devstr, &defaultstr, 1);
845 defblacklisted = blacklist(defaultstr);
846 if (defblacklisted)
847 WARN("Disabling blacklist because %s is blacklisted\n", defaultstr);
848 if (devstr)
849 for (; *devstr; devstr += strlen(devstr)+1) {
850 MMDevice *mmdev;
851 MultiByteToWideChar( CP_UNIXCP, 0, devstr, -1,
852 name, sizeof(name)/sizeof(*name)-1 );
853 name[sizeof(name)/sizeof(*name)-1] = 0;
854 /* Only enable blacklist if the default device isn't blacklisted */
855 if (!defblacklisted && blacklist(devstr)) {
856 WARN("Not adding %s: device is blacklisted\n", devstr);
857 continue;
859 TRACE("Adding %s\n", devstr);
860 dev = palcOpenDevice(devstr);
861 MMDevice_Create(&mmdev, name, NULL, eRender, dev ? DEVICE_STATE_ACTIVE : DEVICE_STATE_NOTPRESENT, !strcmp(devstr, defaultstr));
862 if (dev)
864 ALint freq = 44100;
865 palcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq);
866 openal_setformat(mmdev, freq);
867 palcCloseDevice(dev);
869 else
870 WARN("Could not open device: %04x\n", palcGetError(NULL));
872 LeaveCriticalSection(&openal_crst);
875 static void openal_scancapture(void)
877 WCHAR name[MAX_PATH];
878 ALCdevice *dev;
879 const ALCchar *devstr, *defaultstr;
880 int defblacklisted;
882 EnterCriticalSection(&openal_crst);
883 devstr = palcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
884 defaultstr = palcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
885 pulse_fixup(devstr, &defaultstr, 0);
886 defblacklisted = blacklist(defaultstr);
887 if (defblacklisted)
888 WARN("Disabling blacklist because %s is blacklisted\n", defaultstr);
889 if (devstr && *devstr)
890 for (; *devstr; devstr += strlen(devstr)+1) {
891 MMDevice *mmdev;
892 ALint freq = 44100;
893 MultiByteToWideChar( CP_UNIXCP, 0, devstr, -1,
894 name, sizeof(name)/sizeof(*name)-1 );
895 name[sizeof(name)/sizeof(*name)-1] = 0;
896 if (!defblacklisted && blacklist(devstr)) {
897 WARN("Not adding %s: device is blacklisted\n", devstr);
898 continue;
900 TRACE("Adding %s\n", devstr);
901 dev = palcCaptureOpenDevice(devstr, freq, AL_FORMAT_MONO16, 65536);
902 MMDevice_Create(&mmdev, name, NULL, eCapture, dev ? DEVICE_STATE_ACTIVE : DEVICE_STATE_NOTPRESENT, !strcmp(devstr, defaultstr));
903 if (dev) {
904 openal_setformat(mmdev, freq);
905 palcCaptureCloseDevice(dev);
906 } else
907 WARN("Could not open device: %04x\n", palcGetError(NULL));
909 LeaveCriticalSection(&openal_crst);
911 #endif /*HAVE_OPENAL*/
913 HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
915 MMDevEnumImpl *This = MMDevEnumerator;
917 if (!This)
919 DWORD i = 0;
920 HKEY root, cur;
921 LONG ret;
922 DWORD curflow;
924 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
925 *ppv = NULL;
926 if (!This)
927 return E_OUTOFMEMORY;
928 This->ref = 1;
929 This->IMMDeviceEnumerator_iface.lpVtbl = &MMDevEnumVtbl;
930 MMDevEnumerator = This;
932 ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &root, NULL);
933 if (ret == ERROR_SUCCESS)
934 ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_capture, NULL);
935 if (ret == ERROR_SUCCESS)
936 ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_render, NULL);
937 RegCloseKey(root);
938 cur = key_capture;
939 curflow = eCapture;
940 if (ret != ERROR_SUCCESS)
942 RegCloseKey(key_capture);
943 key_render = key_capture = NULL;
944 WARN("Couldn't create key: %u\n", ret);
945 return E_FAIL;
947 else do {
948 WCHAR guidvalue[39];
949 GUID guid;
950 DWORD len;
951 PROPVARIANT pv = { VT_EMPTY };
953 len = sizeof(guidvalue);
954 ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
955 if (ret == ERROR_NO_MORE_ITEMS)
957 if (cur == key_capture)
959 cur = key_render;
960 curflow = eRender;
961 i = 0;
962 continue;
964 break;
966 if (ret != ERROR_SUCCESS)
967 continue;
968 if (SUCCEEDED(CLSIDFromString(guidvalue, &guid))
969 && SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv))
970 && pv.vt == VT_LPWSTR)
972 MMDevice_Create(NULL, pv.u.pwszVal, &guid, curflow,
973 DEVICE_STATE_NOTPRESENT, FALSE);
974 CoTaskMemFree(pv.u.pwszVal);
976 } while (1);
977 #ifdef HAVE_OPENAL
978 if (openal_loaded)
980 openal_scanrender();
981 openal_scancapture();
983 else
984 FIXME("OpenAL support not enabled, application will not find sound devices\n");
985 #else
986 ERR("OpenAL support not compiled in, application will not find sound devices\n");
987 #endif /*HAVE_OPENAL*/
989 return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
992 void MMDevEnum_Free(void)
994 while (MMDevice_count)
995 MMDevice_Destroy(MMDevice_head[0]);
996 RegCloseKey(key_render);
997 RegCloseKey(key_capture);
998 key_render = key_capture = NULL;
999 HeapFree(GetProcessHeap(), 0, MMDevEnumerator);
1000 MMDevEnumerator = NULL;
1003 static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv)
1005 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1007 if (!ppv)
1008 return E_POINTER;
1009 if (IsEqualIID(riid, &IID_IUnknown)
1010 || IsEqualIID(riid, &IID_IMMDeviceEnumerator))
1011 *ppv = This;
1012 else
1013 *ppv = NULL;
1014 if (!*ppv)
1015 return E_NOINTERFACE;
1016 IUnknown_AddRef((IUnknown*)*ppv);
1017 return S_OK;
1020 static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface)
1022 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1023 LONG ref = InterlockedIncrement(&This->ref);
1024 TRACE("Refcount now %i\n", ref);
1025 return ref;
1028 static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface)
1030 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1031 LONG ref = InterlockedDecrement(&This->ref);
1032 if (!ref)
1033 MMDevEnum_Free();
1034 TRACE("Refcount now %i\n", ref);
1035 return ref;
1038 static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices)
1040 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1041 TRACE("(%p)->(%u,%u,%p)\n", This, flow, mask, devices);
1042 if (!devices)
1043 return E_POINTER;
1044 *devices = NULL;
1045 if (flow >= EDataFlow_enum_count)
1046 return E_INVALIDARG;
1047 if (mask & ~DEVICE_STATEMASK_ALL)
1048 return E_INVALIDARG;
1049 return MMDevCol_Create(devices, flow, mask);
1052 static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device)
1054 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1055 TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
1057 if (!device)
1058 return E_POINTER;
1059 *device = NULL;
1061 if (flow == eRender)
1062 *device = (IMMDevice*)MMDevice_def_play;
1063 else if (flow == eCapture)
1064 *device = (IMMDevice*)MMDevice_def_rec;
1065 else
1067 WARN("Unknown flow %u\n", flow);
1068 return E_INVALIDARG;
1071 if (!*device)
1072 return E_NOTFOUND;
1073 IMMDevice_AddRef(*device);
1074 return S_OK;
1077 static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device)
1079 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1080 DWORD i=0;
1081 IMMDevice *dev = NULL;
1083 TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device);
1084 for (i = 0; i < MMDevice_count; ++i)
1086 WCHAR *str;
1087 dev = (IMMDevice*)MMDevice_head[i];
1088 IMMDevice_GetId(dev, &str);
1090 if (str && !lstrcmpW(str, name))
1092 CoTaskMemFree(str);
1093 break;
1095 CoTaskMemFree(str);
1097 if (dev)
1099 IUnknown_AddRef(dev);
1100 *device = dev;
1101 return S_OK;
1103 WARN("Could not find device %s\n", debugstr_w(name));
1104 return E_NOTFOUND;
1107 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
1109 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1110 TRACE("(%p)->(%p)\n", This, client);
1111 FIXME("stub\n");
1112 return S_OK;
1115 static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
1117 MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
1118 TRACE("(%p)->(%p)\n", This, client);
1119 FIXME("stub\n");
1120 return S_OK;
1123 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl =
1125 MMDevEnum_QueryInterface,
1126 MMDevEnum_AddRef,
1127 MMDevEnum_Release,
1128 MMDevEnum_EnumAudioEndpoints,
1129 MMDevEnum_GetDefaultAudioEndpoint,
1130 MMDevEnum_GetDevice,
1131 MMDevEnum_RegisterEndpointNotificationCallback,
1132 MMDevEnum_UnregisterEndpointNotificationCallback
1135 static HRESULT MMDevPropStore_Create(MMDevice *parent, DWORD access, IPropertyStore **ppv)
1137 MMDevPropStore *This;
1138 if (access != STGM_READ
1139 && access != STGM_WRITE
1140 && access != STGM_READWRITE)
1142 WARN("Invalid access %08x\n", access);
1143 return E_INVALIDARG;
1145 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1146 *ppv = &This->IPropertyStore_iface;
1147 if (!This)
1148 return E_OUTOFMEMORY;
1149 This->IPropertyStore_iface.lpVtbl = &MMDevPropVtbl;
1150 This->ref = 1;
1151 This->parent = parent;
1152 This->access = access;
1153 return S_OK;
1156 static void MMDevPropStore_Destroy(MMDevPropStore *This)
1158 HeapFree(GetProcessHeap(), 0, This);
1161 static HRESULT WINAPI MMDevPropStore_QueryInterface(IPropertyStore *iface, REFIID riid, void **ppv)
1163 MMDevPropStore *This = impl_from_IPropertyStore(iface);
1165 if (!ppv)
1166 return E_POINTER;
1167 if (IsEqualIID(riid, &IID_IUnknown)
1168 || IsEqualIID(riid, &IID_IPropertyStore))
1169 *ppv = This;
1170 else
1171 *ppv = NULL;
1172 if (!*ppv)
1173 return E_NOINTERFACE;
1174 IUnknown_AddRef((IUnknown*)*ppv);
1175 return S_OK;
1178 static ULONG WINAPI MMDevPropStore_AddRef(IPropertyStore *iface)
1180 MMDevPropStore *This = impl_from_IPropertyStore(iface);
1181 LONG ref = InterlockedIncrement(&This->ref);
1182 TRACE("Refcount now %i\n", ref);
1183 return ref;
1186 static ULONG WINAPI MMDevPropStore_Release(IPropertyStore *iface)
1188 MMDevPropStore *This = impl_from_IPropertyStore(iface);
1189 LONG ref = InterlockedDecrement(&This->ref);
1190 TRACE("Refcount now %i\n", ref);
1191 if (!ref)
1192 MMDevPropStore_Destroy(This);
1193 return ref;
1196 static HRESULT WINAPI MMDevPropStore_GetCount(IPropertyStore *iface, DWORD *nprops)
1198 MMDevPropStore *This = impl_from_IPropertyStore(iface);
1199 WCHAR buffer[50];
1200 DWORD i = 0;
1201 HKEY propkey;
1202 HRESULT hr;
1204 TRACE("(%p)->(%p)\n", iface, nprops);
1205 if (!nprops)
1206 return E_POINTER;
1207 hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey);
1208 if (FAILED(hr))
1209 return hr;
1210 *nprops = 0;
1211 do {
1212 DWORD len = sizeof(buffer)/sizeof(*buffer);
1213 if (RegEnumKeyExW(propkey, i, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
1214 break;
1215 i++;
1216 } while (0);
1217 RegCloseKey(propkey);
1218 TRACE("Returning %i\n", i);
1219 *nprops = i;
1220 return S_OK;
1223 static HRESULT WINAPI MMDevPropStore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1225 MMDevPropStore *This = impl_from_IPropertyStore(iface);
1226 WCHAR buffer[50];
1227 DWORD len = sizeof(buffer)/sizeof(*buffer);
1228 HRESULT hr;
1229 HKEY propkey;
1231 TRACE("(%p)->(%u,%p)\n", iface, prop, key);
1232 if (!key)
1233 return E_POINTER;
1235 hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey);
1236 if (FAILED(hr))
1237 return hr;
1239 if (RegEnumKeyExW(propkey, prop, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS
1240 || len <= 40)
1242 WARN("GetAt %u failed\n", prop);
1243 return E_INVALIDARG;
1245 RegCloseKey(propkey);
1246 buffer[39] = 0;
1247 CLSIDFromString(buffer, &key->fmtid);
1248 key->pid = atoiW(&buffer[40]);
1249 return S_OK;
1252 static HRESULT WINAPI MMDevPropStore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *pv)
1254 MMDevPropStore *This = impl_from_IPropertyStore(iface);
1255 TRACE("(%p)->(\"%s,%u\", %p\n", This, debugstr_guid(&key->fmtid), key ? key->pid : 0, pv);
1257 if (!key || !pv)
1258 return E_POINTER;
1259 if (This->access != STGM_READ
1260 && This->access != STGM_READWRITE)
1261 return STG_E_ACCESSDENIED;
1263 /* Special case */
1264 if (IsEqualPropertyKey(*key, PKEY_AudioEndpoint_GUID))
1266 pv->vt = VT_LPWSTR;
1267 pv->u.pwszVal = CoTaskMemAlloc(39 * sizeof(WCHAR));
1268 if (!pv->u.pwszVal)
1269 return E_OUTOFMEMORY;
1270 StringFromGUID2(&This->parent->devguid, pv->u.pwszVal, 39);
1271 return S_OK;
1274 return MMDevice_GetPropValue(&This->parent->devguid, This->parent->flow, key, pv);
1277 static HRESULT WINAPI MMDevPropStore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT pv)
1279 MMDevPropStore *This = impl_from_IPropertyStore(iface);
1281 if (!key || !pv)
1282 return E_POINTER;
1284 if (This->access != STGM_WRITE
1285 && This->access != STGM_READWRITE)
1286 return STG_E_ACCESSDENIED;
1287 return MMDevice_SetPropValue(&This->parent->devguid, This->parent->flow, key, pv);
1290 static HRESULT WINAPI MMDevPropStore_Commit(IPropertyStore *iface)
1292 FIXME("stub\n");
1293 return E_NOTIMPL;
1296 static const IPropertyStoreVtbl MMDevPropVtbl =
1298 MMDevPropStore_QueryInterface,
1299 MMDevPropStore_AddRef,
1300 MMDevPropStore_Release,
1301 MMDevPropStore_GetCount,
1302 MMDevPropStore_GetAt,
1303 MMDevPropStore_GetValue,
1304 MMDevPropStore_SetValue,
1305 MMDevPropStore_Commit
1309 /* Property bag for IBaseFilter activation */
1310 static HRESULT WINAPI PB_QueryInterface(IPropertyBag *iface, REFIID riid, void **ppv)
1312 ERR("Should not be called\n");
1313 *ppv = NULL;
1314 return E_NOINTERFACE;
1317 static ULONG WINAPI PB_AddRef(IPropertyBag *iface)
1319 ERR("Should not be called\n");
1320 return 2;
1323 static ULONG WINAPI PB_Release(IPropertyBag *iface)
1325 ERR("Should not be called\n");
1326 return 1;
1329 static HRESULT WINAPI PB_Read(IPropertyBag *iface, LPCOLESTR name, VARIANT *var, IErrorLog *log)
1331 static const WCHAR dsguid[] = { 'D','S','G','u','i','d', 0 };
1332 IPropertyBagImpl *This = impl_from_IPropertyBag(iface);
1333 TRACE("Trying to read %s, type %u\n", debugstr_w(name), var->n1.n2.vt);
1334 if (!lstrcmpW(name, dsguid))
1336 WCHAR guidstr[39];
1337 StringFromGUID2(&This->devguid, guidstr,sizeof(guidstr)/sizeof(*guidstr));
1338 var->n1.n2.vt = VT_BSTR;
1339 var->n1.n2.n3.bstrVal = SysAllocString(guidstr);
1340 return S_OK;
1342 ERR("Unknown property '%s' queried\n", debugstr_w(name));
1343 return E_FAIL;
1346 static HRESULT WINAPI PB_Write(IPropertyBag *iface, LPCOLESTR name, VARIANT *var)
1348 ERR("Should not be called\n");
1349 return E_FAIL;
1352 static const IPropertyBagVtbl PB_Vtbl =
1354 PB_QueryInterface,
1355 PB_AddRef,
1356 PB_Release,
1357 PB_Read,
1358 PB_Write