wine/dlls/mmdevapi/main.c
2011-04-25 17:24:50 +02:00

279 lines
7.3 KiB
C

/*
* Copyright 2009 Maarten Lankhorst
* Copyright 2011 Andrew Eikum for CodeWeavers
*
* 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"
#include "wine/port.h"
#include <stdarg.h>
#define COBJMACROS
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "wine/library.h"
#include "ole2.h"
#include "olectl.h"
#include "rpcproxy.h"
#include "propsys.h"
#include "initguid.h"
#include "propkeydef.h"
#include "mmdeviceapi.h"
#include "dshow.h"
#include "dsound.h"
#include "audioclient.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
#include "devpkey.h"
#include "winreg.h"
#include "mmdevapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
static HINSTANCE instance;
DriverFuncs drvs;
static BOOL load_driver(const WCHAR *name)
{
WCHAR driver_module[264];
static const WCHAR wineW[] = {'w','i','n','e',0};
static const WCHAR dotdrvW[] = {'.','d','r','v',0};
lstrcpyW(driver_module, wineW);
lstrcatW(driver_module, name);
lstrcatW(driver_module, dotdrvW);
TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module));
drvs.module = LoadLibraryW(driver_module);
if(!drvs.module){
TRACE("Unable to load %s: %u\n", wine_dbgstr_w(driver_module),
GetLastError());
return FALSE;
}
#define LDFC(n) do { drvs.p##n = (void*)GetProcAddress(drvs.module, #n);\
if(!drvs.p##n) return FALSE; } while(0);
LDFC(GetEndpointIDs);
LDFC(GetAudioEndpoint);
#undef LDFC
TRACE("Successfully loaded %s\n", wine_dbgstr_w(driver_module));
return TRUE;
}
static BOOL init_driver(void)
{
static const WCHAR alsaW[] = {'a','l','s','a',0};
static const WCHAR ossW[] = {'o','s','s',0};
static const WCHAR coreaudioW[] = {'c','o','r','e','a','u','d','i','o',0};
static const WCHAR *default_drivers[] = { alsaW, coreaudioW, ossW };
static const WCHAR drv_key[] = {'S','o','f','t','w','a','r','e','\\',
'W','i','n','e','\\','D','r','i','v','e','r','s',0};
static const WCHAR drv_value[] = {'A','u','d','i','o',0};
HKEY key;
UINT i;
if(drvs.module)
return TRUE;
if(RegOpenKeyW(HKEY_CURRENT_USER, drv_key, &key) == ERROR_SUCCESS){
WCHAR driver_name[256];
DWORD size = sizeof(driver_name);
if(RegQueryValueExW(key, drv_value, 0, NULL, (BYTE*)driver_name,
&size) == ERROR_SUCCESS){
BOOL ret = load_driver(driver_name);
RegCloseKey(key);
if(!ret)
ERR("Failed to load driver: %s\n", wine_dbgstr_w(driver_name));
return ret;
}
RegCloseKey(key);
}
for(i = 0; i < sizeof(default_drivers)/sizeof(*default_drivers); ++i)
if(load_driver(default_drivers[i]))
return TRUE;
return FALSE;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
instance = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
break;
case DLL_PROCESS_DETACH:
MMDevEnum_Free();
break;
}
return TRUE;
}
HRESULT WINAPI DllCanUnloadNow(void)
{
return S_FALSE;
}
typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
typedef struct {
IClassFactory IClassFactory_iface;
REFCLSID rclsid;
FnCreateInstance pfnCreateInstance;
} IClassFactoryImpl;
static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
{
return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
}
static HRESULT WINAPI
MMCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj)
{
IClassFactoryImpl *This = impl_from_IClassFactory(iface);
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;
IUnknown_AddRef(iface);
return S_OK;
}
*ppobj = NULL;
return E_NOINTERFACE;
}
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)
{
IClassFactoryImpl *This = impl_from_IClassFactory(iface);
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)
{
IClassFactoryImpl *This = impl_from_IClassFactory(iface);
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[] = {
{ { &MMCF_Vtbl }, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create }
};
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
int i = 0;
TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
if(!init_driver()){
ERR("Driver initialization failed\n");
return E_FAIL;
}
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)) {
IUnknown_AddRef(&MMDEVAPI_CF[i].IClassFactory_iface);
*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;
}
/***********************************************************************
* DllRegisterServer (MMDEVAPI.@)
*/
HRESULT WINAPI DllRegisterServer(void)
{
return __wine_register_resources( instance, NULL );
}
/***********************************************************************
* DllUnregisterServer (MMDEVAPI.@)
*/
HRESULT WINAPI DllUnregisterServer(void)
{
return __wine_unregister_resources( instance, NULL );
}