windows-nt/Source/XPSP1/NT/multimedia/media/midimap/mididev.c
2020-09-26 16:20:57 +08:00

667 lines
19 KiB
C

/**********************************************************************
Copyright (c) 1992-1999 Microsoft Corporation
mididev.c
DESCRIPTION:
Code to match device ID's with associated registry entries
HISTORY:
02/24/95 [jimge] created.
*********************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <winerror.h>
#include <regstr.h>
#include <mmsystem.h>
#include <mmddkp.h>
#include "idf.h"
#include "midimap.h"
#include "debug.h"
typedef struct tagMDEV_NODE *PMDEV_NODE;
typedef struct tagMDEV_NODE
{
PMDEV_NODE pNext;
TCHAR szAlias[CB_MAXALIAS];
DWORD dwDevNode;
TCHAR szDriver[CB_MAXDRIVER];
UINT uDeviceID;
UINT uPort;
BOOL fNewDriver;
} MDEV_NODE;
static TCHAR BCODE gszMediaRsrcKey[] =
REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI");
static TCHAR BCODE gszDriverKey[] =
REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI\\%s");
static TCHAR BCODE gszDriverValue[] = TEXT ("Driver");
static TCHAR BCODE gszDevNodeValue[] = TEXT ("DevNode");
static TCHAR BCODE gszPortValue[] = TEXT ("Port");
static TCHAR BCODE gszActiveValue[] = TEXT ("Active");
static TCHAR BCODE gszMapperConfig[] = TEXT ("MapperConfig");
static PMDEV_NODE gpMDevList = NULL;
static DWORD gdwNewDrivers = (DWORD)-1L;
PRIVATE BOOL FNLOCAL mdev_BuildRegList(
void);
PRIVATE BOOL FNLOCAL mdev_SyncDeviceIDs(
void);
PRIVATE BOOL FNLOCAL mdev_MarkActiveDrivers(
void);
#ifdef DEBUG
PRIVATE VOID FNLOCAL mdev_ListActiveDrivers(
void);
#endif
BOOL FNGLOBAL mdev_Init(
void)
{
if (gpMDevList)
mdev_Free();
if ((!mdev_BuildRegList()) ||
(!mdev_SyncDeviceIDs()) ||
(!mdev_MarkActiveDrivers()))
{
mdev_Free();
return FALSE;
}
#ifdef DEBUG
mdev_ListActiveDrivers();
#endif
return TRUE;
}
//
// mdev_BuildRegList
//
// Builds the base device list out of the registry
//
// Assumes the list has been cleared
//
// For each alias (key) under MediaResources\MIDI
// Make sure the Active value exists and is '1'
// Allocate a list node
// Try to read the alias's devnode
// If the alias's devnode is 0 or missing,
// Read the alias's driver name
// Read the alias's port number
// Add the alias to the global list
//
// The uDeviceID member will not be initialized by this routine;
// mdev_SyncDeviceIDs must be called to figure out the current
// device ID mapping.
//
PRIVATE BOOL FNLOCAL mdev_BuildRegList(
void)
{
BOOL fRet = FALSE;
HKEY hKeyMediaRsrc = NULL;
HKEY hKeyThisAlias = NULL;
DWORD dwEnumAlias = 0;
LPTSTR pstrAlias = NULL;
PMDEV_NODE pmd = NULL;
TCHAR szActive[2];
DWORD dwPort;
DWORD cbValue;
DWORD dwType;
DWORD dwMapperConfig;
cbValue = CB_MAXALIAS * sizeof(TCHAR);
pstrAlias = (LPTSTR)LocalAlloc(LPTR, CB_MAXALIAS * sizeof(TCHAR));
if (NULL == pstrAlias)
{
DPF(1, TEXT ("mdev_Init: Out of memory"));
goto mBRL_Cleanup;
}
if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
gszMediaRsrcKey,
&hKeyMediaRsrc))
{
DPF(1, TEXT ("mdev_Init: Could not open ...\\MediaResoruces\\MIDI"));
goto mBRL_Cleanup;
}
while (ERROR_SUCCESS == RegEnumKey(hKeyMediaRsrc,
dwEnumAlias++,
pstrAlias,
CB_MAXALIAS))
{
if (ERROR_SUCCESS != (RegOpenKey(hKeyMediaRsrc,
pstrAlias,
&hKeyThisAlias)))
{
DPF(1, TEXT ("mdev_Init: Could not open enum'ed key %s"), (LPTSTR)pstrAlias);
continue;
}
// MUST have Active == "1" to be running
//
cbValue = sizeof(szActive);
if (ERROR_SUCCESS != (RegQueryValueEx(hKeyThisAlias,
gszActiveValue,
NULL,
&dwType,
(LPSTR)szActive,
&cbValue)) ||
*szActive != '1')
{
DPF(2, TEXT ("mdev_Init: Device %s exists but is not loaded."),
(LPTSTR)pstrAlias);
RegCloseKey(hKeyThisAlias);
continue;
}
// Determine if we have ever configured with this driver before
//
cbValue = sizeof(dwMapperConfig);
if (ERROR_SUCCESS != (RegQueryValueEx(hKeyThisAlias,
gszMapperConfig,
NULL,
&dwType,
(LPSTR)&dwMapperConfig,
&cbValue)))
dwMapperConfig = 0;
#ifdef DEBUG
if (!dwMapperConfig)
DPF(1, TEXT ("Alias '%s' is a new driver."),
(LPTSTR)pstrAlias);
#endif
// We have a running driver, go ahead and alloc a node
// for it
//
pmd = (PMDEV_NODE)LocalAlloc(LPTR, sizeof(*pmd));
if (NULL == pmd)
{
DPF(1, TEXT ("mdev_Init: Out of memory allocating node for %s"),
(LPTSTR)pstrAlias);
RegCloseKey(hKeyThisAlias);
continue;
}
lstrcpyn(pmd->szAlias, pstrAlias, sizeof(pmd->szAlias) - 1);
pmd->szAlias[sizeof(pmd->szAlias) - 1] = '\0';
pmd->fNewDriver = (dwMapperConfig ? FALSE : TRUE);
// Try to get the DevNode value
//
cbValue = sizeof(pmd->dwDevNode);
if (ERROR_SUCCESS != RegQueryValueEx(hKeyThisAlias,
gszDevNodeValue,
NULL,
&dwType,
(LPSTR)(LPDWORD)&pmd->dwDevNode,
&cbValue))
{
// Ok to not have a devnode value, 3.1 drivers don't
//
DPF(2, TEXT ("mdev_Init: Device %s has no devnode; must be 3.1"),
(LPTSTR)pstrAlias);
pmd->dwDevNode = 0;
}
// Leave something reasonable in driver even if we don't
// expect to use it
//
*pmd->szDriver = '\0';
// If we didn't get a devnode or it was 0, and we can't find the
// driver name to match against, we can't use this entry. (If it
// has no ring 3 driver, it can't be running anyway).
//
if (!pmd->dwDevNode)
{
cbValue = sizeof(pmd->szDriver);
if (ERROR_SUCCESS != RegQueryValueEx(
hKeyThisAlias,
gszDriverValue,
NULL,
&dwType,
(LPSTR)pmd->szDriver,
&cbValue))
{
DPF(1, TEXT ("mdev_Init: Device %s has no ring 3 driver entry"),
(LPTSTR)pstrAlias);
LocalFree((HLOCAL)pmd);
RegCloseKey(hKeyThisAlias);
continue;
}
}
// Success! Now try to figure out the port number
//
cbValue = sizeof(dwPort);
// Guard against INF's which only specify a byte's worth of
// port value
//
dwPort = 0;
if (ERROR_SUCCESS != RegQueryValueEx(hKeyThisAlias,
gszPortValue,
NULL,
&dwType,
(LPSTR)(LPDWORD)&dwPort,
&cbValue))
{
DPF(2, TEXT ("mdev_Init: Device %s has no port entry; using 0."),
(LPTSTR)pstrAlias);
dwPort = 0;
}
pmd->uPort = (UINT)dwPort;
// We have a valid node, put it into the list
//
pmd->pNext = gpMDevList;
gpMDevList = pmd;
RegCloseKey(hKeyThisAlias);
}
fRet = TRUE;
mBRL_Cleanup:
if (hKeyMediaRsrc) RegCloseKey(hKeyMediaRsrc);
if (pstrAlias) LocalFree((HLOCAL)pstrAlias);
return fRet;
}
//
// mdev_SyncDeviceIDs
//
// Traverse the device list and bring the uDeviceID members up to date.
// Also remove any devices which MMSYSTEM claims are not really running.
//
// NOTE: The uDeviceID member is actually the device ID of the base driver.
// If you want to open the device, you have to add uDeviceID and uPort for
// the node you want to open.
//
// Set all uDeviceID's to NO_DEVICEID
//
// For each base device ID in MMSYSTEM (i.e. port 0 on each loaded driver)
// Get the matching alias from MMSYSTEM
// Locate the node with that alias in the device list
// Set that node's uDeviceID
//
// For each node in the device list with non-zero port
// If this node has a DevNode
// Find a matching node by DevNode with port == 0 and get its device ID
// else
// Find a matching node by driver name with port == 0 and get its device ID
//
// NOTE: We match by driver name on DevNode == 0 (3.1 devices) because it
// isn't possible to have multiple instances of a 3.1 driver loaded.
//
// For each node in the device list,
// If the node's uDeviceID is still not set,
// Remove and free the node
//
PRIVATE BOOL FNLOCAL mdev_SyncDeviceIDs(
void)
{
BOOL fRet = FALSE;
LPTSTR pstrAlias = NULL;
PMDEV_NODE pmdCurr;
PMDEV_NODE pmdPrev;
PMDEV_NODE pmdEnum;
UINT cDev;
UINT idxDev;
DWORD cPort;
MMRESULT mmr;
DWORD cbSize;
cbSize = CB_MAXALIAS * sizeof(TCHAR);
pstrAlias = (LPTSTR)LocalAlloc(LPTR, cbSize);
if (NULL == pstrAlias)
{
goto mSDI_Cleanup;
}
// The device list has been built and the uPort member is valid.
// Now update the uDeviceID field to be proper. First, walk the list
// and set them all to NO_DEVICEID.
for (pmdCurr = gpMDevList; pmdCurr; pmdCurr = pmdCurr->pNext)
pmdCurr->uDeviceID = NO_DEVICEID;
// Now walk MMSYSTEM's list of loaded drivers and fill in all the port 0
// nodes with their proper device ID
//
cDev = midiOutGetNumDevs();
for (idxDev = 0; idxDev < cDev; )
{
mmr = (MMRESULT)midiOutMessage((HMIDIOUT)(UINT_PTR)idxDev,
#ifdef WINNT
DRV_QUERYNUMPORTS,
#else
MODM_GETNUMDEVS,
#endif // End WINNT
(DWORD_PTR)(LPDWORD)&cPort,
0);
if (mmr)
{
DPF(1, TEXT ("mdev_Sync: Device ID %u returned %u for MODM_GETNUMDEVS"),
(UINT)idxDev,
(UINT)mmr);
++idxDev;
continue;
}
mmr = (MMRESULT)midiOutMessage((HMIDIOUT)(UINT_PTR)idxDev,
DRV_QUERYDRVENTRY,
#ifdef WINNT
(DWORD_PTR)(LPTSTR)pstrAlias,
#else
(DWORD_PTR)(LPTSTR)pstrPath,
#endif // End Winnt
CB_MAXALIAS);
if (!mmr)
{
for (pmdCurr = gpMDevList; pmdCurr; pmdCurr = pmdCurr->pNext)
{
if ((0 == pmdCurr->uPort) &&
(! lstrcmpi(pstrAlias, pmdCurr->szAlias)))
{
pmdCurr->uDeviceID = idxDev;
break;
}
}
#ifdef DEBUG
if (!pmdCurr)
{
DPF(1, TEXT ("mdev_Sync: Device ID %u not found in device list."),
(UINT)idxDev);
}
#endif
}
else
{
DPF(1, TEXT ("mdev_Sync: Device ID %u returned %u for DRV_QUERYDRVENTRY"),
(UINT)idxDev,
(UINT)mmr);
}
idxDev += (UINT)cPort;
}
// Now walk the list again. This time we catch all the non-zero ports
// and set their uDeviceID properly.
//
for (pmdCurr = gpMDevList; pmdCurr; pmdCurr = pmdCurr->pNext)
{
if (!pmdCurr->uPort)
continue;
if (pmdCurr->dwDevNode)
{
for (pmdEnum = gpMDevList; pmdEnum; pmdEnum = pmdEnum->pNext)
if (0 == pmdEnum->uPort &&
pmdEnum->dwDevNode == pmdCurr->dwDevNode)
{
pmdCurr->uDeviceID = pmdEnum->uDeviceID;
break;
}
}
else
{
for (pmdEnum = gpMDevList; pmdEnum; pmdEnum = pmdEnum->pNext)
if (0 == pmdEnum->uPort &&
!lstrcmpi(pmdEnum->szDriver, pmdCurr->szDriver))
{
pmdCurr->uDeviceID = pmdEnum->uDeviceID;
break;
}
}
#ifdef DEBUG
if (!pmdEnum)
{
DPF(1, TEXT ("mdev_Sync: No parent driver found for %s"),
(LPTSTR)pmdCurr->szAlias);
}
#endif
}
// Now we walk the list one more time and discard anyone without a device
// ID assigned.
//
pmdPrev = NULL;
pmdCurr = gpMDevList;
while (pmdCurr)
{
if (NO_DEVICEID == pmdCurr->uDeviceID)
{
DPF(1, TEXT ("mdev_Sync: Removing %s; never found a device ID"),
(LPTSTR)pmdCurr->szAlias);
if (pmdPrev)
pmdPrev->pNext = pmdCurr->pNext;
else
gpMDevList = pmdCurr->pNext;
LocalFree((HLOCAL)pmdCurr);
pmdCurr = (pmdPrev ? pmdPrev->pNext : gpMDevList);
}
else
{
pmdPrev = pmdCurr;
pmdCurr = pmdCurr->pNext;
}
}
fRet = TRUE;
mSDI_Cleanup:
if (pstrAlias) LocalFree((HLOCAL)pstrAlias);
return fRet;
}
//
// mdev_MarkActiveDrivers
//
// Mark drivers which are loaded and have not been seen before by
// mapper configuration as seen. Also flag that we want to run
// RunOnce if there are any of these
//
PRIVATE BOOL FNLOCAL mdev_MarkActiveDrivers(
void)
{
BOOL fRet = FALSE;
HKEY hKeyMediaRsrc = NULL;
HKEY hKeyThisAlias = NULL;
DWORD dwMapperConfig;
PMDEV_NODE pmd;
if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
gszMediaRsrcKey,
&hKeyMediaRsrc))
{
DPF(1, TEXT ("mdev_MarkActiveDrivers: Could not open ")
TEXT ("...\\MediaResources\\MIDI"));
goto mMAD_Cleanup;
}
gdwNewDrivers = 0;
for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
if (pmd->fNewDriver)
{
++gdwNewDrivers;
// Mark this driver as seen
//
if (ERROR_SUCCESS != (RegOpenKey(hKeyMediaRsrc,
pmd->szAlias,
&hKeyThisAlias)))
{
DPF(1, TEXT ("mdev_MarkActiveDrivers: Could not open alias '%s'"),
(LPTSTR)pmd->szAlias);
goto mMAD_Cleanup;
}
dwMapperConfig = 1;
RegSetValueEx(hKeyThisAlias,
gszMapperConfig,
0,
REG_DWORD,
(LPSTR)&dwMapperConfig,
sizeof(dwMapperConfig));
RegCloseKey(hKeyThisAlias);
}
fRet = TRUE;
mMAD_Cleanup:
if (hKeyMediaRsrc) RegCloseKey(hKeyMediaRsrc);
return fRet;
}
//
// mdev_ListActiveDrivers
//
// List the currently loaded drivers to debug output
//
#ifdef DEBUG
PRIVATE VOID FNLOCAL mdev_ListActiveDrivers(
void)
{
PMDEV_NODE pmd;
static TCHAR BCODE szNo[] = TEXT ("No");
static TCHAR BCODE szYes[] = TEXT ("Yes");
DPF(2, TEXT ("=== mdev_ListActiveDrivers start ==="));
for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
{
DPF(2, TEXT ("Alias %-31.31s Driver %-31.31s"),
(LPTSTR)pmd->szAlias,
(LPTSTR)pmd->szDriver);
DPF(2, TEXT (" dwDevNode %08lX uDeviceID %u uPort %u fNewDriver %s"),
pmd->dwDevNode,
pmd->uDeviceID,
pmd->uPort,
(LPTSTR)(pmd->fNewDriver ? szYes : szNo));
}
DPF(2, TEXT ("=== mdev_ListActiveDrivers end ==="));
}
#endif
//
// mdev_Free
//
// Discard the current device list
//
void FNGLOBAL mdev_Free(
void)
{
PMDEV_NODE pmdNext;
PMDEV_NODE pmdCurr;
pmdCurr = gpMDevList;
while (pmdCurr)
{
pmdNext = pmdCurr->pNext;
LocalFree((HLOCAL)pmdCurr);
pmdCurr = pmdNext;
}
gpMDevList = NULL;
gdwNewDrivers = (DWORD)-1L;
}
//
// mdev_GetDeviceID
//
// Get the current device ID for the given alias.
//
UINT FNGLOBAL mdev_GetDeviceID(
LPTSTR lpstrAlias)
{
PMDEV_NODE pmd;
for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
if (!lstrcmpi(pmd->szAlias, lpstrAlias))
return pmd->uDeviceID + pmd->uPort;
DPF(1, TEXT ("mdev_GetDeviceID: Failed for %s"), lpstrAlias);
return NO_DEVICEID;
}
//
// mdev_GetAlias
//
// Get the registry alias for the requested device ID
//
BOOL FNGLOBAL mdev_GetAlias(
UINT uDeviceID,
LPTSTR lpstrBuffer,
UINT cbBuffer)
{
PMDEV_NODE pmd;
for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
if (uDeviceID == (pmd->uDeviceID + pmd->uPort))
{
lstrcpyn(lpstrBuffer, pmd->szAlias, cbBuffer);
return TRUE;
}
DPF(1, TEXT ("mdev_GetAlias: Failed for device ID %u"), uDeviceID);
return FALSE;
}
//
// mdev_NewDrivers
//
// Returns TRUE if there were new drivers in the registry that we've never
// encountered before
//
BOOL FNGLOBAL mdev_NewDrivers(
void)
{
if (gdwNewDrivers == (DWORD)-1L)
{
DPF(0, TEXT ("mdevNewDrivers() called before mdev_Init()!"));
return FALSE;
}
return (BOOL)(gdwNewDrivers != 0);
}