kernel32: Remove superfluous heap reallocation calls in FormatMessageA/W.
[wine] / dlls / mmdevapi / devenum.c
1 /*
2  * Copyright 2009 Maarten Lankhorst
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
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
30
31 #define NONAMELESSUNION
32 #define CINTERFACE
33 #define COBJMACROS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winnls.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39 #include "wine/unicode.h"
40
41 #include "ole2.h"
42 #include "mmdeviceapi.h"
43 #include "dshow.h"
44 #include "dsound.h"
45 #include "audioclient.h"
46 #include "endpointvolume.h"
47 #include "audiopolicy.h"
48
49 #include "mmdevapi.h"
50 #include "devpkey.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
53
54 static const WCHAR software_mmdevapi[] =
55     { 'S','o','f','t','w','a','r','e','\\',
56       'M','i','c','r','o','s','o','f','t','\\',
57       'W','i','n','d','o','w','s','\\',
58       'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
59       'M','M','D','e','v','i','c','e','s','\\',
60       'A','u','d','i','o',0};
61 static const WCHAR reg_render[] =
62     { 'R','e','n','d','e','r',0 };
63 static const WCHAR reg_capture[] =
64     { 'C','a','p','t','u','r','e',0 };
65 static const WCHAR reg_devicestate[] =
66     { 'D','e','v','i','c','e','S','t','a','t','e',0 };
67 static const WCHAR reg_properties[] =
68     { 'P','r','o','p','e','r','t','i','e','s',0 };
69
70 static HKEY key_render;
71 static HKEY key_capture;
72
73 typedef struct MMDevPropStoreImpl
74 {
75     const IPropertyStoreVtbl *lpVtbl;
76     LONG ref;
77     MMDevice *parent;
78     DWORD access;
79 } MMDevPropStore;
80
81 typedef struct MMDevEnumImpl
82 {
83     const IMMDeviceEnumeratorVtbl *lpVtbl;
84     LONG ref;
85 } MMDevEnumImpl;
86
87 static MMDevEnumImpl *MMDevEnumerator;
88 static MMDevice **MMDevice_head;
89 static MMDevice *MMDevice_def_rec, *MMDevice_def_play;
90 static DWORD MMDevice_count;
91 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl;
92 static const IMMDeviceCollectionVtbl MMDevColVtbl;
93 static const IMMDeviceVtbl MMDeviceVtbl;
94 static const IPropertyStoreVtbl MMDevPropVtbl;
95 static const IMMEndpointVtbl MMEndpointVtbl;
96
97 typedef struct MMDevColImpl
98 {
99     const IMMDeviceCollectionVtbl *lpVtbl;
100     LONG ref;
101     EDataFlow flow;
102     DWORD state;
103 } MMDevColImpl;
104
105 typedef struct IPropertyBagImpl {
106     const IPropertyBagVtbl *lpVtbl;
107     GUID devguid;
108 } IPropertyBagImpl;
109 static const IPropertyBagVtbl PB_Vtbl;
110
111 static HRESULT MMDevPropStore_Create(MMDevice *This, DWORD access, IPropertyStore **ppv);
112
113 /* Creates or updates the state of a device
114  * If GUID is null, a random guid will be assigned
115  * and the device will be created
116  */
117 static void MMDevice_Create(MMDevice **dev, WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault)
118 {
119     HKEY key, root;
120     MMDevice *cur;
121     WCHAR guidstr[39];
122     DWORD i;
123
124     for (i = 0; i < MMDevice_count; ++i)
125     {
126         cur = MMDevice_head[i];
127         if (cur->flow == flow && !lstrcmpW(cur->alname, name))
128         {
129             LONG ret;
130             /* Same device, update state */
131             cur->state = state;
132             StringFromGUID2(&cur->devguid, guidstr, sizeof(guidstr)/sizeof(*guidstr));
133             ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, guidstr, 0, KEY_WRITE, &key);
134             if (ret == ERROR_SUCCESS)
135             {
136                 RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD));
137                 RegCloseKey(key);
138             }
139             goto done;
140         }
141     }
142
143     /* No device found, allocate new one */
144     cur = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur));
145     if (!cur)
146         return;
147     cur->alname = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1)*sizeof(WCHAR));
148     if (!cur->alname)
149     {
150         HeapFree(GetProcessHeap(), 0, cur);
151         return;
152     }
153     lstrcpyW(cur->alname, name);
154     cur->lpVtbl = &MMDeviceVtbl;
155     cur->lpEndpointVtbl = &MMEndpointVtbl;
156     cur->ref = 0;
157     InitializeCriticalSection(&cur->crst);
158     cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst");
159     cur->flow = flow;
160     cur->state = state;
161     if (!id)
162     {
163         id = &cur->devguid;
164         CoCreateGuid(id);
165     }
166     cur->devguid = *id;
167     StringFromGUID2(id, guidstr, sizeof(guidstr)/sizeof(*guidstr));
168     if (flow == eRender)
169         root = key_render;
170     else
171         root = key_capture;
172     if (!RegCreateKeyExW(root, guidstr, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &key, NULL))
173     {
174         HKEY keyprop;
175         RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD));
176         if (!RegCreateKeyExW(key, reg_properties, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &keyprop, NULL))
177         {
178             PROPVARIANT pv;
179             pv.vt = VT_LPWSTR;
180             pv.u.pwszVal = name;
181             MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv);
182             MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv);
183             RegCloseKey(keyprop);
184         }
185         RegCloseKey(key);
186     }
187     if (!MMDevice_head)
188         MMDevice_head = HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head));
189     else
190         MMDevice_head = HeapReAlloc(GetProcessHeap(), 0, MMDevice_head, sizeof(*MMDevice_head)*(1+MMDevice_count));
191     MMDevice_head[MMDevice_count++] = cur;
192
193 done:
194     if (setdefault)
195     {
196         if (flow == eRender)
197             MMDevice_def_play = cur;
198         else
199             MMDevice_def_rec = cur;
200     }
201     if (dev)
202         *dev = cur;
203 }
204
205 static void MMDevice_Destroy(MMDevice *This)
206 {
207     DWORD i;
208     TRACE("Freeing %s\n", debugstr_w(This->alname));
209     /* Since this function is called at destruction time, reordering of the list is unimportant */
210     for (i = 0; i < MMDevice_count; ++i)
211     {
212         if (MMDevice_head[i] == This)
213         {
214             MMDevice_head[i] = MMDevice_head[--MMDevice_count];
215             break;
216         }
217     }
218     This->crst.DebugInfo->Spare[0] = 0;
219     DeleteCriticalSection(&This->crst);
220     HeapFree(GetProcessHeap(), 0, This->alname);
221     HeapFree(GetProcessHeap(), 0, This);
222 }
223
224 static HRESULT WINAPI MMDevice_QueryInterface(IMMDevice *iface, REFIID riid, void **ppv)
225 {
226     MMDevice *This = (MMDevice *)iface;
227     TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ppv);
228
229     if (!ppv)
230         return E_POINTER;
231     *ppv = NULL;
232     if (IsEqualIID(riid, &IID_IUnknown)
233         || IsEqualIID(riid, &IID_IMMDevice))
234         *ppv = This;
235     else if (IsEqualIID(riid, &IID_IMMEndpoint))
236         *ppv = &This->lpEndpointVtbl;
237     if (*ppv)
238     {
239         IUnknown_AddRef((IUnknown*)*ppv);
240         return S_OK;
241     }
242     WARN("Unknown interface %s\n", debugstr_guid(riid));
243     return E_NOINTERFACE;
244 }
245
246 static ULONG WINAPI MMDevice_AddRef(IMMDevice *iface)
247 {
248     MMDevice *This = (MMDevice *)iface;
249     LONG ref;
250
251     ref = InterlockedIncrement(&This->ref);
252     TRACE("Refcount now %i\n", ref);
253     return ref;
254 }
255
256 static ULONG WINAPI MMDevice_Release(IMMDevice *iface)
257 {
258     MMDevice *This = (MMDevice *)iface;
259     LONG ref;
260
261     ref = InterlockedDecrement(&This->ref);
262     TRACE("Refcount now %i\n", ref);
263     return ref;
264 }
265
266 static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD clsctx, PROPVARIANT *params, void **ppv)
267 {
268     MMDevice *This = (MMDevice *)iface;
269     HRESULT hr = E_NOINTERFACE;
270     TRACE("(%p)->(%p,%x,%p,%p)\n", This, riid, clsctx, params, ppv);
271
272     if (!ppv)
273         return E_POINTER;
274
275     if (IsEqualIID(riid, &IID_IAudioClient))
276     {
277         FIXME("IID_IAudioClient unsupported\n");
278     }
279     else if (IsEqualIID(riid, &IID_IAudioEndpointVolume))
280     {
281         FIXME("IID_IAudioEndpointVolume unsupported\n");
282     }
283     else if (IsEqualIID(riid, &IID_IAudioSessionManager)
284              || IsEqualIID(riid, &IID_IAudioSessionManager2))
285     {
286         FIXME("IID_IAudioSessionManager unsupported\n");
287     }
288     else if (IsEqualIID(riid, &IID_IBaseFilter))
289     {
290         if (This->flow == eRender)
291             hr = CoCreateInstance(&CLSID_DSoundRender, NULL, clsctx, riid, ppv);
292         else
293             ERR("Not supported for recording?\n");
294         if (SUCCEEDED(hr))
295         {
296             IPersistPropertyBag *ppb;
297             hr = IUnknown_QueryInterface((IUnknown*)*ppv, &IID_IPersistPropertyBag, (void*)&ppb);
298             if (SUCCEEDED(hr))
299             {
300                 /* ::Load cannot assume the interface stays alive after the function returns,
301                  * so just create the interface on the stack, saves a lot of complicated code */
302                 IPropertyBagImpl bag = { &PB_Vtbl, This->devguid };
303                 hr = IPersistPropertyBag_Load(ppb, (IPropertyBag*)&bag, NULL);
304                 IPersistPropertyBag_Release(ppb);
305                 if (FAILED(hr))
306                     IBaseFilter_Release((IBaseFilter*)*ppv);
307             }
308             else
309             {
310                 FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n");
311                 hr = S_OK;
312             }
313         }
314     }
315     else if (IsEqualIID(riid, &IID_IDeviceTopology))
316     {
317         FIXME("IID_IDeviceTopology unsupported\n");
318     }
319     else if (IsEqualIID(riid, &IID_IDirectSound)
320              || IsEqualIID(riid, &IID_IDirectSound8))
321     {
322         if (This->flow == eRender)
323             hr = CoCreateInstance(&CLSID_DirectSound8, NULL, clsctx, riid, ppv);
324         if (SUCCEEDED(hr))
325         {
326             hr = IDirectSound_Initialize((IDirectSound*)*ppv, &This->devguid);
327             if (FAILED(hr))
328                 IDirectSound_Release((IDirectSound*)*ppv);
329         }
330     }
331     else if (IsEqualIID(riid, &IID_IDirectSoundCapture)
332              || IsEqualIID(riid, &IID_IDirectSoundCapture8))
333     {
334         if (This->flow == eCapture)
335             hr = CoCreateInstance(&CLSID_DirectSoundCapture8, NULL, clsctx, riid, ppv);
336         if (SUCCEEDED(hr))
337         {
338             hr = IDirectSoundCapture_Initialize((IDirectSoundCapture*)*ppv, &This->devguid);
339             if (FAILED(hr))
340                 IDirectSoundCapture_Release((IDirectSoundCapture*)*ppv);
341         }
342     }
343     else
344         ERR("Invalid/unknown iid %s\n", debugstr_guid(riid));
345
346     if (FAILED(hr))
347         *ppv = NULL;
348
349     TRACE("Returning %08x\n", hr);
350     return hr;
351 }
352
353 static HRESULT WINAPI MMDevice_OpenPropertyStore(IMMDevice *iface, DWORD access, IPropertyStore **ppv)
354 {
355     MMDevice *This = (MMDevice *)iface;
356     TRACE("(%p)->(%x,%p)\n", This, access, ppv);
357
358     if (!ppv)
359         return E_POINTER;
360     return MMDevPropStore_Create(This, access, ppv);
361 }
362
363 static HRESULT WINAPI MMDevice_GetId(IMMDevice *iface, WCHAR **itemid)
364 {
365     MMDevice *This = (MMDevice *)iface;
366     WCHAR *str;
367     GUID *id = &This->devguid;
368     static const WCHAR formatW[] = { '{','0','.','0','.','0','.','0','0','0','0','0','0','0','0','}','.',
369                                      '{','%','0','8','X','-','%','0','4','X','-',
370                                      '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
371                                      '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
372                                      '%','0','2','X','%','0','2','X','}',0 };
373
374     TRACE("(%p)->(%p)\n", This, itemid);
375     if (!itemid)
376         return E_POINTER;
377     *itemid = str = CoTaskMemAlloc(56 * sizeof(WCHAR));
378     if (!str)
379         return E_OUTOFMEMORY;
380     wsprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
381                id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
382                id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
383     return S_OK;
384 }
385
386 static HRESULT WINAPI MMDevice_GetState(IMMDevice *iface, DWORD *state)
387 {
388     MMDevice *This = (MMDevice *)iface;
389     TRACE("(%p)->(%p)\n", iface, state);
390
391     if (!state)
392         return E_POINTER;
393     *state = This->state;
394     return S_OK;
395 }
396
397 static const IMMDeviceVtbl MMDeviceVtbl =
398 {
399     MMDevice_QueryInterface,
400     MMDevice_AddRef,
401     MMDevice_Release,
402     MMDevice_Activate,
403     MMDevice_OpenPropertyStore,
404     MMDevice_GetId,
405     MMDevice_GetState
406 };
407
408 static MMDevice *get_this_from_endpoint(IMMEndpoint *iface)
409 {
410     return (MMDevice*)((char*)iface - offsetof(MMDevice,lpEndpointVtbl));
411 }
412
413 static HRESULT WINAPI MMEndpoint_QueryInterface(IMMEndpoint *iface, REFIID riid, void **ppv)
414 {
415     MMDevice *This = get_this_from_endpoint(iface);
416     return IMMDevice_QueryInterface((IMMDevice*)This, riid, ppv);
417 }
418
419 static ULONG WINAPI MMEndpoint_AddRef(IMMEndpoint *iface)
420 {
421     MMDevice *This = get_this_from_endpoint(iface);
422     return IMMDevice_AddRef((IMMDevice*)This);
423 }
424
425 static ULONG WINAPI MMEndpoint_Release(IMMEndpoint *iface)
426 {
427     MMDevice *This = get_this_from_endpoint(iface);
428     return IMMDevice_Release((IMMDevice*)This);
429 }
430
431 static HRESULT WINAPI MMEndpoint_GetDataFlow(IMMEndpoint *iface, EDataFlow *flow)
432 {
433     MMDevice *This = get_this_from_endpoint(iface);
434     if (!flow)
435         return E_POINTER;
436     *flow = This->flow;
437     return S_OK;
438 }
439
440 static const IMMEndpointVtbl MMEndpointVtbl =
441 {
442     MMEndpoint_QueryInterface,
443     MMEndpoint_AddRef,
444     MMEndpoint_Release,
445     MMEndpoint_GetDataFlow
446 };
447
448 static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state)
449 {
450     MMDevColImpl *This;
451
452     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
453     *ppv = NULL;
454     if (!This)
455         return E_OUTOFMEMORY;
456     This->lpVtbl = &MMDevColVtbl;
457     This->ref = 1;
458     This->flow = flow;
459     This->state = state;
460     *ppv = (IMMDeviceCollection*)This;
461     return S_OK;
462 }
463
464 static void MMDevCol_Destroy(MMDevColImpl *This)
465 {
466     HeapFree(GetProcessHeap(), 0, This);
467 }
468
469 static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv)
470 {
471     MMDevColImpl *This = (MMDevColImpl*)iface;
472
473     if (!ppv)
474         return E_POINTER;
475     if (IsEqualIID(riid, &IID_IUnknown)
476         || IsEqualIID(riid, &IID_IMMDeviceCollection))
477         *ppv = This;
478     else
479         *ppv = NULL;
480     if (!*ppv)
481         return E_NOINTERFACE;
482     IUnknown_AddRef((IUnknown*)*ppv);
483     return S_OK;
484 }
485
486 static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface)
487 {
488     MMDevColImpl *This = (MMDevColImpl*)iface;
489     LONG ref = InterlockedIncrement(&This->ref);
490     TRACE("Refcount now %i\n", ref);
491     return ref;
492 }
493
494 static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface)
495 {
496     MMDevColImpl *This = (MMDevColImpl*)iface;
497     LONG ref = InterlockedDecrement(&This->ref);
498     TRACE("Refcount now %i\n", ref);
499     if (!ref)
500         MMDevCol_Destroy(This);
501     return ref;
502 }
503
504 static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs)
505 {
506     MMDevColImpl *This = (MMDevColImpl*)iface;
507     DWORD i;
508
509     TRACE("(%p)->(%p)\n", This, numdevs);
510     if (!numdevs)
511         return E_POINTER;
512
513     *numdevs = 0;
514     for (i = 0; i < MMDevice_count; ++i)
515     {
516         MMDevice *cur = MMDevice_head[i];
517         if ((cur->flow == This->flow || This->flow == eAll)
518             && (cur->state & This->state))
519             ++(*numdevs);
520     }
521     return S_OK;
522 }
523
524 static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT n, IMMDevice **dev)
525 {
526     MMDevColImpl *This = (MMDevColImpl*)iface;
527     DWORD i = 0, j = 0;
528
529     TRACE("(%p)->(%u, %p)\n", This, n, dev);
530     if (!dev)
531         return E_POINTER;
532
533     for (j = 0; j < MMDevice_count; ++j)
534     {
535         MMDevice *cur = MMDevice_head[j];
536         if ((cur->flow == This->flow || This->flow == eAll)
537             && (cur->state & This->state)
538             && i++ == n)
539         {
540             *dev = (IMMDevice *)cur;
541             IMMDevice_AddRef(*dev);
542             return S_OK;
543         }
544     }
545     WARN("Could not obtain item %u\n", n);
546     *dev = NULL;
547     return E_INVALIDARG;
548 }
549
550 static const IMMDeviceCollectionVtbl MMDevColVtbl =
551 {
552     MMDevCol_QueryInterface,
553     MMDevCol_AddRef,
554     MMDevCol_Release,
555     MMDevCol_GetCount,
556     MMDevCol_Item
557 };
558
559 static const WCHAR propkey_formatW[] = {
560     '{','%','0','8','X','-','%','0','4','X','-',
561     '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
562     '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
563     '%','0','2','X','%','0','2','X','}',',','%','d',0 };
564
565 static HRESULT MMDevPropStore_OpenPropKey(const GUID *guid, DWORD flow, HKEY *propkey)
566 {
567     WCHAR buffer[39];
568     LONG ret;
569     HKEY key;
570     StringFromGUID2(guid, buffer, 39);
571     if ((ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, buffer, 0, KEY_READ|KEY_WRITE, &key)) != ERROR_SUCCESS)
572     {
573         WARN("Opening key %s failed with %u\n", debugstr_w(buffer), ret);
574         return E_FAIL;
575     }
576     ret = RegOpenKeyExW(key, reg_properties, 0, KEY_READ|KEY_WRITE, propkey);
577     RegCloseKey(key);
578     if (ret != ERROR_SUCCESS)
579     {
580         WARN("Opening key %s failed with %u\n", debugstr_w(reg_properties), ret);
581         return E_FAIL;
582     }
583     return S_OK;
584 }
585
586 HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv)
587 {
588     WCHAR buffer[80];
589     const GUID *id = &key->fmtid;
590     DWORD type, size;
591     HRESULT hr = S_OK;
592     HKEY regkey;
593     LONG ret;
594
595     hr = MMDevPropStore_OpenPropKey(devguid, flow, &regkey);
596     if (FAILED(hr))
597         return hr;
598     wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3,
599                id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
600                id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid );
601     ret = RegGetValueW(regkey, NULL, buffer, RRF_RT_ANY, &type, NULL, &size);
602     if (ret != ERROR_SUCCESS)
603     {
604         WARN("Reading %s returned %d\n", debugstr_w(buffer), ret);
605         RegCloseKey(regkey);
606         PropVariantClear(pv);
607         return S_OK;
608     }
609
610     switch (type)
611     {
612         case REG_SZ:
613         {
614             pv->vt = VT_LPWSTR;
615             pv->u.pwszVal = CoTaskMemAlloc(size);
616             if (!pv->u.pwszVal)
617                 hr = E_OUTOFMEMORY;
618             else
619                 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_SZ, NULL, (BYTE*)pv->u.pwszVal, &size);
620             break;
621         }
622         case REG_DWORD:
623         {
624             pv->vt = VT_UI4;
625             RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_DWORD, NULL, (BYTE*)&pv->u.ulVal, &size);
626             break;
627         }
628         case REG_BINARY:
629         {
630             pv->vt = VT_BLOB;
631             pv->u.blob.cbSize = size;
632             pv->u.blob.pBlobData = CoTaskMemAlloc(size);
633             if (!pv->u.blob.pBlobData)
634                 hr = E_OUTOFMEMORY;
635             else
636                 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, (BYTE*)pv->u.blob.pBlobData, &size);
637             break;
638         }
639         default:
640             ERR("Unknown/unhandled type: %u\n", type);
641             PropVariantClear(pv);
642             break;
643     }
644     RegCloseKey(regkey);
645     return hr;
646 }
647
648 HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, REFPROPVARIANT pv)
649 {
650     WCHAR buffer[80];
651     const GUID *id = &key->fmtid;
652     HRESULT hr;
653     HKEY regkey;
654     LONG ret;
655
656     hr = MMDevPropStore_OpenPropKey(devguid, flow, &regkey);
657     if (FAILED(hr))
658         return hr;
659     wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3,
660                id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
661                id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid );
662     switch (pv->vt)
663     {
664         case VT_UI4:
665         {
666             ret = RegSetValueExW(regkey, buffer, 0, REG_DWORD, (const BYTE*)&pv->u.ulVal, sizeof(DWORD));
667             break;
668         }
669         case VT_BLOB:
670         {
671             ret = RegSetValueExW(regkey, buffer, 0, REG_BINARY, pv->u.blob.pBlobData, pv->u.blob.cbSize);
672             TRACE("Blob %p %u\n", pv->u.blob.pBlobData, pv->u.blob.cbSize);
673
674             break;
675         }
676         case VT_LPWSTR:
677         {
678             ret = RegSetValueExW(regkey, buffer, 0, REG_SZ, (const BYTE*)pv->u.pwszVal, sizeof(WCHAR)*(1+lstrlenW(pv->u.pwszVal)));
679             break;
680         }
681         default:
682             ret = 0;
683             FIXME("Unhandled type %u\n", pv->vt);
684             hr = E_INVALIDARG;
685             break;
686     }
687     RegCloseKey(regkey);
688     TRACE("Writing %s returned %u\n", debugstr_w(buffer), ret);
689     return hr;
690 }
691
692 #ifdef HAVE_OPENAL
693
694 static void openal_setformat(MMDevice *This, DWORD freq)
695 {
696     HRESULT hr;
697     PROPVARIANT pv = { VT_EMPTY };
698
699     hr = MMDevice_GetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
700     if (SUCCEEDED(hr) && pv.vt == VT_BLOB)
701     {
702         WAVEFORMATEX *pwfx;
703         pwfx = (WAVEFORMATEX*)pv.u.blob.pBlobData;
704         if (pwfx->nSamplesPerSec != freq)
705         {
706             pwfx->nSamplesPerSec = freq;
707             pwfx->nAvgBytesPerSec = freq * pwfx->nBlockAlign;
708             MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
709         }
710         CoTaskMemFree(pwfx);
711     }
712     else
713     {
714         WAVEFORMATEXTENSIBLE wfxe;
715
716         wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
717         wfxe.Format.nChannels = 2;
718         wfxe.Format.wBitsPerSample = 32;
719         wfxe.Format.nBlockAlign = wfxe.Format.nChannels * wfxe.Format.wBitsPerSample/8;
720         wfxe.Format.nSamplesPerSec = freq;
721         wfxe.Format.nAvgBytesPerSec = wfxe.Format.nSamplesPerSec * wfxe.Format.nBlockAlign;
722         wfxe.Format.cbSize = sizeof(wfxe)-sizeof(WAVEFORMATEX);
723         wfxe.Samples.wValidBitsPerSample = 32;
724         wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
725         wfxe.dwChannelMask = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT;
726
727         pv.vt = VT_BLOB;
728         pv.u.blob.cbSize = sizeof(wfxe);
729         pv.u.blob.pBlobData = (BYTE*)&wfxe;
730         MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
731         MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_OEMFormat, &pv);
732     }
733 }
734
735 static int blacklist_pulse;
736
737 static int blacklist(const char *dev) {
738 #ifdef __linux__
739     if (!strncmp(dev, "OSS ", 4))
740         return 1;
741 #endif
742     if (blacklist_pulse && !strncmp(dev, "PulseAudio ", 11))
743         return 1;
744     if (!strncmp(dev, "ALSA ", 5) && strstr(dev, "hw:"))
745         return 1;
746     return 0;
747 }
748
749 static void pulse_fixup(const char *devstr, const char **defstr) {
750     static int warned;
751
752     if (!blacklist_pulse && !local_contexts)
753         blacklist_pulse = 1;
754
755     if (!blacklist_pulse || !devstr || strncmp(*defstr, "PulseAudio ", 11))
756         return;
757
758     if (!warned++) {
759         ERR("Disabling pulseaudio because of old openal version\n");
760         ERR("Please upgrade to openal-soft v1.12 or newer\n");
761     }
762     while (*devstr && !strncmp(devstr, "PulseAudio ", 11)) {
763         devstr += strlen(devstr) + 1;
764     }
765     TRACE("New default: %s\n", devstr);
766     *defstr = devstr;
767 }
768
769 static void openal_scanrender(void)
770 {
771     WCHAR name[MAX_PATH];
772     ALCdevice *dev;
773     const ALCchar *devstr, *defaultstr;
774     int defblacklisted;
775     EnterCriticalSection(&openal_crst);
776     if (palcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) {
777         defaultstr = palcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
778         devstr = palcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
779     } else {
780         defaultstr = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
781         devstr = palcGetString(NULL, ALC_DEVICE_SPECIFIER);
782     }
783     pulse_fixup(devstr, &defaultstr);
784     defblacklisted = blacklist(defaultstr);
785     if (defblacklisted)
786         WARN("Disabling blacklist because %s is blacklisted\n", defaultstr);
787     if (devstr)
788         for (; *devstr; devstr += strlen(devstr)+1) {
789             MMDevice *mmdev;
790             MultiByteToWideChar( CP_UNIXCP, 0, devstr, -1,
791                                  name, sizeof(name)/sizeof(*name)-1 );
792             name[sizeof(name)/sizeof(*name)-1] = 0;
793             /* Only enable blacklist if the default device isn't blacklisted */
794             if (!defblacklisted && blacklist(devstr)) {
795                 WARN("Not adding %s: device is blacklisted\n", devstr);
796                 continue;
797             }
798             TRACE("Adding %s\n", devstr);
799             dev = palcOpenDevice(devstr);
800             MMDevice_Create(&mmdev, name, NULL, eRender, dev ? DEVICE_STATE_ACTIVE : DEVICE_STATE_NOTPRESENT, !strcmp(devstr, defaultstr));
801             if (dev)
802             {
803                 ALint freq = 44100;
804                 palcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq);
805                 openal_setformat(mmdev, freq);
806                 palcCloseDevice(dev);
807             }
808             else
809                 WARN("Could not open device: %04x\n", palcGetError(NULL));
810         }
811     LeaveCriticalSection(&openal_crst);
812 }
813
814 static void openal_scancapture(void)
815 {
816     WCHAR name[MAX_PATH];
817     ALCdevice *dev;
818     const ALCchar *devstr, *defaultstr;
819     int defblacklisted;
820
821     EnterCriticalSection(&openal_crst);
822     devstr = palcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
823     defaultstr = palcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
824     pulse_fixup(devstr, &defaultstr);
825     defblacklisted = blacklist(defaultstr);
826     if (defblacklisted)
827         WARN("Disabling blacklist because %s is blacklisted\n", defaultstr);
828     if (devstr && *devstr)
829         for (; *devstr; devstr += strlen(devstr)+1) {
830             ALint freq = 44100;
831             MultiByteToWideChar( CP_UNIXCP, 0, devstr, -1,
832                                  name, sizeof(name)/sizeof(*name)-1 );
833             name[sizeof(name)/sizeof(*name)-1] = 0;
834             if (!defblacklisted && blacklist(devstr)) {
835                 WARN("Not adding %s: device is blacklisted\n", devstr);
836                 continue;
837             }
838             TRACE("Adding %s\n", devstr);
839             dev = palcCaptureOpenDevice(devstr, freq, AL_FORMAT_MONO16, 65536);
840             MMDevice_Create(NULL, name, NULL, eCapture, dev ? DEVICE_STATE_ACTIVE : DEVICE_STATE_NOTPRESENT, !strcmp(devstr, defaultstr));
841             if (dev)
842                 palcCaptureCloseDevice(dev);
843             else
844                 WARN("Could not open device: %04x\n", palcGetError(NULL));
845         }
846     LeaveCriticalSection(&openal_crst);
847 }
848 #endif /*HAVE_OPENAL*/
849
850 HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
851 {
852     MMDevEnumImpl *This = MMDevEnumerator;
853
854     if (!This)
855     {
856         DWORD i = 0;
857         HKEY root, cur;
858         LONG ret;
859         DWORD curflow;
860
861         This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
862         *ppv = NULL;
863         if (!This)
864             return E_OUTOFMEMORY;
865         This->ref = 1;
866         This->lpVtbl = &MMDevEnumVtbl;
867         MMDevEnumerator = This;
868
869         ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &root, NULL);
870         if (ret == ERROR_SUCCESS)
871             ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_capture, NULL);
872         if (ret == ERROR_SUCCESS)
873             ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_render, NULL);
874         RegCloseKey(root);
875         cur = key_capture;
876         curflow = eCapture;
877         if (ret != ERROR_SUCCESS)
878         {
879             RegCloseKey(key_capture);
880             key_render = key_capture = NULL;
881             WARN("Couldn't create key: %u\n", ret);
882             return E_FAIL;
883         }
884         else do {
885             WCHAR guidvalue[39];
886             GUID guid;
887             DWORD len;
888             PROPVARIANT pv = { VT_EMPTY };
889
890             len = sizeof(guidvalue);
891             ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
892             if (ret == ERROR_NO_MORE_ITEMS)
893             {
894                 if (cur == key_capture)
895                 {
896                     cur = key_render;
897                     curflow = eRender;
898                     i = 0;
899                     continue;
900                 }
901                 break;
902             }
903             if (ret != ERROR_SUCCESS)
904                 continue;
905             if (SUCCEEDED(CLSIDFromString(guidvalue, &guid))
906                 && SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv))
907                 && pv.vt == VT_LPWSTR)
908             {
909                 MMDevice_Create(NULL, pv.u.pwszVal, &guid, curflow,
910                                 DEVICE_STATE_NOTPRESENT, FALSE);
911                 CoTaskMemFree(pv.u.pwszVal);
912             }
913         } while (1);
914 #ifdef HAVE_OPENAL
915         if (openal_loaded)
916         {
917             openal_scanrender();
918             openal_scancapture();
919         }
920 #endif /*HAVE_OPENAL*/
921     }
922     return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
923 }
924
925 void MMDevEnum_Free(void)
926 {
927     while (MMDevice_count)
928         MMDevice_Destroy(MMDevice_head[0]);
929     RegCloseKey(key_render);
930     RegCloseKey(key_capture);
931     key_render = key_capture = NULL;
932     HeapFree(GetProcessHeap(), 0, MMDevEnumerator);
933     MMDevEnumerator = NULL;
934 }
935
936 static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv)
937 {
938     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
939
940     if (!ppv)
941         return E_POINTER;
942     if (IsEqualIID(riid, &IID_IUnknown)
943         || IsEqualIID(riid, &IID_IMMDeviceEnumerator))
944         *ppv = This;
945     else
946         *ppv = NULL;
947     if (!*ppv)
948         return E_NOINTERFACE;
949     IUnknown_AddRef((IUnknown*)*ppv);
950     return S_OK;
951 }
952
953 static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface)
954 {
955     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
956     LONG ref = InterlockedIncrement(&This->ref);
957     TRACE("Refcount now %i\n", ref);
958     return ref;
959 }
960
961 static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface)
962 {
963     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
964     LONG ref = InterlockedDecrement(&This->ref);
965     if (!ref)
966         MMDevEnum_Free();
967     TRACE("Refcount now %i\n", ref);
968     return ref;
969 }
970
971 static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices)
972 {
973     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
974     TRACE("(%p)->(%u,%u,%p)\n", This, flow, mask, devices);
975     if (!devices)
976         return E_POINTER;
977     *devices = NULL;
978     if (flow >= EDataFlow_enum_count)
979         return E_INVALIDARG;
980     if (mask & ~DEVICE_STATEMASK_ALL)
981         return E_INVALIDARG;
982     return MMDevCol_Create(devices, flow, mask);
983 }
984
985 static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device)
986 {
987     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
988     TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
989
990     if (!device)
991         return E_POINTER;
992     *device = NULL;
993
994     if (flow == eRender)
995         *device = (IMMDevice*)MMDevice_def_play;
996     else if (flow == eCapture)
997         *device = (IMMDevice*)MMDevice_def_rec;
998     else
999     {
1000         WARN("Unknown flow %u\n", flow);
1001         return E_INVALIDARG;
1002     }
1003
1004     if (!*device)
1005         return E_NOTFOUND;
1006     IMMDevice_AddRef(*device);
1007     return S_OK;
1008 }
1009
1010 static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device)
1011 {
1012     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
1013     DWORD i=0;
1014     IMMDevice *dev = NULL;
1015
1016     TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device);
1017     for (i = 0; i < MMDevice_count; ++i)
1018     {
1019         WCHAR *str;
1020         dev = (IMMDevice*)MMDevice_head[i];
1021         IMMDevice_GetId(dev, &str);
1022
1023         if (str && !lstrcmpW(str, name))
1024         {
1025             CoTaskMemFree(str);
1026             break;
1027         }
1028         CoTaskMemFree(str);
1029     }
1030     if (dev)
1031     {
1032         IUnknown_AddRef(dev);
1033         *device = dev;
1034         return S_OK;
1035     }
1036     WARN("Could not find device %s\n", debugstr_w(name));
1037     return E_NOTFOUND;
1038 }
1039
1040 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
1041 {
1042     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
1043     TRACE("(%p)->(%p)\n", This, client);
1044     FIXME("stub\n");
1045     return E_NOTIMPL;
1046 }
1047
1048 static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
1049 {
1050     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
1051     TRACE("(%p)->(%p)\n", This, client);
1052     FIXME("stub\n");
1053     return E_NOTIMPL;
1054 }
1055
1056 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl =
1057 {
1058     MMDevEnum_QueryInterface,
1059     MMDevEnum_AddRef,
1060     MMDevEnum_Release,
1061     MMDevEnum_EnumAudioEndpoints,
1062     MMDevEnum_GetDefaultAudioEndpoint,
1063     MMDevEnum_GetDevice,
1064     MMDevEnum_RegisterEndpointNotificationCallback,
1065     MMDevEnum_UnregisterEndpointNotificationCallback
1066 };
1067
1068 static HRESULT MMDevPropStore_Create(MMDevice *parent, DWORD access, IPropertyStore **ppv)
1069 {
1070     MMDevPropStore *This;
1071     if (access != STGM_READ
1072         && access != STGM_WRITE
1073         && access != STGM_READWRITE)
1074     {
1075         WARN("Invalid access %08x\n", access);
1076         return E_INVALIDARG;
1077     }
1078     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1079     *ppv = (IPropertyStore*)This;
1080     if (!This)
1081         return E_OUTOFMEMORY;
1082     This->lpVtbl = &MMDevPropVtbl;
1083     This->ref = 1;
1084     This->parent = parent;
1085     This->access = access;
1086     return S_OK;
1087 }
1088
1089 static void MMDevPropStore_Destroy(MMDevPropStore *This)
1090 {
1091     HeapFree(GetProcessHeap(), 0, This);
1092 }
1093
1094 static HRESULT WINAPI MMDevPropStore_QueryInterface(IPropertyStore *iface, REFIID riid, void **ppv)
1095 {
1096     MMDevPropStore *This = (MMDevPropStore*)iface;
1097
1098     if (!ppv)
1099         return E_POINTER;
1100     if (IsEqualIID(riid, &IID_IUnknown)
1101         || IsEqualIID(riid, &IID_IPropertyStore))
1102         *ppv = This;
1103     else
1104         *ppv = NULL;
1105     if (!*ppv)
1106         return E_NOINTERFACE;
1107     IUnknown_AddRef((IUnknown*)*ppv);
1108     return S_OK;
1109 }
1110
1111 static ULONG WINAPI MMDevPropStore_AddRef(IPropertyStore *iface)
1112 {
1113     MMDevPropStore *This = (MMDevPropStore*)iface;
1114     LONG ref = InterlockedIncrement(&This->ref);
1115     TRACE("Refcount now %i\n", ref);
1116     return ref;
1117 }
1118
1119 static ULONG WINAPI MMDevPropStore_Release(IPropertyStore *iface)
1120 {
1121     MMDevPropStore *This = (MMDevPropStore*)iface;
1122     LONG ref = InterlockedDecrement(&This->ref);
1123     TRACE("Refcount now %i\n", ref);
1124     if (!ref)
1125         MMDevPropStore_Destroy(This);
1126     return ref;
1127 }
1128
1129 static HRESULT WINAPI MMDevPropStore_GetCount(IPropertyStore *iface, DWORD *nprops)
1130 {
1131     MMDevPropStore *This = (MMDevPropStore*)iface;
1132     WCHAR buffer[50];
1133     DWORD i = 0;
1134     HKEY propkey;
1135     HRESULT hr;
1136
1137     TRACE("(%p)->(%p)\n", iface, nprops);
1138     if (!nprops)
1139         return E_POINTER;
1140     hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey);
1141     if (FAILED(hr))
1142         return hr;
1143     *nprops = 0;
1144     do {
1145         DWORD len = sizeof(buffer)/sizeof(*buffer);
1146         if (RegEnumKeyExW(propkey, i, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
1147             break;
1148         i++;
1149     } while (0);
1150     RegCloseKey(propkey);
1151     TRACE("Returning %i\n", i);
1152     *nprops = i;
1153     return S_OK;
1154 }
1155
1156 static HRESULT WINAPI MMDevPropStore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1157 {
1158     MMDevPropStore *This = (MMDevPropStore*)iface;
1159     WCHAR buffer[50];
1160     DWORD len = sizeof(buffer)/sizeof(*buffer);
1161     HRESULT hr;
1162     HKEY propkey;
1163
1164     TRACE("(%p)->(%u,%p)\n", iface, prop, key);
1165     if (!key)
1166         return E_POINTER;
1167
1168     hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey);
1169     if (FAILED(hr))
1170         return hr;
1171
1172     if (RegEnumKeyExW(propkey, prop, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS
1173         || len <= 40)
1174     {
1175         WARN("GetAt %u failed\n", prop);
1176         return E_INVALIDARG;
1177     }
1178     RegCloseKey(propkey);
1179     buffer[39] = 0;
1180     CLSIDFromString(buffer, &key->fmtid);
1181     key->pid = atoiW(&buffer[40]);
1182     return S_OK;
1183 }
1184
1185 static HRESULT WINAPI MMDevPropStore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *pv)
1186 {
1187     MMDevPropStore *This = (MMDevPropStore*)iface;
1188     TRACE("(%p)->(\"%s,%u\", %p\n", This, debugstr_guid(&key->fmtid), key ? key->pid : 0, pv);
1189
1190     if (!key || !pv)
1191         return E_POINTER;
1192     if (This->access != STGM_READ
1193         && This->access != STGM_READWRITE)
1194         return STG_E_ACCESSDENIED;
1195
1196     /* Special case */
1197     if (IsEqualPropertyKey(*key, PKEY_AudioEndpoint_GUID))
1198     {
1199         pv->u.pwszVal = CoTaskMemAlloc(39 * sizeof(WCHAR));
1200         if (!pv->u.pwszVal)
1201             return E_OUTOFMEMORY;
1202         StringFromGUID2(&This->parent->devguid, pv->u.pwszVal, 39);
1203         return S_OK;
1204     }
1205
1206     return MMDevice_GetPropValue(&This->parent->devguid, This->parent->flow, key, pv);
1207 }
1208
1209 static HRESULT WINAPI MMDevPropStore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT pv)
1210 {
1211     MMDevPropStore *This = (MMDevPropStore*)iface;
1212
1213     if (!key || !pv)
1214         return E_POINTER;
1215
1216     if (This->access != STGM_WRITE
1217         && This->access != STGM_READWRITE)
1218         return STG_E_ACCESSDENIED;
1219     return MMDevice_SetPropValue(&This->parent->devguid, This->parent->flow, key, pv);
1220 }
1221
1222 static HRESULT WINAPI MMDevPropStore_Commit(IPropertyStore *iface)
1223 {
1224     FIXME("stub\n");
1225     return E_NOTIMPL;
1226 }
1227
1228 static const IPropertyStoreVtbl MMDevPropVtbl =
1229 {
1230     MMDevPropStore_QueryInterface,
1231     MMDevPropStore_AddRef,
1232     MMDevPropStore_Release,
1233     MMDevPropStore_GetCount,
1234     MMDevPropStore_GetAt,
1235     MMDevPropStore_GetValue,
1236     MMDevPropStore_SetValue,
1237     MMDevPropStore_Commit
1238 };
1239
1240
1241 /* Property bag for IBaseFilter activation */
1242 static HRESULT WINAPI PB_QueryInterface(IPropertyBag *iface, REFIID riid, void **ppv)
1243 {
1244     ERR("Should not be called\n");
1245     *ppv = NULL;
1246     return E_NOINTERFACE;
1247 }
1248
1249 static ULONG WINAPI PB_AddRef(IPropertyBag *iface)
1250 {
1251     ERR("Should not be called\n");
1252     return 2;
1253 }
1254
1255 static ULONG WINAPI PB_Release(IPropertyBag *iface)
1256 {
1257     ERR("Should not be called\n");
1258     return 1;
1259 }
1260
1261 static HRESULT WINAPI PB_Read(IPropertyBag *iface, LPCOLESTR name, VARIANT *var, IErrorLog *log)
1262 {
1263     static const WCHAR dsguid[] = { 'D','S','G','u','i','d', 0 };
1264     IPropertyBagImpl *This = (IPropertyBagImpl*)iface;
1265     TRACE("Trying to read %s, type %u\n", debugstr_w(name), var->n1.n2.vt);
1266     if (!lstrcmpW(name, dsguid))
1267     {
1268         WCHAR guidstr[39];
1269         StringFromGUID2(&This->devguid, guidstr,sizeof(guidstr)/sizeof(*guidstr));
1270         var->n1.n2.vt = VT_BSTR;
1271         var->n1.n2.n3.bstrVal = SysAllocString(guidstr);
1272         return S_OK;
1273     }
1274     ERR("Unknown property '%s' queried\n", debugstr_w(name));
1275     return E_FAIL;
1276 }
1277
1278 static HRESULT WINAPI PB_Write(IPropertyBag *iface, LPCOLESTR name, VARIANT *var)
1279 {
1280     ERR("Should not be called\n");
1281     return E_FAIL;
1282 }
1283
1284 static const IPropertyBagVtbl PB_Vtbl =
1285 {
1286     PB_QueryInterface,
1287     PB_AddRef,
1288     PB_Release,
1289     PB_Read,
1290     PB_Write
1291 };