You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
985 lines
30 KiB
985 lines
30 KiB
/* mme.cpp
|
|
* Handles pnp, etc. for MME APIs
|
|
* Created by FrankYe on 2/14/2001
|
|
* Copyright (c) 2001-2001 Microsoft Corporation
|
|
*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <regstr.h>
|
|
#include <mmsystem.h>
|
|
#include <mmsysp.h>
|
|
#include <ks.h>
|
|
#include <ksmedia.h>
|
|
#include <setupapi.h>
|
|
|
|
#include "debug.h"
|
|
#include "reg.h"
|
|
#include "service.h"
|
|
#include "audiosrv.h"
|
|
|
|
//=============================================================================
|
|
//=== file scope constants ===
|
|
//=============================================================================
|
|
#define REGSTR_VAL_SETUPPREFERREDAUDIODEVICES TEXT("SetupPreferredAudioDevices")
|
|
#define REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT TEXT("SetupPreferredAudioDevicesCount")
|
|
|
|
#define PNPINFOSIZE (256 * 1024)
|
|
|
|
//=============================================================================
|
|
//=== file scope globals ===
|
|
//=============================================================================
|
|
RTL_RESOURCE PnpInfoResource;
|
|
BOOL gfPnpInfoResource = FALSE;
|
|
HANDLE hPnpInfo = NULL;
|
|
PMMPNPINFO pPnpInfo = NULL;
|
|
|
|
//=============================================================================
|
|
//=== security helpers ===
|
|
//=============================================================================
|
|
|
|
PSECURITY_DESCRIPTOR BuildSecurityDescriptor(DWORD AccessMask)
|
|
{
|
|
PSECURITY_DESCRIPTOR pSd;
|
|
PSID pSidSystem;
|
|
PSID pSidEveryone;
|
|
PACL pDacl;
|
|
ULONG cbDacl;
|
|
BOOL fSuccess;
|
|
BOOL f;
|
|
|
|
SID_IDENTIFIER_AUTHORITY AuthorityNt = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY AuthorityWorld = SECURITY_WORLD_SID_AUTHORITY;
|
|
|
|
fSuccess = FALSE;
|
|
|
|
pSd = HeapAlloc(hHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
if (pSd)
|
|
{
|
|
if (InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
if (AllocateAndInitializeSid(&AuthorityNt, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSidSystem))
|
|
{
|
|
ASSERT(IsValidSid(pSidSystem));
|
|
if (AllocateAndInitializeSid(&AuthorityWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSidEveryone))
|
|
{
|
|
ASSERT(IsValidSid(pSidEveryone));
|
|
cbDacl = sizeof(ACL) +
|
|
2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
|
|
GetLengthSid(pSidSystem) +
|
|
GetLengthSid(pSidEveryone);
|
|
|
|
pDacl = (PACL)HeapAlloc(hHeap, 0, cbDacl);
|
|
if (pDacl) {
|
|
if (InitializeAcl(pDacl, cbDacl, ACL_REVISION))
|
|
{
|
|
if (AddAccessAllowedAce(pDacl, ACL_REVISION, GENERIC_ALL, pSidSystem))
|
|
{
|
|
if (AddAccessAllowedAce(pDacl, ACL_REVISION, AccessMask, pSidEveryone))
|
|
{
|
|
if (SetSecurityDescriptorDacl(pSd, TRUE, pDacl, FALSE))
|
|
{
|
|
fSuccess = TRUE;
|
|
} else {
|
|
dprintf(TEXT("BuildSD: SetSecurityDescriptorDacl failed\n"));
|
|
}
|
|
} else {
|
|
dprintf(TEXT("BuildSD: AddAccessAlloweAce for Everyone failed\n"));
|
|
}
|
|
} else {
|
|
dprintf(TEXT("BuildSD: AddAccessAllowedAce for System failed\n"));
|
|
}
|
|
} else {
|
|
dprintf(TEXT("BuildSD: InitializeAcl failed\n"));
|
|
}
|
|
|
|
if (!fSuccess) {
|
|
f = HeapFree(hHeap, 0, pDacl);
|
|
ASSERT(f);
|
|
}
|
|
}
|
|
FreeSid(pSidEveryone);
|
|
} else {
|
|
dprintf(TEXT("BuildSD: AllocateAndInitizeSid failed for Everyone\n"));
|
|
}
|
|
FreeSid(pSidSystem);
|
|
} else {
|
|
dprintf(TEXT("BuildSD: AllocateAndInitizeSid failed for System\n"));
|
|
}
|
|
} else {
|
|
dprintf(TEXT("BuildSD: InitializeSecurityDescriptor failed\n"));
|
|
}
|
|
|
|
if (!fSuccess) {
|
|
f = HeapFree(hHeap, 0, pSd);
|
|
ASSERT(f);
|
|
}
|
|
}
|
|
|
|
return fSuccess ? pSd : NULL;
|
|
}
|
|
|
|
void DestroySecurityDescriptor(PSECURITY_DESCRIPTOR pSd)
|
|
{
|
|
PACL pDacl;
|
|
BOOL fDaclPresent;
|
|
BOOL fDaclDefaulted;
|
|
BOOL f;
|
|
|
|
if (GetSecurityDescriptorDacl(pSd, &fDaclPresent, &pDacl, &fDaclDefaulted))
|
|
{
|
|
if (fDaclPresent)
|
|
{
|
|
f = HeapFree(hHeap, 0, pDacl);
|
|
ASSERT(f);
|
|
}
|
|
} else {
|
|
dprintf(TEXT("DestroySD: GetSecurityDescriptorDacl failed\n"));
|
|
}
|
|
|
|
f = HeapFree(hHeap, 0, pSd);
|
|
ASSERT(f);
|
|
|
|
return;
|
|
}
|
|
|
|
//=============================================================================
|
|
//=== ===
|
|
//=============================================================================
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// PTSTR BroadcastWinmmDeviceChange
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return value:
|
|
//
|
|
// History:
|
|
// 11/9/98 FrankYe Created
|
|
// 2/15/2001 FrankYe Moved from winmm to audiosrv
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
void BroadcastWinmmDeviceChange(void)
|
|
{
|
|
static UINT uWinmmDeviceChange = 0;
|
|
|
|
if (!uWinmmDeviceChange) {
|
|
uWinmmDeviceChange = RegisterWindowMessage(WINMMDEVICECHANGEMSGSTRING);
|
|
// dprintf(TEXT("BroadcastWinmmDeviceChange: WINMMDEVICECHANGEMSG = %d\n"), uWinmmDeviceChange);
|
|
if (!uWinmmDeviceChange) {
|
|
dprintf(TEXT("BroadcastWinmmDeviceChange: RegisterWindowMessage failed!\n"));
|
|
}
|
|
}
|
|
|
|
if (uWinmmDeviceChange) {
|
|
DWORD dwRecipients = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
|
|
long result;
|
|
|
|
// dprintf(TEXT("BroadcastWinmmDeviceChange: BroadcastSystemMessage\n"));
|
|
result = BroadcastSystemMessage(BSF_POSTMESSAGE, &dwRecipients,
|
|
uWinmmDeviceChange, 0, 0);
|
|
if (result < 0) {
|
|
dprintf(TEXT("BroadcastWinmmDeviceChange: BroadcastSystemMessage failed\n"));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// PTSTR MakeRendererDeviceInstanceIdFromDeviceInterface
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return value:
|
|
//
|
|
// History:
|
|
// 11/9/98 FrankYe Created
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
PTSTR MakeRendererDeviceInstanceIdFromDeviceInterface(PWSTR DeviceInterface)
|
|
{
|
|
PTSTR DeviceInstanceId;
|
|
HDEVINFO hdi;
|
|
DWORD dwLastError;
|
|
|
|
// dprintf(TEXT("MRDIIFDI: DeviceInterface=%ls\n"), DeviceInterface);
|
|
DeviceInstanceId = NULL;
|
|
hdi = SetupDiCreateDeviceInfoList(NULL, NULL);
|
|
if (INVALID_HANDLE_VALUE != hdi)
|
|
{
|
|
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
|
|
|
|
// dprintf(TEXT("MRDIIFDI: Created empty DeviceInfoList\n"));
|
|
DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
|
|
if (SetupDiOpenDeviceInterface(hdi, DeviceInterface, 0,
|
|
&DeviceInterfaceData))
|
|
{
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
DWORD cbDeviceInterfaceDetail;
|
|
|
|
// dprintf(TEXT("MRDIIFDI: Opened DeviceInterface\n"));
|
|
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
|
|
if (SetupDiGetDeviceInterfaceDetail(hdi, &DeviceInterfaceData, NULL, 0, &cbDeviceInterfaceDetail, &DeviceInfoData) ||
|
|
(ERROR_INSUFFICIENT_BUFFER == GetLastError()))
|
|
{
|
|
DWORD cchDeviceInstanceId;
|
|
|
|
// dprintf(TEXT("MRDIIFDI: Got DeviceInfoData\n"));
|
|
if (SetupDiGetDeviceInstanceId(hdi, &DeviceInfoData, NULL, 0, &cchDeviceInstanceId) ||
|
|
ERROR_INSUFFICIENT_BUFFER == GetLastError())
|
|
{
|
|
// dprintf(TEXT("MRDIIFDI: DeviceInstanceId is %d characters\n"), cchDeviceInstanceId);
|
|
DeviceInstanceId = (PTSTR)HeapAlloc(hHeap, 0, cchDeviceInstanceId * sizeof(DeviceInstanceId[0]));
|
|
if (DeviceInstanceId)
|
|
{
|
|
// dprintf(TEXT("MRDIIFDI: Allocated storage for DeviceInstanceId\n"));
|
|
if (SetupDiGetDeviceInstanceId(hdi, &DeviceInfoData,
|
|
DeviceInstanceId,
|
|
cchDeviceInstanceId, NULL))
|
|
{
|
|
// dprintf(TEXT("MRDIIFDI: DeviceInstanceId=%ls\n"), DeviceInstanceId);
|
|
} else {
|
|
BOOL f;
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: Couldn't query DeviceInstanceId, LastError=%d\n"), dwLastError);
|
|
f = HeapFree(hHeap, 0, DeviceInstanceId);
|
|
DeviceInstanceId = NULL;
|
|
ASSERT(f);
|
|
}
|
|
} else {
|
|
dprintf(TEXT("MRDIIFDI: Could not allocate storage for DeviceInstanceId\n"));
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: Couldn't query size of DeviceInstanceId, LastError=%d\n"), dwLastError);
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: SetupDiGetDeviceInterfaceDetail failed LastError=%d\n"), dwLastError);
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: SetupDiOpenDeviceInterface failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
|
|
if (!SetupDiDestroyDeviceInfoList(hdi))
|
|
{
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: SetupDiDestroyDeviceInfoList failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: SetupDiCreateDeviceInfoList failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
return DeviceInstanceId;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// MigrageNewDeviceInterfaceSetup
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return value:
|
|
//
|
|
// History:
|
|
// 1/19/99 FrankYe Created
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
void MigrateNewDeviceInterfaceSetup(PMMDEVICEINTERFACEINFO pdii, DWORD CurrentSetupCount)
|
|
{
|
|
HDEVINFO hdi;
|
|
DWORD dwLastError;
|
|
DWORD SetupCount;
|
|
|
|
SetupCount = 0;
|
|
|
|
hdi = SetupDiCreateDeviceInfoList(NULL, NULL);
|
|
if (INVALID_HANDLE_VALUE != hdi)
|
|
{
|
|
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
|
|
|
|
DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
|
|
if (SetupDiOpenDeviceInterface(hdi, pdii->szName, 0, &DeviceInterfaceData))
|
|
{
|
|
HKEY hkeyDeviceInterface;
|
|
|
|
hkeyDeviceInterface = SetupDiCreateDeviceInterfaceRegKeyW(hdi, &DeviceInterfaceData, 0, KEY_SET_VALUE | KEY_QUERY_VALUE, NULL, NULL);
|
|
if (INVALID_HANDLE_VALUE != hkeyDeviceInterface)
|
|
{
|
|
LONG result;
|
|
|
|
result = RegQueryDwordValue(hkeyDeviceInterface, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount);
|
|
if ((ERROR_SUCCESS != result) || (SetupCount < CurrentSetupCount))
|
|
{
|
|
SetupCount = CurrentSetupCount;
|
|
if (ERROR_SUCCESS == RegSetDwordValue(hkeyDeviceInterface, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, SetupCount))
|
|
{
|
|
// dprintf(TEXT("MNDIS: Success\n"));
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MNDIS: RegSetValueEx failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
}
|
|
|
|
result = RegCloseKey(hkeyDeviceInterface);
|
|
ASSERT(ERROR_SUCCESS == result);
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MNDIS: SetupDiCreateDeviceInterfaceRegKey failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: SetupDiOpenDeviceInterface failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
|
|
if (!SetupDiDestroyDeviceInfoList(hdi))
|
|
{
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: SetupDiDestroyDeviceInfoList failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MRDIIFDI: SetupDiCreateDeviceInfoList failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
|
|
pdii->SetupPreferredAudioCount = SetupCount;
|
|
return;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// MigrateNewDeviceInstanceSetup
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return value:
|
|
//
|
|
// History:
|
|
// 11/9/98 FrankYe Created
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
void MigrateNewDeviceInstanceSetup(PTSTR DeviceInstanceId, PDWORD pSetupCountOut)
|
|
{
|
|
HDEVINFO hdi;
|
|
DWORD dwLastError;
|
|
|
|
*pSetupCountOut = 0;
|
|
|
|
hdi = SetupDiCreateDeviceInfoList(NULL, NULL);
|
|
if (INVALID_HANDLE_VALUE != hdi)
|
|
{
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
|
|
// dprintf(TEXT("MNDS: Created empty DeviceInfoList\n"));
|
|
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
|
|
if (SetupDiOpenDeviceInfoW(hdi, DeviceInstanceId, NULL, 0, &DeviceInfoData))
|
|
{
|
|
HKEY hkeyDriver;
|
|
|
|
hkeyDriver = SetupDiOpenDevRegKey(hdi, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE | KEY_SET_VALUE);
|
|
if (INVALID_HANDLE_VALUE != hkeyDriver) {
|
|
HKEY hkeyMmeDrivers;
|
|
|
|
dwLastError = RegOpenKeyEx(hkeyDriver, TEXT("Drivers"), 0, KEY_QUERY_VALUE, &hkeyMmeDrivers);
|
|
if (ERROR_SUCCESS == dwLastError)
|
|
{
|
|
|
|
DWORD fNewInstall;
|
|
BOOL fSetupPreferredAudioDevices;
|
|
DWORD cbfSetupPreferredAudioDevices;
|
|
DWORD SetupCount;
|
|
|
|
// Read the driver's existing setup count. If it doesn't exist
|
|
// then this is a new install.
|
|
dwLastError = RegQueryDwordValue(hkeyDriver, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount);
|
|
if (ERROR_SUCCESS == dwLastError) {
|
|
fNewInstall = FALSE;
|
|
} else if (ERROR_FILE_NOT_FOUND == dwLastError) {
|
|
fNewInstall = TRUE;
|
|
SetupCount = 0;
|
|
dwLastError = ERROR_SUCCESS;
|
|
} else {
|
|
fNewInstall = FALSE;
|
|
SetupCount = 0;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwLastError)
|
|
{
|
|
// Read the driver's SetupPreferredAudioDevices flag.
|
|
cbfSetupPreferredAudioDevices = sizeof(fSetupPreferredAudioDevices);
|
|
dwLastError = RegQueryValueEx(hkeyDriver, REGSTR_VAL_SETUPPREFERREDAUDIODEVICES, NULL, NULL, (PBYTE)&fSetupPreferredAudioDevices, &cbfSetupPreferredAudioDevices);
|
|
if (ERROR_FILE_NOT_FOUND == dwLastError) {
|
|
fSetupPreferredAudioDevices = FALSE;
|
|
dwLastError = ERROR_SUCCESS;
|
|
}
|
|
|
|
// If this is a new install AND the driver .inf set the
|
|
// fSetupPreferredAudioDevices flag, then let's try to
|
|
// increment the machine setupcount and write the driver
|
|
// setupcount.
|
|
if ((ERROR_SUCCESS == dwLastError) && fNewInstall && fSetupPreferredAudioDevices)
|
|
{
|
|
HKEY hkeySetupPreferredAudioDevices;
|
|
|
|
dwLastError = RegCreateKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_MEDIARESOURCES TEXT("\\") REGSTR_VAL_SETUPPREFERREDAUDIODEVICES, &hkeySetupPreferredAudioDevices);
|
|
if (ERROR_SUCCESS == dwLastError)
|
|
{
|
|
dwLastError = RegQueryDwordValue(hkeySetupPreferredAudioDevices, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount);
|
|
if (ERROR_FILE_NOT_FOUND == dwLastError) {
|
|
SetupCount = 0;
|
|
dwLastError = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwLastError)
|
|
{
|
|
SetupCount++;
|
|
dwLastError = RegSetDwordValue(hkeySetupPreferredAudioDevices, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, SetupCount);
|
|
if (ERROR_SUCCESS != dwLastError) dprintf(TEXT("MNDIS: Couldn't set count\n"));
|
|
}
|
|
|
|
RegCloseKey(hkeySetupPreferredAudioDevices);
|
|
} else {
|
|
dprintf(TEXT("MNDIS: Couldn't create hklm\\...\\SetupPreferredAudioDevices\n"));
|
|
}
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwLastError) {
|
|
// We've successfully read, incremented, and written the
|
|
// setup version to HKLM, or we've done nothing because we
|
|
// didn't have to.
|
|
if (fNewInstall) RegSetDwordValue(hkeyDriver, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, SetupCount);
|
|
if (fSetupPreferredAudioDevices) RegDeleteValue(hkeyDriver, REGSTR_VAL_SETUPPREFERREDAUDIODEVICES);
|
|
}
|
|
|
|
}
|
|
|
|
// Return the SetupCount for the driver
|
|
*pSetupCountOut = SetupCount;
|
|
|
|
RegCloseKey(hkeyMmeDrivers);
|
|
|
|
}
|
|
|
|
RegCloseKey(hkeyDriver);
|
|
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MNDS: SetupDiCreateDevRegKey failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MNDS: SetupDiOpenDeviceInfo failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
|
|
if (!SetupDiDestroyDeviceInfoList(hdi))
|
|
{
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MNDS: SetupDiDestroyDeviceInfoList failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
dprintf(TEXT("MNDS: SetupDiCreateDeviceInfoList failed, LastError=%d\n"), dwLastError);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
//
|
|
// MigrateAutoSetupPreferredAudio
|
|
//
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
void MigrateAutoSetupPreferredAudio(PMMDEVICEINTERFACEINFO pdii)
|
|
{
|
|
PTSTR pstrRendererDeviceInstanceId;
|
|
DWORD SetupCount;
|
|
|
|
SetupCount = 0;
|
|
pstrRendererDeviceInstanceId = MakeRendererDeviceInstanceIdFromDeviceInterface(pdii->szName);
|
|
|
|
if (pstrRendererDeviceInstanceId) {
|
|
BOOL f;
|
|
MigrateNewDeviceInstanceSetup(pstrRendererDeviceInstanceId, &SetupCount);
|
|
f = HeapFree(hHeap, 0, pstrRendererDeviceInstanceId);
|
|
ASSERT(f);
|
|
}
|
|
|
|
MigrateNewDeviceInterfaceSetup(pdii, SetupCount);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PMMDEVICEINTERFACEINFO pnpServerInstallDevice
|
|
(
|
|
PCTSTR pszDeviceInterface,
|
|
BOOL fRemove
|
|
)
|
|
{
|
|
PMMDEVICEINTERFACEINFO pdii;
|
|
PWSTR pszDev;
|
|
UINT ii;
|
|
|
|
if (NULL == pPnpInfo)
|
|
{
|
|
dprintf(TEXT("pnpServerInstallDevice called at bad time\n"));
|
|
ASSERT(FALSE);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
pdii = (PMMDEVICEINTERFACEINFO)&(pPnpInfo[1]);
|
|
|
|
pdii = (PMMDEVICEINTERFACEINFO)PAD_POINTER(pdii);
|
|
|
|
for (ii = pPnpInfo->cDevInterfaces; ii; ii--)
|
|
{
|
|
// Searching for the device interface...
|
|
|
|
pszDev = (PWSTR)(&(pdii->szName[0]));
|
|
|
|
if (0 == lstrcmpi(pszDev, pszDeviceInterface))
|
|
{
|
|
break;
|
|
}
|
|
|
|
pdii = (PMMDEVICEINTERFACEINFO)(pszDev + lstrlenW(pszDev) + 1);
|
|
pdii = (PMMDEVICEINTERFACEINFO)PAD_POINTER(pdii);
|
|
}
|
|
|
|
// Getting the current settings...
|
|
|
|
if (0 == ii)
|
|
{
|
|
PMMDEVICEINTERFACEINFO pdiiNext;
|
|
SIZE_T sizePnpInfo;
|
|
|
|
// Does not exist, create it, first ensuring there is enough room
|
|
|
|
pdiiNext = (PMMDEVICEINTERFACEINFO)(pdii->szName + ((lstrlenW(pszDeviceInterface) + 1)));
|
|
pdiiNext = (PMMDEVICEINTERFACEINFO)PAD_POINTER(pdiiNext);
|
|
sizePnpInfo = ((PBYTE)pdiiNext) - ((PBYTE)pPnpInfo);
|
|
if (sizePnpInfo < PNPINFOSIZE)
|
|
{
|
|
// dprintf(TEXT("pnpServerInstallDevice: note: sizePnpInfo = %p\n", sizePnpInfo);
|
|
|
|
pdii->cPnpEvents = 0;
|
|
pdii->fdwInfo = 0L;
|
|
|
|
pszDev = (PWSTR)(&(pdii->szName[0]));
|
|
lstrcpy(pszDev, pszDeviceInterface);
|
|
|
|
pPnpInfo->cDevInterfaces++;
|
|
pPnpInfo->cbSize = (DWORD)sizePnpInfo;
|
|
} else {
|
|
dprintf(TEXT("pnpServerInstallDevice RAN OUT OF PNPINO STORAGE!!!\n"));
|
|
pdii = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Already exists, increment the event count.
|
|
pdii->cPnpEvents++;
|
|
}
|
|
|
|
// Set or clear the "removed" bit.
|
|
if (pdii)
|
|
{
|
|
if (fRemove)
|
|
{
|
|
pdii->fdwInfo |= MMDEVICEINFO_REMOVED;
|
|
// dprintf("pnpServerInstallDevice removed [%ls]\n", pszDeviceInterface);
|
|
}
|
|
else
|
|
{
|
|
pdii->fdwInfo &= (~MMDEVICEINFO_REMOVED);
|
|
// dprintf("pnpServerInstallDevice added [%ls]\n", pszDeviceInterface);
|
|
}
|
|
|
|
}
|
|
|
|
return pdii;
|
|
}
|
|
|
|
|
|
BOOL PnpInfoEnum
|
|
(
|
|
void
|
|
)
|
|
{
|
|
UINT cDevs = 0;
|
|
HDEVINFO hDevInfo;
|
|
BOOL fEnum;
|
|
DWORD ii, dw;
|
|
DWORD cbSize;
|
|
GUID guidClass = KSCATEGORY_AUDIO;
|
|
SP_DEVICE_INTERFACE_DATA did;
|
|
SP_DEVINFO_DATA DevInfoData;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd;
|
|
|
|
cbSize = 300 * sizeof(TCHAR) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
|
|
pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(hHeap, 0, cbSize);
|
|
|
|
if (NULL == pdidd)
|
|
{
|
|
HeapFree(hHeap, 0, pdidd);
|
|
return FALSE;
|
|
}
|
|
|
|
pdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
|
|
hDevInfo = SetupDiGetClassDevs(
|
|
&guidClass,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
|
|
|
|
if (INVALID_HANDLE_VALUE == hDevInfo)
|
|
{
|
|
dprintf(TEXT("SetupDiGetClasDevs failed [0x%08lx].\n"), GetLastError());
|
|
HeapFree(hHeap, 0, pdidd);
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory(&did, sizeof(did));
|
|
|
|
did.cbSize = sizeof(did);
|
|
|
|
ZeroMemory(&DevInfoData, sizeof(SP_DEVINFO_DATA));
|
|
|
|
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
DevInfoData.ClassGuid = KSCATEGORY_AUDIO;
|
|
|
|
for (ii = 0; ;ii++, cDevs++)
|
|
{
|
|
PMMDEVICEINTERFACEINFO pdii;
|
|
|
|
fEnum = SetupDiEnumDeviceInterfaces(
|
|
hDevInfo,
|
|
NULL,
|
|
&guidClass,
|
|
ii,
|
|
&did);
|
|
|
|
if (!fEnum)
|
|
{
|
|
break;
|
|
}
|
|
|
|
dw = 0;
|
|
|
|
fEnum = SetupDiGetDeviceInterfaceDetail(
|
|
hDevInfo,
|
|
&did,
|
|
pdidd,
|
|
cbSize,
|
|
&dw,
|
|
&DevInfoData);
|
|
|
|
if (!fEnum)
|
|
{
|
|
dprintf(TEXT("SetupDiGetDeviceInterfaceDetail failed (0x%08lx).\n"), GetLastError());
|
|
break;
|
|
}
|
|
|
|
// dprintf(TEXT("PnpInfoEnum: Enumerated[%ls]\n"), pdidd->DevicePath);
|
|
|
|
pdii = pnpServerInstallDevice(pdidd->DevicePath, FALSE);
|
|
if (pdii) MigrateAutoSetupPreferredAudio(pdii);
|
|
}
|
|
|
|
if (!SetupDiDestroyDeviceInfoList(hDevInfo))
|
|
{
|
|
ASSERT(!"wdmEnumerateInstalledDevices: SetupDiDestroyDeviceInfoList failed.");
|
|
}
|
|
|
|
HeapFree(hHeap, 0, pdidd);
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
return TRUE;
|
|
|
|
} // PnpInfoEnum()
|
|
|
|
|
|
BOOL InitializePnpInfo
|
|
(
|
|
void
|
|
)
|
|
{
|
|
SECURITY_ATTRIBUTES sa;
|
|
PSECURITY_DESCRIPTOR pSd;
|
|
BOOL result;
|
|
|
|
ASSERT(!gfPnpInfoResource);
|
|
ASSERT(!hPnpInfo);
|
|
ASSERT(!pPnpInfo);
|
|
|
|
result = FALSE;
|
|
|
|
__try {
|
|
RtlInitializeResource(&PnpInfoResource);
|
|
gfPnpInfoResource = TRUE;
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
gfPnpInfoResource = FALSE;;
|
|
}
|
|
|
|
if (!gfPnpInfoResource) return FALSE;
|
|
|
|
pSd = BuildSecurityDescriptor(FILE_MAP_READ);
|
|
if (pSd)
|
|
{
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = pSd;
|
|
sa.bInheritHandle = FALSE;
|
|
|
|
hPnpInfo = CreateFileMapping(GetCurrentProcess(), &sa, PAGE_READWRITE, 0, PNPINFOSIZE, MMGLOBALPNPINFONAME);
|
|
|
|
DestroySecurityDescriptor(pSd);
|
|
|
|
if (hPnpInfo)
|
|
{
|
|
pPnpInfo = (PMMPNPINFO)MapViewOfFile(hPnpInfo, FILE_MAP_WRITE, 0, 0, 0);
|
|
if (pPnpInfo)
|
|
{
|
|
ZeroMemory(pPnpInfo, PNPINFOSIZE);
|
|
pPnpInfo->cbSize = sizeof(MMPNPINFO);
|
|
pPnpInfo->cPnpEvents = 0;
|
|
|
|
result = TRUE;
|
|
|
|
} else {
|
|
dprintf(TEXT("InitializePnpInfo: MapViewOfFile failed!\n"));
|
|
}
|
|
} else {
|
|
dprintf(TEXT("InitializePnpInfo: CreateFileMappingFailed!\n"));
|
|
}
|
|
} else {
|
|
dprintf(TEXT("InitializePnpInfo: BuildSecurityDescriptor failed!\n"));
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
if (pPnpInfo) UnmapViewOfFile(pPnpInfo);
|
|
if (hPnpInfo) CloseHandle(hPnpInfo);
|
|
if (gfPnpInfoResource) RtlDeleteResource(&PnpInfoResource);
|
|
pPnpInfo = NULL;
|
|
hPnpInfo = NULL;
|
|
gfPnpInfoResource = FALSE;
|
|
}
|
|
|
|
return result;
|
|
} // InitializePnpInfo()
|
|
|
|
void DeletePnpInfo(void)
|
|
{
|
|
ASSERT(gfPnpInfoResource);
|
|
ASSERT(hPnpInfo);
|
|
ASSERT(pPnpInfo);
|
|
|
|
UnmapViewOfFile(pPnpInfo);
|
|
CloseHandle(hPnpInfo);
|
|
RtlDeleteResource(&PnpInfoResource);
|
|
|
|
pPnpInfo = NULL;
|
|
hPnpInfo = NULL;
|
|
gfPnpInfoResource = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
//=============================================================================
|
|
//=== rpc functions ===
|
|
//=============================================================================
|
|
|
|
long s_wdmDriverOpenDrvRegKey(IN DWORD dwProcessId, IN LPCTSTR DeviceInterface, IN ULONG samDesired, OUT RHANDLE *phkeyClient)
|
|
{
|
|
HDEVINFO hdi;
|
|
HKEY hkey;
|
|
RPC_STATUS status;
|
|
|
|
// We impersonate the client while calling setupapi so that we are sure
|
|
// the client actually has access to open the driver reg key
|
|
|
|
status = RpcImpersonateClient(NULL);
|
|
if (status) return status;
|
|
|
|
hdi = SetupDiCreateDeviceInfoList(NULL, NULL);
|
|
if (INVALID_HANDLE_VALUE != hdi)
|
|
{
|
|
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
|
|
|
|
DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
|
|
if (SetupDiOpenDeviceInterface(hdi, DeviceInterface, 0,
|
|
&DeviceInterfaceData))
|
|
{
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
DWORD cbDeviceInterfaceDetail;
|
|
|
|
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
|
|
if (SetupDiGetDeviceInterfaceDetail(hdi, &DeviceInterfaceData, NULL, 0, &cbDeviceInterfaceDetail, &DeviceInfoData) ||
|
|
(ERROR_INSUFFICIENT_BUFFER == GetLastError()))
|
|
{
|
|
hkey = SetupDiOpenDevRegKey(hdi, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, samDesired);
|
|
if (INVALID_HANDLE_VALUE != hkey)
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
} else {
|
|
status = GetLastError();
|
|
dprintf(TEXT("s_wdmDriverOpenDrvRegKey: SetupDiOpenDevRegKey failed, Error=%d\n"), status);
|
|
}
|
|
} else {
|
|
status = GetLastError();
|
|
dprintf(TEXT("s_wdmDriverOpenDrvRegKey: SetupDiGetDeviceInterfaceDetail failed, Error=%d\n"), status);
|
|
}
|
|
} else {
|
|
status = GetLastError();
|
|
dprintf(TEXT("s_wdmDriverOpenDrvRegKey: SetupDiOpenDeviceInterface failed, Error=%d\n"), status);
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList(hdi);
|
|
} else {
|
|
status = GetLastError();
|
|
dprintf(TEXT("s_wdmDriverOpenDrvRegKey: SetupDiCreateDeviceInfoList failed, Error=%d\n"), status);
|
|
}
|
|
|
|
// We stop impersonating here because the remaining operations
|
|
// should not depend on the client's privileges.
|
|
|
|
RpcRevertToSelf();
|
|
|
|
if (ERROR_SUCCESS == status)
|
|
{
|
|
HANDLE hClientProcess;
|
|
|
|
hClientProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);
|
|
if (hClientProcess)
|
|
{
|
|
HANDLE hkeyClient;
|
|
|
|
if (DuplicateHandle(GetCurrentProcess(), hkey, hClientProcess, &hkeyClient, 0, FALSE, DUPLICATE_SAME_ACCESS))
|
|
{
|
|
// dprintf(TEXT("s_wdmDriverOpenDrvRegKey hkeyClient=%p\n"), hkeyClient);
|
|
*phkeyClient = (RHANDLE)hkeyClient;
|
|
} else {
|
|
status = GetLastError();
|
|
dprintf(TEXT("s_wdmDriverOpenDrvRegKey: DuplicateHandle failed, Error=%d\n"), status);
|
|
}
|
|
CloseHandle(hClientProcess);
|
|
} else {
|
|
status = GetLastError();
|
|
dprintf(TEXT("s_wdmDriverOpenDrvRegKey: OpenProcess failed, Error=%d\n"), status);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
void s_winmmAdvisePreferredDeviceChange(void)
|
|
{
|
|
// dprintf(TEXT("s_winmmAdvisePreferredDeviceChange\n"));
|
|
ASSERT(pPnpInfo);
|
|
InterlockedIncrement(&pPnpInfo->cPreferredDeviceChanges);
|
|
BroadcastWinmmDeviceChange();
|
|
return;
|
|
}
|
|
|
|
long s_winmmGetPnpInfo(OUT LONG *pcbPnpInfo, OUT BYTE **ppPnpInfoOut)
|
|
{
|
|
static BOOL fEnumDone = FALSE;
|
|
|
|
PBYTE pPnpInfoOut;
|
|
LONG result;
|
|
|
|
// dprintf(TEXT("s_winmmGetPnpInfo\n"));
|
|
|
|
ASSERT(pPnpInfo);
|
|
|
|
RtlAcquireResourceShared(&PnpInfoResource, TRUE);
|
|
pPnpInfoOut = (PBYTE)HeapAlloc(hHeap, 0, pPnpInfo->cbSize);
|
|
if (pPnpInfoOut)
|
|
{
|
|
CopyMemory(pPnpInfoOut, pPnpInfo, pPnpInfo->cbSize);
|
|
*pcbPnpInfo = pPnpInfo->cbSize;
|
|
*ppPnpInfoOut = pPnpInfoOut;
|
|
result = NO_ERROR;
|
|
} else {
|
|
// ISSUE-2001/02/15-FrankYe Do we need to zero the out params?
|
|
result = ERROR_OUTOFMEMORY;
|
|
}
|
|
RtlReleaseResource(&PnpInfoResource);
|
|
return result;
|
|
}
|
|
|
|
//=============================================================================
|
|
//=== pnp interface handlers ===
|
|
//=============================================================================
|
|
void MME_AudioInterfaceArrival(PCTSTR DeviceInterface)
|
|
{
|
|
PMMDEVICEINTERFACEINFO pdii;
|
|
// dprintf(TEXT("MME_AudioInterfaceArrival\n"));
|
|
RtlAcquireResourceExclusive(&PnpInfoResource, TRUE);
|
|
pdii = pnpServerInstallDevice(DeviceInterface, FALSE);
|
|
if (pdii) MigrateAutoSetupPreferredAudio(pdii);
|
|
InterlockedIncrement(&pPnpInfo->cPnpEvents);
|
|
InterlockedIncrement(&pPnpInfo->cPreferredDeviceChanges);
|
|
RtlReleaseResource(&PnpInfoResource);
|
|
if (pdii) BroadcastWinmmDeviceChange();
|
|
return;
|
|
}
|
|
|
|
void MME_AudioInterfaceRemove(PCTSTR DeviceInterface)
|
|
{
|
|
PMMDEVICEINTERFACEINFO pdii;
|
|
// dprintf(TEXT("MME_AudioInterfaceRemove\n"));
|
|
RtlAcquireResourceExclusive(&PnpInfoResource, TRUE);
|
|
pdii = pnpServerInstallDevice(DeviceInterface, TRUE);
|
|
InterlockedIncrement(&pPnpInfo->cPnpEvents);
|
|
InterlockedIncrement(&pPnpInfo->cPreferredDeviceChanges);
|
|
RtlReleaseResource(&PnpInfoResource);
|
|
if (pdii) BroadcastWinmmDeviceChange();
|
|
return;
|
|
}
|
|
|
|
LONG MME_ServiceStart(void)
|
|
{
|
|
ASSERT(pPnpInfo);
|
|
// dprintf(TEXT("MME_ServiceStart\n"));
|
|
RtlAcquireResourceExclusive(&PnpInfoResource, TRUE);
|
|
if (!PnpInfoEnum()) dprintf(TEXT("MME_ServiceStart: PnpInfoEnum failed!\n"));
|
|
InterlockedIncrement(&pPnpInfo->cPnpEvents);
|
|
RtlReleaseResource(&PnpInfoResource);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//=============================================================================
|
|
//=== DLL attach/detach ===
|
|
//=============================================================================
|
|
|
|
BOOL MME_DllProcessAttach(void)
|
|
{
|
|
return InitializePnpInfo();
|
|
}
|
|
|
|
void MME_DllProcessDetach(void)
|
|
{
|
|
return DeletePnpInfo();
|
|
}
|
|
|