user32: Pack the COPYDATASTRUCT structure in messages to allow crossing 32/64 boundaries.
[wine/multimedia.git] / dlls / mmdevapi / devenum.c
blob62855fae0ef203326e7d61f94745d710be91e84f
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 #define NONAMELESSUNION
20 #include "config.h"
22 #include <stdarg.h>
24 #define CINTERFACE
25 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
33 #include "ole2.h"
34 #include "mmdeviceapi.h"
35 #include "dshow.h"
36 #include "dsound.h"
37 #include "audioclient.h"
38 #include "endpointvolume.h"
39 #include "audiopolicy.h"
41 #include "mmdevapi.h"
42 #include "devpkey.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
46 static const WCHAR software_mmdevapi[] =
47 { 'S','o','f','t','w','a','r','e','\\',
48 'M','i','c','r','o','s','o','f','t','\\',
49 'W','i','n','d','o','w','s','\\',
50 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
51 'M','M','D','e','v','i','c','e','s','\\',
52 'A','u','d','i','o',0};
53 static const WCHAR reg_render[] =
54 { 'R','e','n','d','e','r',0 };
55 static const WCHAR reg_capture[] =
56 { 'C','a','p','t','u','r','e',0 };
57 static const WCHAR reg_devicestate[] =
58 { 'D','e','v','i','c','e','S','t','a','t','e',0 };
59 static const WCHAR reg_properties[] =
60 { 'P','r','o','p','e','r','t','i','e','s',0 };
62 static HKEY key_render;
63 static HKEY key_capture;
65 typedef struct MMDevPropStoreImpl
67 const IPropertyStoreVtbl *lpVtbl;
68 LONG ref;
69 MMDevice *parent;
70 DWORD access;
71 } MMDevPropStore;
73 typedef struct MMDevEnumImpl
75 const IMMDeviceEnumeratorVtbl *lpVtbl;
76 LONG ref;
77 } MMDevEnumImpl;
79 static MMDevEnumImpl *MMDevEnumerator;
80 static MMDevice **MMDevice_head;
81 static MMDevice *MMDevice_def_rec, *MMDevice_def_play;
82 static DWORD MMDevice_count;
83 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl;
84 static const IMMDeviceCollectionVtbl MMDevColVtbl;
85 static const IMMDeviceVtbl MMDeviceVtbl;
86 static const IPropertyStoreVtbl MMDevPropVtbl;
87 static const IMMEndpointVtbl MMEndpointVtbl;
89 typedef struct MMDevColImpl
91 const IMMDeviceCollectionVtbl *lpVtbl;
92 LONG ref;
93 EDataFlow flow;
94 DWORD state;
95 } MMDevColImpl;
97 typedef struct IPropertyBagImpl {
98 const IPropertyBagVtbl *lpVtbl;
99 GUID devguid;
100 } IPropertyBagImpl;
101 static const IPropertyBagVtbl PB_Vtbl;
103 static HRESULT MMDevPropStore_Create(MMDevice *This, DWORD access, IPropertyStore **ppv);
105 /* Creates or updates the state of a device
106 * If GUID is null, a random guid will be assigned
107 * and the device will be created
109 static void MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault)
111 HKEY key, root;
112 MMDevice *cur;
113 WCHAR guidstr[39];
114 DWORD i;
116 for (i = 0; i < MMDevice_count; ++i)
118 cur = MMDevice_head[i];
119 if (cur->flow == flow && !lstrcmpW(cur->alname, name))
121 LONG ret;
122 /* Same device, update state */
123 cur->state = state;
124 StringFromGUID2(&cur->devguid, guidstr, sizeof(guidstr)/sizeof(*guidstr));
125 ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, guidstr, 0, KEY_WRITE, &key);
126 if (ret == ERROR_SUCCESS)
128 RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD));
129 RegCloseKey(key);
131 goto done;
135 /* No device found, allocate new one */
136 cur = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur));
137 if (!cur)
138 return;
139 cur->alname = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1)*sizeof(WCHAR));
140 if (!cur->alname)
142 HeapFree(GetProcessHeap(), 0, cur);
143 return;
145 lstrcpyW(cur->alname, name);
146 cur->lpVtbl = &MMDeviceVtbl;
147 cur->lpEndpointVtbl = &MMEndpointVtbl;
148 cur->ref = 0;
149 InitializeCriticalSection(&cur->crst);
150 cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst");
151 cur->flow = flow;
152 cur->state = state;
153 if (!id)
155 id = &cur->devguid;
156 CoCreateGuid(id);
158 cur->devguid = *id;
159 StringFromGUID2(id, guidstr, sizeof(guidstr)/sizeof(*guidstr));
160 if (flow == eRender)
161 root = key_render;
162 else
163 root = key_capture;
164 if (!RegCreateKeyExW(root, guidstr, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &key, NULL))
166 HKEY keyprop;
167 RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD));
168 if (!RegCreateKeyExW(key, reg_properties, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &keyprop, NULL))
170 PROPVARIANT pv;
171 pv.vt = VT_LPWSTR;
172 pv.u.pwszVal = name;
173 MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv);
174 MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv);
175 RegCloseKey(keyprop);
177 RegCloseKey(key);
179 if (!MMDevice_head)
180 MMDevice_head = HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head));
181 else
182 MMDevice_head = HeapReAlloc(GetProcessHeap(), 0, MMDevice_head, sizeof(*MMDevice_head)*(1+MMDevice_count));
183 MMDevice_head[MMDevice_count++] = cur;
185 done:
186 if (setdefault)
188 if (flow == eRender)
189 MMDevice_def_play = cur;
190 else
191 MMDevice_def_rec = cur;
195 static void MMDevice_Destroy(MMDevice *This)
197 DWORD i;
198 TRACE("Freeing %s\n", debugstr_w(This->alname));
199 /* Since this function is called at destruction time, reordering of the list is unimportant */
200 for (i = 0; i < MMDevice_count; ++i)
202 if (MMDevice_head[i] == This)
204 MMDevice_head[i] = MMDevice_head[--MMDevice_count];
205 break;
208 This->crst.DebugInfo->Spare[0] = 0;
209 DeleteCriticalSection(&This->crst);
210 HeapFree(GetProcessHeap(), 0, This->alname);
211 HeapFree(GetProcessHeap(), 0, This);
214 static HRESULT WINAPI MMDevice_QueryInterface(IMMDevice *iface, REFIID riid, void **ppv)
216 MMDevice *This = (MMDevice *)iface;
217 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ppv);
219 if (!ppv)
220 return E_POINTER;
221 *ppv = NULL;
222 if (IsEqualIID(riid, &IID_IUnknown)
223 || IsEqualIID(riid, &IID_IMMDevice))
224 *ppv = This;
225 else if (IsEqualIID(riid, &IID_IMMEndpoint))
226 *ppv = &This->lpEndpointVtbl;
227 if (*ppv)
229 IUnknown_AddRef((IUnknown*)*ppv);
230 return S_OK;
232 WARN("Unknown interface %s\n", debugstr_guid(riid));
233 return E_NOINTERFACE;
236 static ULONG WINAPI MMDevice_AddRef(IMMDevice *iface)
238 MMDevice *This = (MMDevice *)iface;
239 LONG ref;
241 ref = InterlockedIncrement(&This->ref);
242 TRACE("Refcount now %i\n", ref);
243 return ref;
246 static ULONG WINAPI MMDevice_Release(IMMDevice *iface)
248 MMDevice *This = (MMDevice *)iface;
249 LONG ref;
251 ref = InterlockedDecrement(&This->ref);
252 TRACE("Refcount now %i\n", ref);
253 return ref;
256 static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD clsctx, PROPVARIANT *params, void **ppv)
258 MMDevice *This = (MMDevice *)iface;
259 HRESULT hr = E_NOINTERFACE;
260 TRACE("(%p)->(%p,%x,%p,%p)\n", This, riid, clsctx, params, ppv);
262 if (!ppv)
263 return E_POINTER;
265 if (IsEqualIID(riid, &IID_IAudioClient))
267 FIXME("IID_IAudioClient unsupported\n");
269 else if (IsEqualIID(riid, &IID_IAudioEndpointVolume))
271 FIXME("IID_IAudioEndpointVolume unsupported\n");
273 else if (IsEqualIID(riid, &IID_IAudioSessionManager)
274 || IsEqualIID(riid, &IID_IAudioSessionManager2))
276 FIXME("IID_IAudioSessionManager unsupported\n");
278 else if (IsEqualIID(riid, &IID_IBaseFilter))
280 if (This->flow == eRender)
281 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, clsctx, riid, ppv);
282 else
283 ERR("Not supported for recording?\n");
284 if (SUCCEEDED(hr))
286 IPersistPropertyBag *ppb;
287 hr = IUnknown_QueryInterface((IUnknown*)*ppv, &IID_IPersistPropertyBag, (void*)&ppb);
288 if (SUCCEEDED(hr))
290 /* ::Load cannot assume the interface stays alive after the function returns,
291 * so just create the interface on the stack, saves a lot of complicated code */
292 IPropertyBagImpl bag = { &PB_Vtbl, This->devguid };
293 hr = IPersistPropertyBag_Load(ppb, (IPropertyBag*)&bag, NULL);
294 IPersistPropertyBag_Release(ppb);
295 if (FAILED(hr))
296 IBaseFilter_Release((IBaseFilter*)*ppv);
298 else
300 FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n");
301 hr = S_OK;
305 else if (IsEqualIID(riid, &IID_IDeviceTopology))
307 FIXME("IID_IDeviceTopology unsupported\n");
309 else if (IsEqualIID(riid, &IID_IDirectSound)
310 || IsEqualIID(riid, &IID_IDirectSound8))
312 if (This->flow == eRender)
313 hr = CoCreateInstance(&CLSID_DirectSound8, NULL, clsctx, riid, ppv);
314 if (SUCCEEDED(hr))
316 hr = IDirectSound_Initialize((IDirectSound*)*ppv, &This->devguid);
317 if (FAILED(hr))
318 IDirectSound_Release((IDirectSound*)*ppv);
321 else if (IsEqualIID(riid, &IID_IDirectSoundCapture)
322 || IsEqualIID(riid, &IID_IDirectSoundCapture8))
324 if (This->flow == eCapture)
325 hr = CoCreateInstance(&CLSID_DirectSoundCapture8, NULL, clsctx, riid, ppv);
326 if (SUCCEEDED(hr))
328 hr = IDirectSoundCapture_Initialize((IDirectSoundCapture*)*ppv, &This->devguid);
329 if (FAILED(hr))
330 IDirectSoundCapture_Release((IDirectSoundCapture*)*ppv);
333 else
334 ERR("Invalid/unknown iid %s\n", debugstr_guid(riid));
336 if (FAILED(hr))
337 *ppv = NULL;
339 TRACE("Returning %08x\n", hr);
340 return hr;
343 static HRESULT WINAPI MMDevice_OpenPropertyStore(IMMDevice *iface, DWORD access, IPropertyStore **ppv)
345 MMDevice *This = (MMDevice *)iface;
346 TRACE("(%p)->(%x,%p)\n", This, access, ppv);
348 if (!ppv)
349 return E_POINTER;
350 return MMDevPropStore_Create(This, access, ppv);
353 static HRESULT WINAPI MMDevice_GetId(IMMDevice *iface, WCHAR **itemid)
355 MMDevice *This = (MMDevice *)iface;
356 WCHAR *str;
357 GUID *id = &This->devguid;
358 static const WCHAR formatW[] = { '{','0','.','0','.','0','.','0','0','0','0','0','0','0','0','}','.',
359 '{','%','0','8','X','-','%','0','4','X','-',
360 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
361 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
362 '%','0','2','X','%','0','2','X','}',0 };
364 TRACE("(%p)->(%p)\n", This, itemid);
365 if (!itemid)
366 return E_POINTER;
367 *itemid = str = CoTaskMemAlloc(56 * sizeof(WCHAR));
368 if (!str)
369 return E_OUTOFMEMORY;
370 wsprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
371 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
372 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
373 return S_OK;
376 static HRESULT WINAPI MMDevice_GetState(IMMDevice *iface, DWORD *state)
378 MMDevice *This = (MMDevice *)iface;
379 TRACE("(%p)->(%p)\n", iface, state);
381 if (!state)
382 return E_POINTER;
383 *state = This->state;
384 return S_OK;
387 static const IMMDeviceVtbl MMDeviceVtbl =
389 MMDevice_QueryInterface,
390 MMDevice_AddRef,
391 MMDevice_Release,
392 MMDevice_Activate,
393 MMDevice_OpenPropertyStore,
394 MMDevice_GetId,
395 MMDevice_GetState
398 static MMDevice *get_this_from_endpoint(IMMEndpoint *iface)
400 return (MMDevice*)((char*)iface - offsetof(MMDevice,lpEndpointVtbl));
403 static HRESULT WINAPI MMEndpoint_QueryInterface(IMMEndpoint *iface, REFIID riid, void **ppv)
405 MMDevice *This = get_this_from_endpoint(iface);
406 return IMMDevice_QueryInterface((IMMDevice*)This, riid, ppv);
409 static ULONG WINAPI MMEndpoint_AddRef(IMMEndpoint *iface)
411 MMDevice *This = get_this_from_endpoint(iface);
412 return IMMDevice_AddRef((IMMDevice*)This);
415 static ULONG WINAPI MMEndpoint_Release(IMMEndpoint *iface)
417 MMDevice *This = get_this_from_endpoint(iface);
418 return IMMDevice_Release((IMMDevice*)This);
421 static HRESULT WINAPI MMEndpoint_GetDataFlow(IMMEndpoint *iface, EDataFlow *flow)
423 MMDevice *This = get_this_from_endpoint(iface);
424 if (!flow)
425 return E_POINTER;
426 *flow = This->flow;
427 return S_OK;
430 static const IMMEndpointVtbl MMEndpointVtbl =
432 MMEndpoint_QueryInterface,
433 MMEndpoint_AddRef,
434 MMEndpoint_Release,
435 MMEndpoint_GetDataFlow
438 static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state)
440 MMDevColImpl *This;
442 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
443 *ppv = NULL;
444 if (!This)
445 return E_OUTOFMEMORY;
446 This->lpVtbl = &MMDevColVtbl;
447 This->ref = 1;
448 This->flow = flow;
449 This->state = state;
450 *ppv = (IMMDeviceCollection*)This;
451 return S_OK;
454 static void MMDevCol_Destroy(MMDevColImpl *This)
456 HeapFree(GetProcessHeap(), 0, This);
459 static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv)
461 MMDevColImpl *This = (MMDevColImpl*)iface;
463 if (!ppv)
464 return E_POINTER;
465 if (IsEqualIID(riid, &IID_IUnknown)
466 || IsEqualIID(riid, &IID_IMMDeviceCollection))
467 *ppv = This;
468 else
469 *ppv = NULL;
470 if (!*ppv)
471 return E_NOINTERFACE;
472 IUnknown_AddRef((IUnknown*)*ppv);
473 return S_OK;
476 static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface)
478 MMDevColImpl *This = (MMDevColImpl*)iface;
479 LONG ref = InterlockedIncrement(&This->ref);
480 TRACE("Refcount now %i\n", ref);
481 return ref;
484 static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface)
486 MMDevColImpl *This = (MMDevColImpl*)iface;
487 LONG ref = InterlockedDecrement(&This->ref);
488 TRACE("Refcount now %i\n", ref);
489 if (!ref)
490 MMDevCol_Destroy(This);
491 return ref;
494 static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs)
496 MMDevColImpl *This = (MMDevColImpl*)iface;
497 DWORD i;
499 TRACE("(%p)->(%p)\n", This, numdevs);
500 if (!numdevs)
501 return E_POINTER;
503 *numdevs = 0;
504 for (i = 0; i < MMDevice_count; ++i)
506 MMDevice *cur = MMDevice_head[i];
507 if ((cur->flow == This->flow || This->flow == eAll)
508 && (cur->state & This->state))
509 ++(*numdevs);
511 return S_OK;
514 static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT n, IMMDevice **dev)
516 MMDevColImpl *This = (MMDevColImpl*)iface;
517 DWORD i = 0, j = 0;
519 TRACE("(%p)->(%u, %p)\n", This, n, dev);
520 if (!dev)
521 return E_POINTER;
523 for (j = 0; j < MMDevice_count; ++j)
525 MMDevice *cur = MMDevice_head[j];
526 if ((cur->flow == This->flow || This->flow == eAll)
527 && (cur->state & This->state)
528 && i++ == n)
530 *dev = (IMMDevice *)cur;
531 IMMDevice_AddRef(*dev);
532 return S_OK;
535 WARN("Could not obtain item %u\n", n);
536 *dev = NULL;
537 return E_INVALIDARG;
540 static const IMMDeviceCollectionVtbl MMDevColVtbl =
542 MMDevCol_QueryInterface,
543 MMDevCol_AddRef,
544 MMDevCol_Release,
545 MMDevCol_GetCount,
546 MMDevCol_Item
549 static const WCHAR propkey_formatW[] = {
550 '{','%','0','8','X','-','%','0','4','X','-',
551 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
552 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
553 '%','0','2','X','%','0','2','X','}',',','%','d',0 };
555 static HRESULT MMDevPropStore_OpenPropKey(const GUID *guid, DWORD flow, HKEY *propkey)
557 WCHAR buffer[39];
558 LONG ret;
559 HKEY key;
560 StringFromGUID2(guid, buffer, 39);
561 if ((ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, buffer, 0, KEY_READ|KEY_WRITE, &key)) != ERROR_SUCCESS)
563 WARN("Opening key %s failed with %u\n", debugstr_w(buffer), ret);
564 return E_FAIL;
566 ret = RegOpenKeyExW(key, reg_properties, 0, KEY_READ|KEY_WRITE, propkey);
567 RegCloseKey(key);
568 if (ret != ERROR_SUCCESS)
570 WARN("Opening key %s failed with %u\n", debugstr_w(reg_properties), ret);
571 return E_FAIL;
573 return S_OK;
576 HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv)
578 WCHAR buffer[80];
579 const GUID *id = &key->fmtid;
580 DWORD type, size;
581 HRESULT hr = S_OK;
582 HKEY regkey;
583 LONG ret;
585 hr = MMDevPropStore_OpenPropKey(devguid, flow, &regkey);
586 if (FAILED(hr))
587 return hr;
588 wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3,
589 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
590 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid );
591 ret = RegGetValueW(regkey, NULL, buffer, RRF_RT_ANY, &type, NULL, &size);
592 if (ret != ERROR_SUCCESS)
594 WARN("Reading %s returned %d\n", debugstr_w(buffer), ret);
595 RegCloseKey(regkey);
596 PropVariantClear(pv);
597 return S_OK;
600 switch (type)
602 case REG_SZ:
604 pv->vt = VT_LPWSTR;
605 pv->u.pwszVal = CoTaskMemAlloc(size);
606 if (!pv->u.pwszVal)
607 hr = E_OUTOFMEMORY;
608 else
609 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_SZ, NULL, (BYTE*)pv->u.pwszVal, &size);
610 break;
612 case REG_DWORD:
614 pv->vt = VT_UI4;
615 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_DWORD, NULL, (BYTE*)&pv->u.ulVal, &size);
616 break;
618 case REG_BINARY:
620 pv->vt = VT_BLOB;
621 pv->u.blob.cbSize = size;
622 pv->u.blob.pBlobData = CoTaskMemAlloc(size);
623 if (!pv->u.blob.pBlobData)
624 hr = E_OUTOFMEMORY;
625 else
626 RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, (BYTE*)pv->u.blob.pBlobData, &size);
627 break;
629 default:
630 ERR("Unknown/unhandled type: %u\n", type);
631 PropVariantClear(pv);
632 break;
634 RegCloseKey(regkey);
635 return hr;
638 HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, REFPROPVARIANT pv)
640 WCHAR buffer[80];
641 const GUID *id = &key->fmtid;
642 HRESULT hr;
643 HKEY regkey;
644 LONG ret;
646 hr = MMDevPropStore_OpenPropKey(devguid, flow, &regkey);
647 if (FAILED(hr))
648 return hr;
649 wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3,
650 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
651 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid );
652 switch (pv->vt)
654 case VT_UI4:
656 ret = RegSetValueExW(regkey, buffer, 0, REG_DWORD, (const BYTE*)&pv->u.ulVal, sizeof(DWORD));
657 break;
659 case VT_BLOB:
661 ret = RegSetValueExW(regkey, buffer, 0, REG_BINARY, pv->u.blob.pBlobData, pv->u.blob.cbSize);
662 TRACE("Blob %p %u\n", pv->u.blob.pBlobData, pv->u.blob.cbSize);
664 break;
666 case VT_LPWSTR:
668 ret = RegSetValueExW(regkey, buffer, 0, REG_SZ, (const BYTE*)pv->u.pwszVal, sizeof(WCHAR)*(1+lstrlenW(pv->u.pwszVal)));
669 break;
671 default:
672 ret = 0;
673 FIXME("Unhandled type %u\n", pv->vt);
674 hr = E_INVALIDARG;
675 break;
677 RegCloseKey(regkey);
678 TRACE("Writing %s returned %u\n", debugstr_w(buffer), ret);
679 return hr;
682 HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
684 MMDevEnumImpl *This = MMDevEnumerator;
686 if (!This)
688 DWORD i = 0;
689 HKEY root, cur;
690 LONG ret;
691 DWORD curflow;
693 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
694 *ppv = NULL;
695 if (!This)
696 return E_OUTOFMEMORY;
697 This->ref = 1;
698 This->lpVtbl = &MMDevEnumVtbl;
699 MMDevEnumerator = This;
701 ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &root, NULL);
702 if (ret == ERROR_SUCCESS)
703 ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_capture, NULL);
704 if (ret == ERROR_SUCCESS)
705 ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_render, NULL);
706 RegCloseKey(root);
707 cur = key_capture;
708 curflow = eCapture;
709 if (ret != ERROR_SUCCESS)
711 RegCloseKey(key_capture);
712 key_render = key_capture = NULL;
713 WARN("Couldn't create key: %u\n", ret);
714 return E_FAIL;
716 else do {
717 WCHAR guidvalue[39];
718 GUID guid;
719 DWORD len;
720 PROPVARIANT pv = { VT_EMPTY };
722 len = sizeof(guidvalue);
723 ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
724 if (ret == ERROR_NO_MORE_ITEMS)
726 if (cur == key_capture)
728 cur = key_render;
729 curflow = eRender;
730 i = 0;
731 continue;
733 break;
735 if (ret != ERROR_SUCCESS)
736 continue;
737 if (SUCCEEDED(CLSIDFromString(guidvalue, &guid))
738 && SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv))
739 && pv.vt == VT_LPWSTR)
741 MMDevice_Create(pv.u.pwszVal, &guid, curflow,
742 DEVICE_STATE_NOTPRESENT, FALSE);
743 CoTaskMemFree(pv.u.pwszVal);
745 } while (1);
747 return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
750 void MMDevEnum_Free(void)
752 while (MMDevice_count)
753 MMDevice_Destroy(MMDevice_head[0]);
754 RegCloseKey(key_render);
755 RegCloseKey(key_capture);
756 key_render = key_capture = NULL;
757 HeapFree(GetProcessHeap(), 0, MMDevEnumerator);
758 MMDevEnumerator = NULL;
761 static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv)
763 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
765 if (!ppv)
766 return E_POINTER;
767 if (IsEqualIID(riid, &IID_IUnknown)
768 || IsEqualIID(riid, &IID_IMMDeviceEnumerator))
769 *ppv = This;
770 else
771 *ppv = NULL;
772 if (!*ppv)
773 return E_NOINTERFACE;
774 IUnknown_AddRef((IUnknown*)*ppv);
775 return S_OK;
778 static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface)
780 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
781 LONG ref = InterlockedIncrement(&This->ref);
782 TRACE("Refcount now %i\n", ref);
783 return ref;
786 static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface)
788 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
789 LONG ref = InterlockedDecrement(&This->ref);
790 if (!ref)
791 MMDevEnum_Free();
792 TRACE("Refcount now %i\n", ref);
793 return ref;
796 static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices)
798 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
799 TRACE("(%p)->(%u,%u,%p)\n", This, flow, mask, devices);
800 if (!devices)
801 return E_POINTER;
802 *devices = NULL;
803 if (flow >= EDataFlow_enum_count)
804 return E_INVALIDARG;
805 if (mask & ~DEVICE_STATEMASK_ALL)
806 return E_INVALIDARG;
807 return MMDevCol_Create(devices, flow, mask);
810 static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device)
812 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
813 TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
815 if (!device)
816 return E_POINTER;
817 *device = NULL;
819 if (flow == eRender)
820 *device = (IMMDevice*)MMDevice_def_play;
821 else if (flow == eCapture)
822 *device = (IMMDevice*)MMDevice_def_rec;
823 else
825 WARN("Unknown flow %u\n", flow);
826 return E_INVALIDARG;
829 if (!*device)
830 return E_NOTFOUND;
831 IMMDevice_AddRef(*device);
832 return S_OK;
835 static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device)
837 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
838 DWORD i=0;
839 IMMDevice *dev = NULL;
841 TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device);
842 for (i = 0; i < MMDevice_count; ++i)
844 WCHAR *str;
845 dev = (IMMDevice*)MMDevice_head[i];
846 IMMDevice_GetId(dev, &str);
848 if (str && !lstrcmpW(str, name))
850 CoTaskMemFree(str);
851 break;
853 CoTaskMemFree(str);
855 if (dev)
857 IUnknown_AddRef(dev);
858 *device = dev;
859 return S_OK;
861 WARN("Could not find device %s\n", debugstr_w(name));
862 return E_NOTFOUND;
865 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
867 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
868 TRACE("(%p)->(%p)\n", This, client);
869 FIXME("stub\n");
870 return E_NOTIMPL;
873 static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
875 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
876 TRACE("(%p)->(%p)\n", This, client);
877 FIXME("stub\n");
878 return E_NOTIMPL;
881 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl =
883 MMDevEnum_QueryInterface,
884 MMDevEnum_AddRef,
885 MMDevEnum_Release,
886 MMDevEnum_EnumAudioEndpoints,
887 MMDevEnum_GetDefaultAudioEndpoint,
888 MMDevEnum_GetDevice,
889 MMDevEnum_RegisterEndpointNotificationCallback,
890 MMDevEnum_UnregisterEndpointNotificationCallback
893 static HRESULT MMDevPropStore_Create(MMDevice *parent, DWORD access, IPropertyStore **ppv)
895 MMDevPropStore *This;
896 if (access != STGM_READ
897 && access != STGM_WRITE
898 && access != STGM_READWRITE)
900 WARN("Invalid access %08x\n", access);
901 return E_INVALIDARG;
903 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
904 *ppv = (IPropertyStore*)This;
905 if (!This)
906 return E_OUTOFMEMORY;
907 This->lpVtbl = &MMDevPropVtbl;
908 This->ref = 1;
909 This->parent = parent;
910 This->access = access;
911 return S_OK;
914 static void MMDevPropStore_Destroy(MMDevPropStore *This)
916 HeapFree(GetProcessHeap(), 0, This);
919 static HRESULT WINAPI MMDevPropStore_QueryInterface(IPropertyStore *iface, REFIID riid, void **ppv)
921 MMDevPropStore *This = (MMDevPropStore*)iface;
923 if (!ppv)
924 return E_POINTER;
925 if (IsEqualIID(riid, &IID_IUnknown)
926 || IsEqualIID(riid, &IID_IPropertyStore))
927 *ppv = This;
928 else
929 *ppv = NULL;
930 if (!*ppv)
931 return E_NOINTERFACE;
932 IUnknown_AddRef((IUnknown*)*ppv);
933 return S_OK;
936 static ULONG WINAPI MMDevPropStore_AddRef(IPropertyStore *iface)
938 MMDevPropStore *This = (MMDevPropStore*)iface;
939 LONG ref = InterlockedIncrement(&This->ref);
940 TRACE("Refcount now %i\n", ref);
941 return ref;
944 static ULONG WINAPI MMDevPropStore_Release(IPropertyStore *iface)
946 MMDevPropStore *This = (MMDevPropStore*)iface;
947 LONG ref = InterlockedDecrement(&This->ref);
948 TRACE("Refcount now %i\n", ref);
949 if (!ref)
950 MMDevPropStore_Destroy(This);
951 return ref;
954 static HRESULT WINAPI MMDevPropStore_GetCount(IPropertyStore *iface, DWORD *nprops)
956 MMDevPropStore *This = (MMDevPropStore*)iface;
957 WCHAR buffer[50];
958 DWORD i = 0;
959 HKEY propkey;
960 HRESULT hr;
962 TRACE("(%p)->(%p)\n", iface, nprops);
963 if (!nprops)
964 return E_POINTER;
965 hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey);
966 if (FAILED(hr))
967 return hr;
968 *nprops = 0;
969 do {
970 DWORD len = sizeof(buffer)/sizeof(*buffer);
971 if (RegEnumKeyExW(propkey, i, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
972 break;
973 i++;
974 } while (0);
975 RegCloseKey(propkey);
976 TRACE("Returning %i\n", i);
977 *nprops = i;
978 return S_OK;
981 static HRESULT WINAPI MMDevPropStore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
983 MMDevPropStore *This = (MMDevPropStore*)iface;
984 WCHAR buffer[50];
985 DWORD len = sizeof(buffer)/sizeof(*buffer);
986 HRESULT hr;
987 HKEY propkey;
989 TRACE("(%p)->(%u,%p)\n", iface, prop, key);
990 if (!key)
991 return E_POINTER;
993 hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey);
994 if (FAILED(hr))
995 return hr;
997 if (RegEnumKeyExW(propkey, prop, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS
998 || len <= 40)
1000 WARN("GetAt %u failed\n", prop);
1001 return E_INVALIDARG;
1003 RegCloseKey(propkey);
1004 buffer[39] = 0;
1005 CLSIDFromString(buffer, &key->fmtid);
1006 key->pid = atoiW(&buffer[40]);
1007 return S_OK;
1010 static HRESULT WINAPI MMDevPropStore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *pv)
1012 MMDevPropStore *This = (MMDevPropStore*)iface;
1013 TRACE("(%p)->(\"%s,%u\", %p\n", This, debugstr_guid(&key->fmtid), key ? key->pid : 0, pv);
1015 if (!key || !pv)
1016 return E_POINTER;
1017 if (This->access != STGM_READ
1018 && This->access != STGM_READWRITE)
1019 return STG_E_ACCESSDENIED;
1021 /* Special case */
1022 if (IsEqualPropertyKey(*key, PKEY_AudioEndpoint_GUID))
1024 pv->u.pwszVal = CoTaskMemAlloc(39 * sizeof(WCHAR));
1025 if (!pv->u.pwszVal)
1026 return E_OUTOFMEMORY;
1027 StringFromGUID2(&This->parent->devguid, pv->u.pwszVal, 39);
1028 return S_OK;
1031 return MMDevice_GetPropValue(&This->parent->devguid, This->parent->flow, key, pv);
1034 static HRESULT WINAPI MMDevPropStore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT pv)
1036 MMDevPropStore *This = (MMDevPropStore*)iface;
1038 if (!key || !pv)
1039 return E_POINTER;
1041 if (This->access != STGM_WRITE
1042 && This->access != STGM_READWRITE)
1043 return STG_E_ACCESSDENIED;
1044 return MMDevice_SetPropValue(&This->parent->devguid, This->parent->flow, key, pv);
1047 static HRESULT WINAPI MMDevPropStore_Commit(IPropertyStore *iface)
1049 FIXME("stub\n");
1050 return E_NOTIMPL;
1053 static const IPropertyStoreVtbl MMDevPropVtbl =
1055 MMDevPropStore_QueryInterface,
1056 MMDevPropStore_AddRef,
1057 MMDevPropStore_Release,
1058 MMDevPropStore_GetCount,
1059 MMDevPropStore_GetAt,
1060 MMDevPropStore_GetValue,
1061 MMDevPropStore_SetValue,
1062 MMDevPropStore_Commit
1066 /* Property bag for IBaseFilter activation */
1067 static HRESULT WINAPI PB_QueryInterface(IPropertyBag *iface, REFIID riid, void **ppv)
1069 ERR("Should not be called\n");
1070 *ppv = NULL;
1071 return E_NOINTERFACE;
1074 static ULONG WINAPI PB_AddRef(IPropertyBag *iface)
1076 ERR("Should not be called\n");
1077 return 2;
1080 static ULONG WINAPI PB_Release(IPropertyBag *iface)
1082 ERR("Should not be called\n");
1083 return 1;
1086 static HRESULT WINAPI PB_Read(IPropertyBag *iface, LPCOLESTR name, VARIANT *var, IErrorLog *log)
1088 static const WCHAR dsguid[] = { 'D','S','G','u','i','d', 0 };
1089 IPropertyBagImpl *This = (IPropertyBagImpl*)iface;
1090 TRACE("Trying to read %s, type %u\n", debugstr_w(name), var->n1.n2.vt);
1091 if (!lstrcmpW(name, dsguid))
1093 WCHAR guidstr[39];
1094 StringFromGUID2(&This->devguid, guidstr,sizeof(guidstr)/sizeof(*guidstr));
1095 var->n1.n2.vt = VT_BSTR;
1096 var->n1.n2.n3.bstrVal = SysAllocString(guidstr);
1097 return S_OK;
1099 ERR("Unknown property '%s' queried\n", debugstr_w(name));
1100 return E_FAIL;
1103 static HRESULT WINAPI PB_Write(IPropertyBag *iface, LPCOLESTR name, VARIANT *var)
1105 ERR("Should not be called\n");
1106 return E_FAIL;
1109 static const IPropertyBagVtbl PB_Vtbl =
1111 PB_QueryInterface,
1112 PB_AddRef,
1113 PB_Release,
1114 PB_Read,
1115 PB_Write