1
0
mirror of https://github.com/wine-mirror/wine synced 2024-07-01 07:14:31 +00:00
wine/dlls/wineoss.drv/mmdevdrv.c
2023-11-22 22:34:13 +01:00

209 lines
5.6 KiB
C

/*
* Copyright 2011 Andrew Eikum for CodeWeavers
* 2022 Huw Davies
*
* 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
*/
#define COBJMACROS
#include <stdarg.h>
#include <wchar.h>
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
#include "winnls.h"
#include "winreg.h"
#include "ole2.h"
#include "mmdeviceapi.h"
#include "devpkey.h"
#include "dshow.h"
#include "dsound.h"
#include "initguid.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
#include "audioclient.h"
#include "wine/debug.h"
#include "wine/list.h"
#include "wine/unixlib.h"
#include "unixlib.h"
#include "../mmdevapi/mmdevdrv.h"
WINE_DEFAULT_DEBUG_CHANNEL(oss);
typedef struct _OSSDevice {
struct list entry;
EDataFlow flow;
GUID guid;
char devnode[0];
} OSSDevice;
static struct list g_devices = LIST_INIT(g_devices);
static WCHAR drv_key_devicesW[256];
static const WCHAR guidW[] = {'g','u','i','d',0};
BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
{
WCHAR buf[MAX_PATH];
WCHAR *filename;
if(__wine_init_unix_call()) return FALSE;
GetModuleFileNameW(dll, buf, ARRAY_SIZE(buf));
filename = wcsrchr(buf, '\\');
filename = filename ? filename + 1 : buf;
swprintf(drv_key_devicesW, ARRAY_SIZE(drv_key_devicesW),
L"Software\\Wine\\Drivers\\%s\\devices", filename);
break;
}
case DLL_PROCESS_DETACH:
if (!reserved)
{
OSSDevice *iter, *iter2;
LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &g_devices, OSSDevice, entry){
HeapFree(GetProcessHeap(), 0, iter);
}
}
break;
}
return TRUE;
}
static void device_add(OSSDevice *oss_dev)
{
OSSDevice *dev_item;
LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry)
if(IsEqualGUID(&oss_dev->guid, &dev_item->guid)){ /* already in list */
HeapFree(GetProcessHeap(), 0, oss_dev);
return;
}
list_add_tail(&g_devices, &oss_dev->entry);
}
static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
GUID *guid)
{
HKEY key;
BOOL opened = FALSE;
LONG lr;
if(!drv_key){
lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
NULL, &drv_key, NULL);
if(lr != ERROR_SUCCESS){
ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
return;
}
opened = TRUE;
}
lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
NULL, &key, NULL);
if(lr != ERROR_SUCCESS){
ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
goto exit;
}
lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
sizeof(GUID));
if(lr != ERROR_SUCCESS)
ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
RegCloseKey(key);
exit:
if(opened)
RegCloseKey(drv_key);
}
void WINAPI get_device_guid(EDataFlow flow, const char *device, GUID *guid)
{
OSSDevice *oss_dev;
HKEY key = NULL, dev_key;
DWORD type, size = sizeof(*guid);
WCHAR key_name[256];
const unsigned int dev_size = strlen(device) + 1;
if(flow == eCapture)
key_name[0] = '1';
else
key_name[0] = '0';
key_name[1] = ',';
MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
if(RegQueryValueExW(dev_key, guidW, 0, &type,
(BYTE*)guid, &size) == ERROR_SUCCESS){
if(type == REG_BINARY){
RegCloseKey(dev_key);
RegCloseKey(key);
goto exit;
}
ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
wine_dbgstr_w(key_name), type);
}
RegCloseKey(dev_key);
}
}
CoCreateGuid(guid);
set_device_guid(flow, key, key_name, guid);
exit:
if(key)
RegCloseKey(key);
oss_dev = HeapAlloc(GetProcessHeap(), 0, offsetof(OSSDevice, devnode[dev_size]));
if(oss_dev){
oss_dev->flow = flow;
oss_dev->guid = *guid;
memcpy(oss_dev->devnode, device, dev_size);
device_add(oss_dev);
}
}
BOOL WINAPI get_device_name_from_guid(GUID *guid, char **name, EDataFlow *flow)
{
OSSDevice *dev_item;
LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry){
if(!IsEqualGUID(guid, &dev_item->guid))
continue;
if(!(*name = strdup(dev_item->devnode)))
return FALSE;
*flow = dev_item->flow;
return TRUE;
}
return FALSE;
}