/* init.c Level 1 kitchen sink DLL initialisation Copyright (c) Microsoft Corporation 1990. All rights reserved */ #ifdef DEBUG #ifndef DEBUG_RETAIL #define DEBUG_RETAIL #endif #endif #include #include #include "mmsystem.h" #include "mmddk.h" #include "mmsysi.h" #include "drvr.h" #include "thunks.h" /**************************************************************************** global data ****************************************************************************/ HINSTANCE ghInst; // our module handle /* ------------------------------------------------------------------------- ** Thunking stuff ** ------------------------------------------------------------------------- */ LPCB32 PASCAL cb32; LPSOUNDDEVMSGPROC PASCAL wod32Message; LPSOUNDDEVMSGPROC PASCAL wid32Message; LPSOUNDDEVMSGPROC PASCAL mod32Message; LPSOUNDDEVMSGPROC PASCAL mid32Message; LPSOUNDDEVMSGPROC PASCAL aux32Message; JOYMESSAGEPROC PASCAL joy32Message; UINT FAR PASCAL _loadds ThunkInit(void); static BOOL NEAR PASCAL ThunkTerm( void ); LPSOUNDDEVMSGPROC PASCAL wodMapper; LPSOUNDDEVMSGPROC PASCAL widMapper; #ifdef DEBUG_RETAIL BYTE fIdReverse; // reverse wave/midi id's #endif PHNDL pHandleList; #ifdef DEBUG_RETAIL extern int DebugmciSendCommand; // in MCI.C #endif #ifdef DEBUG extern WORD fDebug; #endif /**************************************************************************** strings ****************************************************************************/ static SZCODE szMMWow32[] = "winmm.dll"; static SZCODE szNotifyCB[] = "NotifyCallbackData"; static SZCODE szWodMessage[] = "wod32Message"; static SZCODE szWidMessage[] = "wid32Message"; static SZCODE szModMessage[] = "mod32Message"; static SZCODE szMidMessage[] = "mid32Message"; static SZCODE szAuxMessage[] = "aux32Message"; static SZCODE szTidMessage[] = "tid32Message"; static SZCODE szJoyMessage[] = "joy32Message"; static SZCODE szWaveMapper[] = "wavemapper"; static SZCODE szWodMapper[] = "wodMessage"; static SZCODE szWidMapper[] = "widMessage"; SZCODE szNull[] = ""; SZCODE szSystemIni[] = "system.ini"; SZCODE szDrivers[] = "Drivers"; SZCODE szBoot[] = "boot"; SZCODE szDriverProc[] = "DriverProc"; SZCODE szJoystick[] = "joystick"; SZCODE szJoystickDrv[] = "joystick.drv"; SZCODE szTimerDrv[] = "timer"; #ifdef DEBUG_RETAIL SZCODE szLibMain[] = "MMSYSTEM: Win%dp %ls Version" "%d.%02d MMSystem Version %d.%02d.%03d\r\n"; SZCODE szWinDebug[] = "(Debug)"; SZCODE szWinRetail[] = "(Retail)"; #endif SZCODE szMMSystem[] = "mmsystem"; SZCODE szStackFrames[] = "StackFrames"; SZCODE szStackSize[] = "StackSize"; #ifdef DEBUG_RETAIL SZCODE szDebugOutput[] = "DebugOutput"; SZCODE szMci[] = "mci"; #endif #ifdef DEBUG SZCODE szDebug[] = "Debug"; #endif #ifdef DEBUG_RETAIL /***************************************************************************** * * DebugInit() - called from init.c!LibMain() to handle any DLL load time * initialization in the DEBUG version * ****************************************************************************/ #pragma warning(4:4704) static void NEAR PASCAL DebugInit( void ) { fDebugOutput = GetPrivateProfileInt(szMMSystem,szDebugOutput,0,szSystemIni); DebugmciSendCommand = GetPrivateProfileInt(szMMSystem,szMci,0,szSystemIni); #ifdef DEBUG fDebug = GetPrivateProfileInt(szMMSystem,szDebug,fDebugOutput,szSystemIni); if (fDebug && !fDebugOutput) fDebug = FALSE; if (fDebug) { OutputDebugString( "Breaking for debugging\r\n" ); _asm int 3 } #endif } #endif // ifdef DEBUG_RETAIL /**************************************************************************** Library initialization code libentry took care of calling LibMain() and other things.... ****************************************************************************/ int NEAR PASCAL LibMain( HINSTANCE hInstance, UINT cbHeap, LPSTR lpCmdLine ) { #ifdef DEBUG_RETAIL WORD w; #endif ghInst = hInstance; /* ** Here we do a global alloc of the Callback data array. We then ** Lock and Page Lock the allocated storage and initialize the storage ** to all zeros. We then call WOW32 passing to it the address of the ** Callback data array, which is saved by WOW32. */ hGlobal = GlobalAlloc( GHND, sizeof(CALLBACK_DATA) ); if ( hGlobal == (HGLOBAL)NULL ) { return FALSE; } vpCallbackData = (VPCALLBACK_DATA)GlobalLock( hGlobal ); if ( vpCallbackData == NULL ) { return FALSE; } if ( !HugePageLock( vpCallbackData, (DWORD)sizeof(CALLBACK_DATA) ) ) { return FALSE; } /* ** Now we create our interrupt callback stacks. */ if ( StackInit() == FALSE ) { return FALSE; } /* ** Now we install our interrupt service routine. InstallInterruptHandler ** return FALSE if it couldn't set the interrupt vector. If this is the ** case we have to terminate the load of the dll. */ if ( InstallInterruptHandler() == FALSE ) { return FALSE; } #ifdef DEBUG_RETAIL DebugInit(); w = (WORD)GetVersion(); #endif DPRINTF(( szLibMain, WinFlags & WF_WIN386 ? 386 : 286, (LPSTR)(GetSystemMetrics(SM_DEBUG) ? szWinDebug : szWinRetail), LOBYTE(w), HIBYTE(w), HIBYTE(mmsystemGetVersion()), LOBYTE(mmsystemGetVersion()), MMSYSRELEASE )); #ifdef DEBUG DPRINTF(("MMSYSTEM: NumTasks: %d\r\n", GetNumTasks())); // // 3.0 - MMSYSTEM must be loaded by MMSOUND (ie at boot time) // check for this and fail to load otherwise. // // the real reason we need loaded at boot time is so we can get // in the enable/disable chain. // if (GetNumTasks() > 1) { DOUT("MMSYSTEM: ***!!! Not correctly installed !!!***\r\n"); ////////return FALSE; -Dont fail loading, just don't Enable() } #endif #ifdef DEBUG_RETAIL // // fIdReverse being TRUE causes mmsystem to reverse all wave/midi // logical device id's. // // this prevents apps/drivers assuming a driver load order. // // see wave.c!MapWaveId() and midi.c!MapId() // fIdReverse = LOBYTE(LOWORD(GetCurrentTime())) & (BYTE)0x01; if (fIdReverse) ROUT("MMSYSTEM: wave/midi driver id's will be inverted"); #endif // // do a LoadLibrary() on ourself // LoadLibrary(szMMSystem); return TRUE; } /**************************************************************************** DrvFree - Handler for a DRV_FREE driver message ****************************************************************************/ void FAR PASCAL DrvFree( void ) { MCITerminate(); // mci.c free heap WndTerminate(); // mmwnd.c destroy window, unregister class if ( mmwow32Lib != 0L ) { ThunkTerm(); } } /**************************************************************************** DrvLoad - handler for a DRV_LOAD driver message ****************************************************************************/ BOOL FAR PASCAL DrvLoad(void) { /* ** The VFW1.1 wave mapper was GP faulting in Daytona when running dangerous ** creatures videos. Since it was trying to load an invalid selector in ** its callback routine it's doubtful we can ever enable them. ** */ #if 0 // The wave mappers were GP faulting in Daytona so NOOP for now HDRVR h; /* 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 (h = mmDrvOpen(szWaveMapper)) { mmDrvInstall(h, &wodMapper, MMDRVI_MAPPER|MMDRVI_WAVEOUT|MMDRVI_HDRV); /* open again to get usage count in DLL correct */ h = mmDrvOpen(szWaveMapper); mmDrvInstall(h, &widMapper, MMDRVI_MAPPER|MMDRVI_WAVEIN |MMDRVI_HDRV); } #endif // NOOP wave mapper if ( TimeInit() && WndInit() ) { return TRUE; } // // something failed, backout the changes // DrvFree(); return FALSE; } /******************************Public*Routine******************************\ * StackInit * * * * History: * dd-mm-93 - StephenE - Created * \**************************************************************************/ BOOL FAR PASCAL StackInit( void ) { # define GMEM_STACK_FLAGS (GMEM_FIXED | GMEM_SHARE) # define DEF_STACK_SIZE 0x600 // 1.5k # define DEF_STACK_FRAMES 3 # define MIN_STACK_SIZE 64 # define MIN_STACK_FRAMES 1 DWORD dwStackBytes; WORD wStackFrames; // // The original Window 3.1 code didn't create stack frames for the // Windows Enchanced mode. However, WOW only emulates standard mode so // I won't bother with this distinction. // // if (WinFlags & WF_ENHANCED) // return TRUE; // /* read stackframes and stacksize from system.ini */ gwStackSize = GetPrivateProfileInt( szMMSystem, szStackSize, DEF_STACK_SIZE, szSystemIni ); /* make sure value isn't something bad */ if ( gwStackSize < DEF_STACK_SIZE ) { gwStackSize = DEF_STACK_SIZE; } wStackFrames = GetPrivateProfileInt( szMMSystem, szStackFrames, DEF_STACK_FRAMES, szSystemIni ); // // Always create at least DEF_STACK_FRAMES stack frames. // if ( wStackFrames < DEF_STACK_FRAMES ) { wStackFrames = DEF_STACK_FRAMES; } gwStackFrames = wStackFrames; /* round to nearest number of WORDs */ gwStackSize = (gwStackSize + 1) & ~1; dwStackBytes = (DWORD)gwStackSize * (DWORD)gwStackFrames; /* try to alloc memory */ if ( dwStackBytes >= 0x10000 || !(gwStackSelector = GlobalAlloc(GMEM_STACK_FLAGS, dwStackBytes)) ) { gwStackFrames = DEF_STACK_FRAMES; gwStackSize = DEF_STACK_SIZE; /* do as little at runtime as possible.. */ dwStackBytes = (DWORD)(DEF_STACK_FRAMES * DEF_STACK_SIZE); /* try allocating defaults--if this fails, we are HOSED! */ gwStackSelector = GlobalAlloc( GMEM_STACK_FLAGS, dwStackBytes ); } /* ** set to first available stack */ gwStackUse = (WORD)dwStackBytes; /* ** did we get memory for stacks?? */ if ( !gwStackSelector ) { /* ** no stacks available... as if we have a chance of survival! */ gwStackUse = 0; return FALSE; } /* looks good... */ return TRUE; } /*****************************Private*Routine******************************\ * StackInit * * * * History: * dd-mm-93 - StephenE - Created * \**************************************************************************/ BOOL NEAR PASCAL StackTerminate( void ) { if ( gwStackSelector ) { DOUT("MMSTACKS: Freeing stacks\r\n"); gwStackSelector = GlobalFree( gwStackSelector ); if ( gwStackSelector ) DOUT("MMSTACKS: GlobalFree failed!\r\n"); } /* return the outcome... non-zero is bad */ return ( (BOOL)gwStackSelector ); } /* StackTerminate() */ /***************************************************************************** * @doc EXTERNAL MMSYSTEM * * @api WORD | 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. * ****************************************************************************/ WORD WINAPI mmsystemGetVersion(void) { return(MMSYSTEM_VERSION); } /***************************************************************************** * * @doc INTERNAL * * @api BOOL | DrvTerminate | This function cleans up the installable * driver interface. * ****************************************************************************/ static void NEAR PASCAL DrvTerminate(void) { // don't know about system exit dll order - so do nothing. } /***************************************************************************** * @doc INTERNAL * * @api BOOL | mmDrvInstall | This function installs a WAVE driver * * @parm HANDLE | hDriver | Module handle or driver handle containing driver * * @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_MAPPER | install this driver as the mapper * @flag MMDRVI_HDRV | hDriver is a installable driver * * @rdesc returns NULL if unable to install driver * ****************************************************************************/ BOOL WINAPI mmDrvInstall( HANDLE hDriver, DRIVERMSGPROC *drvMessage, UINT wFlags ) { DWORD dw; HINSTANCE hModule; UINT msg_num_devs; SZCODE *szMessage; hModule = GetDriverModuleHandle((HDRVR)hDriver); switch (wFlags & MMDRVI_TYPE) { case MMDRVI_WAVEOUT: msg_num_devs = WODM_GETNUMDEVS; szMessage = szWodMapper; break; case MMDRVI_WAVEIN: msg_num_devs = WIDM_GETNUMDEVS; szMessage = szWidMapper; break; default: goto error_exit; } if (hModule != NULL) *drvMessage = (DRIVERMSGPROC)GetProcAddress(hModule, szMessage); if (*drvMessage == NULL) goto error_exit; // // send the init message, if the driver returns a error, should we // unload them??? // dw = (*(*drvMessage))(0,DRVM_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) goto error_exit; return TRUE; error_exit: if (hDriver) CloseDriver(hDriver, 0, 0); return FALSE; } /***************************************************************************** * * @doc INTERNAL * * @api HDRVR | 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 OpenDriver or NULL if the alias * was not found in the [Drivers] section. * ****************************************************************************/ HDRVR NEAR PASCAL mmDrvOpen( LPSTR szAlias ) { char buf[3]; if (GetPrivateProfileString( szDrivers,szAlias,szNull,buf, sizeof(buf),szSystemIni )) { return OpenDriver(szAlias, NULL, 0L); } else { return NULL; } } /*****************************Private*Routine******************************\ * ThunkInit * * Tries to setup the thunking system. If this can not be performed * it returns an error code of MMSYSERR_NODRIVER. Otherwise it returns * MMSYSERR_NOERROR to indicate sucess. * * History: * dd-mm-93 - StephenE - Created * \**************************************************************************/ UINT FAR PASCAL _loadds ThunkInit( void ) { mmwow32Lib = LoadLibraryEx32W( szMMWow32, NULL, 0L ); if ( mmwow32Lib == 0L ) { return MMSYSERR_NODRIVER; } cb32 = (LPCB32)GetProcAddress32W(mmwow32Lib, szNotifyCB ); /* ** Now we notify WOW32 that all is OK by passing the 16:16 bit pointer ** to the CALLBACK_DATA to it. */ Notify_Callback_Data( vpCallbackData ); /* ** Now initialize the rest of the thunking system */ wod32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szWodMessage ); wid32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szWidMessage ); mod32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szModMessage ); mid32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szMidMessage ); aux32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szAuxMessage ); mci32Message = (LPMCIMESSAGE)GetProcAddress32W( mmwow32Lib, "mci32Message" ); tid32Message = (TIDMESSAGEPROC)GetProcAddress32W( mmwow32Lib, szTidMessage ); joy32Message = (JOYMESSAGEPROC)GetProcAddress32W( mmwow32Lib, szJoyMessage ); return MMSYSERR_NOERROR; } /*****************************Private*Routine******************************\ * ThunkTerm * * * * History: * dd-mm-93 - StephenE - Created * \**************************************************************************/ static BOOL NEAR PASCAL ThunkTerm( void ) { /* ** Free the interrupt stack frames and uninstall the interrupt handler. */ StackTerminate(); DeInstallInterruptHandler(); /* ** Next we notify WOW32 that we are going away by passing NULL to ** Notify_Callback_Data, then free the storage. */ Notify_Callback_Data( NULL ); HugePageUnlock( vpCallbackData, (DWORD)sizeof(CALLBACK_DATA) ); GlobalUnlock( hGlobal ); GlobalFree( hGlobal ); return 1; }