kernel32/tests: Fix some of the heap tests for 64-bit.
[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 #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"
30
31 #include "ole2.h"
32 #include "mmdeviceapi.h"
33
34 #include "mmdevapi.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
37
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 };
55
56 typedef struct MMDevEnumImpl
57 {
58     const IMMDeviceEnumeratorVtbl *lpVtbl;
59     LONG ref;
60 } MMDevEnumImpl;
61
62 static MMDevEnumImpl *MMDevEnumerator;
63 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl;
64 static const IMMDeviceCollectionVtbl MMDevColVtbl;
65
66 typedef struct MMDevColImpl
67 {
68     const IMMDeviceCollectionVtbl *lpVtbl;
69     LONG ref;
70     EDataFlow flow;
71     DWORD state;
72 } MMDevColImpl;
73
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
77  */
78 static void MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD state)
79 {
80     FIXME("stub\n");
81 }
82
83 static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state)
84 {
85     MMDevColImpl *This;
86
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;
97 }
98
99 static void MMDevCol_Destroy(MMDevColImpl *This)
100 {
101     HeapFree(GetProcessHeap(), 0, This);
102 }
103
104 static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv)
105 {
106     MMDevColImpl *This = (MMDevColImpl*)iface;
107
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;
119 }
120
121 static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface)
122 {
123     MMDevColImpl *This = (MMDevColImpl*)iface;
124     LONG ref = InterlockedIncrement(&This->ref);
125     TRACE("Refcount now %i\n", ref);
126     return ref;
127 }
128
129 static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface)
130 {
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;
137 }
138
139 static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs)
140 {
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;
147 }
148
149 static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT i, IMMDevice **dev)
150 {
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;
157 }
158
159 static const IMMDeviceCollectionVtbl MMDevColVtbl =
160 {
161     MMDevCol_QueryInterface,
162     MMDevCol_AddRef,
163     MMDevCol_Release,
164     MMDevCol_GetCount,
165     MMDevCol_Item
166 };
167
168 HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
169 {
170     MMDevEnumImpl *This = MMDevEnumerator;
171
172     if (!This)
173     {
174         DWORD i = 0;
175         HKEY root, cur, key_capture = NULL, key_render = NULL;
176         LONG ret;
177
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;
185
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)
193         {
194             RegCloseKey(key_capture);
195             RegCloseKey(key_render);
196             TRACE("Couldn't open key: %u\n", ret);
197         }
198         else do {
199             WCHAR guidvalue[39];
200             WCHAR alname[128];
201             GUID guid;
202             DWORD len;
203
204             len = sizeof(guidvalue);
205             ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
206             if (ret == ERROR_NO_MORE_ITEMS)
207             {
208                 if (cur == key_capture)
209                 {
210                     cur = key_render;
211                     i = 0;
212                     continue;
213                 }
214                 break;
215             }
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);
226     }
227     return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
228 }
229
230 void MMDevEnum_Free(void)
231 {
232     HeapFree(GetProcessHeap(), 0, MMDevEnumerator);
233     MMDevEnumerator = NULL;
234 }
235
236 static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv)
237 {
238     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
239
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;
251 }
252
253 static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface)
254 {
255     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
256     LONG ref = InterlockedIncrement(&This->ref);
257     TRACE("Refcount now %i\n", ref);
258     return ref;
259 }
260
261 static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface)
262 {
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;
269 }
270
271 static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices)
272 {
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);
283 }
284
285 static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device)
286 {
287     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
288     TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
289     FIXME("stub\n");
290     return E_NOTFOUND;
291 }
292
293 static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device)
294 {
295     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
296     TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device);
297     FIXME("stub\n");
298     return E_NOTIMPL;
299 }
300
301 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
302 {
303     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
304     TRACE("(%p)->(%p)\n", This, client);
305     FIXME("stub\n");
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
310 {
311     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
312     TRACE("(%p)->(%p)\n", This, client);
313     FIXME("stub\n");
314     return E_NOTIMPL;
315 }
316
317 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl =
318 {
319     MMDevEnum_QueryInterface,
320     MMDevEnum_AddRef,
321     MMDevEnum_Release,
322     MMDevEnum_EnumAudioEndpoints,
323     MMDevEnum_GetDefaultAudioEndpoint,
324     MMDevEnum_GetDevice,
325     MMDevEnum_RegisterEndpointNotificationCallback,
326     MMDevEnum_UnregisterEndpointNotificationCallback
327 };