msvcrt/tests: Test _dup2 for failure when second arg is negative.
[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 "wine/debug.h"
28
29 #include "ole2.h"
30 #include "mmdeviceapi.h"
31
32 #include "mmdevapi.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
35
36 typedef struct MMDevEnumImpl
37 {
38     const IMMDeviceEnumeratorVtbl *lpVtbl;
39     LONG ref;
40 } MMDevEnumImpl;
41
42 static MMDevEnumImpl *MMDevEnumerator;
43 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl;
44
45 typedef struct MMDevColImpl
46 {
47     const IMMDeviceCollectionVtbl *lpVtbl;
48     LONG ref;
49     MMDevEnumImpl *parent;
50     EDataFlow flow;
51     DWORD state;
52 } MMDevColImpl;
53 static const IMMDeviceCollectionVtbl MMDevColVtbl;
54
55 static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, MMDevEnumImpl *parent, EDataFlow flow, DWORD state)
56 {
57     MMDevColImpl *This;
58     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
59     *ppv = NULL;
60     if (!This)
61         return E_OUTOFMEMORY;
62     This->lpVtbl = &MMDevColVtbl;
63     This->ref = 1;
64     This->parent = parent;
65     This->flow = flow;
66     This->state = state;
67     *ppv = (IMMDeviceCollection*)This;
68     return S_OK;
69 }
70
71 static void MMDevCol_Destroy(MMDevColImpl *This)
72 {
73     HeapFree(GetProcessHeap(), 0, This);
74 }
75
76 static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv)
77 {
78     MMDevColImpl *This = (MMDevColImpl*)iface;
79
80     if (!ppv)
81         return E_POINTER;
82     if (IsEqualIID(riid, &IID_IUnknown)
83         || IsEqualIID(riid, &IID_IMMDeviceCollection))
84         *ppv = This;
85     else
86         *ppv = NULL;
87     if (!*ppv)
88         return E_NOINTERFACE;
89     IUnknown_AddRef((IUnknown*)*ppv);
90     return S_OK;
91 }
92
93 static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface)
94 {
95     MMDevColImpl *This = (MMDevColImpl*)iface;
96     LONG ref = InterlockedIncrement(&This->ref);
97     TRACE("Refcount now %i\n", ref);
98     return ref;
99 }
100
101 static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface)
102 {
103     MMDevColImpl *This = (MMDevColImpl*)iface;
104     LONG ref = InterlockedDecrement(&This->ref);
105     TRACE("Refcount now %i\n", ref);
106     if (!ref)
107         MMDevCol_Destroy(This);
108     return ref;
109 }
110
111 static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs)
112 {
113     MMDevColImpl *This = (MMDevColImpl*)iface;
114     TRACE("(%p)->(%p)\n", This, numdevs);
115     if (!numdevs)
116         return E_POINTER;
117     *numdevs = 0;
118     return S_OK;
119 }
120
121 static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT i, IMMDevice **dev)
122 {
123     MMDevColImpl *This = (MMDevColImpl*)iface;
124     TRACE("(%p)->(%u, %p)\n", This, i, dev);
125     if (!dev)
126         return E_POINTER;
127     *dev = NULL;
128     return E_INVALIDARG;
129 }
130
131 static const IMMDeviceCollectionVtbl MMDevColVtbl =
132 {
133     MMDevCol_QueryInterface,
134     MMDevCol_AddRef,
135     MMDevCol_Release,
136     MMDevCol_GetCount,
137     MMDevCol_Item
138 };
139
140 HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
141 {
142     MMDevEnumImpl *This = MMDevEnumerator;
143
144     if (!This)
145     {
146         This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
147         *ppv = NULL;
148         if (!This)
149             return E_OUTOFMEMORY;
150         This->ref = 1;
151         This->lpVtbl = &MMDevEnumVtbl;
152         MMDevEnumerator = This;
153     }
154     return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
155 }
156
157 void MMDevEnum_Free(void)
158 {
159     HeapFree(GetProcessHeap(), 0, MMDevEnumerator);
160     MMDevEnumerator = NULL;
161 }
162
163 static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv)
164 {
165     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
166
167     if (!ppv)
168         return E_POINTER;
169     if (IsEqualIID(riid, &IID_IUnknown)
170         || IsEqualIID(riid, &IID_IMMDeviceEnumerator))
171         *ppv = This;
172     else
173         *ppv = NULL;
174     if (!*ppv)
175         return E_NOINTERFACE;
176     IUnknown_AddRef((IUnknown*)*ppv);
177     return S_OK;
178 }
179
180 static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface)
181 {
182     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
183     LONG ref = InterlockedIncrement(&This->ref);
184     TRACE("Refcount now %i\n", ref);
185     return ref;
186 }
187
188 static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface)
189 {
190     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
191     LONG ref = InterlockedDecrement(&This->ref);
192     if (!ref)
193         MMDevEnum_Free();
194     TRACE("Refcount now %i\n", ref);
195     return ref;
196 }
197
198 static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices)
199 {
200     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
201     TRACE("(%p)->(%u,%u,%p)\n", This, flow, mask, devices);
202     if (!devices)
203         return E_POINTER;
204     *devices = NULL;
205     if (flow >= EDataFlow_enum_count)
206         return E_INVALIDARG;
207     if (mask & ~DEVICE_STATEMASK_ALL)
208         return E_INVALIDARG;
209     return MMDevCol_Create(devices, This, flow, mask);
210 }
211
212 static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device)
213 {
214     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
215     TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
216     FIXME("stub\n");
217     return E_NOTFOUND;
218 }
219
220 static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device)
221 {
222     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
223     TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device);
224     FIXME("stub\n");
225     return E_NOTIMPL;
226 }
227
228 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
229 {
230     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
231     TRACE("(%p)->(%p)\n", This, client);
232     FIXME("stub\n");
233     return E_NOTIMPL;
234 }
235
236 static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
237 {
238     MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
239     TRACE("(%p)->(%p)\n", This, client);
240     FIXME("stub\n");
241     return E_NOTIMPL;
242 }
243
244 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl =
245 {
246     MMDevEnum_QueryInterface,
247     MMDevEnum_AddRef,
248     MMDevEnum_Release,
249     MMDevEnum_EnumAudioEndpoints,
250     MMDevEnum_GetDefaultAudioEndpoint,
251     MMDevEnum_GetDevice,
252     MMDevEnum_RegisterEndpointNotificationCallback,
253     MMDevEnum_UnregisterEndpointNotificationCallback
254 };