mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
674 lines
18 KiB
674 lines
18 KiB
/*
|
|
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 <windows.h>
|
|
#include <mmsysver.h>
|
|
#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 thuynking 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;
|
|
}
|
|
|