d3dxof: Do not expect a separator when there is no element.
[wine/multimedia.git] / dlls / mmdevapi / devenum.c
bloba70857311ef1c48b1ea9806d59c60ed44e8b6230
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 #define CINTERFACE
24 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "wine/debug.h"
31 #include "ole2.h"
32 #include "mmdeviceapi.h"
34 #include "mmdevapi.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
38 static const WCHAR software_mmdevapi[] =
39 { 'S','o','f','t','w','a','r','e','\\',
40 'M','i','c','r','o','s','o','f','t','\\',
41 'W','i','n','d','o','w','s','\\',
42 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
43 'M','M','D','e','v','i','c','e','s','\\',
44 'A','u','d','i','o',0};
45 static const WCHAR reg_render[] =
46 { 'R','e','n','d','e','r',0 };
47 static const WCHAR reg_capture[] =
48 { 'C','a','p','t','u','r','e',0 };
49 static const WCHAR reg_devicestate[] =
50 { 'D','e','v','i','c','e','S','t','a','t','e',0 };
51 static const WCHAR reg_alname[] =
52 { 'A','L','N','a','m','e',0 };
53 static const WCHAR reg_properties[] =
54 { 'P','r','o','p','e','r','t','i','e','s',0 };
56 typedef struct MMDevEnumImpl
58 const IMMDeviceEnumeratorVtbl *lpVtbl;
59 LONG ref;
60 } MMDevEnumImpl;
62 static MMDevEnumImpl *MMDevEnumerator;
63 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl;
64 static const IMMDeviceCollectionVtbl MMDevColVtbl;
66 typedef struct MMDevColImpl
68 const IMMDeviceCollectionVtbl *lpVtbl;
69 LONG ref;
70 EDataFlow flow;
71 DWORD state;
72 } MMDevColImpl;
74 /* Creates or updates the state of a device
75 * If GUID is null, a random guid will be assigned
76 * and the device will be created
78 static void MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD state)
80 FIXME("stub\n");
83 static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state)
85 MMDevColImpl *This;
87 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
88 *ppv = NULL;
89 if (!This)
90 return E_OUTOFMEMORY;
91 This->lpVtbl = &MMDevColVtbl;
92 This->ref = 1;
93 This->flow = flow;
94 This->state = state;
95 *ppv = (IMMDeviceCollection*)This;
96 return S_OK;
99 static void MMDevCol_Destroy(MMDevColImpl *This)
101 HeapFree(GetProcessHeap(), 0, This);
104 static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv)
106 MMDevColImpl *This = (MMDevColImpl*)iface;
108 if (!ppv)
109 return E_POINTER;
110 if (IsEqualIID(riid, &IID_IUnknown)
111 || IsEqualIID(riid, &IID_IMMDeviceCollection))
112 *ppv = This;
113 else
114 *ppv = NULL;
115 if (!*ppv)
116 return E_NOINTERFACE;
117 IUnknown_AddRef((IUnknown*)*ppv);
118 return S_OK;
121 static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface)
123 MMDevColImpl *This = (MMDevColImpl*)iface;
124 LONG ref = InterlockedIncrement(&This->ref);
125 TRACE("Refcount now %i\n", ref);
126 return ref;
129 static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface)
131 MMDevColImpl *This = (MMDevColImpl*)iface;
132 LONG ref = InterlockedDecrement(&This->ref);
133 TRACE("Refcount now %i\n", ref);
134 if (!ref)
135 MMDevCol_Destroy(This);
136 return ref;
139 static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs)
141 MMDevColImpl *This = (MMDevColImpl*)iface;
142 TRACE("(%p)->(%p)\n", This, numdevs);
143 if (!numdevs)
144 return E_POINTER;
145 *numdevs = 0;
146 return S_OK;
149 static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT i, IMMDevice **dev)
151 MMDevColImpl *This = (MMDevColImpl*)iface;
152 TRACE("(%p)->(%u, %p)\n", This, i, dev);
153 if (!dev)
154 return E_POINTER;
155 *dev = NULL;
156 return E_INVALIDARG;
159 static const IMMDeviceCollectionVtbl MMDevColVtbl =
161 MMDevCol_QueryInterface,
162 MMDevCol_AddRef,
163 MMDevCol_Release,
164 MMDevCol_GetCount,
165 MMDevCol_Item
168 HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
170 MMDevEnumImpl *This = MMDevEnumerator;
172 if (!This)
174 DWORD i = 0;
175 HKEY root, cur, key_capture = NULL, key_render = NULL;
176 LONG ret;
178 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
179 *ppv = NULL;
180 if (!This)
181 return E_OUTOFMEMORY;
182 This->ref = 1;
183 This->lpVtbl = &MMDevEnumVtbl;
184 MMDevEnumerator = This;
186 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, KEY_READ, &root);
187 if (ret == ERROR_SUCCESS)
188 ret = RegOpenKeyExW(root, reg_capture, 0, KEY_READ, &key_capture);
189 if (ret == ERROR_SUCCESS)
190 ret = RegOpenKeyExW(root, reg_render, 0, KEY_READ, &key_render);
191 cur = key_capture;
192 if (ret != ERROR_SUCCESS)
194 RegCloseKey(key_capture);
195 RegCloseKey(key_render);
196 TRACE("Couldn't open key: %u\n", ret);
198 else do {
199 WCHAR guidvalue[39];
200 WCHAR alname[128];
201 GUID guid;
202 DWORD len;
204 len = sizeof(guidvalue);
205 ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
206 if (ret == ERROR_NO_MORE_ITEMS)
208 if (cur == key_capture)
210 cur = key_render;
211 i = 0;
212 continue;
214 break;
216 if (ret != ERROR_SUCCESS)
217 continue;
218 len = sizeof(alname);
219 RegGetValueW(cur, guidvalue, reg_alname, RRF_RT_REG_SZ, NULL, alname, &len);
220 if (SUCCEEDED(CLSIDFromString(guidvalue, &guid)))
221 MMDevice_Create(alname, &guid,
222 cur == key_capture ? eCapture : eRender,
223 DEVICE_STATE_NOTPRESENT);
224 } while (1);
225 RegCloseKey(root);
227 return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
230 void MMDevEnum_Free(void)
232 HeapFree(GetProcessHeap(), 0, MMDevEnumerator);
233 MMDevEnumerator = NULL;
236 static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv)
238 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
240 if (!ppv)
241 return E_POINTER;
242 if (IsEqualIID(riid, &IID_IUnknown)
243 || IsEqualIID(riid, &IID_IMMDeviceEnumerator))
244 *ppv = This;
245 else
246 *ppv = NULL;
247 if (!*ppv)
248 return E_NOINTERFACE;
249 IUnknown_AddRef((IUnknown*)*ppv);
250 return S_OK;
253 static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface)
255 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
256 LONG ref = InterlockedIncrement(&This->ref);
257 TRACE("Refcount now %i\n", ref);
258 return ref;
261 static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface)
263 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
264 LONG ref = InterlockedDecrement(&This->ref);
265 if (!ref)
266 MMDevEnum_Free();
267 TRACE("Refcount now %i\n", ref);
268 return ref;
271 static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices)
273 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
274 TRACE("(%p)->(%u,%u,%p)\n", This, flow, mask, devices);
275 if (!devices)
276 return E_POINTER;
277 *devices = NULL;
278 if (flow >= EDataFlow_enum_count)
279 return E_INVALIDARG;
280 if (mask & ~DEVICE_STATEMASK_ALL)
281 return E_INVALIDARG;
282 return MMDevCol_Create(devices, flow, mask);
285 static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device)
287 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
288 TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
289 FIXME("stub\n");
290 return E_NOTFOUND;
293 static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device)
295 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
296 TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device);
297 FIXME("stub\n");
298 return E_NOTIMPL;
301 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
303 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
304 TRACE("(%p)->(%p)\n", This, client);
305 FIXME("stub\n");
306 return E_NOTIMPL;
309 static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
311 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
312 TRACE("(%p)->(%p)\n", This, client);
313 FIXME("stub\n");
314 return E_NOTIMPL;
317 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl =
319 MMDevEnum_QueryInterface,
320 MMDevEnum_AddRef,
321 MMDevEnum_Release,
322 MMDevEnum_EnumAudioEndpoints,
323 MMDevEnum_GetDefaultAudioEndpoint,
324 MMDevEnum_GetDevice,
325 MMDevEnum_RegisterEndpointNotificationCallback,
326 MMDevEnum_UnregisterEndpointNotificationCallback