wpcap: Handle different layout of the native packet header structure on 32-bit.
[wine.git] / dlls / mmdevapi / main.c
blob36c94908d670fd113a730b3a9a39f995342d4c85
1 /*
2 * Copyright 2009 Maarten Lankhorst
3 * Copyright 2011 Andrew Eikum for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #include <wchar.h>
23 #include "ntstatus.h"
24 #define COBJMACROS
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
30 #include "ole2.h"
31 #include "olectl.h"
32 #include "rpcproxy.h"
33 #include "propsys.h"
34 #include "propkeydef.h"
35 #include "mmdeviceapi.h"
36 #include "mmsystem.h"
37 #include "dsound.h"
38 #include "audioclient.h"
39 #include "endpointvolume.h"
40 #include "audiopolicy.h"
41 #include "devpkey.h"
42 #include "winreg.h"
43 #include "spatialaudioclient.h"
45 #include "mmdevapi_private.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
50 DriverFuncs drvs;
52 const WCHAR drv_keyW[] = L"Software\\Wine\\Drivers";
54 static const char *get_priority_string(int prio)
56 switch(prio){
57 case Priority_Unavailable:
58 return "Unavailable";
59 case Priority_Low:
60 return "Low";
61 case Priority_Neutral:
62 return "Neutral";
63 case Priority_Preferred:
64 return "Preferred";
66 return "Invalid";
69 static BOOL load_driver(const WCHAR *name, DriverFuncs *driver)
71 NTSTATUS status;
72 WCHAR driver_module[264], path[MAX_PATH];
73 struct test_connect_params params;
75 lstrcpyW(driver_module, L"wine");
76 lstrcatW(driver_module, name);
77 lstrcatW(driver_module, L".drv");
79 TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module));
81 driver->module = LoadLibraryW(driver_module);
82 if(!driver->module){
83 TRACE("Unable to load %s: %lu\n", wine_dbgstr_w(driver_module),
84 GetLastError());
85 return FALSE;
88 if ((status = NtQueryVirtualMemory(GetCurrentProcess(), driver->module, MemoryWineUnixFuncs,
89 &driver->module_unixlib, sizeof(driver->module_unixlib), NULL))) {
90 ERR("Unable to load UNIX functions: %lx\n", status);
91 goto fail;
94 if ((status = __wine_unix_call(driver->module_unixlib, process_attach, NULL))) {
95 ERR("Unable to initialize library: %lx\n", status);
96 goto fail;
99 #define LDFC(n) do { driver->p##n = (void*)GetProcAddress(driver->module, #n);\
100 if(!driver->p##n) { goto fail; } } while(0)
101 LDFC(get_device_guid);
102 LDFC(get_device_name_from_guid);
103 #undef LDFC
105 GetModuleFileNameW(NULL, path, ARRAY_SIZE(path));
106 params.name = wcsrchr(path, '\\');
107 params.name = params.name ? params.name + 1 : path;
108 params.priority = Priority_Neutral;
110 if ((status = __wine_unix_call(driver->module_unixlib, test_connect, &params))) {
111 ERR("Unable to retrieve driver priority: %lx\n", status);
112 goto fail;
115 driver->priority = params.priority;
117 lstrcpyW(driver->module_name, driver_module);
119 TRACE("Successfully loaded %s with priority %s\n",
120 wine_dbgstr_w(driver_module), get_priority_string(driver->priority));
122 return TRUE;
123 fail:
124 FreeLibrary(driver->module);
125 return FALSE;
128 static BOOL WINAPI init_driver(INIT_ONCE *once, void *param, void **context)
130 static WCHAR default_list[] = L"pulse,alsa,oss,coreaudio";
131 DriverFuncs driver;
132 HKEY key;
133 WCHAR reg_list[256], *p, *next, *driver_list = default_list;
135 if(RegOpenKeyW(HKEY_CURRENT_USER, drv_keyW, &key) == ERROR_SUCCESS){
136 DWORD size = sizeof(reg_list);
138 if(RegQueryValueExW(key, L"Audio", 0, NULL, (BYTE*)reg_list, &size) == ERROR_SUCCESS){
139 if(reg_list[0] == '\0'){
140 TRACE("User explicitly chose no driver\n");
141 RegCloseKey(key);
142 return TRUE;
145 driver_list = reg_list;
148 RegCloseKey(key);
151 TRACE("Loading driver list %s\n", wine_dbgstr_w(driver_list));
152 for(next = p = driver_list; next; p = next + 1){
153 next = wcschr(p, ',');
154 if(next)
155 *next = '\0';
157 driver.priority = Priority_Unavailable;
158 if(load_driver(p, &driver)){
159 if(driver.priority == Priority_Unavailable)
160 FreeLibrary(driver.module);
161 else if(!drvs.module || driver.priority > drvs.priority){
162 TRACE("Selecting driver %s with priority %s\n",
163 wine_dbgstr_w(p), get_priority_string(driver.priority));
164 if(drvs.module)
165 FreeLibrary(drvs.module);
166 drvs = driver;
167 }else
168 FreeLibrary(driver.module);
169 }else
170 TRACE("Failed to load driver %s\n", wine_dbgstr_w(p));
172 if(next)
173 *next = ',';
176 if (drvs.module != 0){
177 load_devices_from_reg();
178 load_driver_devices(eRender);
179 load_driver_devices(eCapture);
182 return drvs.module != 0;
185 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
187 TRACE("(0x%p, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);
189 switch (fdwReason)
191 case DLL_PROCESS_ATTACH:
192 DisableThreadLibraryCalls(hinstDLL);
193 break;
194 case DLL_PROCESS_DETACH:
195 if (drvs.module_unixlib) {
196 const NTSTATUS status = __wine_unix_call(drvs.module_unixlib, process_detach, NULL);
197 if (status)
198 WARN("Unable to deinitialize library: %lx\n", status);
201 main_loop_stop();
203 if (!lpvReserved)
204 MMDevEnum_Free();
205 break;
208 return TRUE;
211 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
213 typedef struct {
214 IClassFactory IClassFactory_iface;
215 REFCLSID rclsid;
216 FnCreateInstance pfnCreateInstance;
217 } IClassFactoryImpl;
219 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
221 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
224 static HRESULT WINAPI
225 MMCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
227 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
228 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
229 if (ppobj == NULL)
230 return E_POINTER;
231 if (IsEqualIID(riid, &IID_IUnknown) ||
232 IsEqualIID(riid, &IID_IClassFactory))
234 *ppobj = iface;
235 IClassFactory_AddRef(iface);
236 return S_OK;
238 *ppobj = NULL;
239 return E_NOINTERFACE;
242 static ULONG WINAPI MMCF_AddRef(LPCLASSFACTORY iface)
244 return 2;
247 static ULONG WINAPI MMCF_Release(LPCLASSFACTORY iface)
249 /* static class, won't be freed */
250 return 1;
253 static HRESULT WINAPI MMCF_CreateInstance(
254 LPCLASSFACTORY iface,
255 LPUNKNOWN pOuter,
256 REFIID riid,
257 LPVOID *ppobj)
259 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
260 TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);
262 if (pOuter)
263 return CLASS_E_NOAGGREGATION;
265 if (ppobj == NULL) {
266 WARN("invalid parameter\n");
267 return E_POINTER;
269 *ppobj = NULL;
270 return This->pfnCreateInstance(riid, ppobj);
273 static HRESULT WINAPI MMCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
275 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
276 FIXME("(%p, %d) stub!\n", This, dolock);
277 return S_OK;
280 static const IClassFactoryVtbl MMCF_Vtbl = {
281 MMCF_QueryInterface,
282 MMCF_AddRef,
283 MMCF_Release,
284 MMCF_CreateInstance,
285 MMCF_LockServer
288 static IClassFactoryImpl MMDEVAPI_CF[] = {
289 { { &MMCF_Vtbl }, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create }
292 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
294 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
295 unsigned int i = 0;
296 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
298 InitOnceExecuteOnce(&init_once, init_driver, NULL, NULL);
300 if (ppv == NULL) {
301 WARN("invalid parameter\n");
302 return E_INVALIDARG;
305 *ppv = NULL;
307 if (!IsEqualIID(riid, &IID_IClassFactory) &&
308 !IsEqualIID(riid, &IID_IUnknown)) {
309 WARN("no interface for %s\n", debugstr_guid(riid));
310 return E_NOINTERFACE;
313 for (i = 0; i < ARRAY_SIZE(MMDEVAPI_CF); ++i)
315 if (IsEqualGUID(rclsid, MMDEVAPI_CF[i].rclsid)) {
316 IClassFactory_AddRef(&MMDEVAPI_CF[i].IClassFactory_iface);
317 *ppv = &MMDEVAPI_CF[i];
318 return S_OK;
322 WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid),
323 debugstr_guid(riid), ppv);
324 return CLASS_E_CLASSNOTAVAILABLE;
327 struct activate_async_op {
328 IActivateAudioInterfaceAsyncOperation IActivateAudioInterfaceAsyncOperation_iface;
329 LONG ref;
331 IActivateAudioInterfaceCompletionHandler *callback;
332 HRESULT result_hr;
333 IUnknown *result_iface;
336 static struct activate_async_op *impl_from_IActivateAudioInterfaceAsyncOperation(IActivateAudioInterfaceAsyncOperation *iface)
338 return CONTAINING_RECORD(iface, struct activate_async_op, IActivateAudioInterfaceAsyncOperation_iface);
341 static HRESULT WINAPI activate_async_op_QueryInterface(IActivateAudioInterfaceAsyncOperation *iface,
342 REFIID riid, void **ppv)
344 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
346 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
348 if (!ppv)
349 return E_POINTER;
351 if (IsEqualIID(riid, &IID_IUnknown) ||
352 IsEqualIID(riid, &IID_IActivateAudioInterfaceAsyncOperation)) {
353 *ppv = &This->IActivateAudioInterfaceAsyncOperation_iface;
354 } else {
355 *ppv = NULL;
356 return E_NOINTERFACE;
359 IUnknown_AddRef((IUnknown*)*ppv);
360 return S_OK;
363 static ULONG WINAPI activate_async_op_AddRef(IActivateAudioInterfaceAsyncOperation *iface)
365 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
366 LONG ref = InterlockedIncrement(&This->ref);
367 TRACE("(%p) refcount now %li\n", This, ref);
368 return ref;
371 static ULONG WINAPI activate_async_op_Release(IActivateAudioInterfaceAsyncOperation *iface)
373 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
374 LONG ref = InterlockedDecrement(&This->ref);
375 TRACE("(%p) refcount now %li\n", This, ref);
376 if (!ref) {
377 if(This->result_iface)
378 IUnknown_Release(This->result_iface);
379 IActivateAudioInterfaceCompletionHandler_Release(This->callback);
380 free(This);
382 return ref;
385 static HRESULT WINAPI activate_async_op_GetActivateResult(IActivateAudioInterfaceAsyncOperation *iface,
386 HRESULT *result_hr, IUnknown **result_iface)
388 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
390 TRACE("(%p)->(%p, %p)\n", This, result_hr, result_iface);
392 *result_hr = This->result_hr;
394 if(This->result_hr == S_OK){
395 *result_iface = This->result_iface;
396 IUnknown_AddRef(*result_iface);
399 return S_OK;
402 static IActivateAudioInterfaceAsyncOperationVtbl IActivateAudioInterfaceAsyncOperation_vtbl = {
403 activate_async_op_QueryInterface,
404 activate_async_op_AddRef,
405 activate_async_op_Release,
406 activate_async_op_GetActivateResult,
409 static DWORD WINAPI activate_async_threadproc(void *user)
411 struct activate_async_op *op = user;
413 SetThreadDescription(GetCurrentThread(), L"wine_mmdevapi_activate_async");
415 IActivateAudioInterfaceCompletionHandler_ActivateCompleted(op->callback, &op->IActivateAudioInterfaceAsyncOperation_iface);
417 IActivateAudioInterfaceAsyncOperation_Release(&op->IActivateAudioInterfaceAsyncOperation_iface);
419 return 0;
422 static HRESULT get_mmdevice_by_activatepath(const WCHAR *path, IMMDevice **mmdev)
424 IMMDeviceEnumerator *devenum;
425 HRESULT hr;
427 static const WCHAR DEVINTERFACE_AUDIO_RENDER_WSTR[] = L"{E6327CAD-DCEC-4949-AE8A-991E976A79D2}";
428 static const WCHAR DEVINTERFACE_AUDIO_CAPTURE_WSTR[] = L"{2EEF81BE-33FA-4800-9670-1CD474972C3F}";
429 static const WCHAR MMDEV_PATH_PREFIX[] = L"\\\\?\\SWD#MMDEVAPI#";
431 hr = MMDevEnum_Create(&IID_IMMDeviceEnumerator, (void**)&devenum);
432 if (FAILED(hr)) {
433 WARN("Failed to create MMDeviceEnumerator: %08lx\n", hr);
434 return hr;
437 if (!lstrcmpiW(path, DEVINTERFACE_AUDIO_RENDER_WSTR)){
438 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, eMultimedia, mmdev);
439 } else if (!lstrcmpiW(path, DEVINTERFACE_AUDIO_CAPTURE_WSTR)){
440 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eCapture, eMultimedia, mmdev);
441 } else if (!memcmp(path, MMDEV_PATH_PREFIX, sizeof(MMDEV_PATH_PREFIX) - sizeof(WCHAR))) {
442 WCHAR device_id[56]; /* == strlen("{0.0.1.00000000}.{fd47d9cc-4218-4135-9ce2-0c195c87405b}") + 1 */
444 lstrcpynW(device_id, path + (ARRAY_SIZE(MMDEV_PATH_PREFIX) - 1), ARRAY_SIZE(device_id));
446 hr = IMMDeviceEnumerator_GetDevice(devenum, device_id, mmdev);
447 } else {
448 FIXME("Unrecognized device id format: %s\n", debugstr_w(path));
449 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
452 if (FAILED(hr)) {
453 WARN("Failed to get requested device (%s): %08lx\n", debugstr_w(path), hr);
454 *mmdev = NULL;
455 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
458 IMMDeviceEnumerator_Release(devenum);
460 return hr;
463 /***********************************************************************
464 * ActivateAudioInterfaceAsync (MMDEVAPI.17)
466 HRESULT WINAPI ActivateAudioInterfaceAsync(const WCHAR *path, REFIID riid,
467 PROPVARIANT *params, IActivateAudioInterfaceCompletionHandler *done_handler,
468 IActivateAudioInterfaceAsyncOperation **op_out)
470 struct activate_async_op *op;
471 HANDLE ht;
472 IMMDevice *mmdev;
474 TRACE("(%s, %s, %p, %p, %p)\n", debugstr_w(path), debugstr_guid(riid),
475 params, done_handler, op_out);
477 op = malloc(sizeof(*op));
478 if (!op)
479 return E_OUTOFMEMORY;
481 op->ref = 2; /* returned ref and threadproc ref */
482 op->IActivateAudioInterfaceAsyncOperation_iface.lpVtbl = &IActivateAudioInterfaceAsyncOperation_vtbl;
483 op->callback = done_handler;
484 IActivateAudioInterfaceCompletionHandler_AddRef(done_handler);
486 op->result_hr = get_mmdevice_by_activatepath(path, &mmdev);
487 if (SUCCEEDED(op->result_hr)) {
488 op->result_hr = IMMDevice_Activate(mmdev, riid, CLSCTX_INPROC_SERVER, params, (void**)&op->result_iface);
489 IMMDevice_Release(mmdev);
490 }else
491 op->result_iface = NULL;
493 ht = CreateThread(NULL, 0, &activate_async_threadproc, op, 0, NULL);
494 CloseHandle(ht);
496 *op_out = &op->IActivateAudioInterfaceAsyncOperation_iface;
498 return S_OK;