1 /* 2 * Copyright 2009 Maarten Lankhorst 3 * Copyright 2011 Andrew Eikum for CodeWeavers 4 * 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. 9 * 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. 14 * 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 18 */ 19 20 #include "config.h" 21 #include "wine/port.h" 22 23 #include <stdarg.h> 24 25 #define COBJMACROS 26 #include "windef.h" 27 #include "winbase.h" 28 #include "wingdi.h" 29 #include "wine/library.h" 30 31 #include "ole2.h" 32 #include "olectl.h" 33 #include "rpcproxy.h" 34 #include "propsys.h" 35 #include "propkeydef.h" 36 #include "mmdeviceapi.h" 37 #include "mmsystem.h" 38 #include "dsound.h" 39 #include "audioclient.h" 40 #include "endpointvolume.h" 41 #include "audiopolicy.h" 42 #include "devpkey.h" 43 #include "winreg.h" 44 45 #include "mmdevapi.h" 46 #include "wine/debug.h" 47 #include "wine/unicode.h" 48 49 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); 50 51 static HINSTANCE instance; 52 53 DriverFuncs drvs; 54 55 const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\\', 56 'W','i','n','e','\\','D','r','i','v','e','r','s',0}; 57 58 static const char *get_priority_string(int prio) 59 { 60 switch(prio){ 61 case Priority_Unavailable: 62 return "Unavailable"; 63 case Priority_Low: 64 return "Low"; 65 case Priority_Neutral: 66 return "Neutral"; 67 case Priority_Preferred: 68 return "Preferred"; 69 } 70 return "Invalid"; 71 } 72 73 static BOOL load_driver(const WCHAR *name, DriverFuncs *driver) 74 { 75 WCHAR driver_module[264]; 76 static const WCHAR wineW[] = {'w','i','n','e',0}; 77 static const WCHAR dotdrvW[] = {'.','d','r','v',0}; 78 79 lstrcpyW(driver_module, wineW); 80 lstrcatW(driver_module, name); 81 lstrcatW(driver_module, dotdrvW); 82 83 TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module)); 84 85 driver->module = LoadLibraryW(driver_module); 86 if(!driver->module){ 87 TRACE("Unable to load %s: %u\n", wine_dbgstr_w(driver_module), 88 GetLastError()); 89 return FALSE; 90 } 91 92 #define LDFC(n) do { driver->p##n = (void*)GetProcAddress(driver->module, #n);\ 93 if(!driver->p##n) { FreeLibrary(driver->module); return FALSE; } } while(0) 94 LDFC(GetPriority); 95 LDFC(GetEndpointIDs); 96 LDFC(GetAudioEndpoint); 97 LDFC(GetAudioSessionManager); 98 #undef LDFC 99 100 /* optional - do not fail if not found */ 101 driver->pGetPropValue = (void*)GetProcAddress(driver->module, "GetPropValue"); 102 103 driver->priority = driver->pGetPriority(); 104 lstrcpyW(driver->module_name, driver_module); 105 106 TRACE("Successfully loaded %s with priority %s\n", 107 wine_dbgstr_w(driver_module), get_priority_string(driver->priority)); 108 109 return TRUE; 110 } 111 112 static BOOL WINAPI init_driver(INIT_ONCE *once, void *param, void **context) 113 { 114 static const WCHAR drv_value[] = {'A','u','d','i','o',0}; 115 116 static WCHAR default_list[] = {'p','u','l','s','e',',','a','l','s','a',',','o','s','s',',', 117 'c','o','r','e','a','u','d','i','o',',','a','n','d','r','o','i','d',0}; 118 119 DriverFuncs driver; 120 HKEY key; 121 WCHAR reg_list[256], *p, *next, *driver_list = default_list; 122 123 if(RegOpenKeyW(HKEY_CURRENT_USER, drv_keyW, &key) == ERROR_SUCCESS){ 124 DWORD size = sizeof(reg_list); 125 126 if(RegQueryValueExW(key, drv_value, 0, NULL, (BYTE*)reg_list, 127 &size) == ERROR_SUCCESS){ 128 if(reg_list[0] == '\0'){ 129 TRACE("User explicitly chose no driver\n"); 130 RegCloseKey(key); 131 return TRUE; 132 } 133 134 driver_list = reg_list; 135 } 136 137 RegCloseKey(key); 138 } 139 140 TRACE("Loading driver list %s\n", wine_dbgstr_w(driver_list)); 141 for(next = p = driver_list; next; p = next + 1){ 142 next = strchrW(p, ','); 143 if(next) 144 *next = '\0'; 145 146 driver.priority = Priority_Unavailable; 147 if(load_driver(p, &driver)){ 148 if(driver.priority == Priority_Unavailable) 149 FreeLibrary(driver.module); 150 else if(!drvs.module || driver.priority > drvs.priority){ 151 TRACE("Selecting driver %s with priority %s\n", 152 wine_dbgstr_w(p), get_priority_string(driver.priority)); 153 if(drvs.module) 154 FreeLibrary(drvs.module); 155 drvs = driver; 156 }else 157 FreeLibrary(driver.module); 158 }else 159 TRACE("Failed to load driver %s\n", wine_dbgstr_w(p)); 160 161 if(next) 162 *next = ','; 163 } 164 165 return drvs.module != 0; 166 } 167 168 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 169 { 170 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); 171 172 switch (fdwReason) 173 { 174 case DLL_PROCESS_ATTACH: 175 instance = hinstDLL; 176 DisableThreadLibraryCalls(hinstDLL); 177 break; 178 case DLL_PROCESS_DETACH: 179 if(lpvReserved) 180 break; 181 MMDevEnum_Free(); 182 break; 183 } 184 185 return TRUE; 186 } 187 188 HRESULT WINAPI DllCanUnloadNow(void) 189 { 190 return S_FALSE; 191 } 192 193 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj); 194 195 typedef struct { 196 IClassFactory IClassFactory_iface; 197 REFCLSID rclsid; 198 FnCreateInstance pfnCreateInstance; 199 } IClassFactoryImpl; 200 201 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) 202 { 203 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); 204 } 205 206 static HRESULT WINAPI 207 MMCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj) 208 { 209 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 210 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj); 211 if (ppobj == NULL) 212 return E_POINTER; 213 if (IsEqualIID(riid, &IID_IUnknown) || 214 IsEqualIID(riid, &IID_IClassFactory)) 215 { 216 *ppobj = iface; 217 IClassFactory_AddRef(iface); 218 return S_OK; 219 } 220 *ppobj = NULL; 221 return E_NOINTERFACE; 222 } 223 224 static ULONG WINAPI MMCF_AddRef(LPCLASSFACTORY iface) 225 { 226 return 2; 227 } 228 229 static ULONG WINAPI MMCF_Release(LPCLASSFACTORY iface) 230 { 231 /* static class, won't be freed */ 232 return 1; 233 } 234 235 static HRESULT WINAPI MMCF_CreateInstance( 236 LPCLASSFACTORY iface, 237 LPUNKNOWN pOuter, 238 REFIID riid, 239 LPVOID *ppobj) 240 { 241 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 242 TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj); 243 244 if (pOuter) 245 return CLASS_E_NOAGGREGATION; 246 247 if (ppobj == NULL) { 248 WARN("invalid parameter\n"); 249 return E_POINTER; 250 } 251 *ppobj = NULL; 252 return This->pfnCreateInstance(riid, ppobj); 253 } 254 255 static HRESULT WINAPI MMCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) 256 { 257 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 258 FIXME("(%p, %d) stub!\n", This, dolock); 259 return S_OK; 260 } 261 262 static const IClassFactoryVtbl MMCF_Vtbl = { 263 MMCF_QueryInterface, 264 MMCF_AddRef, 265 MMCF_Release, 266 MMCF_CreateInstance, 267 MMCF_LockServer 268 }; 269 270 static IClassFactoryImpl MMDEVAPI_CF[] = { 271 { { &MMCF_Vtbl }, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create } 272 }; 273 274 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 275 { 276 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; 277 unsigned int i = 0; 278 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); 279 280 if(!InitOnceExecuteOnce(&init_once, init_driver, NULL, NULL)) { 281 ERR("Driver initialization failed\n"); 282 return E_FAIL; 283 } 284 285 if (ppv == NULL) { 286 WARN("invalid parameter\n"); 287 return E_INVALIDARG; 288 } 289 290 *ppv = NULL; 291 292 if (!IsEqualIID(riid, &IID_IClassFactory) && 293 !IsEqualIID(riid, &IID_IUnknown)) { 294 WARN("no interface for %s\n", debugstr_guid(riid)); 295 return E_NOINTERFACE; 296 } 297 298 for (i = 0; i < sizeof(MMDEVAPI_CF)/sizeof(MMDEVAPI_CF[0]); ++i) 299 { 300 if (IsEqualGUID(rclsid, MMDEVAPI_CF[i].rclsid)) { 301 IClassFactory_AddRef(&MMDEVAPI_CF[i].IClassFactory_iface); 302 *ppv = &MMDEVAPI_CF[i]; 303 return S_OK; 304 } 305 } 306 307 WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid), 308 debugstr_guid(riid), ppv); 309 return CLASS_E_CLASSNOTAVAILABLE; 310 } 311 312 /*********************************************************************** 313 * DllRegisterServer (MMDEVAPI.@) 314 */ 315 HRESULT WINAPI DllRegisterServer(void) 316 { 317 return __wine_register_resources( instance ); 318 } 319 320 /*********************************************************************** 321 * DllUnregisterServer (MMDEVAPI.@) 322 */ 323 HRESULT WINAPI DllUnregisterServer(void) 324 { 325 return __wine_unregister_resources( instance ); 326 } 327