main.c 8.6 KB
Newer Older
1 2
/*
 * Copyright 2009 Maarten Lankhorst
3
 * Copyright 2011 Andrew Eikum for CodeWeavers
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"
21
#include "wine/port.h"
22 23 24

#include <stdarg.h>

25
#define COBJMACROS
26 27
#include "windef.h"
#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 35
#include "propsys.h"
#include "propkeydef.h"
36
#include "mmdeviceapi.h"
37
#include "mmsystem.h"
38 39 40 41 42
#include "dsound.h"
#include "audioclient.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
#include "devpkey.h"
43
#include "winreg.h"
44

45
#include "mmdevapi.h"
46
#include "wine/debug.h"
47
#include "wine/unicode.h"
48

49 50
WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);

51
static HINSTANCE instance;
52

53
DriverFuncs drvs;
54

55 56 57
const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\\',
    'W','i','n','e','\\','D','r','i','v','e','r','s',0};

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
static const char *get_priority_string(int prio)
{
    switch(prio){
    case Priority_Unavailable:
        return "Unavailable";
    case Priority_Low:
        return "Low";
    case Priority_Neutral:
        return "Neutral";
    case Priority_Preferred:
        return "Preferred";
    }
    return "Invalid";
}

static BOOL load_driver(const WCHAR *name, DriverFuncs *driver)
74
{
75 76 77
    WCHAR driver_module[264];
    static const WCHAR wineW[] = {'w','i','n','e',0};
    static const WCHAR dotdrvW[] = {'.','d','r','v',0};
78

79 80 81
    lstrcpyW(driver_module, wineW);
    lstrcatW(driver_module, name);
    lstrcatW(driver_module, dotdrvW);
82

83
    TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module));
84

85 86
    driver->module = LoadLibraryW(driver_module);
    if(!driver->module){
87 88 89
        TRACE("Unable to load %s: %u\n", wine_dbgstr_w(driver_module),
                GetLastError());
        return FALSE;
90
    }
91

92 93 94
#define LDFC(n) do { driver->p##n = (void*)GetProcAddress(driver->module, #n);\
        if(!driver->p##n) { FreeLibrary(driver->module); return FALSE; } } while(0)
    LDFC(GetPriority);
95 96
    LDFC(GetEndpointIDs);
    LDFC(GetAudioEndpoint);
97
    LDFC(GetAudioSessionManager);
98 99
#undef LDFC

100 101 102 103 104
    driver->priority = driver->pGetPriority();
    lstrcpyW(driver->module_name, driver_module);

    TRACE("Successfully loaded %s with priority %s\n",
            wine_dbgstr_w(driver_module), get_priority_string(driver->priority));
105 106 107 108 109 110 111

    return TRUE;
}

static BOOL init_driver(void)
{
    static const WCHAR drv_value[] = {'A','u','d','i','o',0};
112 113 114 115 116

    static WCHAR default_list[] = {'a','l','s','a',',','o','s','s',',',
        'c','o','r','e','a','u','d','i','o',0};

    DriverFuncs driver;
117
    HKEY key;
118
    WCHAR reg_list[256], *p, *next, *driver_list = default_list;
119 120 121 122

    if(drvs.module)
        return TRUE;

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 129 130
            if(reg_list[0] == '\0'){
                TRACE("User explicitly chose no driver\n");
                RegCloseKey(key);
131
                return TRUE;
132 133
            }

134
            driver_list = reg_list;
135
        }
136 137

        RegCloseKey(key);
138 139
    }

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
    TRACE("Loading driver list %s\n", wine_dbgstr_w(driver_list));
    for(next = p = driver_list; next; p = next + 1){
        next = strchrW(p, ',');
        if(next)
            *next = '\0';

        driver.priority = Priority_Unavailable;
        if(load_driver(p, &driver)){
            if(driver.priority == Priority_Unavailable)
                FreeLibrary(driver.module);
            else if(!drvs.module || driver.priority > drvs.priority){
                TRACE("Selecting driver %s with priority %s\n",
                        wine_dbgstr_w(p), get_priority_string(driver.priority));
                if(drvs.module)
                    FreeLibrary(drvs.module);
                drvs = driver;
            }else
                FreeLibrary(driver.module);
        }else
            TRACE("Failed to load driver %s\n", wine_dbgstr_w(p));

        if(next)
            *next = ',';
    }
164

165
    return drvs.module != 0;
166
}
167

168 169 170 171 172 173 174
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);

    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
175
            instance = hinstDLL;
176 177 178
            DisableThreadLibraryCalls(hinstDLL);
            break;
        case DLL_PROCESS_DETACH:
179 180
            if(lpvReserved)
                break;
181
            MMDevEnum_Free();
182 183 184 185 186 187 188 189 190 191 192
            break;
    }

    return TRUE;
}

HRESULT WINAPI DllCanUnloadNow(void)
{
    return S_FALSE;
}

193 194 195
typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);

typedef struct {
196
    IClassFactory IClassFactory_iface;
197 198 199 200
    REFCLSID rclsid;
    FnCreateInstance pfnCreateInstance;
} IClassFactoryImpl;

201 202 203 204 205
static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
{
    return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
}

206
static HRESULT WINAPI
207
MMCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
208
{
209
    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
210 211 212 213 214 215 216
    TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
    if (ppobj == NULL)
        return E_POINTER;
    if (IsEqualIID(riid, &IID_IUnknown) ||
        IsEqualIID(riid, &IID_IClassFactory))
    {
        *ppobj = iface;
217
        IClassFactory_AddRef(iface);
218 219 220
        return S_OK;
    }
    *ppobj = NULL;
221 222
    return E_NOINTERFACE;
}
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240

static ULONG WINAPI MMCF_AddRef(LPCLASSFACTORY iface)
{
    return 2;
}

static ULONG WINAPI MMCF_Release(LPCLASSFACTORY iface)
{
    /* static class, won't be freed */
    return 1;
}

