diff --git a/reactos/dll/win32/CMakeLists.txt b/reactos/dll/win32/CMakeLists.txt index ce9b521caef..f8e5d37d179 100644 --- a/reactos/dll/win32/CMakeLists.txt +++ b/reactos/dll/win32/CMakeLists.txt @@ -82,6 +82,7 @@ add_subdirectory(mciqtz32) add_subdirectory(mciseq) add_subdirectory(mciwave) add_subdirectory(mlang) +add_subdirectory(mmdevapi) add_subdirectory(mmdrv) add_subdirectory(modemui) add_subdirectory(mpr) diff --git a/reactos/dll/win32/mmdevapi/CMakeLists.txt b/reactos/dll/win32/mmdevapi/CMakeLists.txt new file mode 100644 index 00000000000..70a28de6845 --- /dev/null +++ b/reactos/dll/win32/mmdevapi/CMakeLists.txt @@ -0,0 +1,20 @@ + +remove_definitions(-D_WIN32_WINNT=0x502) +add_definitions(-D_WIN32_WINNT=0x600) + +add_definitions(-D__WINESRC__) +include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine) +spec2def(mmdevapi.dll mmdevapi.spec ADD_IMPORTLIB) + +list(APPEND SOURCE + audiovolume.c + devenum.c + main.c + ${CMAKE_CURRENT_BINARY_DIR}/mmdevapi_stubs.c + ${CMAKE_CURRENT_BINARY_DIR}/mmdevapi.def) + +add_library(mmdevapi SHARED ${SOURCE} mmdevapi.rc) +set_module_type(mmdevapi win32dll) +target_link_libraries(mmdevapi uuid wine) +add_importlibs(mmdevapi ole32 oleaut32 user32 advapi32 msvcrt kernel32 ntdll) +add_cd_file(TARGET mmdevapi DESTINATION reactos/system32 FOR all) diff --git a/reactos/dll/win32/mmdevapi/audiovolume.c b/reactos/dll/win32/mmdevapi/audiovolume.c new file mode 100644 index 00000000000..4cc3226be78 --- /dev/null +++ b/reactos/dll/win32/mmdevapi/audiovolume.c @@ -0,0 +1,290 @@ +/* + * Copyright 2010 Maarten Lankhorst 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 + */ + + +#define NONAMELESSUNION +#define COBJMACROS +#include "config.h" + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "ole2.h" +#include "mmdeviceapi.h" +#include "mmsystem.h" +#include "dsound.h" +#include "audioclient.h" +#include "endpointvolume.h" +#include "audiopolicy.h" + +#include "mmdevapi.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); + +static const IAudioEndpointVolumeExVtbl AEVImpl_Vtbl; + +typedef struct AEVImpl { + IAudioEndpointVolumeEx IAudioEndpointVolumeEx_iface; + LONG ref; +} AEVImpl; + +static inline AEVImpl *impl_from_IAudioEndpointVolumeEx(IAudioEndpointVolumeEx *iface) +{ + return CONTAINING_RECORD(iface, AEVImpl, IAudioEndpointVolumeEx_iface); +} + +HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolume **ppv) +{ + AEVImpl *This; + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); + *ppv = (IAudioEndpointVolume*)This; + if (!This) + return E_OUTOFMEMORY; + This->IAudioEndpointVolumeEx_iface.lpVtbl = &AEVImpl_Vtbl; + This->ref = 1; + return S_OK; +} + +static void AudioEndpointVolume_Destroy(AEVImpl *This) +{ + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT WINAPI AEV_QueryInterface(IAudioEndpointVolumeEx *iface, REFIID riid, void **ppv) +{ + AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv); + if (!ppv) + return E_POINTER; + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IAudioEndpointVolume) || + IsEqualIID(riid, &IID_IAudioEndpointVolumeEx)) { + *ppv = This; + } + else + return E_NOINTERFACE; + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; +} + +static ULONG WINAPI AEV_AddRef(IAudioEndpointVolumeEx *iface) +{ + AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) new ref %u\n", This, ref); + return ref; +} + +static ULONG WINAPI AEV_Release(IAudioEndpointVolumeEx *iface) +{ + AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); + ULONG ref = InterlockedDecrement(&This->ref); + TRACE("(%p) new ref %u\n", This, ref); + if (!ref) + AudioEndpointVolume_Destroy(This); + return ref; +} + +static HRESULT WINAPI AEV_RegisterControlChangeNotify(IAudioEndpointVolumeEx *iface, IAudioEndpointVolumeCallback *notify) +{ + TRACE("(%p)->(%p)\n", iface, notify); + if (!notify) + return E_POINTER; + FIXME("stub\n"); + return S_OK; +} + +static HRESULT WINAPI AEV_UnregisterControlChangeNotify(IAudioEndpointVolumeEx *iface, IAudioEndpointVolumeCallback *notify) +{ + TRACE("(%p)->(%p)\n", iface, notify); + if (!notify) + return E_POINTER; + FIXME("stub\n"); + return S_OK; +} + +static HRESULT WINAPI AEV_GetChannelCount(IAudioEndpointVolumeEx *iface, UINT *count) +{ + TRACE("(%p)->(%p)\n", iface, count); + if (!count) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_SetMasterVolumeLevel(IAudioEndpointVolumeEx *iface, float leveldb, const GUID *ctx) +{ + TRACE("(%p)->(%f,%s)\n", iface, leveldb, debugstr_guid(ctx)); + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_SetMasterVolumeLevelScalar(IAudioEndpointVolumeEx *iface, float level, const GUID *ctx) +{ + TRACE("(%p)->(%f,%s)\n", iface, level, debugstr_guid(ctx)); + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetMasterVolumeLevel(IAudioEndpointVolumeEx *iface, float *leveldb) +{ + TRACE("(%p)->(%p)\n", iface, leveldb); + if (!leveldb) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetMasterVolumeLevelScalar(IAudioEndpointVolumeEx *iface, float *level) +{ + TRACE("(%p)->(%p)\n", iface, level); + if (!level) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_SetChannelVolumeLevel(IAudioEndpointVolumeEx *iface, UINT chan, float leveldb, const GUID *ctx) +{ + TRACE("(%p)->(%f,%s)\n", iface, leveldb, debugstr_guid(ctx)); + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_SetChannelVolumeLevelScalar(IAudioEndpointVolumeEx *iface, UINT chan, float level, const GUID *ctx) +{ + TRACE("(%p)->(%u,%f,%s)\n", iface, chan, level, debugstr_guid(ctx)); + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetChannelVolumeLevel(IAudioEndpointVolumeEx *iface, UINT chan, float *leveldb) +{ + TRACE("(%p)->(%u,%p)\n", iface, chan, leveldb); + if (!leveldb) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetChannelVolumeLevelScalar(IAudioEndpointVolumeEx *iface, UINT chan, float *level) +{ + TRACE("(%p)->(%u,%p)\n", iface, chan, level); + if (!level) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_SetMute(IAudioEndpointVolumeEx *iface, BOOL mute, const GUID *ctx) +{ + TRACE("(%p)->(%u,%s)\n", iface, mute, debugstr_guid(ctx)); + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetMute(IAudioEndpointVolumeEx *iface, BOOL *mute) +{ + TRACE("(%p)->(%p)\n", iface, mute); + if (!mute) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetVolumeStepInfo(IAudioEndpointVolumeEx *iface, UINT *stepsize, UINT *stepcount) +{ + TRACE("(%p)->(%p,%p)\n", iface, stepsize, stepcount); + if (!stepsize && !stepcount) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_VolumeStepUp(IAudioEndpointVolumeEx *iface, const GUID *ctx) +{ + TRACE("(%p)->(%s)\n", iface, debugstr_guid(ctx)); + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_VolumeStepDown(IAudioEndpointVolumeEx *iface, const GUID *ctx) +{ + TRACE("(%p)->(%s)\n", iface, debugstr_guid(ctx)); + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_QueryHardwareSupport(IAudioEndpointVolumeEx *iface, DWORD *mask) +{ + TRACE("(%p)->(%p)\n", iface, mask); + if (!mask) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetVolumeRange(IAudioEndpointVolumeEx *iface, float *mindb, float *maxdb, float *inc) +{ + TRACE("(%p)->(%p,%p,%p)\n", iface, mindb, maxdb, inc); + if (!mindb || !maxdb || !inc) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI AEV_GetVolumeRangeChannel(IAudioEndpointVolumeEx *iface, UINT chan, float *mindb, float *maxdb, float *inc) +{ + TRACE("(%p)->(%p,%p,%p)\n", iface, mindb, maxdb, inc); + if (!mindb || !maxdb || !inc) + return E_POINTER; + FIXME("stub\n"); + return E_NOTIMPL; +} + +static const IAudioEndpointVolumeExVtbl AEVImpl_Vtbl = { + AEV_QueryInterface, + AEV_AddRef, + AEV_Release, + AEV_RegisterControlChangeNotify, + AEV_UnregisterControlChangeNotify, + AEV_GetChannelCount, + AEV_SetMasterVolumeLevel, + AEV_SetMasterVolumeLevelScalar, + AEV_GetMasterVolumeLevel, + AEV_GetMasterVolumeLevelScalar, + AEV_SetChannelVolumeLevel, + AEV_SetChannelVolumeLevelScalar, + AEV_GetChannelVolumeLevel, + AEV_GetChannelVolumeLevelScalar, + AEV_SetMute, + AEV_GetMute, + AEV_GetVolumeStepInfo, + AEV_VolumeStepUp, + AEV_VolumeStepDown, + AEV_QueryHardwareSupport, + AEV_GetVolumeRange, + AEV_GetVolumeRangeChannel +}; diff --git a/reactos/dll/win32/mmdevapi/devenum.c b/reactos/dll/win32/mmdevapi/devenum.c new file mode 100644 index 00000000000..eebf4ed839c --- /dev/null +++ b/reactos/dll/win32/mmdevapi/devenum.c @@ -0,0 +1,1574 @@ +/* + * Copyright 2009 Maarten Lankhorst + * + * 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 + +#define NONAMELESSUNION +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "wine/unicode.h" + +#include "initguid.h" +#include "ole2.h" +#include "mmdeviceapi.h" +#include "dshow.h" +#include "dsound.h" +#include "audioclient.h" +#include "endpointvolume.h" +#include "audiopolicy.h" + +#include "mmdevapi.h" +#include "devpkey.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); + +static const WCHAR software_mmdevapi[] = + { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'M','M','D','e','v','i','c','e','s','\\', + 'A','u','d','i','o',0}; +static const WCHAR reg_render[] = + { 'R','e','n','d','e','r',0 }; +static const WCHAR reg_capture[] = + { 'C','a','p','t','u','r','e',0 }; +static const WCHAR reg_devicestate[] = + { 'D','e','v','i','c','e','S','t','a','t','e',0 }; +static const WCHAR reg_properties[] = + { 'P','r','o','p','e','r','t','i','e','s',0 }; +static const WCHAR slashW[] = {'\\',0}; +static const WCHAR reg_out_nameW[] = {'D','e','f','a','u','l','t','O','u','t','p','u','t',0}; +static const WCHAR reg_vout_nameW[] = {'D','e','f','a','u','l','t','V','o','i','c','e','O','u','t','p','u','t',0}; +static const WCHAR reg_in_nameW[] = {'D','e','f','a','u','l','t','I','n','p','u','t',0}; +static const WCHAR reg_vin_nameW[] = {'D','e','f','a','u','l','t','V','o','i','c','e','I','n','p','u','t',0}; + +static HKEY key_render; +static HKEY key_capture; + +typedef struct MMDevPropStoreImpl +{ + IPropertyStore IPropertyStore_iface; + LONG ref; + MMDevice *parent; + DWORD access; +} MMDevPropStore; + +typedef struct MMDevEnumImpl +{ + IMMDeviceEnumerator IMMDeviceEnumerator_iface; + LONG ref; +} MMDevEnumImpl; + +static MMDevEnumImpl *MMDevEnumerator; +static MMDevice **MMDevice_head; +static MMDevice *MMDevice_def_rec, *MMDevice_def_play; +static DWORD MMDevice_count; +static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl; +static const IMMDeviceCollectionVtbl MMDevColVtbl; +static const IMMDeviceVtbl MMDeviceVtbl; +static const IPropertyStoreVtbl MMDevPropVtbl; +static const IMMEndpointVtbl MMEndpointVtbl; + +static IMMDevice info_device; + +typedef struct MMDevColImpl +{ + IMMDeviceCollection IMMDeviceCollection_iface; + LONG ref; + EDataFlow flow; + DWORD state; +} MMDevColImpl; + +typedef struct IPropertyBagImpl { + IPropertyBag IPropertyBag_iface; + GUID devguid; +} IPropertyBagImpl; + +static const IPropertyBagVtbl PB_Vtbl; + +static HRESULT MMDevPropStore_Create(MMDevice *This, DWORD access, IPropertyStore **ppv); + +static inline MMDevPropStore *impl_from_IPropertyStore(IPropertyStore *iface) +{ + return CONTAINING_RECORD(iface, MMDevPropStore, IPropertyStore_iface); +} + +static inline MMDevEnumImpl *impl_from_IMMDeviceEnumerator(IMMDeviceEnumerator *iface) +{ + return CONTAINING_RECORD(iface, MMDevEnumImpl, IMMDeviceEnumerator_iface); +} + +static inline MMDevColImpl *impl_from_IMMDeviceCollection(IMMDeviceCollection *iface) +{ + return CONTAINING_RECORD(iface, MMDevColImpl, IMMDeviceCollection_iface); +} + +static inline IPropertyBagImpl *impl_from_IPropertyBag(IPropertyBag *iface) +{ + return CONTAINING_RECORD(iface, IPropertyBagImpl, IPropertyBag_iface); +} + +static const WCHAR propkey_formatW[] = { + '{','%','0','8','X','-','%','0','4','X','-', + '%','0','4','X','-','%','0','2','X','%','0','2','X','-', + '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X', + '%','0','2','X','%','0','2','X','}',',','%','d',0 }; + +static HRESULT MMDevPropStore_OpenPropKey(const GUID *guid, DWORD flow, HKEY *propkey) +{ + WCHAR buffer[39]; + LONG ret; + HKEY key; + StringFromGUID2(guid, buffer, 39); + if ((ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, buffer, 0, KEY_READ|KEY_WRITE, &key)) != ERROR_SUCCESS) + { + WARN("Opening key %s failed with %u\n", debugstr_w(buffer), ret); + return E_FAIL; + } + ret = RegOpenKeyExW(key, reg_properties, 0, KEY_READ|KEY_WRITE, propkey); + RegCloseKey(key); + if (ret != ERROR_SUCCESS) + { + WARN("Opening key %s failed with %u\n", debugstr_w(reg_properties), ret); + return E_FAIL; + } + return S_OK; +} + +static HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv) +{ + WCHAR buffer[80]; + const GUID *id = &key->fmtid; + DWORD type, size; + HRESULT hr = S_OK; + HKEY regkey; + LONG ret; + + hr = MMDevPropStore_OpenPropKey(devguid, flow, ®key); + if (FAILED(hr)) + return hr; + wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3, + id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], + id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid ); + ret = RegGetValueW(regkey, NULL, buffer, RRF_RT_ANY, &type, NULL, &size); + if (ret != ERROR_SUCCESS) + { + WARN("Reading %s returned %d\n", debugstr_w(buffer), ret); + RegCloseKey(regkey); + PropVariantClear(pv); + return S_OK; + } + + switch (type) + { + case REG_SZ: + { + pv->vt = VT_LPWSTR; + pv->u.pwszVal = CoTaskMemAlloc(size); + if (!pv->u.pwszVal) + hr = E_OUTOFMEMORY; + else + RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_SZ, NULL, (BYTE*)pv->u.pwszVal, &size); + break; + } + case REG_DWORD: + { + pv->vt = VT_UI4; + RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_DWORD, NULL, (BYTE*)&pv->u.ulVal, &size); + break; + } + case REG_BINARY: + { + pv->vt = VT_BLOB; + pv->u.blob.cbSize = size; + pv->u.blob.pBlobData = CoTaskMemAlloc(size); + if (!pv->u.blob.pBlobData) + hr = E_OUTOFMEMORY; + else + RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, (BYTE*)pv->u.blob.pBlobData, &size); + break; + } + default: + ERR("Unknown/unhandled type: %u\n", type); + PropVariantClear(pv); + break; + } + RegCloseKey(regkey); + return hr; +} + +static HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, REFPROPVARIANT pv) +{ + WCHAR buffer[80]; + const GUID *id = &key->fmtid; + HRESULT hr; + HKEY regkey; + LONG ret; + + hr = MMDevPropStore_OpenPropKey(devguid, flow, ®key); + if (FAILED(hr)) + return hr; + wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3, + id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], + id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid ); + switch (pv->vt) + { + case VT_UI4: + { + ret = RegSetValueExW(regkey, buffer, 0, REG_DWORD, (const BYTE*)&pv->u.ulVal, sizeof(DWORD)); + break; + } + case VT_BLOB: + { + ret = RegSetValueExW(regkey, buffer, 0, REG_BINARY, pv->u.blob.pBlobData, pv->u.blob.cbSize); + TRACE("Blob %p %u\n", pv->u.blob.pBlobData, pv->u.blob.cbSize); + + break; + } + case VT_LPWSTR: + { + ret = RegSetValueExW(regkey, buffer, 0, REG_SZ, (const BYTE*)pv->u.pwszVal, sizeof(WCHAR)*(1+lstrlenW(pv->u.pwszVal))); + break; + } + default: + ret = 0; + FIXME("Unhandled type %u\n", pv->vt); + hr = E_INVALIDARG; + break; + } + RegCloseKey(regkey); + TRACE("Writing %s returned %u\n", debugstr_w(buffer), ret); + return hr; +} + +/* Creates or updates the state of a device + * If GUID is null, a random guid will be assigned + * and the device will be created + */ +static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault) +{ + HKEY key, root; + MMDevice *cur = NULL; + WCHAR guidstr[39]; + DWORD i; + + static const PROPERTYKEY deviceinterface_key = { + {0x233164c8, 0x1b2c, 0x4c7d, {0xbc, 0x68, 0xb6, 0x71, 0x68, 0x7a, 0x25, 0x67}}, 1 + }; + + for (i = 0; i < MMDevice_count; ++i) + { + MMDevice *device = MMDevice_head[i]; + if (device->flow == flow && IsEqualGUID(&device->devguid, id)){ + cur = device; + break; + } + } + + if(!cur){ + /* No device found, allocate new one */ + cur = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cur)); + if (!cur) + return NULL; + + cur->IMMDevice_iface.lpVtbl = &MMDeviceVtbl; + cur->IMMEndpoint_iface.lpVtbl = &MMEndpointVtbl; + + InitializeCriticalSection(&cur->crst); + cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst"); + + if (!MMDevice_head) + MMDevice_head = HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head)); + else + MMDevice_head = HeapReAlloc(GetProcessHeap(), 0, MMDevice_head, sizeof(*MMDevice_head)*(1+MMDevice_count)); + MMDevice_head[MMDevice_count++] = cur; + }else if(cur->ref > 0) + WARN("Modifying an MMDevice with postitive reference count!\n"); + + HeapFree(GetProcessHeap(), 0, cur->drv_id); + cur->drv_id = name; + + cur->flow = flow; + cur->state = state; + cur->devguid = *id; + + StringFromGUID2(&cur->devguid, guidstr, sizeof(guidstr)/sizeof(*guidstr)); + + if (flow == eRender) + root = key_render; + else + root = key_capture; + + if (RegCreateKeyExW(root, guidstr, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &key, NULL) == ERROR_SUCCESS) + { + HKEY keyprop; + RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD)); + if (!RegCreateKeyExW(key, reg_properties, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &keyprop, NULL)) + { + PROPVARIANT pv; + + pv.vt = VT_LPWSTR; + pv.u.pwszVal = name; + MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv); + + pv.u.pwszVal = guidstr; + MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv); + + RegCloseKey(keyprop); + } + RegCloseKey(key); + } + + if (setdefault) + { + if (flow == eRender) + MMDevice_def_play = cur; + else + MMDevice_def_rec = cur; + } + return cur; +} + +static HRESULT load_devices_from_reg(void) +{ + DWORD i = 0; + HKEY root, cur; + LONG ret; + DWORD curflow; + + ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &root, NULL); + if (ret == ERROR_SUCCESS) + ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_capture, NULL); + if (ret == ERROR_SUCCESS) + ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_render, NULL); + RegCloseKey(root); + cur = key_capture; + curflow = eCapture; + if (ret != ERROR_SUCCESS) + { + RegCloseKey(key_capture); + key_render = key_capture = NULL; + WARN("Couldn't create key: %u\n", ret); + return E_FAIL; + } + + do { + WCHAR guidvalue[39]; + GUID guid; + DWORD len; + PROPVARIANT pv = { VT_EMPTY }; + + len = sizeof(guidvalue)/sizeof(guidvalue[0]); + ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL); + if (ret == ERROR_NO_MORE_ITEMS) + { + if (cur == key_capture) + { + cur = key_render; + curflow = eRender; + i = 0; + continue; + } + break; + } + if (ret != ERROR_SUCCESS) + continue; + if (SUCCEEDED(CLSIDFromString(guidvalue, &guid)) + && SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv)) + && pv.vt == VT_LPWSTR) + { + DWORD size_bytes = (strlenW(pv.u.pwszVal) + 1) * sizeof(WCHAR); + WCHAR *name = HeapAlloc(GetProcessHeap(), 0, size_bytes); + memcpy(name, pv.u.pwszVal, size_bytes); + MMDevice_Create(name, &guid, curflow, + DEVICE_STATE_NOTPRESENT, FALSE); + CoTaskMemFree(pv.u.pwszVal); + } + } while (1); + + return S_OK; +} + +static HRESULT set_format(MMDevice *dev) +{ + HRESULT hr; + IAudioClient *client; + WAVEFORMATEX *fmt; + PROPVARIANT pv = { VT_EMPTY }; + + hr = drvs.pGetAudioEndpoint(&dev->devguid, &dev->IMMDevice_iface, &client); + if(FAILED(hr)) + return hr; + + hr = IAudioClient_GetMixFormat(client, &fmt); + if(FAILED(hr)){ + IAudioClient_Release(client); + return hr; + } + + IAudioClient_Release(client); + + pv.vt = VT_BLOB; + pv.u.blob.cbSize = sizeof(WAVEFORMATEX) + fmt->cbSize; + pv.u.blob.pBlobData = (BYTE*)fmt; + MMDevice_SetPropValue(&dev->devguid, dev->flow, + &PKEY_AudioEngine_DeviceFormat, &pv); + MMDevice_SetPropValue(&dev->devguid, dev->flow, + &PKEY_AudioEngine_OEMFormat, &pv); + + return S_OK; +} + +static HRESULT load_driver_devices(EDataFlow flow) +{ + WCHAR **ids; + GUID *guids; + UINT num, def, i; + HRESULT hr; + + if(!drvs.pGetEndpointIDs) + return S_OK; + + hr = drvs.pGetEndpointIDs(flow, &ids, &guids, &num, &def); + if(FAILED(hr)) + return hr; + + for(i = 0; i < num; ++i){ + MMDevice *dev; + dev = MMDevice_Create(ids[i], &guids[i], flow, DEVICE_STATE_ACTIVE, + def == i); + set_format(dev); + } + + HeapFree(GetProcessHeap(), 0, guids); + HeapFree(GetProcessHeap(), 0, ids); + + return S_OK; +} + +static void MMDevice_Destroy(MMDevice *This) +{ + DWORD i; + TRACE("Freeing %s\n", debugstr_w(This->drv_id)); + /* Since this function is called at destruction time, reordering of the list is unimportant */ + for (i = 0; i < MMDevice_count; ++i) + { + if (MMDevice_head[i] == This) + { + MMDevice_head[i] = MMDevice_head[--MMDevice_count]; + break; + } + } + This->crst.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->crst); + HeapFree(GetProcessHeap(), 0, This->drv_id); + HeapFree(GetProcessHeap(), 0, This); +} + +static inline MMDevice *impl_from_IMMDevice(IMMDevice *iface) +{ + return CONTAINING_RECORD(iface, MMDevice, IMMDevice_iface); +} + +static HRESULT WINAPI MMDevice_QueryInterface(IMMDevice *iface, REFIID riid, void **ppv) +{ + MMDevice *This = impl_from_IMMDevice(iface); + TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ppv); + + if (!ppv) + return E_POINTER; + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IMMDevice)) + *ppv = This; + else if (IsEqualIID(riid, &IID_IMMEndpoint)) + *ppv = &This->IMMEndpoint_iface; + if (*ppv) + { + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; + } + WARN("Unknown interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI MMDevice_AddRef(IMMDevice *iface) +{ + MMDevice *This = impl_from_IMMDevice(iface); + LONG ref; + + ref = InterlockedIncrement(&This->ref); + TRACE("Refcount now %i\n", ref); + return ref; +} + +static ULONG WINAPI MMDevice_Release(IMMDevice *iface) +{ + MMDevice *This = impl_from_IMMDevice(iface); + LONG ref; + + ref = InterlockedDecrement(&This->ref); + TRACE("Refcount now %i\n", ref); + return ref; +} + +static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD clsctx, PROPVARIANT *params, void **ppv) +{ + HRESULT hr = E_NOINTERFACE; + MMDevice *This = impl_from_IMMDevice(iface); + + TRACE("(%p)->(%p,%x,%p,%p)\n", iface, riid, clsctx, params, ppv); + + if (!ppv) + return E_POINTER; + + if (IsEqualIID(riid, &IID_IAudioClient)){ + hr = drvs.pGetAudioEndpoint(&This->devguid, iface, (IAudioClient**)ppv); + }else if (IsEqualIID(riid, &IID_IAudioEndpointVolume)) + hr = AudioEndpointVolume_Create(This, (IAudioEndpointVolume**)ppv); + else if (IsEqualIID(riid, &IID_IAudioSessionManager) + || IsEqualIID(riid, &IID_IAudioSessionManager2)) + { + hr = drvs.pGetAudioSessionManager(iface, (IAudioSessionManager2**)ppv); + } + else if (IsEqualIID(riid, &IID_IBaseFilter)) + { + if (This->flow == eRender) + hr = CoCreateInstance(&CLSID_DSoundRender, NULL, clsctx, riid, ppv); + else + ERR("Not supported for recording?\n"); + if (SUCCEEDED(hr)) + { + IPersistPropertyBag *ppb; + hr = IUnknown_QueryInterface((IUnknown*)*ppv, &IID_IPersistPropertyBag, (void*)&ppb); + if (SUCCEEDED(hr)) + { + /* ::Load cannot assume the interface stays alive after the function returns, + * so just create the interface on the stack, saves a lot of complicated code */ + IPropertyBagImpl bag = { { &PB_Vtbl } }; + bag.devguid = This->devguid; + hr = IPersistPropertyBag_Load(ppb, &bag.IPropertyBag_iface, NULL); + IPersistPropertyBag_Release(ppb); + if (FAILED(hr)) + IBaseFilter_Release((IBaseFilter*)*ppv); + } + else + { + FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n"); + hr = S_OK; + } + } + } + else if (IsEqualIID(riid, &IID_IDeviceTopology)) + { + FIXME("IID_IDeviceTopology unsupported\n"); + } + else if (IsEqualIID(riid, &IID_IDirectSound) + || IsEqualIID(riid, &IID_IDirectSound8)) + { + if (This->flow == eRender) + hr = CoCreateInstance(&CLSID_DirectSound8, NULL, clsctx, riid, ppv); + if (SUCCEEDED(hr)) + { + hr = IDirectSound_Initialize((IDirectSound*)*ppv, &This->devguid); + if (FAILED(hr)) + IDirectSound_Release((IDirectSound*)*ppv); + } + } + else if (IsEqualIID(riid, &IID_IDirectSoundCapture) + || IsEqualIID(riid, &IID_IDirectSoundCapture8)) + { + if (This->flow == eCapture) + hr = CoCreateInstance(&CLSID_DirectSoundCapture8, NULL, clsctx, riid, ppv); + if (SUCCEEDED(hr)) + { + hr = IDirectSoundCapture_Initialize((IDirectSoundCapture*)*ppv, &This->devguid); + if (FAILED(hr)) + IDirectSoundCapture_Release((IDirectSoundCapture*)*ppv); + } + } + else + ERR("Invalid/unknown iid %s\n", debugstr_guid(riid)); + + if (FAILED(hr)) + *ppv = NULL; + + TRACE("Returning %08x\n", hr); + return hr; +} + +static HRESULT WINAPI MMDevice_OpenPropertyStore(IMMDevice *iface, DWORD access, IPropertyStore **ppv) +{ + MMDevice *This = impl_from_IMMDevice(iface); + TRACE("(%p)->(%x,%p)\n", This, access, ppv); + + if (!ppv) + return E_POINTER; + return MMDevPropStore_Create(This, access, ppv); +} + +static HRESULT WINAPI MMDevice_GetId(IMMDevice *iface, WCHAR **itemid) +{ + MMDevice *This = impl_from_IMMDevice(iface); + WCHAR *str; + GUID *id = &This->devguid; + static const WCHAR formatW[] = { '{','0','.','0','.','%','u','.','0','0','0','0','0','0','0','0','}','.', + '{','%','0','8','X','-','%','0','4','X','-', + '%','0','4','X','-','%','0','2','X','%','0','2','X','-', + '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X', + '%','0','2','X','%','0','2','X','}',0 }; + + TRACE("(%p)->(%p)\n", This, itemid); + if (!itemid) + return E_POINTER; + *itemid = str = CoTaskMemAlloc(56 * sizeof(WCHAR)); + if (!str) + return E_OUTOFMEMORY; + wsprintfW( str, formatW, This->flow, id->Data1, id->Data2, id->Data3, + id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], + id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); + TRACE("returning %s\n", wine_dbgstr_w(str)); + return S_OK; +} + +static HRESULT WINAPI MMDevice_GetState(IMMDevice *iface, DWORD *state) +{ + MMDevice *This = impl_from_IMMDevice(iface); + TRACE("(%p)->(%p)\n", iface, state); + + if (!state) + return E_POINTER; + *state = This->state; + return S_OK; +} + +static const IMMDeviceVtbl MMDeviceVtbl = +{ + MMDevice_QueryInterface, + MMDevice_AddRef, + MMDevice_Release, + MMDevice_Activate, + MMDevice_OpenPropertyStore, + MMDevice_GetId, + MMDevice_GetState +}; + +static inline MMDevice *impl_from_IMMEndpoint(IMMEndpoint *iface) +{ + return CONTAINING_RECORD(iface, MMDevice, IMMEndpoint_iface); +} + +static HRESULT WINAPI MMEndpoint_QueryInterface(IMMEndpoint *iface, REFIID riid, void **ppv) +{ + MMDevice *This = impl_from_IMMEndpoint(iface); + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); + return IMMDevice_QueryInterface(&This->IMMDevice_iface, riid, ppv); +} + +static ULONG WINAPI MMEndpoint_AddRef(IMMEndpoint *iface) +{ + MMDevice *This = impl_from_IMMEndpoint(iface); + TRACE("(%p)\n", This); + return IMMDevice_AddRef(&This->IMMDevice_iface); +} + +static ULONG WINAPI MMEndpoint_Release(IMMEndpoint *iface) +{ + MMDevice *This = impl_from_IMMEndpoint(iface); + TRACE("(%p)\n", This); + return IMMDevice_Release(&This->IMMDevice_iface); +} + +static HRESULT WINAPI MMEndpoint_GetDataFlow(IMMEndpoint *iface, EDataFlow *flow) +{ + MMDevice *This = impl_from_IMMEndpoint(iface); + TRACE("(%p)->(%p)\n", This, flow); + if (!flow) + return E_POINTER; + *flow = This->flow; + return S_OK; +} + +static const IMMEndpointVtbl MMEndpointVtbl = +{ + MMEndpoint_QueryInterface, + MMEndpoint_AddRef, + MMEndpoint_Release, + MMEndpoint_GetDataFlow +}; + +static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state) +{ + MMDevColImpl *This; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + *ppv = NULL; + if (!This) + return E_OUTOFMEMORY; + This->IMMDeviceCollection_iface.lpVtbl = &MMDevColVtbl; + This->ref = 1; + This->flow = flow; + This->state = state; + *ppv = &This->IMMDeviceCollection_iface; + return S_OK; +} + +static void MMDevCol_Destroy(MMDevColImpl *This) +{ + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv) +{ + MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); + + if (!ppv) + return E_POINTER; + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IMMDeviceCollection)) + *ppv = This; + else + *ppv = NULL; + if (!*ppv) + return E_NOINTERFACE; + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface) +{ + MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("Refcount now %i\n", ref); + return ref; +} + +static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface) +{ + MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); + LONG ref = InterlockedDecrement(&This->ref); + TRACE("Refcount now %i\n", ref); + if (!ref) + MMDevCol_Destroy(This); + return ref; +} + +static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs) +{ + MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); + DWORD i; + + TRACE("(%p)->(%p)\n", This, numdevs); + if (!numdevs) + return E_POINTER; + + *numdevs = 0; + for (i = 0; i < MMDevice_count; ++i) + { + MMDevice *cur = MMDevice_head[i]; + if ((cur->flow == This->flow || This->flow == eAll) + && (cur->state & This->state)) + ++(*numdevs); + } + return S_OK; +} + +static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT n, IMMDevice **dev) +{ + MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); + DWORD i = 0, j = 0; + + TRACE("(%p)->(%u, %p)\n", This, n, dev); + if (!dev) + return E_POINTER; + + for (j = 0; j < MMDevice_count; ++j) + { + MMDevice *cur = MMDevice_head[j]; + if ((cur->flow == This->flow || This->flow == eAll) + && (cur->state & This->state) + && i++ == n) + { + *dev = &cur->IMMDevice_iface; + IMMDevice_AddRef(*dev); + return S_OK; + } + } + WARN("Could not obtain item %u\n", n); + *dev = NULL; + return E_INVALIDARG; +} + +static const IMMDeviceCollectionVtbl MMDevColVtbl = +{ + MMDevCol_QueryInterface, + MMDevCol_AddRef, + MMDevCol_Release, + MMDevCol_GetCount, + MMDevCol_Item +}; + +HRESULT MMDevEnum_Create(REFIID riid, void **ppv) +{ + MMDevEnumImpl *This = MMDevEnumerator; + + if (!This) + { + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + *ppv = NULL; + if (!This) + return E_OUTOFMEMORY; + This->ref = 1; + This->IMMDeviceEnumerator_iface.lpVtbl = &MMDevEnumVtbl; + MMDevEnumerator = This; + + load_devices_from_reg(); + load_driver_devices(eRender); + load_driver_devices(eCapture); + } + return IUnknown_QueryInterface((IUnknown*)This, riid, ppv); +} + +void MMDevEnum_Free(void) +{ + while (MMDevice_count) + MMDevice_Destroy(MMDevice_head[0]); + RegCloseKey(key_render); + RegCloseKey(key_capture); + key_render = key_capture = NULL; + HeapFree(GetProcessHeap(), 0, MMDevEnumerator); + MMDevEnumerator = NULL; +} + +static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); + + if (!ppv) + return E_POINTER; + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IMMDeviceEnumerator)) + *ppv = This; + else + *ppv = NULL; + if (!*ppv) + return E_NOINTERFACE; + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("Refcount now %i\n", ref); + return ref; +} + +static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + LONG ref = InterlockedDecrement(&This->ref); + if (!ref) + MMDevEnum_Free(); + TRACE("Refcount now %i\n", ref); + return ref; +} + +static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + TRACE("(%p)->(%u,%u,%p)\n", This, flow, mask, devices); + if (!devices) + return E_POINTER; + *devices = NULL; + if (flow >= EDataFlow_enum_count) + return E_INVALIDARG; + if (mask & ~DEVICE_STATEMASK_ALL) + return E_INVALIDARG; + return MMDevCol_Create(devices, flow, mask); +} + +static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + WCHAR reg_key[256]; + HKEY key; + HRESULT hr; + + TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device); + + if (!device) + return E_POINTER; + + if((flow != eRender && flow != eCapture) || + (role != eConsole && role != eMultimedia && role != eCommunications)){ + WARN("Unknown flow (%u) or role (%u)\n", flow, role); + return E_INVALIDARG; + } + + *device = NULL; + + if(!drvs.module_name[0]) + return E_NOTFOUND; + + lstrcpyW(reg_key, drv_keyW); + lstrcatW(reg_key, slashW); + lstrcatW(reg_key, drvs.module_name); + + if(RegOpenKeyW(HKEY_CURRENT_USER, reg_key, &key) == ERROR_SUCCESS){ + const WCHAR *reg_x_name, *reg_vx_name; + WCHAR def_id[256]; + DWORD size = sizeof(def_id), state; + + if(flow == eRender){ + reg_x_name = reg_out_nameW; + reg_vx_name = reg_vout_nameW; + }else{ + reg_x_name = reg_in_nameW; + reg_vx_name = reg_vin_nameW; + } + + if(role == eCommunications && + RegQueryValueExW(key, reg_vx_name, 0, NULL, + (BYTE*)def_id, &size) == ERROR_SUCCESS){ + hr = IMMDeviceEnumerator_GetDevice(iface, def_id, device); + if(SUCCEEDED(hr)){ + if(SUCCEEDED(IMMDevice_GetState(*device, &state)) && + state == DEVICE_STATE_ACTIVE){ + RegCloseKey(key); + return S_OK; + } + } + + TRACE("Unable to find voice device %s\n", wine_dbgstr_w(def_id)); + } + + if(RegQueryValueExW(key, reg_x_name, 0, NULL, + (BYTE*)def_id, &size) == ERROR_SUCCESS){ + hr = IMMDeviceEnumerator_GetDevice(iface, def_id, device); + if(SUCCEEDED(hr)){ + if(SUCCEEDED(IMMDevice_GetState(*device, &state)) && + state == DEVICE_STATE_ACTIVE){ + RegCloseKey(key); + return S_OK; + } + } + + TRACE("Unable to find device %s\n", wine_dbgstr_w(def_id)); + } + + RegCloseKey(key); + } + + if (flow == eRender) + *device = &MMDevice_def_play->IMMDevice_iface; + else + *device = &MMDevice_def_rec->IMMDevice_iface; + + if (!*device) + return E_NOTFOUND; + IMMDevice_AddRef(*device); + return S_OK; +} + +static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + DWORD i=0; + IMMDevice *dev = NULL; + + static const WCHAR wine_info_deviceW[] = {'W','i','n','e',' ', + 'i','n','f','o',' ','d','e','v','i','c','e',0}; + + TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device); + + if(!name || !device) + return E_POINTER; + + if(!lstrcmpW(name, wine_info_deviceW)){ + *device = &info_device; + return S_OK; + } + + for (i = 0; i < MMDevice_count; ++i) + { + WCHAR *str; + dev = &MMDevice_head[i]->IMMDevice_iface; + IMMDevice_GetId(dev, &str); + + if (str && !lstrcmpW(str, name)) + { + CoTaskMemFree(str); + IMMDevice_AddRef(dev); + *device = dev; + return S_OK; + } + CoTaskMemFree(str); + } + TRACE("Could not find device %s\n", debugstr_w(name)); + return E_INVALIDARG; +} + +struct NotificationClientWrapper { + IMMNotificationClient *client; + struct list entry; +}; + +static struct list g_notif_clients = LIST_INIT(g_notif_clients); +static HANDLE g_notif_thread; + +static CRITICAL_SECTION g_notif_lock; +static CRITICAL_SECTION_DEBUG g_notif_lock_debug = +{ + 0, 0, &g_notif_lock, + { &g_notif_lock_debug.ProcessLocksList, &g_notif_lock_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": g_notif_lock") } +}; +static CRITICAL_SECTION g_notif_lock = { &g_notif_lock_debug, -1, 0, 0, 0, 0 }; + +static void notify_clients(EDataFlow flow, ERole role, const WCHAR *id) +{ + struct NotificationClientWrapper *wrapper; + LIST_FOR_EACH_ENTRY(wrapper, &g_notif_clients, + struct NotificationClientWrapper, entry) + IMMNotificationClient_OnDefaultDeviceChanged(wrapper->client, flow, + role, id); + + /* Windows 7 treats changes to eConsole as changes to eMultimedia */ + if(role == eConsole) + notify_clients(flow, eMultimedia, id); +} + +static int notify_if_changed(EDataFlow flow, ERole role, HKEY key, + const WCHAR *val_name, WCHAR *old_val, IMMDevice *def_dev) +{ + WCHAR new_val[64], *id; + DWORD size; + HRESULT hr; + + size = sizeof(new_val); + if(RegQueryValueExW(key, val_name, 0, NULL, + (BYTE*)new_val, &size) != ERROR_SUCCESS){ + if(old_val[0] != 0){ + /* set by user -> system default */ + if(def_dev){ + hr = IMMDevice_GetId(def_dev, &id); + if(FAILED(hr)){ + ERR("GetId failed: %08x\n", hr); + return 0; + } + }else + id = NULL; + + notify_clients(flow, role, id); + old_val[0] = 0; + CoTaskMemFree(id); + + return 1; + } + + /* system default -> system default, noop */ + return 0; + } + + if(!lstrcmpW(old_val, new_val)){ + /* set by user -> same value */ + return 0; + } + + if(new_val[0] != 0){ + /* set by user -> different value */ + notify_clients(flow, role, new_val); + memcpy(old_val, new_val, sizeof(new_val)); + return 1; + } + + /* set by user -> system default */ + if(def_dev){ + hr = IMMDevice_GetId(def_dev, &id); + if(FAILED(hr)){ + ERR("GetId failed: %08x\n", hr); + return 0; + } + }else + id = NULL; + + notify_clients(flow, role, id); + old_val[0] = 0; + CoTaskMemFree(id); + + return 1; +} + +static DWORD WINAPI notif_thread_proc(void *user) +{ + HKEY key; + WCHAR reg_key[256]; + WCHAR out_name[64], vout_name[64], in_name[64], vin_name[64]; + DWORD size; + + lstrcpyW(reg_key, drv_keyW); + lstrcatW(reg_key, slashW); + lstrcatW(reg_key, drvs.module_name); + + if(RegCreateKeyExW(HKEY_CURRENT_USER, reg_key, 0, NULL, 0, + MAXIMUM_ALLOWED, NULL, &key, NULL) != ERROR_SUCCESS){ + ERR("RegCreateKeyEx failed: %u\n", GetLastError()); + return 1; + } + + size = sizeof(out_name); + if(RegQueryValueExW(key, reg_out_nameW, 0, NULL, + (BYTE*)out_name, &size) != ERROR_SUCCESS) + out_name[0] = 0; + + size = sizeof(vout_name); + if(RegQueryValueExW(key, reg_vout_nameW, 0, NULL, + (BYTE*)vout_name, &size) != ERROR_SUCCESS) + vout_name[0] = 0; + + size = sizeof(in_name); + if(RegQueryValueExW(key, reg_in_nameW, 0, NULL, + (BYTE*)in_name, &size) != ERROR_SUCCESS) + in_name[0] = 0; + + size = sizeof(vin_name); + if(RegQueryValueExW(key, reg_vin_nameW, 0, NULL, + (BYTE*)vin_name, &size) != ERROR_SUCCESS) + vin_name[0] = 0; + + while(1){ + if(RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, + NULL, FALSE) != ERROR_SUCCESS){ + ERR("RegNotifyChangeKeyValue failed: %u\n", GetLastError()); + RegCloseKey(key); + g_notif_thread = NULL; + return 1; + } + + EnterCriticalSection(&g_notif_lock); + + notify_if_changed(eRender, eConsole, key, reg_out_nameW, + out_name, &MMDevice_def_play->IMMDevice_iface); + notify_if_changed(eRender, eCommunications, key, reg_vout_nameW, + vout_name, &MMDevice_def_play->IMMDevice_iface); + notify_if_changed(eCapture, eConsole, key, reg_in_nameW, + in_name, &MMDevice_def_rec->IMMDevice_iface); + notify_if_changed(eCapture, eCommunications, key, reg_vin_nameW, + vin_name, &MMDevice_def_rec->IMMDevice_iface); + + LeaveCriticalSection(&g_notif_lock); + } + + RegCloseKey(key); + + g_notif_thread = NULL; + + return 0; +} + +static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + struct NotificationClientWrapper *wrapper; + + TRACE("(%p)->(%p)\n", This, client); + + if(!client) + return E_POINTER; + + wrapper = HeapAlloc(GetProcessHeap(), 0, sizeof(*wrapper)); + if(!wrapper) + return E_OUTOFMEMORY; + + wrapper->client = client; + + EnterCriticalSection(&g_notif_lock); + + list_add_tail(&g_notif_clients, &wrapper->entry); + + if(!g_notif_thread){ + g_notif_thread = CreateThread(NULL, 0, notif_thread_proc, NULL, 0, NULL); + if(!g_notif_thread) + ERR("CreateThread failed: %u\n", GetLastError()); + } + + LeaveCriticalSection(&g_notif_lock); + + return S_OK; +} + +static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client) +{ + MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + struct NotificationClientWrapper *wrapper, *wrapper2; + + TRACE("(%p)->(%p)\n", This, client); + + if(!client) + return E_POINTER; + + EnterCriticalSection(&g_notif_lock); + + LIST_FOR_EACH_ENTRY_SAFE(wrapper, wrapper2, &g_notif_clients, + struct NotificationClientWrapper, entry){ + if(wrapper->client == client){ + list_remove(&wrapper->entry); + HeapFree(GetProcessHeap(), 0, wrapper); + LeaveCriticalSection(&g_notif_lock); + return S_OK; + } + } + + LeaveCriticalSection(&g_notif_lock); + + return E_NOTFOUND; +} + +static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl = +{ + MMDevEnum_QueryInterface, + MMDevEnum_AddRef, + MMDevEnum_Release, + MMDevEnum_EnumAudioEndpoints, + MMDevEnum_GetDefaultAudioEndpoint, + MMDevEnum_GetDevice, + MMDevEnum_RegisterEndpointNotificationCallback, + MMDevEnum_UnregisterEndpointNotificationCallback +}; + +static HRESULT MMDevPropStore_Create(MMDevice *parent, DWORD access, IPropertyStore **ppv) +{ + MMDevPropStore *This; + if (access != STGM_READ + && access != STGM_WRITE + && access != STGM_READWRITE) + { + WARN("Invalid access %08x\n", access); + return E_INVALIDARG; + } + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + *ppv = &This->IPropertyStore_iface; + if (!This) + return E_OUTOFMEMORY; + This->IPropertyStore_iface.lpVtbl = &MMDevPropVtbl; + This->ref = 1; + This->parent = parent; + This->access = access; + return S_OK; +} + +static void MMDevPropStore_Destroy(MMDevPropStore *This) +{ + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT WINAPI MMDevPropStore_QueryInterface(IPropertyStore *iface, REFIID riid, void **ppv) +{ + MMDevPropStore *This = impl_from_IPropertyStore(iface); + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); + + if (!ppv) + return E_POINTER; + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IPropertyStore)) + *ppv = This; + else + *ppv = NULL; + if (!*ppv) + return E_NOINTERFACE; + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI MMDevPropStore_AddRef(IPropertyStore *iface) +{ + MMDevPropStore *This = impl_from_IPropertyStore(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("Refcount now %i\n", ref); + return ref; +} + +static ULONG WINAPI MMDevPropStore_Release(IPropertyStore *iface) +{ + MMDevPropStore *This = impl_from_IPropertyStore(iface); + LONG ref = InterlockedDecrement(&This->ref); + TRACE("Refcount now %i\n", ref); + if (!ref) + MMDevPropStore_Destroy(This); + return ref; +} + +static HRESULT WINAPI MMDevPropStore_GetCount(IPropertyStore *iface, DWORD *nprops) +{ + MMDevPropStore *This = impl_from_IPropertyStore(iface); + WCHAR buffer[50]; + DWORD i = 0; + HKEY propkey; + HRESULT hr; + + TRACE("(%p)->(%p)\n", iface, nprops); + if (!nprops) + return E_POINTER; + hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey); + if (FAILED(hr)) + return hr; + *nprops = 0; + do { + DWORD len = sizeof(buffer)/sizeof(*buffer); + if (RegEnumKeyExW(propkey, i, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + break; + i++; + } while (0); + RegCloseKey(propkey); + TRACE("Returning %i\n", i); + *nprops = i; + return S_OK; +} + +static HRESULT WINAPI MMDevPropStore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key) +{ + MMDevPropStore *This = impl_from_IPropertyStore(iface); + WCHAR buffer[50]; + DWORD len = sizeof(buffer)/sizeof(*buffer); + HRESULT hr; + HKEY propkey; + + TRACE("(%p)->(%u,%p)\n", iface, prop, key); + if (!key) + return E_POINTER; + + hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey); + if (FAILED(hr)) + return hr; + + if (RegEnumKeyExW(propkey, prop, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS + || len <= 40) + { + WARN("GetAt %u failed\n", prop); + return E_INVALIDARG; + } + RegCloseKey(propkey); + buffer[39] = 0; + CLSIDFromString(buffer, &key->fmtid); + key->pid = atoiW(&buffer[40]); + return S_OK; +} + +static HRESULT WINAPI MMDevPropStore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *pv) +{ + MMDevPropStore *This = impl_from_IPropertyStore(iface); + TRACE("(%p)->(\"%s,%u\", %p)\n", This, key ? debugstr_guid(&key->fmtid) : NULL, key ? key->pid : 0, pv); + + if (!key || !pv) + return E_POINTER; + if (This->access != STGM_READ + && This->access != STGM_READWRITE) + return STG_E_ACCESSDENIED; + + /* Special case */ + if (IsEqualPropertyKey(*key, PKEY_AudioEndpoint_GUID)) + { + pv->vt = VT_LPWSTR; + pv->u.pwszVal = CoTaskMemAlloc(39 * sizeof(WCHAR)); + if (!pv->u.pwszVal) + return E_OUTOFMEMORY; + StringFromGUID2(&This->parent->devguid, pv->u.pwszVal, 39); + return S_OK; + } + + return MMDevice_GetPropValue(&This->parent->devguid, This->parent->flow, key, pv); +} + +static HRESULT WINAPI MMDevPropStore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT pv) +{ + MMDevPropStore *This = impl_from_IPropertyStore(iface); + TRACE("(%p)->(\"%s,%u\", %p)\n", This, key ? debugstr_guid(&key->fmtid) : NULL, key ? key->pid : 0, pv); + + if (!key || !pv) + return E_POINTER; + + if (This->access != STGM_WRITE + && This->access != STGM_READWRITE) + return STG_E_ACCESSDENIED; + return MMDevice_SetPropValue(&This->parent->devguid, This->parent->flow, key, pv); +} + +static HRESULT WINAPI MMDevPropStore_Commit(IPropertyStore *iface) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static const IPropertyStoreVtbl MMDevPropVtbl = +{ + MMDevPropStore_QueryInterface, + MMDevPropStore_AddRef, + MMDevPropStore_Release, + MMDevPropStore_GetCount, + MMDevPropStore_GetAt, + MMDevPropStore_GetValue, + MMDevPropStore_SetValue, + MMDevPropStore_Commit +}; + + +/* Property bag for IBaseFilter activation */ +static HRESULT WINAPI PB_QueryInterface(IPropertyBag *iface, REFIID riid, void **ppv) +{ + ERR("Should not be called\n"); + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI PB_AddRef(IPropertyBag *iface) +{ + ERR("Should not be called\n"); + return 2; +} + +static ULONG WINAPI PB_Release(IPropertyBag *iface) +{ + ERR("Should not be called\n"); + return 1; +} + +static HRESULT WINAPI PB_Read(IPropertyBag *iface, LPCOLESTR name, VARIANT *var, IErrorLog *log) +{ + static const WCHAR dsguid[] = { 'D','S','G','u','i','d', 0 }; + IPropertyBagImpl *This = impl_from_IPropertyBag(iface); + TRACE("Trying to read %s, type %u\n", debugstr_w(name), var->n1.n2.vt); + if (!lstrcmpW(name, dsguid)) + { + WCHAR guidstr[39]; + StringFromGUID2(&This->devguid, guidstr,sizeof(guidstr)/sizeof(*guidstr)); + var->n1.n2.vt = VT_BSTR; + var->n1.n2.n3.bstrVal = SysAllocString(guidstr); + return S_OK; + } + ERR("Unknown property '%s' queried\n", debugstr_w(name)); + return E_FAIL; +} + +static HRESULT WINAPI PB_Write(IPropertyBag *iface, LPCOLESTR name, VARIANT *var) +{ + ERR("Should not be called\n"); + return E_FAIL; +} + +static const IPropertyBagVtbl PB_Vtbl = +{ + PB_QueryInterface, + PB_AddRef, + PB_Release, + PB_Read, + PB_Write +}; + +static ULONG WINAPI info_device_ps_AddRef(IPropertyStore *iface) +{ + return 2; +} + +static ULONG WINAPI info_device_ps_Release(IPropertyStore *iface) +{ + return 1; +} + +static HRESULT WINAPI info_device_ps_GetValue(IPropertyStore *iface, + REFPROPERTYKEY key, PROPVARIANT *pv) +{ + TRACE("(static)->(\"%s,%u\", %p)\n", debugstr_guid(&key->fmtid), key ? key->pid : 0, pv); + + if (!key || !pv) + return E_POINTER; + + if (IsEqualPropertyKey(*key, DEVPKEY_Device_Driver)) + { + INT size = (lstrlenW(drvs.module_name) + 1) * sizeof(WCHAR); + pv->vt = VT_LPWSTR; + pv->u.pwszVal = CoTaskMemAlloc(size); + if (!pv->u.pwszVal) + return E_OUTOFMEMORY; + memcpy(pv->u.pwszVal, drvs.module_name, size); + return S_OK; + } + + return E_INVALIDARG; +} + +static const IPropertyStoreVtbl info_device_ps_Vtbl = +{ + NULL, + info_device_ps_AddRef, + info_device_ps_Release, + NULL, + NULL, + info_device_ps_GetValue, + NULL, + NULL +}; + +static IPropertyStore info_device_ps = { + &info_device_ps_Vtbl +}; + +static ULONG WINAPI info_device_AddRef(IMMDevice *iface) +{ + return 2; +} + +static ULONG WINAPI info_device_Release(IMMDevice *iface) +{ + return 1; +} + +static HRESULT WINAPI info_device_OpenPropertyStore(IMMDevice *iface, + DWORD access, IPropertyStore **ppv) +{ + TRACE("(static)->(%x, %p)\n", access, ppv); + *ppv = &info_device_ps; + return S_OK; +} + +static const IMMDeviceVtbl info_device_Vtbl = +{ + NULL, + info_device_AddRef, + info_device_Release, + NULL, + info_device_OpenPropertyStore, + NULL, + NULL +}; + +static IMMDevice info_device = { + &info_device_Vtbl +}; diff --git a/reactos/dll/win32/mmdevapi/main.c b/reactos/dll/win32/mmdevapi/main.c new file mode 100644 index 00000000000..447813f12fe --- /dev/null +++ b/reactos/dll/win32/mmdevapi/main.c @@ -0,0 +1,326 @@ +/* + * 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 + +#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 "propkeydef.h" +#include "mmdeviceapi.h" +#include "mmsystem.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" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); + +static HINSTANCE instance; + +DriverFuncs drvs; + +const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\\', + 'W','i','n','e','\\','D','r','i','v','e','r','s',0}; + +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) +{ + 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)); + + driver->module = LoadLibraryW(driver_module); + if(!driver->module){ + TRACE("Unable to load %s: %u\n", wine_dbgstr_w(driver_module), + GetLastError()); + return FALSE; + } + +#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); + LDFC(GetEndpointIDs); + LDFC(GetAudioEndpoint); + LDFC(GetAudioSessionManager); +#undef LDFC + + 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)); + + return TRUE; +} + +static BOOL init_driver(void) +{ + static const WCHAR drv_value[] = {'A','u','d','i','o',0}; + + static WCHAR default_list[] = {'a','l','s','a',',','o','s','s',',', + 'c','o','r','e','a','u','d','i','o',0}; + + DriverFuncs driver; + HKEY key; + WCHAR reg_list[256], *p, *next, *driver_list = default_list; + + if(drvs.module) + return TRUE; + + if(RegOpenKeyW(HKEY_CURRENT_USER, drv_keyW, &key) == ERROR_SUCCESS){ + DWORD size = sizeof(reg_list); + + if(RegQueryValueExW(key, drv_value, 0, NULL, (BYTE*)reg_list, + &size) == ERROR_SUCCESS){ + if(reg_list[0] == '\0'){ + TRACE("User explicitly chose no driver\n"); + RegCloseKey(key); + return TRUE; + } + + driver_list = reg_list; + } + + RegCloseKey(key); + } + + 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 = ','; + } + + return drvs.module != 0; +} + +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: + if(lpvReserved) + break; + 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(IClassFactory *iface, REFIID riid, void **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; + IClassFactory_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) +{ + unsigned 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)) { + IClassFactory_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 ); +} + +/*********************************************************************** + * DllUnregisterServer (MMDEVAPI.@) + */ +HRESULT WINAPI DllUnregisterServer(void) +{ + return __wine_unregister_resources( instance ); +} diff --git a/reactos/dll/win32/mmdevapi/mmdevapi.h b/reactos/dll/win32/mmdevapi/mmdevapi.h new file mode 100644 index 00000000000..2a04780a162 --- /dev/null +++ b/reactos/dll/win32/mmdevapi/mmdevapi.h @@ -0,0 +1,77 @@ +/* + * Copyright 2009 Maarten Lankhorst + * + * 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 + */ + +#ifndef __WINE_CONFIG_H +# error You must include config.h to use this header +#endif + +extern HRESULT MMDevEnum_Create(REFIID riid, void **ppv) DECLSPEC_HIDDEN; +extern void MMDevEnum_Free(void) DECLSPEC_HIDDEN; + + +/* Changes to this enum must be synced in drivers. */ +enum _DriverPriority { + Priority_Unavailable = 0, /* driver won't work */ + Priority_Low, /* driver may work, but unlikely */ + Priority_Neutral, /* driver makes no judgment */ + Priority_Preferred /* driver thinks it's correct */ +}; + +typedef struct _DriverFuncs { + HMODULE module; + WCHAR module_name[64]; + int priority; + + /* Returns a "priority" value for the driver. Highest priority wins. + * If multiple drivers think they are valid, they will return a + * priority value reflecting the likelihood that they are actually + * valid. See enum _DriverPriority. */ + int (WINAPI *pGetPriority)(void); + + /* ids gets an array of human-friendly endpoint names + * keys gets an array of driver-specific stuff that is used + * in GetAudioEndpoint to identify the endpoint + * it is the caller's responsibility to free both arrays, and + * all of the elements in both arrays with HeapFree() */ + HRESULT (WINAPI *pGetEndpointIDs)(EDataFlow flow, WCHAR ***ids, + GUID **guids, UINT *num, UINT *default_index); + HRESULT (WINAPI *pGetAudioEndpoint)(void *key, IMMDevice *dev, + IAudioClient **out); + HRESULT (WINAPI *pGetAudioSessionManager)(IMMDevice *device, + IAudioSessionManager2 **out); +} DriverFuncs; + +extern DriverFuncs drvs DECLSPEC_HIDDEN; + +typedef struct MMDevice { + IMMDevice IMMDevice_iface; + IMMEndpoint IMMEndpoint_iface; + LONG ref; + + CRITICAL_SECTION crst; + + EDataFlow flow; + DWORD state; + GUID devguid; + WCHAR *drv_id; +} MMDevice; + +extern HRESULT AudioClient_Create(MMDevice *parent, IAudioClient **ppv) DECLSPEC_HIDDEN; +extern HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolume **ppv) DECLSPEC_HIDDEN; + +extern const WCHAR drv_keyW[] DECLSPEC_HIDDEN; diff --git a/reactos/dll/win32/mmdevapi/mmdevapi.rc b/reactos/dll/win32/mmdevapi/mmdevapi.rc new file mode 100644 index 00000000000..faad6414f2f --- /dev/null +++ b/reactos/dll/win32/mmdevapi/mmdevapi.rc @@ -0,0 +1 @@ +1 WINE_REGISTRY mmdevapi_classes.rgs diff --git a/reactos/dll/win32/mmdevapi/mmdevapi.spec b/reactos/dll/win32/mmdevapi/mmdevapi.spec new file mode 100644 index 00000000000..5c06642a5ae --- /dev/null +++ b/reactos/dll/win32/mmdevapi/mmdevapi.spec @@ -0,0 +1,19 @@ + 2 stub MMDEVAPI_2 + 3 stub MMDEVAPI_3 + 4 stub MMDEVAPI_4 + 5 stub MMDEVAPI_5 + 6 stub MMDEVAPI_6 + 7 stub MMDEVAPI_7 + 8 stub MMDEVAPI_8 + 9 stub MMDEVAPI_9 +10 stub MMDEVAPI_10 +11 stub MMDEVAPI_11 +12 stub MMDEVAPI_12 +13 stub MMDEVAPI_13 +14 stub MMDEVAPI_14 +15 stub MMDEVAPI_15 + +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject( ptr ptr ptr ) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/reactos/dll/win32/mmdevapi/mmdevapi_classes.idl b/reactos/dll/win32/mmdevapi/mmdevapi_classes.idl new file mode 100644 index 00000000000..a93dd3f5f72 --- /dev/null +++ b/reactos/dll/win32/mmdevapi/mmdevapi_classes.idl @@ -0,0 +1,26 @@ +/* + * COM Classes for mmdevapi + * + * Copyright 2010 Alexandre Julliard + * + * 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 + */ + +[ + helpstring("MMDeviceEnumerator class"), + threading(both), + uuid(bcde0395-e52f-467c-8e3d-c4579291692e) +] +coclass MMDeviceEnumerator { interface IMMDeviceEnumerator; } diff --git a/reactos/dll/win32/mmdevapi/mmdevapi_classes.rgs b/reactos/dll/win32/mmdevapi/mmdevapi_classes.rgs new file mode 100644 index 00000000000..15a7fdaea5c --- /dev/null +++ b/reactos/dll/win32/mmdevapi/mmdevapi_classes.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove Interface + { + } + NoRemove CLSID + { + '{BCDE0395-E52F-467C-8E3D-C4579291692E}' = s 'MMDeviceEnumerator class' + { + InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } + } + } +} diff --git a/reactos/include/psdk/CMakeLists.txt b/reactos/include/psdk/CMakeLists.txt index 5b6743c681e..e73eda997d7 100644 --- a/reactos/include/psdk/CMakeLists.txt +++ b/reactos/include/psdk/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND SOURCE # asysta.idl atliface.idl audioclient.idl + audiopolicy.idl bdaiface.idl # binres.idl bits.idl @@ -33,6 +34,7 @@ list(APPEND SOURCE # dbprop.idl # dbs.idl devenum.idl + devicetopology.idl dimm.idl dispex.idl docobj.idl @@ -40,6 +42,7 @@ list(APPEND SOURCE downloadmgr.idl dxgi.idl # dyngraph.idl + endpointvolume.idl exdisp.idl fusion.idl hlink.idl diff --git a/reactos/include/psdk/audiopolicy.idl b/reactos/include/psdk/audiopolicy.idl new file mode 100644 index 00000000000..d1832bb523e --- /dev/null +++ b/reactos/include/psdk/audiopolicy.idl @@ -0,0 +1,240 @@ +/* + * Core Audio audio policy definitions + * + * Copyright 2009 Maarten Lankhorst + * + * 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 + * + */ + +import "oaidl.idl"; +import "ocidl.idl"; +import "propidl.idl"; +import "audiosessiontypes.h"; +import "audioclient.idl"; + +interface IAudioSessionEvents; +interface IAudioSessionControl; +interface IAudioSessionControl2; +interface IAudioSessionManager; +interface IAudioVolumeDuckNotification; +interface IAudioSessionNotification; +interface IAudioSessionEnumerator; +interface IAudioSessionManager2; + +typedef enum AudioSessionDisconnectReason /*[local]*/ +{ + DisconnectReasonDeviceRemoval = 0, + DisconnectReasonServerShutdown, + DisconnectReasonFormatChanged, + DisconnectReasonSessionLogoff, + DisconnectReasonSessionDisconnected, + DisconnectReasonExclusiveModeOverride, +} AudioSessionDisconnectReason; + +[ + local, + uuid(24918acc-64b3-37c1-8ca9-74a66e9957a8), + pointer_default(unique), + object +] +interface IAudioSessionEvents : IUnknown +{ + HRESULT OnDisplayNameChanged( + [string,in] LPCWSTR NewDisplayName, + [in] LPCGUID EventContext + ); + HRESULT OnIconPathChanged( + [string,in] LPCWSTR NewIconPath, + [in] LPCGUID EventContext + ); + HRESULT OnSimpleVolumeChanged( + [in] float NewVolume, + [in] BOOL NewMute, + [in] LPCGUID EventContext + ); + HRESULT OnChannelVolumeChanged( + [in] DWORD ChannelCount, + [size_is(ChannelCount),in] float *NewChannelVolumeArray, + [in] DWORD ChangedChannel, + [in] LPCGUID EventContext + ); + HRESULT OnGroupingParamChanged( + [in] LPCGUID NewGroupingParam, + [in] LPCGUID EventContext + ); + HRESULT OnStateChanged( + [in] AudioSessionState NewState + ); + HRESULT OnSessionDisconnected( + [in] AudioSessionDisconnectReason DisconnectReason + ); +} + +[ + local, + uuid(f4b1a599-7266-4319-a8ca-e70acb11e8cd), + pointer_default(unique), + object +] +interface IAudioSessionControl : IUnknown +{ + HRESULT GetState( + [out] AudioSessionState *pRetVal + ); + HRESULT GetDisplayName( + [string,out] LPWSTR *pRetVal + ); + HRESULT SetDisplayName( + [string,in] LPCWSTR DisplayName, + [unique,in] LPCGUID EventContext + ); + HRESULT GetIconPath( + [string,out] LPWSTR *pRetVal + ); + HRESULT SetIconPath( + [string,in] LPCWSTR Value, + [unique,in] LPCGUID EventContext + ); + HRESULT GetGroupingParam( + [out] GUID *pRetVal + ); + HRESULT SetGroupingParam( + [in] LPCGUID Override, + [unique,in] LPCGUID EventContext + ); + HRESULT RegisterAudioSessionNotification( + [in] IAudioSessionEvents *NewNotifications + ); + HRESULT UnregisterAudioSessionNotification( + [in] IAudioSessionEvents *NewNotifications + ); +} + +[ + local, + uuid(bfb7ff88-7239-4fc9-8fa2-07c950be9c6d), + pointer_default(unique), + object +] +interface IAudioSessionControl2 : IAudioSessionControl +{ + HRESULT GetSessionIdentifier( + [string,out] LPWSTR *pRetVal + ); + HRESULT GetSessionInstanceIdentifier( + [string,out] LPWSTR *pRetVal + ); + HRESULT GetProcessId( + [out] DWORD *pRetVal + ); + HRESULT IsSystemSoundsSession(void); + HRESULT SetDuckingPreferences( + [in] BOOL optOut + ); +}; + +[ + local, + uuid(bfa971f1-4d5e-40bb-935e-967039bfbee4), + pointer_default(unique), + object +] +interface IAudioSessionManager : IUnknown +{ + HRESULT GetAudioSessionControl( + [in] LPCGUID AudioSessionGuid, + [in] DWORD StreamFlags, + [out] IAudioSessionControl **SessionControl + ); + HRESULT GetSimpleAudioVolume( + [in] LPCGUID AudioSessionGuid, + [in] DWORD StreamFlags, + [out] ISimpleAudioVolume **AudioVolume + ); +}; + +[ + local, + uuid(c3b284d4-6d39-4359-b3cf-b56ddb3bb39c), + pointer_default(unique), + object +] +interface IAudioVolumeDuckNotification : IUnknown +{ + HRESULT OnVolumeDuckNotification( + [in] LPCWSTR sessionID, + [in] UINT32 countCommunicationSessions + ); + HRESULT OnVolumeUnduckNotification( + [in] LPCWSTR sessionID + ); +}; + +[ + local, + uuid(641dd20b-4d41-49cc-aba3-174b9477bb08), + pointer_default(unique), + object +] +interface IAudioSessionNotification : IUnknown +{ + HRESULT OnSessionCreated( + [in] IAudioSessionControl *NewSession + ); +}; + +[ + local, + uuid(e2f5bb11-0570-40ca-acdd-3aa01277dee8), + pointer_default(unique), + object +] +interface IAudioSessionEnumerator : IUnknown +{ + HRESULT GetCount( + [out] INT *SessionCount + ); + HRESULT GetSession( + [in] INT SessionCount, + [out] IAudioSessionControl **Session + ); +}; + +[ + local, + uuid(77aa99a0-1bd6-484f-8bc7-2c654c9a9b6f), + pointer_default(unique), + object +] +interface IAudioSessionManager2 : IAudioSessionManager +{ + HRESULT GetSessionEnumerator( + [retval,out] IAudioSessionEnumerator **SessionEnum + ); + HRESULT RegisterSessionNotification( + [in] IAudioSessionNotification *SessionNotification + ); + HRESULT UnregisterSessionNotification( + [in] IAudioSessionNotification *SessionNotification + ); + HRESULT RegisterDuckNotification( + [string,in] LPCWSTR sessionID, + [in] IAudioVolumeDuckNotification *duckNotification + ); + HRESULT UnregisterDuckNotification( + [in] IAudioVolumeDuckNotification *duckNotification + ); +}; diff --git a/reactos/include/psdk/devicetopology.idl b/reactos/include/psdk/devicetopology.idl new file mode 100644 index 00000000000..0cacce286ce --- /dev/null +++ b/reactos/include/psdk/devicetopology.idl @@ -0,0 +1,736 @@ +/* + * Core Audio device topology definitions + * + * Copyright 2009 Maarten Lankhorst + * + * 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 + * + */ + +interface IPart; +interface IControlInterface; +interface IDeviceTopology; +interface IControlChangeNotify; + +import "oaidl.idl"; +import "ocidl.idl"; +import "propidl.idl"; + +cpp_quote("#ifndef E_NOTFOUND") +cpp_quote("#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)") +cpp_quote("#endif") + +cpp_quote("#define DEVTOPO_HARDWARE_INITIATED_EVENTCONTEXT 0x64726148 /* 'draH' */") +cpp_quote("DEFINE_GUID(EVENTCONTEXT_VOLUMESLIDER, 0xe2c2e9de, 0x09b1, 0x4b04,0x84,0xe5, 0x07, 0x93, 0x12, 0x25, 0xee, 0x04);") + +cpp_quote("#define _IKsControl_") +cpp_quote("#include ") +cpp_quote("#include ") +cpp_quote("#ifndef _KS_") + +typedef struct { + ULONG FormatSize; + ULONG Flags; + ULONG SampleSize; + ULONG Reserved; + GUID MajorFormat; + GUID SubFormat; + GUID Specifier; +} KSDATAFORMAT; + +typedef KSDATAFORMAT *PKSDATAFORMAT; + +typedef struct +{ + union + { + struct { + GUID Set; + ULONG Id; + ULONG Flags; + }; + LONGLONG Alignment; + }; +} KSIDENTIFIER; + +typedef KSIDENTIFIER KSPROPERTY, *PKSPROPERTY; +typedef KSIDENTIFIER KSMETHOD, *PKSMETHOD; +typedef KSIDENTIFIER KSEVENT, *PKSEVENT; + +typedef enum +{ + eConnTypeUnknown = 0, + eConnType3Point5mm, + eConnTypeQuarter, + eConnTypeAtapiInternal, + eConnTypeRCA, + eConnTypeOptical, + eConnTypeOtherDigital, + eConnTypeOtherAnalog, + eConnTypeMultichannelAnalogDIN, + eConnTypeXlrProfessional, + eConnTypeRj11Modem, + eConnTypeCombination +} EPcxConnectionType; + +typedef enum +{ + eGeoLocRear = 1, + eGeoLocFront, + eGeoLocLeft, + eGeoLocRight, + eGeoLocTop, + eGeoLocBottom, + eGeoLocRearPanel, + eGeoLocRiser, + eGeoLocInsideMobileLid, + eGeoLocDrivebay, + eGeoLocHDMI, + eGeoLocOutsideMobileLid, + eGeoLocATAPI, + eGeoLocReserved5, + eGeoLocReserved6 +} EPcxGeoLocation; + +typedef enum +{ + eGenLocPrimaryBox = 0, + eGenLocInternal, + eGenLocSeparate, + eGenLocOther +} EPcxGenLocation; + +typedef enum +{ + ePortConnJack = 0, + ePortConnIntegratedDevice, + ePortConnBothIntegratedAndJack, + ePortConnUnknown +} EPxcPortConnection; + +typedef struct +{ + DWORD ChannelMapping; + COLORREF Color; + EPcxConnectionType ConnectionType; + EPcxGeoLocation GeoLocation; + EPcxGenLocation GenLocation; + EPxcPortConnection PortConnection; + BOOL IsConnected; +} KSJACK_DESCRIPTION; + +typedef KSJACK_DESCRIPTION *PKSJACK_DESCRIPTION; + +typedef struct _LUID +{ + DWORD LowPart; + LONG HighPart; +} LUID; + +typedef struct _LUID *PLUID; + +typedef enum +{ + KSJACK_SINK_CONNECTIONTYPE_HDMI = 0, + KSJACK_SINK_CONNECTIONTYPE_DISPLAYPORT +} KSJACK_SINK_CONNECTIONTYPE; + +typedef struct _tagKSJACK_SINK_INFORMATION +{ + KSJACK_SINK_CONNECTIONTYPE ConnType; + WORD ManufacturerId; + WORD ProductId; + WORD AudioLatency; + BOOL HDCPCapable; + BOOL AICapable; + UCHAR SinkDescriptionLength; + WCHAR SinkDescription[32]; + LUID PortId; +} KSJACK_SINK_INFORMATION; + +typedef struct _tagKSJACK_DESCRIPTION2 +{ + DWORD DeviceStateInfo; + DWORD JackCapabilities; +} KSJACK_DESCRIPTION2; + +typedef struct _tagKSJACK_DESCRIPTION2 *PKSJACK_DESCRIPTION2; + +cpp_quote("#endif") + +typedef enum +{ + In = 0, + Out +} DataFlow; + +typedef enum +{ + Connector = 0, + Subunit +} PartType; + +typedef enum +{ + Unknown_Connector = 0, + Physical_Internal, + Physical_External, + Software_IO, + Software_Fixed, + Network +} ConnectorType; + +[ + pointer_default(unique), + nonextensible, + uuid(28f54685-06fd-11d2-b27a-00a0c9223196), + local, + object +] +interface IKsControl : IUnknown +{ + HRESULT KsProperty( + [in] PKSPROPERTY Property, + [in] ULONG PropertyLength, + [in,out] void *PropertyData, + [in] ULONG DataLength, + [out] ULONG *BytesReturned + ); + HRESULT KsMethod( + [in] PKSMETHOD Method, + [in] ULONG MethodLength, + [in,out] void *MethodData, + [in] ULONG DataLength, + [out] ULONG *BytesReturned + ); + HRESULT KsEvent( + [in] PKSEVENT Event, + [in] ULONG EventLength, + [in,out] void *EventData, + [in] ULONG DataLength, + [out] ULONG *BytesReturned + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(c2f8e001-f205-4bc9-99bc-c13b1e048ccb), + local, + object +] +interface IPerChannelDbLevel : IUnknown +{ + HRESULT GetChannelCount( + [out] UINT *pcChannels + ); + HRESULT GetLevelRange( + [in] UINT nChannel, + [out] float *pfMinLevelDB, + [out] float *pfMaxLevelDB, + [out] float *pfStepping + ); + HRESULT GetLevel( + [in] UINT nChannel, + [out] float *pfLevelDB + ); + HRESULT SetLevel( + [in] UINT nChannel, + [in] float fLevelDB, + [in,unique] LPCGUID pguidEventContext + ); + HRESULT SetLevelUniform( + [in] float fLevelDB, + [in,unique] LPCGUID pguidEventContext + ); + HRESULT SetLevelAllChannels( + [size_is(cChannels),in] float *aLevelsDB, + [in] ULONG cChannels, + [in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(7fb7b48f-531d-44a2-bcb3-5ad5a134b3dc), + local, + object +] +interface IAudioVolumeLevel : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb11c46f-ec28-493c-b88a-5db88062ce98), + local, + object +] +interface IAudioChannelConfig : IUnknown +{ + HRESULT SetChannelConfig( + [in] DWORD dwConfig, + [in] LPCGUID pguidEventContext + ); + HRESULT GetChannelConfig( + [in] DWORD dwConfig, + [retval,out] DWORD *pdwConfig + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(7d8b1437-dd53-4350-9c1b-1ee2890bf938), + local, + object +] +interface IAudioLoudness : IUnknown +{ + HRESULT GetEnabled( + [out] BOOL *pbEnabled + ); + HRESULT SetEnabled( + [in] BOOL bEnabled, + [in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(4f03dc02-5e6e-4653-8f72-a030c123d598), + local, + object +] +interface IAudioInputSelector : IUnknown +{ + HRESULT GetSelection( + [out] UINT *pnIdSelected + ); + HRESULT SetSelection( + [in] UINT nIdSelect, + [unique,in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb515f69-94a7-429e-8b9c-271b3f11a3ab), + local, + object +] +interface IAudioOutputSelector : IUnknown +{ + HRESULT GetSelection( + [out] UINT *pnIdSelected + ); + HRESULT SetSelection( + [in] UINT nIdSelect, + [unique,in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb515f69-94a7-429e-8b9c-271b3f11a3ab), + local, + object +] +interface IAudioMute : IUnknown +{ + HRESULT SetMute( + [in] BOOL bMute, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT GetMute( + [out] BOOL *pbMute + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(a2b1a1d9-4db3-425d-a2b2-bd335cb3e2e5), + local, + object +] +interface IAudioBass : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(5e54b6d7-b44b-40d9-9a9e-e691d9ce6edf), + local, + object +] +interface IAudioMidRange : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(0a717812-694e-4907-b74b-bafa5cfdca7b), + local, + object +] +interface IAudioTreble : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb515f69-94a7-429e-8b9c-271b3f11a3ab), + local, + object +] +interface IAudioAutoGainControl : IUnknown +{ + HRESULT GetEnabled( + [in] BOOL bEnabled, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT GetMute( + [out] BOOL *pbEnabled + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(dd79923c-0599-45e0-b8b6-c8df7db6e796), + local, + object +] +interface IAudioPeakMeter : IUnknown +{ + HRESULT GetChannelCount( + [out] UINT *pcChannels + ); + HRESULT GetLevel( + [in] UINT nChannel, + [out] float *pfLevel + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(3b22bcbf-2586-4af0-8583-205d391b807c), + local, + object +] +interface IDeviceSpecificProperty : IUnknown +{ + HRESULT GetType( + [out] VARTYPE *pVType + ); + HRESULT GetValue( + [out] VARTYPE *pvType, + [out,in] DWORD *pcbValue + ); + HRESULT SetValue( + [in] void *pvValue, + [in] DWORD cbValue, + [in] LPCGUID pguidEventContext + ); + HRESULT Get4BRange( + [out] LONG *plMin, + [out] LONG *plMax, + [out] LONG *plStepping + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(3cb4a69d-bb6f-4d2b-95b7-452d2c155db5), + local, + object +] +interface IKsFormatSupport : IUnknown +{ + HRESULT IsFormatSupported( + [size_is(cbFormat),in] PKSDATAFORMAT pKsFormat, + [in] DWORD cbFormat, + [out] BOOL *pbSupported + ); + HRESULT GetDevicePreferredFormat( + [out] PKSDATAFORMAT *ppKsFormat + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(4509f757-2d46-4637-8e62-ce7db944f57b), + local, + object +] +interface IKsJackDescription : IUnknown +{ + HRESULT GetJackCount( + [out] UINT *pcJacks + ); + HRESULT GetJackDescription( + [in] UINT nJack, + [out] KSJACK_DESCRIPTION *pDescription + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(478f3a9b-e0c9-4827-9228-6f5505ffe76a), + local, + object +] +interface IKsJackDescription2 : IUnknown +{ + HRESULT GetJackCount( + [out] UINT *pcJacks + ); + HRESULT GetJackDescription2( + [in] UINT nJack, + [out] KSJACK_DESCRIPTION2 *pDescription2 + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(d9bd72ed-290f-4581-9ff3-61027a8fe532), + local, + object +] +interface IKsJackSinkInformation : IUnknown +{ + HRESULT GetJackSinkInformation( + [out] KSJACK_SINK_INFORMATION *pJackSinkInformation + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(6daa848c-5eb0-45cc-aea5-998a2cda1ffb), + local, + object +] +interface IPartsList : IUnknown +{ + HRESULT GetCount( + [out] UINT *pCount + ); + HRESULT GetPart( + [in] UINT nIndex, + [out] IPart **ppPart + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(ae2de0e4-5bca-4f2d-aa46-5d13f8fdb3a9), + local, + object +] +interface IPart : IUnknown +{ + HRESULT GetName( + [out] LPWSTR *ppwstrName + ); + HRESULT GetLocalId( + [out] UINT *pnId + ); + HRESULT GetGlobalId( + [out] LPWSTR *ppwstrGlobalId + ); + HRESULT GetPartType( + [out] PartType *pPartType + ); + HRESULT GetSubType( + [out] GUID *pSubType + ); + HRESULT GetControlInterfaceCount( + [out] UINT *pCount + ); + HRESULT GetControlInterface( + [in] UINT nIndex, + [out] IControlInterface **ppInterfaceDesc + ); + HRESULT EnumPartsIncoming( + [out] IPartsList **ppParts + ); + HRESULT EnumPartsOutgoing( + [out] IPartsList **ppParts + ); + HRESULT GetTopologyObjects( + [out] IDeviceTopology **ppTopology + ); + HRESULT Activate( + [in] DWORD dwClsContext, + [in] REFIID refiid, + [iid_is(refiid),out] void **ppvObject + ); + HRESULT RegisterControlChangeCallback( + [in] REFGUID riid, + [in] IControlChangeNotify *pNotify + ); + HRESULT UnregisterControlChangeCallback( + [in] IControlChangeNotify *pNotify + ); +}; + +[ + pointer_default(unique), + nonextensible, + uuid(9c2c4058-23f5-41de-877a-df3af236a09e), + local, + object +] +interface IConnector : IUnknown +{ + HRESULT GetType( + [out] ConnectorType *pType + ); + HRESULT GetDataFlow( + [out] DataFlow *pFlow + ); + HRESULT ConnectTo( + [in] IConnector *pConnectTo + ); + HRESULT Disconnect(void); + HRESULT IsConnected( + [out] BOOL *pbConnected + ); + HRESULT GetConnectedTo( + [out] IConnector **ppConTo + ); + HRESULT GetConnectorIdConnectedTo( + [out] LPWSTR *ppwstrConnectorId + ); + HRESULT GetDeviceIdConnectedTo( + [out] LPWSTR *ppwstrDeviceId + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(82149a85-dba6-4487-86bb-ea8f7fefcc71), + local, + object +] +interface ISubUnit: IUnknown +{ + /* Empty IUnknown interface.. */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(45d37c3f-5140-444a-ae24-400789f3cbf3), + local, + object +] +interface IControlInterface : IUnknown +{ + HRESULT GetName( + [out] LPWSTR *ppwstrName + ); + HRESULT GetIID( + [out] GUID *pIID + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(a09513ed-c709-4d21-bd7b-5f34c47f3947), + local, + object +] +interface IControlChangeNotify : IUnknown +{ + HRESULT OnNotify( + [in] DWORD dwSenderProcessId, + [in] LPCGUID ppguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(2a07407e-6497-4a18-9787-32f79bd0d98f), + local, + object +] +interface IDeviceTopology : IUnknown +{ + HRESULT GetConnectorCount( + [out] UINT *pCount + ); + HRESULT GetConnector( + [in] UINT nIndex, + [out] IConnector **ppConnector + ); + HRESULT GetSubunitCount( + [out] UINT *pCount + ); + HRESULT GetSubunit( + [in] UINT nIndex, + [out] ISubUnit **ppConnector + ); + HRESULT GetPartById( + [in] UINT nId, + [out] IPart **ppPart + ); + HRESULT GetDeviceId( + [out] LPWSTR *ppwstrDeviceId + ); + HRESULT GetSignalPath( + [in] IPart *pIPartFrom, + [in] IPart *pIPartTo, + [in] BOOL bRejectMixedPaths, + [out] IPartsList **ppParts + ); +} + +[ + version(1.0) +] +library DevTopologyLib +{ + [ + uuid(1df639d0-5ec1-47aa-9379-828dc1aa8c59), + ] + coclass DeviceTopology + { + interface IDeviceTopology; + } +} diff --git a/reactos/include/psdk/devpropdef.h b/reactos/include/psdk/devpropdef.h index f53086efcc4..ab8fbf0643e 100644 --- a/reactos/include/psdk/devpropdef.h +++ b/reactos/include/psdk/devpropdef.h @@ -96,8 +96,13 @@ typedef struct _DEVPROPKEY { const DEVPROPKEY DECLSPEC_HIDDEN DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } #endif #else +#ifdef __GNUC__ +#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) \ + EXTERN_C const DEVPROPKEY DECLSPEC_HIDDEN name +#else #define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) \ EXTERN_C const DEVPROPKEY DECLSPEC_HIDDEN DECLSPEC_SELECTANY name +#endif #endif /* INITGUID */ #ifndef IsEqualDevPropKey diff --git a/reactos/include/psdk/endpointvolume.idl b/reactos/include/psdk/endpointvolume.idl new file mode 100644 index 00000000000..eaf4f8a128c --- /dev/null +++ b/reactos/include/psdk/endpointvolume.idl @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2009 Maarten Lankhorst + * + * 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 + */ + +import "unknwn.idl"; +import "devicetopology.idl"; + +typedef struct AUDIO_VOLUME_NOTIFICATION_DATA +{ + GUID guidEventContext; + BOOL bMuted; + FLOAT fMasterVolume; + UINT nChannels; + FLOAT afChannelVolumes[1]; +} AUDIO_VOLUME_NOTIFICATION_DATA; + +cpp_quote("typedef struct AUDIO_VOLUME_NOTIFICATION_DATA *PAUDIO_VOLUME_NOTIFICATION_DATA;") + +cpp_quote("#define ENDPOINT_HARDWARE_SUPPORT_VOLUME 0x1") +cpp_quote("#define ENDPOINT_HARDWARE_SUPPORT_MUTE 0x2") +cpp_quote("#define ENDPOINT_HARDWARE_SUPPORT_METER 0x4") + +interface IAudioEndpointVolumeCallback; +interface IAudioEndpointVolume; +interface IAudioEndpointVolumeEx; +interface IAudioMeterInformation; + +[ + pointer_default(unique), + nonextensible, + uuid(657804fa-d6ad-4496-8a60-352752af4f89), + local, + object +] +interface IAudioEndpointVolumeCallback : IUnknown +{ + HRESULT OnNotify( + AUDIO_VOLUME_NOTIFICATION_DATA *pNotify + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(5cdf2c82-841e-4546-9722-0cf74078229a), + local, + object +] +interface IAudioEndpointVolume : IUnknown +{ + HRESULT RegisterControlChangeNotify( + [in] IAudioEndpointVolumeCallback *pNotify + ); + HRESULT UnregisterControlChangeNotify( + [in] IAudioEndpointVolumeCallback *pNotify + ); + HRESULT GetChannelCount( + [out] UINT *pnChannelCount + ); + HRESULT SetMasterVolumeLevel( + [in] FLOAT fLevelDB, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT SetMasterVolumeLevelScalar( + [in] FLOAT fLevel, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT GetMasterVolumeLevel( + [out] FLOAT *fLevelDB + ); + HRESULT GetMasterVolumeLevelScalar( + [out] FLOAT *fLevel + ); + HRESULT SetChannelVolumeLevel( + [in] UINT nChannel, + [in] FLOAT fLevelDB, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT SetChannelVolumeLevelScalar( + [in] UINT nChannel, + [in] FLOAT fLevel, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT GetChannelVolumeLevel( + [in] UINT nChannel, + [out] FLOAT *fLevelDB + ); + HRESULT GetChannelVolumeLevelScalar( + [in] UINT nChannel, + [out] FLOAT *fLevel + ); + HRESULT SetMute( + [in] BOOL bMute, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT GetMute( + [out] BOOL *bMute + ); + HRESULT GetVolumeStepInfo( + [out] UINT *pnStep, + [out] UINT *pnStepCount + ); + HRESULT VolumeStepUp( + [unique,in] LPCGUID pguidEventContext + ); + HRESULT VolumeStepDown( + [unique,in] LPCGUID pguidEventContext + ); + HRESULT QueryHardwareSupport( + [out] DWORD *pdwHardwareSupportMask + ); + HRESULT GetVolumeRange( + [out] FLOAT *pflVolumeMindB, + [out] FLOAT *pflVolumeMaxdB, + [out] FLOAT *pflVolumeIncrementdB + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(66e11784-f695-4f28-a505-a7080081a78f), + local, + object +] +interface IAudioEndpointVolumeEx : IAudioEndpointVolume +{ + HRESULT GetVolumeRangeChannel( + [in] UINT iChannel, + [out] FLOAT *pflVolumeMindB, + [out] FLOAT *pflVolumeMaxdB, + [out] FLOAT *pflVolumeIncrementdB + ); +} diff --git a/reactos/include/psdk/ksmedia.h b/reactos/include/psdk/ksmedia.h index bef44f557e4..5146a9d8636 100644 --- a/reactos/include/psdk/ksmedia.h +++ b/reactos/include/psdk/ksmedia.h @@ -814,6 +814,110 @@ typedef struct ULONG ChannelMask; } KSDATARANGE_MUSIC, *PKSDATARANGE_MUSIC; +#if (NTDDI_VERSION >= NTDDI_WINXPSP1) + +#define STATIC_KSPROPSETID_Jack\ + 0x4509f757, 0x2d46, 0x4637, {0x8e, 0x62, 0xce, 0x7d, 0xb9, 0x44, 0xf5, 0x7b} +DEFINE_GUIDSTRUCT("4509F757-2D46-4637-8E62-CE7DB944F57B", KSPROPSETID_Jack); +#define KSPROPSETID_Jack DEFINE_GUIDNAMED(KSPROPSETID_Jack) + +typedef enum { + KSPROPERTY_JACK_DESCRIPTION = 1, + KSPROPERTY_JACK_DESCRIPTION2, + KSPROPERTY_JACK_SINK_INFO, + KSPROPERTY_JACK_CONTAINERID +} KSPROPERTY_JACK; + +typedef enum { + eConnTypeUnknown, + eConnType3Point5mm, + eConnTypeQuarter, + eConnTypeAtapiInternal, + eConnTypeRCA, + eConnTypeOptical, + eConnTypeOtherDigital, + eConnTypeOtherAnalog, + eConnTypeMultichannelAnalogDIN, + eConnTypeXlrProfessional, + eConnTypeRJ11Modem, + eConnTypeCombination +} EPcxConnectionType; + +#define eGeoLocReserved5 eGeoLocNotApplicable + +typedef enum { + eGeoLocRear = 0x1, + eGeoLocFront, + eGeoLocLeft, + eGeoLocRight, + eGeoLocTop, + eGeoLocBottom, + eGeoLocRearPanel, + eGeoLocRiser, + eGeoLocInsideMobileLid, + eGeoLocDrivebay, + eGeoLocHDMI, + eGeoLocOutsideMobileLid, + eGeoLocATAPI, + eGeoLocNotApplicable, + eGeoLocReserved6, + EPcxGeoLocation_enum_count +} EPcxGeoLocation; + +typedef enum { + eGenLocPrimaryBox = 0, + eGenLocInternal, + eGenLocSeparate, + eGenLocOther, + EPcxGenLocation_enum_count +} EPcxGenLocation; + +typedef enum { + ePortConnJack = 0, + ePortConnIntegratedDevice, + ePortConnBothIntegratedAndJack, + ePortConnUnknown +} EPxcPortConnection; + +typedef struct { + DWORD ChannelMapping; + DWORD Color; + EPcxConnectionType ConnectionType; + EPcxGeoLocation GeoLocation; + EPcxGenLocation GenLocation; + EPxcPortConnection PortConnection; + BOOL IsConnected; +} KSJACK_DESCRIPTION, *PKSJACK_DESCRIPTION; + +typedef enum { + KSJACK_SINK_CONNECTIONTYPE_HDMI = 0, + KSJACK_SINK_CONNECTIONTYPE_DISPLAYPORT +} KSJACK_SINK_CONNECTIONTYPE; + +#define MAX_SINK_DESCRIPTION_NAME_LENGTH 32 + +typedef struct _tagKSJACK_SINK_INFORMATION { + KSJACK_SINK_CONNECTIONTYPE ConnType; + WORD ManufacturerId; + WORD ProductId; + WORD AudioLatency; + BOOL HDCPCapable; + BOOL AICapable; + UCHAR SinkDescriptionLength; + WCHAR SinkDescription[MAX_SINK_DESCRIPTION_NAME_LENGTH]; + LUID PortId; +} KSJACK_SINK_INFORMATION, *PKSJACK_SINK_INFORMATION; + +#define JACKDESC2_PRESENCE_DETECT_CAPABILITY 0x1 +#define JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY 0x2 + +typedef struct _tagKSJACK_DESCRIPTION2 { + DWORD DeviceStateInfo; + DWORD JackCapabilities; +} KSJACK_DESCRIPTION2, *PKSJACK_DESCRIPTION2; + +#endif /* (NTDDI_VERSION >= NTDDI_WINXPSP1) */ + #ifndef _SPEAKER_POSITIONS_ #define _SPEAKER_POSITIONS_ diff --git a/reactos/lib/sdk/uuid/otherguids.c b/reactos/lib/sdk/uuid/otherguids.c index c3f3589b7c2..f12cbb7e8e0 100644 --- a/reactos/lib/sdk/uuid/otherguids.c +++ b/reactos/lib/sdk/uuid/otherguids.c @@ -51,3 +51,6 @@ DEFINE_GUID(CLSID_StdPicture, 0x0BE35204, 0x8F91, 0x11CE, 0x9D,0xE3, 0x00,0xAA,0 DEFINE_GUID(CLSID_StdFont, 0x0BE35203, 0x8F91, 0x11CE, 0x9D,0xE3, 0x00,0xAA,0x00,0x4B,0xB8,0x51); DEFINE_GUID(SID_VariantConversion, 0x1f101481,0xbccd,0x11d0,0x93,0x36,0x00,0xa0,0xc9,0xd,0xca,0xa9); + +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 3d21994fefb..d11c0ee7e5a 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -103,6 +103,7 @@ reactos/dll/win32/mciqtz32 # Synced to Wine-1.7.1 reactos/dll/win32/mciseq # Synced to Wine-1.7.1 reactos/dll/win32/mciwave # Synced to Wine-1.5.19 reactos/dll/win32/mlang # Synced to Wine-1.7.1 +reactos/dll/win32/mmdevapi # Synced to Wine-1.7.1 reactos/dll/win32/mpr # Synced to Wine-1.7.1 reactos/dll/win32/mprapi # Synced to Wine-1.5.19 reactos/dll/win32/msacm32 # Synced to Wine-1.7.1 diff --git a/reactos/media/inf/syssetup.inf b/reactos/media/inf/syssetup.inf index c63420a8361..44dc64f8043 100644 --- a/reactos/media/inf/syssetup.inf +++ b/reactos/media/inf/syssetup.inf @@ -59,6 +59,7 @@ AddReg=Classes 11,,jscript.dll,1 ;11,,ksproxy.ax,1 11,,mlang.dll,1 +11,,mmdevapi.dll,1 11,,mscat32.dll,1 11,,msctf.dll,1 11,,mshtml.dll,3