|
|
/****************************************************************************\
* * Module Name : winmm.c * * Multimedia support library * * This module contains the entry point, startup and termination code * * Copyright (c) 1991-2001 Microsoft Corporation * \****************************************************************************/
#define UNICODE
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "winmmi.h"
#include "mmioi.h"
#include "mci.h"
#include <regstr.h>
#include <winuser.h>
#include <wtsapi32.h>
#include <dbt.h>
#include <ks.h>
#include <ksmedia.h>
#include <winsta.h>
#include <stdlib.h>
#include "winuserp.h"
#include "audiosrvc.h"
#include "agfxp.h"
#define _INC_WOW_CONVERSIONS
#include "mmwow32.h"
BOOL WaveInit(void); BOOL MidiInit(void); BOOL AuxInit(void); BOOL MixerInit(void); void InitDevices(void); HANDLE mmDrvOpen(LPWSTR szAlias); void WOWAppExit(HANDLE hTask); void MigrateSoundEvents(void); UINT APIENTRY mmDrvInstall(HANDLE hDriver, WCHAR * wszDrvEntry, DRIVERMSGPROC drvMessage, UINT wFlags); STATIC void NEAR PASCAL mregAddIniScheme(LPTSTR lszSection, LPTSTR lszSchemeID, LPTSTR lszSchemeName, LPTSTR lszINI); STATIC void NEAR PASCAL mregCreateSchemeID(LPTSTR szSchemeName, LPTSTR szSchemeID); int lstrncmpi (LPTSTR pszA, LPTSTR pszB, size_t cch); void RemoveMediaPath (LPTSTR pszTarget, LPTSTR pszSource);
MMRESULT waveOutDesertHandle(HWAVEOUT hWaveOut); MMRESULT waveInDesertHandle(HWAVEIN hWaveIn); MMRESULT midiOutDesertHandle(HMIDIOUT hMidiOut); MMRESULT midiInDesertHandle(HMIDIIN hMidiIn); MMRESULT mixerDesertHandle(HMIXER hmx);
#ifndef cchLENGTH
#define cchLENGTH(_sz) (sizeof(_sz) / sizeof(_sz[0]))
#endif
/****************************************************************************
global data
****************************************************************************/
HANDLE ghInst; // Module handle
BOOL gfDisablePreferredDeviceReordering = FALSE; BOOL WinmmRunningInServer; // Are we running in the user/base server?
BOOL WinmmRunningInWOW; // Are we running in WOW
BOOL WinmmRunningInSession; // Are we running in remote session
WCHAR SessionProtocolName[WPROTOCOLNAME_LENGTH];
// |
// The tls is used simply as an indication that the thread has entered
// waveOutOpen or waveOutGetDevCaps for a non-mapper device. Then, we detect
// re-entrancy into either of these APIs. In the case of re-entrancy we
// might have a driver that is enumerating and caching device IDs. To improve
// the chances of such a driver working, we disable preferred device
// reordering in this case. Note we rely on the OS to initialize the tls to 0.
//
DWORD gTlsIndex = TLS_OUT_OF_INDEXES; // Thread local storage index;
CRITICAL_SECTION DriverListCritSec; // Protect driver interface globals
CRITICAL_SECTION DriverLoadFreeCritSec; // Protect driver load/unload
CRITICAL_SECTION NumDevsCritSec; // Protect Numdevs/Device ID's
CRITICAL_SECTION MapperInitCritSec; // Protect test of mapper initialized
HANDLE hClientPnpInfo = NULL; PMMPNPINFO pClientPnpInfo = NULL; CRITICAL_SECTION PnpCritSec;
RTL_RESOURCE gHandleListResource; // Serializes access to handles.
BOOL gfLogon = FALSE;
HANDLE hEventApiInit = NULL;
WAVEDRV waveoutdrvZ; // wave output device driver list head
WAVEDRV waveindrvZ; // wave input device driver list head
MIDIDRV midioutdrvZ; // midi output device driver list
MIDIDRV midiindrvZ; // midi input device driver list
AUXDRV auxdrvZ; // aux device driver list
UINT wTotalMidiOutDevs; // total midi output devices
UINT wTotalMidiInDevs; // total midi input devices
UINT wTotalWaveOutDevs; // total wave output devices
UINT wTotalWaveInDevs; // total wave input devices
UINT wTotalAuxDevs; // total auxiliary output devices
LONG cPnpEvents; // number of processed pnp events
LONG cPreferredDeviceChanges = 0; // number of processed preferred device changes
typedef struct tag_wdmdeviceinterface *PWDMDEVICEINTERFACE; typedef struct tag_wdmdeviceinterface { PWDMDEVICEINTERFACE Next; DWORD cUsage; LONG cPnpEvents; WCHAR szDeviceInterface[0]; } WDMDEVICEINTERFACE, *PWDMDEVICEINTERFACE;
WDMDEVICEINTERFACE wdmDevZ;
LPCRITICAL_SECTION acs[] = { &HandleListCritSec, &DriverListCritSec, &DriverLoadFreeCritSec, &MapperInitCritSec, &NumDevsCritSec, &PnpCritSec, &WavHdrCritSec, &SoundCritSec, &midiStrmHdrCritSec, &joyCritSec, &mciGlobalCritSec, &mciCritSec, &TimerThreadCritSec, &ResolutionCritSec };
// HACK!!!
SERVICE_STATUS_HANDLE hss; SERVICE_STATUS gss;
#ifdef DEBUG_RETAIL
BYTE fIdReverse; // reverse wave/midi id's
#endif
// For sounds:
STATIC TCHAR gszControlIniTime[] = TEXT("ControlIniTimeStamp"); TCHAR gszControlPanel[] = TEXT("Control Panel"); TCHAR gszSchemesRootKey[] = TEXT("AppEvents\\Schemes"); TCHAR gszJustSchemesKey[] = TEXT("Schemes"); TCHAR aszExplorer[] = TEXT("Explorer"); TCHAR aszDefault[] = TEXT(".Default"); TCHAR aszCurrent[] = TEXT(".Current"); TCHAR gszAppEventsKey[] = TEXT("AppEvents"); TCHAR gszSchemeAppsKey[] = TEXT("Apps"); TCHAR aszSoundsSection[] = TEXT("Sounds"); TCHAR aszSoundSection[] = TEXT("Sound"); TCHAR aszActiveKey[] = TEXT("Active"); TCHAR aszBoolOne[] = TEXT("1");
TCHAR asz2Format[] = TEXT("%s\\%s"); TCHAR asz3Format[] = TEXT("%s\\%s\\%s"); TCHAR asz4Format[] = TEXT("%s\\%s\\%s\\%s"); TCHAR asz5Format[] = TEXT("%s\\%s\\%s\\%s\\%s"); TCHAR asz6Format[] = TEXT("%s\\%s\\%s\\%s\\%s\\%s");
STATIC TCHAR aszSchemeLabelsKey[] = TEXT("EventLabels"); STATIC TCHAR aszSchemeNamesKey[] = TEXT("Names"); STATIC TCHAR aszControlINI[] = TEXT("control.ini"); STATIC TCHAR aszWinINI[] = TEXT("win.ini"); STATIC TCHAR aszSchemesSection[] = TEXT("SoundSchemes"); STATIC TCHAR gszSoundScheme[] = TEXT("SoundScheme.%s"); STATIC TCHAR aszCurrentSection[] = TEXT("Current"); STATIC TCHAR aszYourOldScheme[] = TEXT("Your Old Scheme"); STATIC TCHAR aszNone[] = TEXT("<none>"); STATIC TCHAR aszDummyDrv[] = TEXT("mmsystem.dll"); STATIC TCHAR aszDummySnd[] = TEXT("SystemDefault"); STATIC TCHAR aszDummySndValue[] = TEXT(","); STATIC TCHAR aszExtendedSounds[] = TEXT("ExtendedSounds"); STATIC TCHAR aszExtendedSoundsYes[] = TEXT("yes");
STATIC TCHAR gszApp[] = TEXT("App"); STATIC TCHAR gszSystem[] = TEXT("System");
STATIC TCHAR gszAsterisk[] = TEXT("Asterisk"); STATIC TCHAR gszDefault[] = TEXT("Default"); STATIC TCHAR gszExclamation[] = TEXT("Exclamation"); STATIC TCHAR gszExit[] = TEXT("Exit"); STATIC TCHAR gszQuestion[] = TEXT("Question"); STATIC TCHAR gszStart[] = TEXT("Start"); STATIC TCHAR gszHand[] = TEXT("Hand");
STATIC TCHAR gszClose[] = TEXT("Close"); STATIC TCHAR gszMaximize[] = TEXT("Maximize"); STATIC TCHAR gszMinimize[] = TEXT("Minimize"); STATIC TCHAR gszOpen[] = TEXT("Open"); STATIC TCHAR gszRestoreDown[] = TEXT("RestoreDown"); STATIC TCHAR gszRestoreUp[] = TEXT("RestoreUp");
STATIC TCHAR aszOptionalClips[] = REGSTR_PATH_SETUP REGSTR_KEY_SETUP TEXT("\\OptionalComponents\\Clips"); STATIC TCHAR aszInstalled[] = TEXT("Installed");
STATIC TCHAR * gpszSounds[] = { gszClose, gszMaximize, gszMinimize, gszOpen, gszRestoreDown, gszRestoreUp, gszAsterisk, gszDefault, gszExclamation, gszExit, gszQuestion, gszStart, gszHand };
STATIC TCHAR aszMigration[] = TEXT("Migrated Schemes"); #define wCurrentSchemeMigrationLEVEL 1
static struct { LPCTSTR pszEvent; int idDescription; LPCTSTR pszApp; } gaEventLabels[] = { { TEXT("AppGPFault"), STR_LABEL_APPGPFAULT, aszDefault }, { TEXT("Close"), STR_LABEL_CLOSE, aszDefault }, { TEXT("EmptyRecycleBin"), STR_LABEL_EMPTYRECYCLEBIN, aszExplorer }, { TEXT("Maximize"), STR_LABEL_MAXIMIZE, aszDefault }, { TEXT("MenuCommand"), STR_LABEL_MENUCOMMAND, aszDefault }, { TEXT("MenuPopup"), STR_LABEL_MENUPOPUP, aszDefault }, { TEXT("Minimize"), STR_LABEL_MINIMIZE, aszDefault }, { TEXT("Open"), STR_LABEL_OPEN, aszDefault }, { TEXT("RestoreDown"), STR_LABEL_RESTOREDOWN, aszDefault }, { TEXT("RestoreUp"), STR_LABEL_RESTOREUP, aszDefault }, { TEXT("RingIn"), STR_LABEL_RINGIN, aszDefault }, { TEXT("RingOut"), STR_LABEL_RINGOUT, aszDefault }, { TEXT("SystemAsterisk"), STR_LABEL_SYSTEMASTERISK, aszDefault }, { TEXT(".Default"), STR_LABEL_SYSTEMDEFAULT, aszDefault }, { TEXT("SystemExclamation"), STR_LABEL_SYSTEMEXCLAMATION, aszDefault }, { TEXT("SystemExit"), STR_LABEL_SYSTEMEXIT, aszDefault }, { TEXT("SystemHand"), STR_LABEL_SYSTEMHAND, aszDefault }, { TEXT("SystemQuestion"), STR_LABEL_SYSTEMQUESTION, aszDefault }, { TEXT("SystemStart"), STR_LABEL_SYSTEMSTART, aszDefault }, };
TCHAR gszDefaultBeepOldAlias[] = TEXT("SystemDefault");
#define nEVENTLABELS (sizeof(gaEventLabels)/sizeof(gaEventLabels[0]))
STATIC TCHAR gszChimes[] = TEXT("chimes.wav"); STATIC TCHAR gszDing[] = TEXT("ding.wav"); STATIC TCHAR gszTada[] = TEXT("tada.wav"); STATIC TCHAR gszChord[] = TEXT("chord.wav");
STATIC TCHAR * gpszKnownWAVFiles[] = { gszChord, gszTada, gszChimes, gszDing, };
#define INISECTION 768
#define BIGINISECTION 2048
TCHAR szNull[] = TEXT(""); TCHAR aszSetup[] = REGSTR_PATH_SETUP; TCHAR aszValMedia[] = REGSTR_VAL_MEDIA; TCHAR aszValMediaUnexpanded[] = TEXT("MediaPathUnexpanded");
extern HANDLE hInstalledDriverList; // List of installed driver instances
extern int cInstalledDrivers; // High water count of installed driver instances
HANDLE ghSessionNotification = NULL; HANDLE ghSessionNotificationEvent = NULL; BOOL gfSessionDisconnected = FALSE;
#define g_szWinmmConsoleAudioEvent L"Global\\WinMMConsoleAudioEvent"
//=============================================================================
//=== Reg helpers ===
//=============================================================================
LONG RegPrepareEnum(HKEY hkey, PDWORD pcSubkeys, PTSTR *ppstrSubkeyNameBuffer, PDWORD pcchSubkeyNameBuffer) { DWORD cSubkeys; DWORD cchMaxSubkeyName; LONG lresult;
lresult = RegQueryInfoKey(hkey, NULL, NULL, NULL, &cSubkeys, &cchMaxSubkeyName, NULL, NULL, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS == lresult) { PTSTR SubkeyName; SubkeyName = (PTSTR)HeapAlloc(hHeap, 0, (cchMaxSubkeyName+1) * sizeof(TCHAR)); if (SubkeyName) { *pcSubkeys = cSubkeys; *ppstrSubkeyNameBuffer = SubkeyName; *pcchSubkeyNameBuffer = cchMaxSubkeyName+1; } else { lresult = ERROR_OUTOFMEMORY; } } return lresult; }
LONG RegEnumOpenKey(HKEY hkey, DWORD dwIndex, PTSTR SubkeyName, DWORD cchSubkeyName, REGSAM samDesired, PHKEY phkeyResult) { LONG lresult;
lresult = RegEnumKeyEx(hkey, dwIndex, SubkeyName, &cchSubkeyName, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS == lresult) { HKEY hkeyResult; lresult = RegOpenKeyEx(hkey, SubkeyName, 0, samDesired, &hkeyResult); if (ERROR_SUCCESS == lresult) *phkeyResult = hkeyResult; } return lresult; }
/**************************************************************************
Terminal server helper functions
**************************************************************************/ BOOL IsPersonalTerminalServicesEnabled( VOID ) { static BOOL fRet; static BOOL fVerified = FALSE;
DWORDLONG dwlConditionMask; OSVERSIONINFOEX osVersionInfo;
if ( fVerified ) goto exitpt;
RtlZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX)); osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osVersionInfo.wProductType = VER_NT_WORKSTATION; osVersionInfo.wSuiteMask = VER_SUITE_SINGLEUSERTS;
dwlConditionMask = 0; VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
fRet = VerifyVersionInfo( &osVersionInfo, VER_PRODUCT_TYPE | VER_SUITENAME, dwlConditionMask );
fVerified = TRUE;
exitpt:
return(fRet); }
//
// Check if console audio is enabled in remote session
//
BOOL IsTsConsoleAudio( VOID ) { BOOL RemoteConsoleAudio = FALSE; // Allow audio play at the console
static HANDLE hConsoleAudioEvent = NULL;
if (NtCurrentPeb()->SessionId == 0 || IsPersonalTerminalServicesEnabled()) {
if (hConsoleAudioEvent == NULL) { hConsoleAudioEvent = OpenEvent(SYNCHRONIZE, FALSE, g_szWinmmConsoleAudioEvent); }
if (hConsoleAudioEvent != NULL) { DWORD status;
status = WaitForSingleObject(hConsoleAudioEvent, 0);
if (status == WAIT_OBJECT_0) { RemoteConsoleAudio = TRUE; } } else { dprintf(("Remote session: console audio event NULL with error: %d\n", GetLastError())); } }
return RemoteConsoleAudio; }
//
// returns TRUE if we are on the console
//
BOOL IsActiveConsoleSession( VOID ) { return (USER_SHARED_DATA->ActiveConsoleId == NtCurrentPeb()->SessionId); }
void InitSession(void); BOOL WaveReInit(void);
//
// Check if the session is changed and load additional audio drivers
// this is a case only for reconnecting the console from Terminal Server
//
BOOL CheckSessionChanged(VOID) { static BOOL bCalled = FALSE; static BOOL bWasntRedirecting; BOOL bOld; BOOL bDontRedirect; BOOL bRefreshPreferredDevices;
bRefreshPreferredDevices = FALSE;
bDontRedirect = IsActiveConsoleSession() || IsTsConsoleAudio();
if ( !InterlockedExchange( &bCalled, TRUE )) { bWasntRedirecting = !bDontRedirect; }
bOld = InterlockedExchange( &bWasntRedirecting, bDontRedirect); if ( bOld ^ bWasntRedirecting ) { //
// session conditions changed
//
dprintf(( "Session state changed: %s", (bWasntRedirecting)?"CONSOLE":"SESSION" )); //
// close the old registry handle
//
mmRegFree();
//
// add new devices
//
InitSession(); WaveReInit();
bRefreshPreferredDevices = TRUE; }
return bRefreshPreferredDevices; }
/*****************************************************************************
* * WTSCurrentSessionIsDisonnected * * Determines whether current session is disconnected. * ****************************************************************************/ BOOL WTSCurrentSessionIsDisconnected(void) { if (NULL == ghSessionNotification) { // We create the event signalled so that we'll get the connect state
// from audiosrv on first successful pass through this function.
WinAssert(NULL == ghSessionNotificationEvent); ghSessionNotificationEvent = CreateEvent(NULL, FALSE, TRUE, NULL); if (ghSessionNotificationEvent) { LONG lresult; lresult = winmmRegisterSessionNotificationEvent(ghSessionNotificationEvent, &ghSessionNotification); if (lresult) { CloseHandle(ghSessionNotificationEvent); ghSessionNotificationEvent = NULL; ghSessionNotification = NULL; } } }
if (ghSessionNotification) { WinAssert(ghSessionNotificationEvent); if (WAIT_OBJECT_0 == WaitForSingleObjectEx(ghSessionNotificationEvent, 0, TRUE)) { INT ConnectState; LONG lresult;
// Get new state from audiosrv
lresult = winmmSessionConnectState(&ConnectState); if (!lresult) { gfSessionDisconnected = (WTSDisconnected == ConnectState); } } }
return gfSessionDisconnected; }
/**************************************************************************
@doc EXTERNAL
@api BOOL | mmDeleteMultipleCriticalSections | This procedure deletes multiple critical sections.
@parm LPCRITICAL_SECTION* | ppCritcalSections | Pointer to an array of pointers to critical sections
@parm LONG | nCount | Number of critical sections pointers in the array.
@rdesc VOID
**************************************************************************/ void mmDeleteMultipleCriticalSections(LPCRITICAL_SECTION *ppCriticalSections, LONG nCount) { int i; for (i = 0; i < nCount; i++) DeleteCriticalSection(ppCriticalSections[i]); return; }
/**************************************************************************
@doc EXTERNAL
@api BOOL | mmInitializeMultipleCriticalSections | This procedure initializes multiple critical sections.
@parm LPCRITICAL_SECTION* | ppCritcalSections | Pointer to an array of pointers to critical sections
@parm LONG | nCount | Number of critical sections pointers in the array.
@rdesc The return value is TRUE if the initialization completed ok, FALSE if not.
**************************************************************************/ BOOL mmInitializeMultipleCriticalSections(LPCRITICAL_SECTION *ppCriticalSections, LONG nCount) { int i; // Must be signed for loops to work properly
for (i = 0; i < nCount; i++) { if (!mmInitializeCriticalSection(ppCriticalSections[i])) break; }
if (i == nCount) return TRUE;
// Back up index to the last successful initialization
i--;
// There must have been a failure. Clean up the ones that succeeded.
for ( ; i >= 0; i--) { DeleteCriticalSection(ppCriticalSections[i]); } return FALSE; }
/*
* Initialization for terminal server */ void InitSession(void) { WSINFO SessionInfo;
BOOL bCons = (BOOL)IsActiveConsoleSession(); if ( bCons || IsTsConsoleAudio() ) WinmmRunningInSession = FALSE; else WinmmRunningInSession = TRUE;
if (WinmmRunningInSession) {
memset( &SessionInfo, 0, sizeof(SessionInfo)); GetWinStationInfo(&SessionInfo); lstrcpyW(SessionProtocolName, SessionInfo.ProtocolName); dprintf(("Remote session protocol %ls", SessionProtocolName)); dprintf(("Remote audio driver name %ls", SessionInfo.AudioDriverName));
} else { SessionProtocolName[0] = 0; }
}
/**************************************************************************
@doc INTERNAL
@api VOID | DeletePnpInfo | Frees the pClientPnpInfo file mapping @rdesc There is no return value
**************************************************************************/ void DeletePnpInfo(void) { if (pClientPnpInfo) { BOOL f;
WinAssert(hClientPnpInfo);
f = UnmapViewOfFile(pClientPnpInfo); WinAssert(f); pClientPnpInfo = NULL; f = CloseHandle(hClientPnpInfo); WinAssert(f); hClientPnpInfo = NULL; } return; }
/**************************************************************************
@doc EXTERNAL
@api BOOL | DllProcessAttach | This procedure is called whenever a process attaches to the DLL.
@parm PVOID | hModule | Handle of the DLL.
@rdesc The return value is TRUE if the initialisation completed ok, FALSE if not.
**************************************************************************/ BOOL DllProcessAttach(PVOID hModule) { HANDLE hModWow32; PIMAGE_NT_HEADERS NtHeaders; // For checking if we're in the server.
BOOL fSuccess;
#if DBG
CHAR strname[MAX_PATH]; GetModuleFileNameA(NULL, strname, sizeof(strname)); dprintf2(("Process attaching, exe=%hs (Pid %x Tid %x)", strname, GetCurrentProcessId(), GetCurrentThreadId())); #endif
// We don't need to know when threads start
DisableThreadLibraryCalls(hModule);
// Get access to the process heap. This is cheaper in terms of
// overall resource being chewed up than creating our own heap.
hHeap = RtlProcessHeap(); if (hHeap == NULL) { return FALSE; }
// Allocate our tls
gTlsIndex = TlsAlloc(); if (TLS_OUT_OF_INDEXES == gTlsIndex) return FALSE;
//
// Find out if we're in WOW
//
#ifdef _WIN64
WinmmRunningInWOW = FALSE; #else
if ( (hModWow32 = GetModuleHandleW( L"WOW32.DLL" )) != NULL ) { WinmmRunningInWOW = TRUE; GetVDMPointer = (LPGETVDMPOINTER)GetProcAddress( hModWow32, "WOWGetVDMPointer"); lpWOWHandle32 = (LPWOWHANDLE32)GetProcAddress( hModWow32, "WOWHandle32" ); lpWOWHandle16 = (LPWOWHANDLE16)GetProcAddress( hModWow32, "WOWHandle16" ); } else { WinmmRunningInWOW = FALSE; } #endif
//
// This checks if we're running in CSRSS and this will never happen as of
// Win2k
//
WinmmRunningInServer = FALSE;
if (mmInitializeMultipleCriticalSections(acs, sizeof(acs)/sizeof(acs[0]))) { NTSTATUS nts; hEventApiInit = CreateEvent(NULL, TRUE, FALSE, NULL);
__try { RtlInitializeResource(&gHandleListResource); nts = STATUS_SUCCESS; } __except (EXCEPTION_EXECUTE_HANDLER) { nts = GetExceptionCode(); } if ((hEventApiInit) && (NT_SUCCESS(nts))) { InitDebugLevel(); InitSession(); InitDevices();
// it is important that the MCI window initialisation is done AFTER
// we have initialised Wave, Midi, etc. devices. Note the server
// uses Wave devices, but nothing else (e.g. MCI, midi...)
if (!WinmmRunningInServer) { mciGlobalInit(); } } else { // EventApiInit Create failed
if (hEventApiInit) CloseHandle(hEventApiInit); hEventApiInit = NULL; mmDeleteMultipleCriticalSections(acs, sizeof(acs)/sizeof(acs[0])); TlsFree(gTlsIndex); return (FALSE); } } else { // Failed to initialize critical sections.
TlsFree(gTlsIndex); return (FALSE); }
// Added to remove warning.
return TRUE; }
/**************************************************************************
@doc EXTERNAL
@api BOOL | DllInstanceInit | This procedure is called whenever a process attaches or detaches from the DLL.
@parm PVOID | hModule | Handle of the DLL.
@parm ULONG | Reason | What the reason for the call is.
@parm PCONTEXT | pContext | Some random other information.
@rdesc The return value is TRUE if the initialisation completed ok, FALSE if not.
**************************************************************************/
BOOL DllInstanceInit(PVOID hModule, ULONG Reason, PCONTEXT pContext) { PIMAGE_NT_HEADERS NtHeaders; // For checking if we're in the server.
HANDLE hModWow32; DWORD dwThread; BOOL f;
ghInst = (HANDLE) hModule;
DBG_UNREFERENCED_PARAMETER(pContext);
if (Reason == DLL_PROCESS_ATTACH) {
return DllProcessAttach(hModule);
} else if (Reason == DLL_PROCESS_DETACH) {
dprintf2(("Process ending (Pid %x Tid %x)", GetCurrentProcessId(), GetCurrentThreadId()));
// Squirt("Entering process detach");
// Can't really use RPC during DllMain, so let's just close first
AudioSrvBindingFree();
if (ghSessionNotification) { WinAssert(ghSessionNotificationEvent); winmmUnregisterSessionNotification(ghSessionNotification); CloseHandle(ghSessionNotificationEvent); ghSessionNotification = NULL; ghSessionNotificationEvent = NULL; } else { WinAssert(!ghSessionNotificationEvent); }
if (!WinmmRunningInServer) { TimeCleanup(0); // DLL cleanup
}
mmRegFree(); JoyCleanup(); //qzheng
DeletePnpInfo();
if (hInstalledDriverList) { GlobalFree ((HGLOBAL)hInstalledDriverList); hInstalledDriverList = NULL; cInstalledDrivers = 0; // Count of installed drivers
}
InvalidatePreferredDevices();
if (hEventApiInit) CloseHandle(hEventApiInit);
mmDeleteMultipleCriticalSections(acs, sizeof(acs)/sizeof(acs[0]));
RtlDeleteResource(&gHandleListResource);
TlsFree(gTlsIndex); } else if (Reason == 999) { // This is a dummy call to an entry point in ADVAPI32.DLL. By
// statically linking to the library we avoid the following:
// An application links to winmm.dll and advapi32.dll
// When the application loads the list of dependent dlls is built,
// and a list of the dll init routines is created. It happens
// that the winmm init routine is called first.
// IF there is a sound card in the system, winmm's dll init routine
// call LoadLibrary on the sound driver DLL. This DLL WILL
// reference advapi32.dll - and call entry points in advapi32.
// Unfortunately the init routine of advapi32.dll is marked as
// having RUN - although that is not yet the case as we are still
// within the load routine for winmm.
// When the advapi32 entry point runs, it relies on its init
// routine having completed; specifically a CriticalSection should
// have been initialised. This is not the case, and BOOM!
// The workaround is to ensure that advapi32.dll runs its init
// routine first. This is done by making sure that WINMM has a
// static link to the dll.
ImpersonateSelf(999); // This routine will never be called.
// If it is called, it will fail.
}
return TRUE; }
/*****************************************************************************
* @doc EXTERNAL MMSYSTEM * * @api void | WOWAppExit | This function cleans up when a (WOW) application * terminates. * * @parm HANDLE | hTask | Thread id of application (equivalent to windows task * handle). * * @rdesc Nothing * * @comm Note that NOT ALL threads are WOW threads. We rely here on the * fact that ONLY MCI creates threads other than WOW threads which * use our low level device resources. * * Note also that once a thread is inside here no other threads can * go through here so, since we clean up MCI devices first, their * low level devices will be freed before we get to their threads. * ****************************************************************************/
void WOWAppExit(HANDLE hTask) { MCIDEVICEID DeviceID; HANDLE h, hNext;
dprintf3(("WOW Multi-media - thread %x exiting", hTask));
//
// Free MCI devices allocated by this task (thread).
//
EnterCriticalSection(&mciCritSec); for (DeviceID=1; DeviceID < MCI_wNextDeviceID; DeviceID++) {
if (MCI_VALID_DEVICE_ID(DeviceID) && MCI_lpDeviceList[DeviceID]->hCreatorTask == hTask) { //
// Note that the loop control variables are globals so will be
// reloaded on each iteration.
//
// Also no new devices will be opened by APPs because this is WOW
//
// Hence it's safe (and essential!) to leave the critical
// section which we send the close command
//
dprintf2(("MCI device %ls (%d) not released.", MCI_lpDeviceList[DeviceID]->lpstrInstallName, DeviceID)); LeaveCriticalSection(&mciCritSec); mciSendCommandW(DeviceID, MCI_CLOSE, 0, 0); EnterCriticalSection(&mciCritSec); } } LeaveCriticalSection(&mciCritSec);
//
// Free any timers
//
TimeCleanup((DWORD)(DWORD_PTR)hTask);
//
// free all WAVE/MIDI/MMIO handles
//
// ISSUE-2001/01/16-FrankYe This violates the order in which locks should
// be acquired. The HandleListCritSec should be the last lock taken,
// but here it is held while calling winmm APIs
EnterCriticalSection(&HandleListCritSec); h = GetHandleFirst();
while (h) { hNext = GetHandleNext(h);
if (GetHandleOwner(h) == hTask) { HANDLE hdrvDestroy;
//
// hack for the wave/midi mapper, always free handles backward.
//
if (hNext && GetHandleOwner(hNext) == hTask) { h = hNext; continue; }
//
// do this so even if the close fails we will not
// find it again.
//
SetHandleOwner(h, NULL);
//
// set the hdrvDestroy global so DriverCallback will not
// do anything for this device
//
hdrvDestroy = h;
switch(GetHandleType(h)) { case TYPE_WAVEOUT: dprintf1(("WaveOut handle (%04X) was not released.", h)); waveOutReset((HWAVEOUT)h); waveOutClose((HWAVEOUT)h); break;
case TYPE_WAVEIN: dprintf1(("WaveIn handle (%04X) was not released.", h)); waveInReset((HWAVEIN)h); waveInClose((HWAVEIN)h); break;
case TYPE_MIDIOUT: dprintf1(("MidiOut handle (%04X) was not released.", h)); midiOutReset((HMIDIOUT)h); midiOutClose((HMIDIOUT)h); break;
case TYPE_MIDIIN: dprintf1(("MidiIn handle (%04X) was not released.", h)); midiInReset((HMIDIIN)h); midiInClose((HMIDIIN)h); break;
//
// This is not required because WOW does not open any
// mmio files.
//
// case TYPE_MMIO:
// dprintf1(("MMIO handle (%04X) was not released.", h));
// if (mmioClose((HMMIO)h, 0) != 0)
// mmioClose((HMMIO)h, MMIO_FHOPEN);
// break;
}
//
// unset hdrvDestroy so DriverCallback will work.
// some hosebag drivers (like the TIMER driver)
// may pass NULL as their driver handle.
// so dont set it to NULL.
//
hdrvDestroy = (HANDLE)-1;
//
// the reason we start over is because a single free may cause
// multiple free's (ie MIDIMAPPER has another HMIDI open, ...)
//
h = GetHandleFirst(); } else { h = GetHandleNext(h); } } LeaveCriticalSection(&HandleListCritSec);
//
// Clean up an installed IO procs for mmio
//
// This is not required because wow does not install any io procs.
//
// mmioCleanupIOProcs(hTask);
//
// If avicap32.dll is loaded, then ask it to clean up
// capture drivers
{ HMODULE hmod; hmod = GetModuleHandle(TEXT("avicap32.dll")); if (hmod) { typedef void (*AppCleanupProc)(HANDLE); AppCleanupProc fp;
fp = (AppCleanupProc) GetProcAddress(hmod, "AppCleanup"); if (fp) { fp(hTask); } } } }
BOOL IsWinlogon(void) { TCHAR szTarget[] = TEXT("winlogon.Exe"); TCHAR szTemp[MAX_PATH]; UINT ii; static BOOL fAlreadyChecked = FALSE; static BOOL fIsWinlogon = FALSE;
if (fAlreadyChecked) return fIsWinlogon;
if (0 == GetModuleFileName(NULL, szTemp, sizeof(szTemp)/sizeof(szTemp[0]))) { //
// GetModuleFileName fails...
//
return FALSE; }
for (ii = lstrlen(szTemp) - 1; ii; ii--) { if ('\\' == szTemp[ii]) { ii++;
fIsWinlogon = !lstrcmpi(&(szTemp[ii]), szTarget); fAlreadyChecked = TRUE; return fIsWinlogon; } }
return FALSE; }
void FreeUnusedDrivers(PMMDRV pmmdrvZ) { PMMDRV pmmdrv = pmmdrvZ->Next;
while (pmmdrv != pmmdrvZ) { PMMDRV pmmdrvNext = pmmdrv->Next; ASSERT(pmmdrv->hDriver); if ((0 == pmmdrv->NumDevs) && (0 == (pmmdrv->fdwDriver & MMDRV_DESERTED))) { // For pnp driver we send DRVM_EXIT
if (pmmdrv->cookie) pmmdrv->drvMessage(0, DRVM_EXIT, 0L, 0L, (DWORD_PTR)pmmdrv->cookie); DrvClose(pmmdrv->hDriver, 0, 0);
DeleteCriticalSection(&pmmdrv->MixerCritSec);
// Remove from list
pmmdrv->Prev->Next = pmmdrv->Next; pmmdrv->Next->Prev = pmmdrv->Prev;
// Zero memory to help catch reuse bugs
ZeroMemory(pmmdrv, sizeof(*pmmdrv)); HeapFree(hHeap, 0, pmmdrv); } pmmdrv = pmmdrvNext; }
return; }
extern BOOL IMixerLoadDrivers( void ); void InitDevices(void) { cPnpEvents = 0;
// Initialize various lists
ZeroMemory(&wdmDevZ, sizeof(wdmDevZ)); ZeroMemory(&waveoutdrvZ, sizeof(waveoutdrvZ)); ZeroMemory(&waveindrvZ, sizeof(waveindrvZ)); waveoutdrvZ.Next = waveoutdrvZ.Prev = &waveoutdrvZ; waveindrvZ.Next = waveindrvZ.Prev = &waveindrvZ;
ZeroMemory(&midioutdrvZ, sizeof(midioutdrvZ)); ZeroMemory(&midiindrvZ, sizeof(midiindrvZ)); midioutdrvZ.Next = midioutdrvZ.Prev = &midioutdrvZ; midiindrvZ.Next = midiindrvZ.Prev = &midiindrvZ;
ZeroMemory(&auxdrvZ, sizeof(auxdrvZ)); auxdrvZ.Next = auxdrvZ.Prev = &auxdrvZ;
ZeroMemory(&mixerdrvZ, sizeof(mixerdrvZ)); mixerdrvZ.Next = mixerdrvZ.Prev = &mixerdrvZ;
// Now initialize different device classes
WaveInit();
//
// The server only needs wave to do message beeps.
//
if (!WinmmRunningInServer) { MidiInit(); if (!TimeInit()) { dprintf1(("Failed to initialize timer services")); } midiEmulatorInit(); AuxInit(); JoyInit(); MixerInit(); // IMixerLoadDrivers();
//
// Clear up any drivers which don't have any devices (we do it this
// way so we don't keep loading and unloading mmdrv.dll).
//
// Note - we only load the mappers if there are real devices so we
// don't need to worry about unloading them.
//
FreeUnusedDrivers(&waveindrvZ); FreeUnusedDrivers(&midioutdrvZ); FreeUnusedDrivers(&midiindrvZ); FreeUnusedDrivers(&auxdrvZ); } FreeUnusedDrivers(&waveoutdrvZ); }
/*****************************************************************************
* @doc EXTERNAL MMSYSTEM * * @api UINT | mmsystemGetVersion | This function returns the current * version number of the Multimedia extensions system software. * * @rdesc The return value specifies the major and minor version numbers of * the Multimedia extensions. The high-order byte specifies the major * version number. The low-order byte specifies the minor version number. * ****************************************************************************/ UINT APIENTRY mmsystemGetVersion(void) { return(MMSYSTEM_VERSION); }
#define MAXDRIVERORDINAL 9
/****************************************************************************
strings
****************************************************************************/ STATICDT SZCODE szWodMessage[] = WOD_MESSAGE; STATICDT SZCODE szWidMessage[] = WID_MESSAGE; STATICDT SZCODE szModMessage[] = MOD_MESSAGE; STATICDT SZCODE szMidMessage[] = MID_MESSAGE; STATICDT SZCODE szAuxMessage[] = AUX_MESSAGE; STATICDT SZCODE szMxdMessage[] = MXD_MESSAGE;
STATICDT WSZCODE wszWave[] = L"wave"; STATICDT WSZCODE wszMidi[] = L"midi"; STATICDT WSZCODE wszAux[] = L"aux"; STATICDT WSZCODE wszMixer[] = L"mixer"; STATICDT WSZCODE wszMidiMapper[] = L"midimapper"; STATICDT WSZCODE wszWaveMapper[] = L"wavemapper"; STATICDT WSZCODE wszAuxMapper[] = L"auxmapper"; STATICDT WSZCODE wszMixerMapper[] = L"mixermapper";
WSZCODE wszNull[] = L""; WSZCODE wszSystemIni[] = L"system.ini"; WSZCODE wszDrivers[] = DRIVERS_SECTION;
/*
** WaveMapperInit ** ** Initialize the wave mapper if it's not already initialized. ** */ BOOL WaveMapperInitialized = FALSE; void WaveMapperInit(void) { HDRVR h = NULL; BOOL fLoadOutput = TRUE; BOOL fLoadInput = TRUE;
EnterNumDevs("WaveMapperInit"); EnterCriticalSection(&MapperInitCritSec);
if (WaveMapperInitialized) { LeaveCriticalSection(&MapperInitCritSec); LeaveNumDevs("WaveMapperInit"); return; }
/* The wave mapper.
* * MMSYSTEM allows the user to install a special wave driver which is * not visible to the application as a physical device (it is not * included in the number returned from getnumdevs). * * An application opens the wave mapper when it does not care which * physical device is used to input or output waveform data. Thus * it is the wave mapper's task to select a physical device that can * render the application-specified waveform format or to convert the * data into a format that is renderable by an available physical * device. */
if (wTotalWaveInDevs + wTotalWaveOutDevs > 0) { if (0 != (h = mmDrvOpen(wszWaveMapper))) { fLoadOutput = mmDrvInstall(h, wszWaveMapper, NULL, MMDRVI_MAPPER|MMDRVI_WAVEOUT|MMDRVI_HDRV);
if (!WinmmRunningInServer) { h = mmDrvOpen(wszWaveMapper); fLoadInput = mmDrvInstall(h, wszWaveMapper, NULL, MMDRVI_MAPPER|MMDRVI_WAVEIN |MMDRVI_HDRV); } }
WaveMapperInitialized |= ((0 != h) && (fLoadOutput) && (fLoadInput))?TRUE:FALSE; }
LeaveCriticalSection(&MapperInitCritSec); LeaveNumDevs("WaveMapperInit"); }
/*
** MidiMapperInit ** ** Initialize the MIDI mapper if it's not already initialized. ** */ BOOL MidiMapperInitialized = FALSE; void MidiMapperInit(void) { HDRVR h;
EnterNumDevs("MidiMapperInit"); EnterCriticalSection(&MapperInitCritSec);
if (MidiMapperInitialized) { LeaveCriticalSection(&MapperInitCritSec); LeaveNumDevs("MidiMapperInit"); return; }
/* The midi mapper.
* * MMSYSTEM allows the user to install a special midi driver which is * not visible to the application as a physical device (it is not * included in the number returned from getnumdevs). * * An application opens the midi mapper when it does not care which * physical device is used to input or output midi data. It * is the midi mapper's task to modify the midi data so that it is * suitable for playback on the connected synthesizer hardware. */
// EnterNumDevs("MidiMapperInit");
if (wTotalMidiInDevs + wTotalMidiOutDevs > 0) { if (0 != (h = mmDrvOpen(wszMidiMapper))) { mmDrvInstall(h, wszMidiMapper, NULL, MMDRVI_MAPPER|MMDRVI_MIDIOUT|MMDRVI_HDRV);
h = mmDrvOpen(wszMidiMapper); mmDrvInstall(h, wszMidiMapper, NULL, MMDRVI_MAPPER|MMDRVI_MIDIIN |MMDRVI_HDRV); }
MidiMapperInitialized = TRUE; } // LeaveNumDevs("MidiMapperInit");
LeaveCriticalSection(&MapperInitCritSec); LeaveNumDevs("MidiMapperInit"); }
/*****************************************************************************
* @doc INTERNAL WAVE * * @api BOOL | WaveInit | This function initialises the wave services. * * @rdesc Returns TRUE if the services of all loaded wave drivers are * correctly initialised, FALSE if an error occurs. * * @comm the wave devices are loaded in the following order * * \Device\WaveIn0 * \Device\WaveIn1 * \Device\WaveIn2 * \Device\WaveIn3 * ****************************************************************************/ BOOL WaveInit(void) { WCHAR szKey[ (sizeof(wszWave) + sizeof( WCHAR )) / sizeof( WCHAR ) ]; int i; HDRVR h;
// Find the real WAVE drivers
lstrcpyW(szKey, wszWave); szKey[ (sizeof(szKey) / sizeof( WCHAR )) - 1 ] = (WCHAR)'\0'; for (i=0; i<=MAXDRIVERORDINAL; i++) { h = mmDrvOpen(szKey); if (h) { mmDrvInstall(h, szKey, NULL, MMDRVI_WAVEOUT|MMDRVI_HDRV);
if (!WinmmRunningInServer) { h = mmDrvOpen(szKey); mmDrvInstall(h, szKey, NULL, MMDRVI_WAVEIN |MMDRVI_HDRV); } } szKey[ (sizeof(wszWave) / sizeof(WCHAR)) - 1] = (WCHAR)('1' + i); }
return TRUE; }
BOOL WaveReInit(void) { WCHAR szKey[ (sizeof(wszWave) + sizeof( WCHAR )) / sizeof( WCHAR ) ]; int i; HDRVR h;
EnterCriticalSection(&NumDevsCritSec); // Find the real WAVE drivers
lstrcpyW(szKey, wszWave); szKey[ (sizeof(szKey) / sizeof( WCHAR )) - 1 ] = (WCHAR)'\0'; for (i=0; i<=MAXDRIVERORDINAL; i++) { h = mmDrvOpen(szKey); if (h) { mmDrvInstall(h, szKey, NULL, MMDRVI_WAVEOUT|MMDRVI_HDRV);
if (!WinmmRunningInServer) { h = mmDrvOpen(szKey); mmDrvInstall(h, szKey, NULL, MMDRVI_WAVEIN |MMDRVI_HDRV); } } szKey[ (sizeof(wszWave) / sizeof(WCHAR)) - 1] = (WCHAR)('1' + i); }
FreeUnusedDrivers(&waveoutdrvZ);
LeaveCriticalSection(&NumDevsCritSec);
return TRUE; } /*****************************************************************************
* @doc INTERNAL MIDI * * @api BOOL | MidiInit | This function initialises the midi services. * * @rdesc The return value is TRUE if the services are initialised, FALSE if * an error occurs * * @comm the midi devices are loaded from SYSTEM.INI in the following order * * midi * midi1 * midi2 * midi3 * ****************************************************************************/ BOOL MidiInit(void) { WCHAR szKey[ (sizeof(wszMidi) + sizeof( WCHAR )) / sizeof( WCHAR ) ]; int i; HDRVR h;
// Find the real MIDI drivers
lstrcpyW(szKey, wszMidi); szKey[ (sizeof(szKey) / sizeof( WCHAR )) - 1 ] = (WCHAR)'\0'; for (i=0; i<=MAXDRIVERORDINAL; i++) { h = mmDrvOpen(szKey); if (h) { mmDrvInstall(h, szKey, NULL, MMDRVI_MIDIOUT|MMDRVI_HDRV);
h = mmDrvOpen(szKey); mmDrvInstall(h, szKey, NULL, MMDRVI_MIDIIN |MMDRVI_HDRV); }
szKey[ (sizeof(wszMidi) / sizeof(WCHAR)) - 1] = (WCHAR)('1' + i); }
return TRUE; }
/*****************************************************************************
* @doc INTERNAL AUX * * @api BOOL | AuxInit | This function initialises the auxiliary output * services. * * @rdesc The return value is TRUE if the services are initialised, FALSE if * an error occurs * * @comm SYSTEM.INI is searched for auxn.drv=.... where n can be from 1 to 4. * Each driver is loaded and the number of devices it supports is read * from it. * * AUX devices are loaded from SYSTEM.INI in the following order * * aux * aux1 * aux2 * aux3 * ****************************************************************************/ BOOL AuxInit(void) { WCHAR szKey[ (sizeof(wszAux) + sizeof( WCHAR )) / sizeof( WCHAR ) ]; int i; HDRVR h;
// Find the real Aux drivers
lstrcpyW(szKey, wszAux); szKey[ (sizeof(szKey) / sizeof( WCHAR )) - 1 ] = (WCHAR)'\0'; for (i=0; i<=MAXDRIVERORDINAL; i++) { h = mmDrvOpen(szKey); if (h) { mmDrvInstall(h, szKey, NULL, MMDRVI_AUX|MMDRVI_HDRV); }
// advance driver ordinal
szKey[ (sizeof(wszAux) / sizeof(WCHAR)) - 1] = (WCHAR)('1' + i); }
/* The aux mapper.
* * MMSYSTEM allows the user to install a special aux driver which is * not visible to the application as a physical device (it is not * included in the number returned from getnumdevs). * * I'm not sure why anyone would do this but I'll provide the * capability for symmetry. * */
if (wTotalAuxDevs > 0) { h = mmDrvOpen(wszAuxMapper); if (h) { mmDrvInstall(h, wszAuxMapper, NULL, MMDRVI_MAPPER|MMDRVI_AUX|MMDRVI_HDRV); } }
return TRUE; }
/*****************************************************************************
* @doc INTERNAL MIXER * * @api BOOL | MixerInit | This function initialises the mixer drivers * services. * * @rdesc The return value is TRUE if the services are initialised, FALSE if * an error occurs * * @comm SYSTEM.INI is searched for mixern.drv=.... where n can be from 1 to 4. * Each driver is loaded and the number of devices it supports is read * from it. * * MIXER devices are loaded from SYSTEM.INI in the following order * * mixer * mixer1 * mixer2 * mixer3 * ****************************************************************************/ BOOL MixerInit(void) { WCHAR szKey[ (sizeof(wszMixer) + sizeof( WCHAR )) / sizeof( WCHAR ) ]; int i; HDRVR h;
// Find the real Mixer drivers
lstrcpyW(szKey, wszMixer); szKey[ (sizeof(szKey) / sizeof( WCHAR )) - 1 ] = (WCHAR)'\0'; for (i=0; i<=MAXDRIVERORDINAL; i++) { h = mmDrvOpen(szKey); if (h) { mmDrvInstall(h, szKey, NULL, MMDRVI_MIXER|MMDRVI_HDRV); }
// advance driver ordinal
szKey[ (sizeof(wszMixer) / sizeof(WCHAR)) - 1] = (WCHAR)('1' + i); }
#ifdef MIXER_MAPPER
/* The Mixer mapper.
* * MMSYSTEM allows the user to install a special aux driver which is * not visible to the application as a physical device (it is not * included in the number returned from getnumdevs). * * I'm not sure why anyone would do this but I'll provide the * capability for symmetry. * */
if (guTotalMixerDevs > 0) { h = mmDrvOpen(wszMixerMapper); if (h) { mmDrvInstall(h, wszMixerMapper, NULL, MMDRVI_MAPPER|MMDRVI_MIXER|MMDRVI_HDRV); } } #endif
return TRUE; }
/*****************************************************************************
* * @doc INTERNAL * * @api HANDLE | mmDrvOpen | This function load's an installable driver, but * first checks weather it exists in the [Drivers] section. * * @parm LPSTR | szAlias | driver alias to load * * @rdesc The return value is return value from DrvOpen or NULL if the alias * was not found in the [Drivers] section. * ****************************************************************************/
HANDLE mmDrvOpen(LPWSTR szAlias) { WCHAR buf[300]; // Make this large to bypass GetPrivate... bug
if ( winmmGetPrivateProfileString( wszDrivers, szAlias, wszNull, buf, sizeof(buf) / sizeof(WCHAR), wszSystemIni) ) { return (HANDLE)DrvOpen(szAlias, NULL, 0L); } else { return NULL; } }
/*****************************************************************************
* @doc INTERNAL * * @api HANDLE | mmDrvInstall | This function installs/removes a WAVE/MIDI driver * * @parm HANDLE | hDriver | Module handle or driver handle containing driver * * @parm WCHAR * | wszDrvEntry | String corresponding to hDriver to be stored for * later use * * @parm DRIVERMSGPROC | drvMessage | driver message procedure, if NULL * the standard name will be used (looked for with GetProcAddress) * * @parm UINT | wFlags | flags * * @flag MMDRVI_TYPE | driver type mask * @flag MMDRVI_WAVEIN | install driver as a wave input driver * @flag MMDRVI_WAVEOUT | install driver as a wave ouput driver * @flag MMDRVI_MIDIIN | install driver as a midi input driver * @flag MMDRVI_MIDIOUT | install driver as a midi output driver * @flag MMDRVI_AUX | install driver as a aux driver * @flag MMDRVI_MIXER | install driver as a mixer driver * * @flag MMDRVI_MAPPER | install this driver as the mapper * @flag MMDRVI_HDRV | hDriver is a installable driver * @flag MMDRVI_REMOVE | remove the driver * * @rdesc returns NULL if unable to install driver * ****************************************************************************/
UINT APIENTRY mmDrvInstall( HANDLE hDriver, WCHAR * wszDrvEntry, DRIVERMSGPROC drvMessage, UINT wFlags ) { #define SZ_SIZE 128
int i; DWORD dw; PMMDRV pdrvZ; PMMDRV pdrv; SIZE_T cbdrv; HANDLE hModule; UINT msg_num_devs; UINT *pTotalDevs; CHAR *szMessage; WCHAR sz[SZ_SIZE]; BOOL fMixerCritSec;
fMixerCritSec = FALSE; pdrvZ = NULL; pdrv = NULL;
if (hDriver && (wFlags & MMDRVI_HDRV)) { hModule = DrvGetModuleHandle(hDriver); } else { hModule = hDriver; hDriver = NULL; }
switch (wFlags & MMDRVI_TYPE) { case MMDRVI_WAVEOUT: pdrvZ = &waveoutdrvZ; cbdrv = sizeof(WAVEDRV); msg_num_devs = WODM_GETNUMDEVS; pTotalDevs = &wTotalWaveOutDevs; szMessage = szWodMessage; break;
case MMDRVI_WAVEIN: pdrvZ = &waveindrvZ; cbdrv = sizeof(WAVEDRV); msg_num_devs = WIDM_GETNUMDEVS; pTotalDevs = &wTotalWaveInDevs; szMessage = szWidMessage; break;
case MMDRVI_MIDIOUT: pdrvZ = &midioutdrvZ; cbdrv = sizeof(MIDIDRV); msg_num_devs = MODM_GETNUMDEVS; pTotalDevs = &wTotalMidiOutDevs; szMessage = szModMessage; break;
case MMDRVI_MIDIIN: pdrvZ = &midiindrvZ; cbdrv = sizeof(MIDIDRV); msg_num_devs = MIDM_GETNUMDEVS; pTotalDevs = &wTotalMidiInDevs; szMessage = szMidMessage; break;
case MMDRVI_AUX: pdrvZ = &auxdrvZ; cbdrv = sizeof(AUXDRV); msg_num_devs = AUXDM_GETNUMDEVS; pTotalDevs = &wTotalAuxDevs; szMessage = szAuxMessage; break;
case MMDRVI_MIXER: pdrvZ = &mixerdrvZ; cbdrv = sizeof(MIXERDRV); msg_num_devs = MXDM_GETNUMDEVS; pTotalDevs = &guTotalMixerDevs; szMessage = szMxdMessage; break;
default: goto error_exit; }
if (drvMessage == NULL && hModule != NULL) drvMessage = (DRIVERMSGPROC)GetProcAddress(hModule, szMessage);
if (drvMessage == NULL) goto error_exit;
//
// try to find the driver already installed
//
pdrv = pdrvZ->Next; while (pdrv != pdrvZ && pdrv->drvMessage != drvMessage) pdrv = pdrv->Next; if (pdrv != pdrvZ) { pdrv = NULL; goto error_exit; // we found it, don't reinstall it
}
//
// Make a new MMDRV for the device.
//
pdrv = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cbdrv); if (!pdrv) goto error_exit;
pdrv->hDriver = hDriver; pdrv->Usage = 1; pdrv->cookie = 0; // This is 0 for non-WDM drivers.
pdrv->fdwDriver = (wFlags & MMDRVI_MAPPER) ? MMDRV_MAPPER : 0; pdrv->fdwDriver |= DrvIsPreXp(hDriver) ? MMDRV_PREXP : 0; pdrv->drvMessage = drvMessage; WinAssert(lstrlenA(szMessage) < sizeof(pdrv->wszMessage)/sizeof(WCHAR)); mbstowcs(pdrv->wszMessage, szMessage, sizeof(pdrv->wszMessage)/sizeof(WCHAR)); lstrcpyW( pdrv->wszSessProtocol, SessionProtocolName );
winmmGetPrivateProfileString(wszDrivers, // ini section
wszDrvEntry, // key name
wszDrvEntry, // default if no match
sz, // return buffer
SZ_SIZE, // sizeof of return buffer
wszSystemIni); // ini. file
lstrcpyW(pdrv->wszDrvEntry,sz);
if (!mmInitializeCriticalSection(&pdrv->MixerCritSec)) goto error_exit; fMixerCritSec = TRUE;
//
// Mixer drivers get extra message?!
//
if (MMDRVI_MIXER == (wFlags & MMDRVI_TYPE)) { //
// send the init message, if the driver returns a error, should we
// unload them???
//
dw = drvMessage(0, MXDM_INIT,0L,0L,0L); }
//
// call driver to get num-devices it supports
//
dw = drvMessage(0,msg_num_devs,0L,0L,0L);
//
// the device returned a error, or has no devices
//
// if (HIWORD(dw) != 0 || LOWORD(dw) == 0)
if ((HIWORD(dw) != 0) || (0 == LOWORD(dw))) goto error_exit;
pdrv->NumDevs = LOWORD(dw);
//
// dont increment number of dev's for the mapper
//
if (!(pdrv->fdwDriver & MMDRV_MAPPER)) *pTotalDevs += pdrv->NumDevs;
//
// add to end of the driver list
//
mregAddDriver(pdrvZ, pdrv);
return TRUE; // return a non-zero value
error_exit: if (hDriver && !(wFlags & MMDRVI_REMOVE)) DrvClose(hDriver, 0, 0); if (fMixerCritSec) DeleteCriticalSection(&pdrv->MixerCritSec); WinAssert(pdrv != pdrvZ); if (pdrv) HeapFree(hHeap, 0, pdrv);
return FALSE;
#undef SZ_SIZE
}
/**************************************************************************
wdmDevInterfaceInstall
Notes: Assumes that the NumDevsCritSec is owned as necessary
**************************************************************************/ HANDLE wdmDevInterfaceInstall ( LPCWSTR pszDev, LONG cPnpEvents ) { PWDMDEVICEINTERFACE pwdmDev; EnterCriticalSection(&NumDevsCritSec);
//
// Look for device interface...
//
pwdmDev = wdmDevZ.Next; while (pwdmDev) { WinAssert(pwdmDev->cUsage); if (!lstrcmpiW(pwdmDev->szDeviceInterface, pszDev)) { pwdmDev->cUsage++; pwdmDev->cPnpEvents = cPnpEvents; break; } pwdmDev = pwdmDev->Next; }
if (!pwdmDev) { SIZE_T cbszDev; //
// Device interface not found...
//
cbszDev = (lstrlen(pszDev) + 1) * sizeof(pszDev[0]); pwdmDev = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(*pwdmDev) + cbszDev); if (pwdmDev) { pwdmDev->cUsage = 1; pwdmDev->cPnpEvents = cPnpEvents; lstrcpyW(pwdmDev->szDeviceInterface, pszDev); pwdmDev->Next = wdmDevZ.Next; wdmDevZ.Next = pwdmDev; } }
LeaveCriticalSection(&NumDevsCritSec);
return (pwdmDev ? pwdmDev->szDeviceInterface : NULL); }
/**************************************************************************
wdmDevInterfaceInc
Notes: Enters/Leaves the NumDevsCritSec
**************************************************************************/ BOOL wdmDevInterfaceInc ( PCWSTR dwCookie ) { PWDMDEVICEINTERFACE pwdmDev; if (NULL == dwCookie) { return FALSE; }
EnterCriticalSection(&NumDevsCritSec);
//
// Look for device interface...
//
pwdmDev = wdmDevZ.Next; while (pwdmDev) { WinAssert(pwdmDev->cUsage); if (dwCookie == pwdmDev->szDeviceInterface) { pwdmDev->cUsage++; LeaveCriticalSection(&NumDevsCritSec); return TRUE; } pwdmDev = pwdmDev->Next; }
//
// If we get down here, it means that we're trying to increment the
// reference to a interface that doesn't exist anymore
//
WinAssert(FALSE); LeaveCriticalSection(&NumDevsCritSec);
return FALSE; }
/**************************************************************************
wdmDevInterfaceDec
Notes: Enters/Leaves the NumDevsCritSec
**************************************************************************/ BOOL wdmDevInterfaceDec ( PCWSTR dwCookie ) { PWDMDEVICEINTERFACE pwdmDevPrev; if (NULL == dwCookie) { return FALSE; }
EnterCriticalSection(&NumDevsCritSec);
//
// Look for device interface...
//
pwdmDevPrev = &wdmDevZ; while (pwdmDevPrev->Next) { PWDMDEVICEINTERFACE pwdmDev = pwdmDevPrev->Next;
WinAssert(pwdmDev->cUsage); if (dwCookie == pwdmDev->szDeviceInterface) { if (0 == --pwdmDev->cUsage) { pwdmDevPrev->Next = pwdmDev->Next; HeapFree(hHeap, 0, pwdmDev); } LeaveCriticalSection(&NumDevsCritSec); return TRUE; } pwdmDevPrev = pwdmDev; } //
// If we get down here it means that we are trying to decrement the
// reference to an interface that doesn't exist anymore.
//
WinAssert(FALSE); LeaveCriticalSection(&NumDevsCritSec);
return FALSE; }
//--------------------------------------------------------------------------;
//
// void CleanUpHandles
//
// Description:
// Given a particular subsystem and device interface, cleans up the
// handles.
//
// Arguments:
// UINT uFlags: Has one of MMDRVI_* flags to indictate which class of
// handle needs to be checked for desertion.
//
// HANDLE cookie: Device interface
//
// Return (void):
//
// History:
// 01/25/99 Fwong Adding Pnp Support.
//
//--------------------------------------------------------------------------;
void CleanUpHandles ( UINT wFlags, PCWSTR cookie ) { HANDLE hMM; UINT uType; PHNDL pSearch; BOOL fFound;
// Convert MMDRVI_* type flags to TYPE_*
switch(wFlags & MMDRVI_TYPE) { case MMDRVI_WAVEOUT: uType = TYPE_WAVEOUT; break; case MMDRVI_WAVEIN: uType = TYPE_WAVEIN; break; case MMDRVI_MIDIOUT: uType = TYPE_MIDIOUT; break; case MMDRVI_MIDIIN: uType = TYPE_MIDIIN; break; case MMDRVI_MIXER: uType = TYPE_MIXER; break; case MMDRVI_AUX: uType = TYPE_AUX; break; default: uType = TYPE_UNKNOWN; WinAssert(TYPE_UNKNOWN != uType); }
// Note: Since we are not freeing any handles (just marking them
// deserted), we don't have to mess with the HandleListCritSec
for (pSearch = pHandleList; NULL != pSearch; pSearch = pSearch->pNext) { if ((cookie != pSearch->cookie) || (uType != pSearch->uType)) { continue; }
// Both the cookie and type match...
hMM = PHtoH(pSearch);
switch (uType) { case TYPE_WAVEOUT: waveOutDesertHandle((HWAVEOUT)hMM); break;
case TYPE_WAVEIN: waveInDesertHandle((HWAVEIN)hMM); break;
case TYPE_MIDIOUT: midiOutDesertHandle((HMIDIOUT)hMM); break;
case TYPE_MIDIIN: midiInDesertHandle((HMIDIIN)hMM); break;
case TYPE_MIXER: mixerDesertHandle((HMIXER)hMM); break; case TYPE_AUX: // We don't expect open handles of this type
WinAssert(TYPE_AUX != uType); break; } } } // CleanUpHandles()
UINT APIENTRY wdmDrvInstall ( HANDLE hDriver, LPTSTR pszDriverFile, HANDLE cookie, UINT wFlags ) { int i; DWORD dw; PMMDRV pdrvZ; PMMDRV pdrv; SIZE_T cbdrv; HANDLE hModule; UINT msg_init; UINT msg_num_devs; UINT *pTotalDevs; CHAR *szMessage; DRIVERMSGPROC pfnDrvMessage; WCHAR sz[MAX_PATH]; BOOL fMixerCritSec;
// Squirt("Entering wdmDrvInstall");
fMixerCritSec = FALSE;
pdrv = NULL; pfnDrvMessage = NULL;
if (hDriver && (wFlags & MMDRVI_HDRV)) { hModule = DrvGetModuleHandle(hDriver); } else { hModule = hDriver; hDriver = NULL; }
switch (wFlags & MMDRVI_TYPE) { case MMDRVI_WAVEOUT: pdrvZ = &waveoutdrvZ; cbdrv = sizeof(WAVEDRV); msg_init = WODM_INIT; msg_num_devs = WODM_GETNUMDEVS; pTotalDevs = &wTotalWaveOutDevs; szMessage = szWodMessage; break;
case MMDRVI_WAVEIN: pdrvZ = &waveindrvZ; cbdrv = sizeof(WAVEDRV); msg_init = WIDM_INIT; msg_num_devs = WIDM_GETNUMDEVS; pTotalDevs = &wTotalWaveInDevs; szMessage = szWidMessage; break;
case MMDRVI_MIDIOUT: pdrvZ = &midioutdrvZ; cbdrv = sizeof(MIDIDRV); msg_init = MODM_INIT; msg_num_devs = MODM_GETNUMDEVS; pTotalDevs = &wTotalMidiOutDevs; szMessage = szModMessage; break;
case MMDRVI_MIDIIN: pdrvZ = &midiindrvZ; cbdrv = sizeof(MIDIDRV); msg_init = MIDM_INIT; msg_num_devs = MIDM_GETNUMDEVS; pTotalDevs = &wTotalMidiInDevs; szMessage = szMidMessage; break;
case MMDRVI_AUX: pdrvZ = &auxdrvZ; cbdrv = sizeof(AUXDRV); msg_init = AUXM_INIT; msg_num_devs = AUXDM_GETNUMDEVS; pTotalDevs = &wTotalAuxDevs; szMessage = szAuxMessage; break;
case MMDRVI_MIXER: pdrvZ = &mixerdrvZ; cbdrv = sizeof(MIXERDRV); msg_init = MXDM_INIT; msg_num_devs = MXDM_GETNUMDEVS; pTotalDevs = &guTotalMixerDevs; szMessage = szMxdMessage; break;
default: goto error_exit; }
pfnDrvMessage = (DRIVERMSGPROC)GetProcAddress(hModule, szMessage);
if (NULL == pfnDrvMessage) goto error_exit;
//
// either install or remove the specified driver
//
if (wFlags & MMDRVI_REMOVE) { //
// try to find the driver already installed
//
for (pdrv = pdrvZ->Next; pdrv != pdrvZ; pdrv = pdrv->Next) { if (pdrv->fdwDriver & MMDRV_DESERTED) continue; if (cookie) { // This is a wdm driver so we're matching up with cookie.
if (pdrv->cookie == cookie) break; } else { // ISSUE-2001/01/14-FrankYe Will this ever be called
// on non WDM driver???
// Not WDM driver, so matching up with pfnDrvMessage.
if (pdrv->drvMessage == pfnDrvMessage) break; } } //
// Driver not found.
//
if (pdrv == pdrvZ) pdrv = NULL; if (NULL == pdrv) goto error_exit;
//
// don't decrement number of dev's for the mapper
//
// Note: Moved this to before the usage check...
//
if (!(pdrv->fdwDriver & MMDRV_MAPPER)) *pTotalDevs -= pdrv->NumDevs;
//
// Mark no devs otherwise the device mapping will be skewed.
//
pdrv->NumDevs = 0;
//
// Mark this driver as removed
//
pdrv->fdwDriver |= MMDRV_DESERTED;
CleanUpHandles(wFlags & MMDRVI_TYPE, pdrv->cookie);
mregDecUsagePtr(pdrv);
return TRUE; } else { //
// try to find the driver already installed
//
for (pdrv = pdrvZ->Next; pdrv != pdrvZ; pdrv = pdrv->Next) { if (pdrv->fdwDriver & MMDRV_DESERTED) continue; if (cookie) { // This is a wdm driver so we're matching up with cookie.
if (pdrv->cookie == cookie) break; } else { // ISSUE-2001/01/14-FrankYe Will this ever be called
// on non WDM driver???
// Not WDM driver, so matching up with pfnDrvMessage.
if (pdrv->drvMessage == pfnDrvMessage) break; } }
//
// If driver found, don't re-install.
//
if (pdrv != pdrvZ) { pdrv = NULL; goto error_exit; }
//
// Create a MMDRV for the device
//
pdrv = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cbdrv); if (!pdrv) goto error_exit;
//
// Initialize MMDRV structure
//
pdrv->hDriver = hDriver; pdrv->NumDevs = 0; pdrv->Usage = 1; pdrv->cookie = cookie; pdrv->fdwDriver = (wFlags & MMDRVI_MAPPER) ? MMDRV_MAPPER : 0; pdrv->fdwDriver |= DrvIsPreXp(hDriver) ? MMDRV_PREXP : 0; pdrv->drvMessage = pfnDrvMessage; WinAssert(lstrlenA(szMessage) < sizeof(pdrv->wszMessage)/sizeof(WCHAR)); mbstowcs(pdrv->wszMessage, szMessage, sizeof(pdrv->wszMessage)/sizeof(WCHAR)); lstrcpyW(pdrv->wszDrvEntry, pszDriverFile); if (!mmInitializeCriticalSection(&pdrv->MixerCritSec)) goto error_exit; fMixerCritSec = TRUE;
//
// Sending init message
//
dw = pfnDrvMessage(0,msg_init,0L,0L,(DWORD_PTR)cookie);
//
// call driver to get num-devices it supports
//
dw = pfnDrvMessage(0,msg_num_devs,0L,(DWORD_PTR)cookie,0L);
//
// the device returned a error, or has no devices
//
if (0 != HIWORD(dw) || 0 == LOWORD(dw)) goto error_exit;
pdrv->NumDevs = LOWORD(dw); wdmDevInterfaceInc(cookie);
// Squirt("Driver [%ls:0x%04x] supports %d devices", pszDriverFile, wFlags & MMDRVI_TYPE, dw);
//
// dont increment number of dev's for the mapper
//
if (!(pdrv->fdwDriver & MMDRV_MAPPER)) *pTotalDevs += pdrv->NumDevs;
//
// add to end of the driver list
//
mregAddDriver(pdrvZ, pdrv);
// Squirt("Installed driver");
return TRUE; }
error_exit: // ISSUE-2001/01/05-FrankYe On add, if msg_init was sent it might be good
// to also send DRVM_EXIT before closing the driver.
if (fMixerCritSec) DeleteCriticalSection(&pdrv->MixerCritSec); if (pdrv) HeapFree(hHeap, 0, pdrv); return FALSE; }
void KickMapper ( UINT uFlags ) { PMMDRV pmd; DWORD dw; DRIVERMSGPROC pfnDrvMessage = NULL; MMRESULT mmr;
switch (uFlags & MMDRVI_TYPE) { case MMDRVI_WAVEOUT: { mmr = waveReferenceDriverById(&waveoutdrvZ, WAVE_MAPPER, &pmd, NULL); break; } case MMDRVI_WAVEIN: { mmr = waveReferenceDriverById(&waveindrvZ, WAVE_MAPPER, &pmd, NULL); break; }
case MMDRVI_MIDIOUT: { mmr = midiReferenceDriverById(&midioutdrvZ, MIDI_MAPPER, &pmd, NULL); break; }
case MMDRVI_MIDIIN: { mmr = midiReferenceDriverById(&midiindrvZ, MIDI_MAPPER, &pmd, NULL); break; }
case MMDRVI_AUX: { mmr = auxReferenceDriverById(AUX_MAPPER, &pmd, NULL); break; }
case MMDRVI_MIXER: { #ifdef MIXER_MAPPER
mmr = mixerReferenceDriverById(MIXER_MAPPER, &pmd, NULL); #else
mmr = MMSYSERR_NODRIVER; #endif
break; }
default: WinAssert(FALSE); mmr = MMSYSERR_NODRIVER; return; }
if (!mmr) { if (pmd->drvMessage) { pmd->drvMessage(0, DRVM_MAPPER_RECONFIGURE, 0L, 0L, 0L); } mregDecUsagePtr(pmd); } }
void wdmDriverLoadClass( IN HKEY hkey, IN PCTSTR DeviceInterface, IN UINT uFlags, IN OUT PTSTR *ppstrLeftOverDriver, IN OUT HDRVR *phLeftOverDriver) { PTSTR pstrClass; HKEY hkeyClass;
WinAssert((NULL == *ppstrLeftOverDriver) == (NULL == *phLeftOverDriver));
switch (uFlags & MMDRVI_TYPE) { case MMDRVI_WAVEOUT: case MMDRVI_WAVEIN: pstrClass = TEXT("Drivers\\wave"); break; case MMDRVI_MIDIOUT: case MMDRVI_MIDIIN: pstrClass = TEXT("Drivers\\midi"); break; case MMDRVI_MIXER: pstrClass = TEXT("Drivers\\mixer"); break; case MMDRVI_AUX: pstrClass = TEXT("Drivers\\aux"); break; default: pstrClass = NULL; }
if (pstrClass && !RegOpenKeyEx(hkey, pstrClass, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkeyClass)) { DWORD cSubkeys; PTSTR pstrSubkeyNameBuffer; DWORD cchSubkeyNameBuffer;
if (!RegPrepareEnum(hkeyClass, &cSubkeys, &pstrSubkeyNameBuffer, &cchSubkeyNameBuffer)) { DWORD dwIndex;
for (dwIndex = 0; dwIndex < cSubkeys; dwIndex++) { HKEY hkeyClassDriver; if (!RegEnumOpenKey(hkeyClass, dwIndex, pstrSubkeyNameBuffer, cchSubkeyNameBuffer, KEY_QUERY_VALUE, &hkeyClassDriver)) { PTSTR pstrDriver; if (!RegQuerySzValue(hkeyClassDriver, TEXT("Driver"), &pstrDriver)) { HDRVR h; BOOL fLoaded = FALSE;
// dprintf(("wdmDriverLoadClass %s %ls on %ls", (uFlags & MMDRVI_REMOVE) ? "removing" : "installing", pstrClass, DeviceInterface));
EnterCriticalSection(&NumDevsCritSec); if (!*phLeftOverDriver || lstrcmpi(pstrDriver, *ppstrLeftOverDriver)) { if (*phLeftOverDriver) { DrvClose(*phLeftOverDriver, 0, 0); HeapFree(hHeap, 0, *ppstrLeftOverDriver); } // dprintf(("wdmDriverLoadClass, opening driver %ls", pstrDriver));
h = mmDrvOpen(pstrDriver); } else { HeapFree(hHeap, 0, pstrDriver); h = *phLeftOverDriver; pstrDriver = *ppstrLeftOverDriver; } *phLeftOverDriver = NULL; *ppstrLeftOverDriver = NULL;
if (h) { fLoaded = wdmDrvInstall(h, pstrDriver, (HANDLE)DeviceInterface, uFlags | MMDRVI_HDRV); } else { HeapFree(hHeap, 0, pstrDriver); pstrDriver = NULL; }
// dprintf(("wdmDriverLoadClass, fLoaded = %s", fLoaded ? "TRUE" : "FALSE"));
if (!fLoaded) { *phLeftOverDriver = h; *ppstrLeftOverDriver = pstrDriver; } LeaveCriticalSection(&NumDevsCritSec); }
RegCloseKey(hkeyClassDriver); } } HeapFree(hHeap, 0, pstrSubkeyNameBuffer); } RegCloseKey(hkeyClass); } }
void wdmDriverLoadAllClasses(IN PCTSTR DeviceInterface, UINT uFlags) { HKEY hkey = NULL; LONG result; // dprintf(("wdmDriverLoadAllClasses on %ls", DeviceInterface));
result = wdmDriverOpenDrvRegKey(DeviceInterface, KEY_ENUMERATE_SUB_KEYS, &hkey); if (!result) { HDRVR hUnusedDriver = NULL; PTSTR pstrUnusedDriver = NULL; WinAssert(hkey); wdmDriverLoadClass(hkey, DeviceInterface, uFlags | MMDRVI_WAVEOUT, &pstrUnusedDriver, &hUnusedDriver); wdmDriverLoadClass(hkey, DeviceInterface, uFlags | MMDRVI_WAVEIN, &pstrUnusedDriver, &hUnusedDriver); wdmDriverLoadClass(hkey, DeviceInterface, uFlags | MMDRVI_MIDIOUT, &pstrUnusedDriver, &hUnusedDriver); wdmDriverLoadClass(hkey, DeviceInterface, uFlags | MMDRVI_MIDIIN, &pstrUnusedDriver, &hUnusedDriver); wdmDriverLoadClass(hkey, DeviceInterface, uFlags | MMDRVI_AUX, &pstrUnusedDriver, &hUnusedDriver); // wdmDriverLoadClass(hkey, DeviceInterface, uFlags | MMDRVI_JOY);
wdmDriverLoadClass(hkey, DeviceInterface, uFlags | MMDRVI_MIXER, &pstrUnusedDriver, &hUnusedDriver);
if (hUnusedDriver) { WinAssert(pstrUnusedDriver); DrvClose(hUnusedDriver, 0, 0); HeapFree(hHeap, 0, pstrUnusedDriver); } RegCloseKey(hkey); } else { dprintf(("wdmDriverLoadAllClasses: wdmDriverOpenDrvRegKey returned error %d", result)); } return; }
void wdmPnpUpdateDriver ( DWORD dwType, LPCWSTR pszID, LONG cPnpEvents ) { HANDLE cookie;
cookie = wdmDevInterfaceInstall(pszID, cPnpEvents);
if(0 == cookie) { return; }
if(WinmmRunningInServer) { Squirt("Running in CSRSS?!?!"); WinAssert(FALSE); return; }
// ISSUE-2001/01/16-FrankYe This violates the order in which locks should
// be acquired. The HandleListCritSec should be the last lock taken,
// but here it is held while calling other functions that will acquire
// NumDevsCritSec. I'm not sure why we need to acquire
// HandleListCritSec here.
EnterCriticalSection(&HandleListCritSec);
switch (dwType) { case DBT_DEVICEARRIVAL: // Squirt("wdmPnpUpdateDriver:DBT_DEVICEARRIVAL [%ls]", pszID);
wdmDriverLoadAllClasses(cookie, 0); break;
case DBT_DEVICEREMOVECOMPLETE: // Squirt("wdmPnpUpdateDriver:DBT_DEVICEREMOVECOMPLETE [%ls]", pszID);
// ISSUE-2001/02/08-FrankYe I think we never DrvClose drivers anymore!
wdmDriverLoadAllClasses(cookie, MMDRVI_REMOVE); break;
default: break; }
LeaveCriticalSection(&HandleListCritSec);
wdmDevInterfaceDec(cookie); } // wdmPnpUpdateDriver()
void KickMappers ( void ) { KickMapper(MMDRVI_WAVEOUT); KickMapper(MMDRVI_WAVEIN); KickMapper(MMDRVI_MIDIOUT); KickMapper(MMDRVI_MIDIIN); KickMapper(MMDRVI_AUX); KickMapper(MMDRVI_MIXER); }
BOOL ClientPnpChange(void) { BOOL fDeviceChange; PMMPNPINFO pPnpInfo; LONG cbPnpInfo; PMMDEVICEINTERFACEINFO pdii; UINT ii;
fDeviceChange = FALSE;
if (ERROR_SUCCESS != winmmGetPnpInfo(&cbPnpInfo, &pPnpInfo)) return fDeviceChange;
// Always grab NumDevsCriticalSection before DriverLoadFree CS
EnterCriticalSection(&NumDevsCritSec); EnterCriticalSection(&DriverLoadFreeCritSec);
cPnpEvents = pPnpInfo->cPnpEvents; // Adding new instances...
pdii = (PMMDEVICEINTERFACEINFO)&(pPnpInfo[1]); pdii = PAD_POINTER(pdii);
for (ii = pPnpInfo->cDevInterfaces; ii; ii--) { PWDMDEVICEINTERFACE pwdmDev; PWSTR pstr; UINT jj;
pstr = &(pdii->szName[0]);
pwdmDev = wdmDevZ.Next; while (pwdmDev) { WinAssert(pwdmDev->cUsage); { if (0 == lstrcmpi(pwdmDev->szDeviceInterface, pstr)) { if (pdii->cPnpEvents > pwdmDev->cPnpEvents) { // if it has to be updated it must be removed first...
wdmPnpUpdateDriver(DBT_DEVICEREMOVECOMPLETE, pstr, 0); if (0 == (pdii->fdwInfo & MMDEVICEINFO_REMOVED)) { wdmPnpUpdateDriver(DBT_DEVICEARRIVAL, pstr, pdii->cPnpEvents); }
fDeviceChange = TRUE; }
break; } pwdmDev = pwdmDev->Next; } }
if (!pwdmDev) { // Device interface should be installed.
if (0 == (pdii->fdwInfo & MMDEVICEINFO_REMOVED)) { wdmPnpUpdateDriver(DBT_DEVICEARRIVAL, pstr, pdii->cPnpEvents); }
fDeviceChange = TRUE; }
pdii = (PMMDEVICEINTERFACEINFO)(pstr + lstrlenW(pstr) + 1); pdii = PAD_POINTER(pdii); pstr = (PWSTR)(&pdii[1]); }
LeaveCriticalSection(&DriverLoadFreeCritSec); LeaveCriticalSection(&NumDevsCritSec);
HeapFree(hHeap, 0, pPnpInfo);
return fDeviceChange; }
void ClientUpdatePnpInfo(void) { static BOOL fFirstCall = TRUE; static BOOL InThisFunction = FALSE; BOOL fWasFirstCall;
if (IsWinlogon() && !gfLogon) { dprintf(("ClientUpdatePnpInfo: warning: called in winlogon before logged on")); return; }
fWasFirstCall = InterlockedExchange(&fFirstCall, FALSE); if (fWasFirstCall) { // Note AudioSrvBinding happens in WinmmLogon for winlogon
winmmWaitForService(); if (!IsWinlogon()) AudioSrvBinding();
if (NULL == pClientPnpInfo) { hClientPnpInfo = OpenFileMapping(FILE_MAP_READ, FALSE, MMGLOBALPNPINFONAME); if (hClientPnpInfo) { pClientPnpInfo = MapViewOfFile(hClientPnpInfo, FILE_MAP_READ, 0, 0, 0); if (!pClientPnpInfo) { CloseHandle(hClientPnpInfo); hClientPnpInfo = NULL; } } if (!hClientPnpInfo) dprintf(("ClientUpdatePnpInfo: WARNING: Could not OpenFileMapping")); }
SetEvent(hEventApiInit);
} else { WaitForSingleObjectEx(hEventApiInit, INFINITE, FALSE); }
EnterCriticalSection(&PnpCritSec); if (!InterlockedExchange(&InThisFunction, TRUE)) { BOOL fDeviceChange; BOOL fPreferredDeviceChange; fPreferredDeviceChange = CheckSessionChanged();
fDeviceChange = FALSE;
if (pClientPnpInfo && (cPnpEvents != pClientPnpInfo->cPnpEvents)) fDeviceChange = ClientPnpChange();
if (fDeviceChange) InvalidatePreferredDevices();
fPreferredDeviceChange |= (pClientPnpInfo && (cPreferredDeviceChanges != pClientPnpInfo->cPreferredDeviceChanges)); if (fPreferredDeviceChange && pClientPnpInfo) cPreferredDeviceChanges = pClientPnpInfo->cPreferredDeviceChanges;
if (fWasFirstCall || fDeviceChange || fPreferredDeviceChange) RefreshPreferredDevices();
if (fDeviceChange) KickMappers();
InterlockedExchange(&InThisFunction, FALSE); } LeaveCriticalSection(&PnpCritSec); }
void WinmmLogon(BOOL fConsole) { // dprintf(("WinmmLogon (%s session)", fConsole ? "console" : "remote"));
WinAssert(IsWinlogon()); WinAssert(!gfLogon); // WinAssert(fConsole ? !WinmmRunningInSession : WinmmRunningInSession);
if (!IsWinlogon()) return; AudioSrvBinding(); gfLogon = TRUE; // ISSUE-2001/05/04-FrankYe This is a NOP now, should remove this and
// implementation in audiosrv.
gfxLogon(GetCurrentProcessId()); return; }
void WinmmLogoff(void) { HANDLE handle; // dprintf(("WinmmLogoff"));
WinAssert(IsWinlogon()); WinAssert(gfLogon); if (!IsWinlogon()) return; gfxLogoff(); // It is very important to close this context handle now because it is associated
// with the logged on user. Otherwise the handle remains open, associated with the
// logged on user, even after he logs off.
if (ghSessionNotification) { WinAssert(ghSessionNotificationEvent); winmmUnregisterSessionNotification(ghSessionNotification); CloseHandle(ghSessionNotificationEvent); ghSessionNotification = NULL; ghSessionNotificationEvent = NULL; } else { WinAssert(!ghSessionNotificationEvent); } AudioSrvBindingFree(); gfLogon = FALSE; return; }
/*
************************************************************************* * MigrateSoundEvents * * Description: * Looks at the sounds section in win.ini for sound entries. * Gets a current scheme name from the current section in control.ini * Failing that it tries to find the current scheme in the registry * Failing that it uses .default as the current scheme. * Copies each of the entries in the win.ini sound section into the * registry under the scheme name obtained * If the scheme name came from control.ini, it creates a key from the * scheme name. This key is created by removing all the existing spaces * in the scheme name. This key and scheme name is added to the registry * ************************************************************************* */ // ISSUE-2000/10/30-FrankYe Delete Winlogon's call to this function, then
// delete this function
void MigrateAllDrivers(void) { return; }
void MigrateSoundEvents (void) { TCHAR aszEvent[SCH_TYPE_MAX_LENGTH];
// If a MediaPathUnexpanded key exists (it will be something
// like "%SystemRoot%\Media"), expand it into a fully-qualified
// path and write out a matching MediaPath key (which will look
// like "c:\win\media"). This is done every time we enter the
// migration path, whether or not there's anything else to do.
//
// Setup would like to write the MediaPath key with the
// "%SystemRoot%" stuff still in it--but while we could touch
// our apps to understand expansion, any made-for-Win95 apps
// probably wouldn't think to expand the string, and so wouldn't
// work properly. Instead, it writes the MediaPathUnexpanded
// key, and we make sure that the MediaPath key is kept up-to-date
// in the event that the Windows drive gets remapped (isn't
// NT cool that way?).
//
if (mmRegQueryMachineValue (aszSetup, aszValMediaUnexpanded, cchLENGTH(aszEvent), aszEvent)) { WCHAR szExpanded[MAX_PATH];
ExpandEnvironmentStrings (aszEvent, szExpanded, cchLENGTH(szExpanded)); mmRegSetMachineValue (aszSetup, aszValMedia, szExpanded); } }
int lstrncmpi (LPTSTR pszA, LPTSTR pszB, size_t cch) { #ifdef UNICODE
size_t cchA, cchB; TCHAR *pch;
for (cchA = 1, pch = pszA; cchA < cch; cchA++, pch++) { if (*pch == TEXT('\0')) break; } for (cchB = 1, pch = pszB; cchB < cch; cchB++, pch++) { if (*pch == TEXT('\0')) break; }
return (CompareStringW (GetThreadLocale(), NORM_IGNORECASE, pszA, cchA, pszB, cchB) )-2; // CompareStringW returns {1,2,3} instead of {-1,0,1}.
#else
return strnicmp (pszA, pszB, cch); #endif
}
#if DBG
void Squirt(LPSTR lpszFormat, ...) { char buf[512]; UINT n; va_list va;
n = wsprintfA(buf, "WINMM: (pid %x) ", GetCurrentProcessId());
va_start(va, lpszFormat); n += vsprintf(buf+n, lpszFormat, va); va_end(va);
buf[n++] = '\n'; buf[n] = 0; OutputDebugStringA(buf); Sleep(0); // let terminal catch up
}
#else
void Squirt(LPSTR lpszFormat, ...) { }
#endif
|