static HRESULT WINAPI MMCF_CreateInstance(
    LPCLASSFACTORY iface,
    LPUNKNOWN pOuter,
    REFIID riid,
    LPVOID *ppobj)
{
241
    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);

    if (pOuter)
        return CLASS_E_NOAGGREGATION;

    if (ppobj == NULL) {
        WARN("invalid parameter\n");
        return E_POINTER;
    }
    *ppobj = NULL;
    return This->pfnCreateInstance(riid, ppobj);
}

static HRESULT WINAPI MMCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
{
257
    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
258 259 260 261 262 263 264 265 266 267 268 269 270
    FIXME("(%p, %d) stub!\n", This, dolock);
    return S_OK;
}

static const IClassFactoryVtbl MMCF_Vtbl = {
    MMCF_QueryInterface,
    MMCF_AddRef,
    MMCF_Release,
    MMCF_CreateInstance,
    MMCF_LockServer
};

static IClassFactoryImpl MMDEVAPI_CF[] = {
271
    { { &MMCF_Vtbl }, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create }
272 273 274 275
};

HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
276
    unsigned int i = 0;
277 278
    TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);

279 280 281 282 283
    if(!init_driver()){
        ERR("Driver initialization failed\n");
        return E_FAIL;
    }

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    if (ppv == NULL) {
        WARN("invalid parameter\n");
        return E_INVALIDARG;
    }

    *ppv = NULL;

    if (!IsEqualIID(riid, &IID_IClassFactory) &&
        !IsEqualIID(riid, &IID_IUnknown)) {
        WARN("no interface for %s\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }

    for (i = 0; i < sizeof(MMDEVAPI_CF)/sizeof(MMDEVAPI_CF[0]); ++i)
    {
        if (IsEqualGUID(rclsid, MMDEVAPI_CF[i].rclsid)) {
300
            IClassFactory_AddRef(&MMDEVAPI_CF[i].IClassFactory_iface);
301 302 303 304 305 306 307 308 309 310
            *ppv = &MMDEVAPI_CF[i];
            return S_OK;
        }
        i++;
    }

    WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid),
         debugstr_guid(riid), ppv);
    return CLASS_E_CLASSNOTAVAILABLE;
}
311 312 313 314 315 316

/***********************************************************************
 *		DllRegisterServer (MMDEVAPI.@)
 */
HRESULT WINAPI DllRegisterServer(void)
{
317
    return __wine_register_resources( instance );
318 319 320 321 322 323 324
}

/***********************************************************************
 *		DllUnregisterServer (MMDEVAPI.@)
 */
HRESULT WINAPI DllUnregisterServer(void)
{
325
    return __wine_unregister_resources( instance );
326
}