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