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.
1693 lines
41 KiB
1693 lines
41 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: ddhelp.c
|
|
* Content: helper app to cleanup after dead processes
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 29-mar-95 craige initial implementation
|
|
* 05-apr-95 craige re-worked
|
|
* 11-apr-95 craige fixed messed up freeing of DC list
|
|
* 12-apr-95 craige only allocate each DC once
|
|
* 09-may-95 craige call fn in dll
|
|
* 24-jun-95 craige track pids; slay all attached if asked
|
|
* 19-jul-95 craige free DC list at DDRAW request
|
|
* 20-jul-95 craige internal reorg to prevent thunking during modeset;
|
|
* memory allocation bugs
|
|
* 15-aug-95 craige bug 538: 1 thread/process being watched
|
|
* 02-sep-95 craige bug 795: prevent callbacks at WM_ENDSESSION
|
|
* 16-sep-95 craige bug 1117: don't leave view of file mapped always
|
|
* 16-sep-95 craige bug 1117: also close thread handles when done!
|
|
* 20-sep-95 craige bug 1172: turn off callbacks instead of killing self
|
|
* 22-sep-95 craige bug 1117: also don't alloc dll structs unboundedly
|
|
* 29-nov-95 angusm added case for creating a sound focus thread
|
|
* 12-jul-96 kylej Change ExitProcess to TerminateProcess on exception
|
|
* 18-jul-96 andyco added dplayhelp_xxx functions to allow > 1 dplay app to
|
|
* host a game on a single machine.
|
|
* 25-jul-96 andyco watchnewpid - broke code out of winmain so dplayhelp_addserver
|
|
* could call it.
|
|
* 2-oct-96 andyco propagated from \orange\ddhelp.2 to \mustard\ddhelp
|
|
* 3-oct-96 andyco made the winmain crit section "cs" a global so we can take
|
|
* it in dphelps receive thread before forwarding requests
|
|
* 12-oct-96 colinmc new service to load the DirectX VXD into DDHELP
|
|
* (necessary for the Win16 lock stuff)
|
|
* 15-oct-96 toddla multimonitor support (call CreateDC with device name)
|
|
* 22-jan-97 kipo return an error code from DPlayHelp_AddServer
|
|
* 23-jan-97 dereks added APM notification events
|
|
* 27-jan-97 colinmc vxd handling stuff is no longer Win16 specific
|
|
* 29-jan-97 colinmc
|
|
* 24-feb-97 ketand Add a callback for WM_DISPLAYCHANGE
|
|
* 19-mar-97 twillie Exorcized the DPlay Demon from DDHelp
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.c"
|
|
|
|
#undef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#ifdef WIN95
|
|
#ifdef _WIN32
|
|
#define WINMMDEVICECHANGEMSGSTRINGA "winmm_devicechange"
|
|
#define WINMMDEVICECHANGEMSGSTRINGW L"winmm_devicechange"
|
|
#ifdef UNICODE
|
|
#define WINMMDEVICECHANGEMSGSTRING WINMMDEVICECHANGEMSGSTRINGW
|
|
#else
|
|
#define WINMMDEVICECHANGEMSGSTRING WINMMDEVICECHANGEMSGSTRINGA
|
|
#endif
|
|
#else
|
|
#define WINMMDEVICECHANGEMSGSTRING "winmm_devicechange"
|
|
#endif
|
|
|
|
#define FILE_FLAG_GLOBAL_HANDLE 0x00800000
|
|
WINBASEAPI
|
|
DWORD
|
|
WINAPI
|
|
RegisterServiceProcess(
|
|
DWORD dwProcessId,
|
|
DWORD dwServiceType
|
|
);
|
|
|
|
#define RSP_UNREGISTER_SERVICE 0x00000000
|
|
#define RSP_SIMPLE_SERVICE 0x00000001
|
|
#endif
|
|
|
|
#ifndef WIN95
|
|
#ifdef DBG
|
|
#undef DEBUG
|
|
#define DEBUG
|
|
#endif
|
|
#endif
|
|
|
|
//#include <windows.h>
|
|
//#include <mmsystem.h>
|
|
#include <mmreg.h>
|
|
#undef PBT_APMRESUMEAUTOMATIC
|
|
#include <pbt.h>
|
|
#include <dbt.h>
|
|
|
|
//#include "ddhelp.h"
|
|
#include "ddrawi.h"
|
|
#include "dpf.h"
|
|
#define NOSHARED
|
|
#include "memalloc.h"
|
|
|
|
#ifdef NEED_WIN16LOCK
|
|
extern void _stdcall GetpWin16Lock( LPVOID FAR *);
|
|
extern void _stdcall _EnterSysLevel( LPVOID );
|
|
extern void _stdcall _LeaveSysLevel( LPVOID );
|
|
LPVOID lpWin16Lock;
|
|
#endif
|
|
|
|
HANDLE hInstApp;
|
|
extern BOOL bIsActive;
|
|
BOOL bHasModeSetThread;
|
|
BOOL bNoCallbacks;
|
|
extern void HelperThreadProc( LPVOID *pdata );
|
|
CRITICAL_SECTION cs; // the crit section we take in winmain
|
|
// this is a global so dphelp can take it before
|
|
// forwarding enum requests that come in on its
|
|
// receive thread (manbugs 3907)
|
|
HANDLE hApmSuspendEvent; // Event set when we enter an APM suspension state
|
|
HANDLE hApmResumeEvent; // Event set when we leave the above state
|
|
|
|
#ifdef WIN95
|
|
UINT gumsgWinmmDeviceChange = 0; // window message for
|
|
// winmm device changes
|
|
|
|
/*
|
|
* Handle to the DirectSound VXD. DDHELP needs its own handle as, on mode
|
|
* switches and cleanups DDHELP can invoked DDRAW code that needs to talk
|
|
* to the VXD. The VXD is opened on the first request from a client (currently
|
|
* only DDRAW) and closed only when DDHELP shuts down.
|
|
*/
|
|
HANDLE hDSVxd = INVALID_HANDLE_VALUE;
|
|
HANDLE hDDVxd = INVALID_HANDLE_VALUE;
|
|
|
|
typedef struct _DEVICECHANGENOTIFYLIST
|
|
{
|
|
struct _DEVICECHANGENOTIFYLIST *link;
|
|
LPDEVICECHANGENOTIFYPROC lpNotify;
|
|
} DEVICECHANGENOTIFYLIST, *LPDEVICECHANGENOTIFYLIST;
|
|
|
|
LPDEVICECHANGENOTIFYLIST lpDeviceChangeNotifyList;
|
|
#endif /* WIN95 */
|
|
|
|
typedef struct HDCLIST
|
|
{
|
|
struct HDCLIST *link;
|
|
HDC hdc;
|
|
HANDLE req_id;
|
|
char isdisp;
|
|
char fname[1];
|
|
} HDCLIST, *LPHDCLIST;
|
|
|
|
static LPHDCLIST lpHDCList;
|
|
|
|
typedef struct HDLLLIST
|
|
{
|
|
struct HDLLLIST *link;
|
|
HANDLE hdll;
|
|
DWORD dwRefCnt;
|
|
char fname[1];
|
|
} HDLLLIST, *LPHDLLLIST;
|
|
|
|
static LPHDLLLIST lpHDLLList;
|
|
|
|
/*
|
|
* 8 callbacks: we can use up to 3 currently: ddraw, dsound
|
|
*/
|
|
#define MAX_CALLBACKS 8
|
|
|
|
typedef struct _PROCESSDATA
|
|
{
|
|
struct _PROCESSDATA *link;
|
|
DWORD pid;
|
|
struct
|
|
{
|
|
LPHELPNOTIFYPROC lpNotify;
|
|
HANDLE req_id;
|
|
} pdata[MAX_CALLBACKS];
|
|
} PROCESSDATA, *LPPROCESSDATA;
|
|
|
|
LPPROCESSDATA lpProcessList;
|
|
CRITICAL_SECTION pdCSect;
|
|
|
|
|
|
typedef struct THREADLIST
|
|
{
|
|
struct THREADLIST *link;
|
|
ULONG_PTR hInstance;
|
|
HANDLE hEvent;
|
|
} THREADLIST, *LPTHREADLIST;
|
|
|
|
typedef struct
|
|
{
|
|
LPVOID lpDD;
|
|
LPHELPMODESETNOTIFYPROC lpProc;
|
|
HANDLE hEvent;
|
|
} MODESETTHREADDATA, *LPMODESETTHREADDATA;
|
|
|
|
LPTHREADLIST lpThreadList;
|
|
THREADLIST DOSBoxThread;
|
|
|
|
// Who to call when a display change message is sent to the
|
|
// DDHELPER's window. This variable is reserved by DDraw.
|
|
// This works because DDraw itself is loaded into DDHelper's
|
|
// process and so the function will remain valid.
|
|
VOID (*g_pfnOnDisplayChange)(void) = NULL;
|
|
|
|
/*
|
|
* freeDCList
|
|
*
|
|
* Free all DC's that an requestor allocated.
|
|
*/
|
|
void freeDCList( HANDLE req_id )
|
|
{
|
|
LPHDCLIST pdcl;
|
|
LPHDCLIST last;
|
|
LPHDCLIST next;
|
|
|
|
DPF( 4, "Freeing DCList" );
|
|
pdcl = lpHDCList;
|
|
last = NULL;
|
|
while( pdcl != NULL )
|
|
{
|
|
next = pdcl->link;
|
|
if( (pdcl->req_id == req_id) || req_id == (HANDLE) -1 )
|
|
{
|
|
if( last == NULL )
|
|
{
|
|
lpHDCList = lpHDCList->link;
|
|
}
|
|
else
|
|
{
|
|
last->link = pdcl->link;
|
|
}
|
|
if( pdcl->isdisp )
|
|
{
|
|
DPF( 5, " ReleaseDC( NULL, %08lx)", pdcl->hdc );
|
|
// ReleaseDC( NULL, pdcl->hdc );
|
|
DeleteDC( pdcl->hdc );
|
|
DPF( 5, " Back from Release" );
|
|
}
|
|
else
|
|
{
|
|
DPF( 5, " DeleteDC( %08lx)", pdcl->hdc );
|
|
DeleteDC( pdcl->hdc );
|
|
DPF( 5, " Back from DeleteDC" );
|
|
}
|
|
MemFree( pdcl );
|
|
}
|
|
else
|
|
{
|
|
last = pdcl;
|
|
}
|
|
pdcl = next;
|
|
}
|
|
if ( req_id == (HANDLE) -1 )
|
|
{
|
|
DDASSERT (lpHDCList == NULL);
|
|
}
|
|
DPF( 4, "DCList FREE" );
|
|
|
|
} /* freeDCList */
|
|
|
|
/*
|
|
* addDC
|
|
*/
|
|
void addDC( char *fname, BOOL isdisp, HANDLE req_id )
|
|
{
|
|
LPHDCLIST pdcl;
|
|
HDC hdc;
|
|
UINT u;
|
|
|
|
pdcl = lpHDCList;
|
|
while( pdcl != NULL )
|
|
{
|
|
if( !_stricmp( fname, pdcl->fname ) )
|
|
{
|
|
DPF( 4, "DC for %s already obtained (%08lx)", fname, pdcl->hdc );
|
|
return;
|
|
}
|
|
pdcl = pdcl->link;
|
|
}
|
|
|
|
if( isdisp )
|
|
{
|
|
hdc = CreateDC( "display", NULL, NULL, NULL);
|
|
DPF( 4, "CreateDC( \"display\" ) = %08lx", hdc );
|
|
}
|
|
else
|
|
{
|
|
DPF( 4, "About to CreateDC( \"%s\" )", fname );
|
|
//
|
|
// if fname is a device name of the form "\\.\XXXXXX"
|
|
// we need to call CreateDC differently
|
|
//
|
|
u = SetErrorMode( SEM_NOOPENFILEERRORBOX );
|
|
if (fname && fname[0] == '\\' && fname[1] == '\\' && fname[2] == '.')
|
|
hdc = CreateDC( NULL, fname, NULL, NULL);
|
|
else
|
|
hdc = CreateDC( fname, NULL, NULL, NULL);
|
|
SetErrorMode( u );
|
|
}
|
|
|
|
pdcl = MemAlloc( sizeof( HDCLIST ) + lstrlen( fname ) );
|
|
if( pdcl != NULL )
|
|
{
|
|
pdcl->hdc = hdc;
|
|
pdcl->link = lpHDCList;
|
|
pdcl->isdisp = (CHAR)isdisp;
|
|
pdcl->req_id = req_id;
|
|
lstrcpy( pdcl->fname, fname );
|
|
lpHDCList = pdcl;
|
|
}
|
|
|
|
} /* addDC */
|
|
|
|
/*
|
|
* loadDLL
|
|
*/
|
|
DWORD loadDLL( LPSTR fname, LPSTR func, DWORD context )
|
|
{
|
|
HANDLE hdll;
|
|
LPHDLLLIST pdll;
|
|
DWORD rc = 0;
|
|
|
|
/*
|
|
* load the dll
|
|
*/
|
|
hdll = LoadLibrary( fname );
|
|
DPF( 5, "%s: hdll = %08lx", fname, hdll );
|
|
if( hdll == NULL )
|
|
{
|
|
DPF( 1, "Could not load library %s",fname );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* invoke specified function
|
|
*/
|
|
|
|
if( func[0] != 0 )
|
|
{
|
|
LPDD32BITDRIVERINIT pfunc;
|
|
pfunc = (LPVOID) GetProcAddress( hdll, func );
|
|
if( pfunc != NULL )
|
|
{
|
|
rc = pfunc( context );
|
|
}
|
|
else
|
|
{
|
|
DPF( 1, "Could not find procedure %s", func );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = 1;
|
|
}
|
|
|
|
/*
|
|
* see if we have recorded this DLL loading already
|
|
*/
|
|
pdll = lpHDLLList;
|
|
while( pdll != NULL )
|
|
{
|
|
if( !lstrcmpi( pdll->fname, fname ) )
|
|
{
|
|
DPF( 3, "DLL '%s' already loaded", fname );
|
|
break;
|
|
}
|
|
pdll = pdll->link;
|
|
}
|
|
if( pdll == NULL )
|
|
{
|
|
pdll = MemAlloc( sizeof( HDLLLIST ) + lstrlen( fname ) );
|
|
if( pdll != NULL )
|
|
{
|
|
pdll->hdll = hdll;
|
|
pdll->link = lpHDLLList;
|
|
lstrcpy( pdll->fname, fname );
|
|
lpHDLLList = pdll;
|
|
}
|
|
}
|
|
if( pdll != NULL )
|
|
{
|
|
pdll->dwRefCnt++;
|
|
}
|
|
return rc;
|
|
|
|
} /* loadDLL */
|
|
|
|
/*
|
|
* freeDLL
|
|
*/
|
|
HANDLE freeDLL( LPSTR fname )
|
|
{
|
|
LPHDLLLIST pdll;
|
|
LPHDLLLIST last;
|
|
HANDLE hdll;
|
|
|
|
pdll = lpHDLLList;
|
|
last = NULL;
|
|
while( pdll != NULL )
|
|
{
|
|
if( !lstrcmpi( pdll->fname, fname ) )
|
|
{
|
|
DPF( 4, "Want to free DLL %s (%08lx)", fname, pdll->hdll );
|
|
hdll = pdll->hdll;
|
|
if( last == NULL )
|
|
{
|
|
lpHDLLList = lpHDLLList->link;
|
|
}
|
|
else
|
|
{
|
|
last->link = pdll->link;
|
|
}
|
|
MemFree( pdll );
|
|
return hdll;
|
|
}
|
|
last = pdll;
|
|
pdll = pdll->link;
|
|
}
|
|
return NULL;
|
|
|
|
} /* freeDLL */
|
|
|
|
#ifdef WIN95
|
|
/*
|
|
* return a handle to the DirectSound VXD
|
|
*/
|
|
DWORD getDSVxdHandle( void )
|
|
{
|
|
if( INVALID_HANDLE_VALUE == hDSVxd )
|
|
{
|
|
hDSVxd = CreateFile( "\\\\.\\DSOUND.VXD",
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_GLOBAL_HANDLE,
|
|
NULL );
|
|
#ifdef DEBUG
|
|
if( INVALID_HANDLE_VALUE == hDSVxd )
|
|
DPF( 0, "Could not load the DirectSound VXD" );
|
|
#endif /* DEBUG */
|
|
}
|
|
return (DWORD) hDSVxd;
|
|
} /* getDSVxdHandle */
|
|
|
|
/*
|
|
* return a handle to the DirectDraw VXD
|
|
*/
|
|
DWORD getDDVxdHandle( void )
|
|
{
|
|
if( INVALID_HANDLE_VALUE == hDDVxd )
|
|
{
|
|
hDDVxd = CreateFile( "\\\\.\\DDRAW.VXD",
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_GLOBAL_HANDLE,
|
|
NULL );
|
|
#ifdef DEBUG
|
|
if( INVALID_HANDLE_VALUE == hDDVxd )
|
|
DPF( 0, "Could not load the DirectDraw VXD" );
|
|
#endif /* DEBUG */
|
|
}
|
|
return (DWORD) hDDVxd;
|
|
} /* getDDVxdHandle */
|
|
|
|
/*
|
|
* addDeviceChangeNotify
|
|
*/
|
|
void addDeviceChangeNotify(LPDEVICECHANGENOTIFYPROC lpNotify)
|
|
{
|
|
LPDEVICECHANGENOTIFYLIST pNode;
|
|
|
|
pNode = (LPDEVICECHANGENOTIFYLIST)MemAlloc(sizeof(DEVICECHANGENOTIFYLIST));
|
|
|
|
if(pNode)
|
|
{
|
|
pNode->link = lpDeviceChangeNotifyList;
|
|
pNode->lpNotify = lpNotify;
|
|
|
|
lpDeviceChangeNotifyList = pNode;
|
|
}
|
|
|
|
} /* addDeviceChangeNotify */
|
|
|
|
/*
|
|
* delDeviceChangeNotify
|
|
*/
|
|
void delDeviceChangeNotify(LPDEVICECHANGENOTIFYPROC lpNotify)
|
|
{
|
|
LPDEVICECHANGENOTIFYLIST pNode;
|
|
LPDEVICECHANGENOTIFYLIST pPrev;
|
|
|
|
for(pNode = lpDeviceChangeNotifyList, pPrev = NULL; pNode; pPrev = pNode, pNode = pNode->link)
|
|
{
|
|
if(lpNotify == pNode->lpNotify)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pNode)
|
|
{
|
|
if(pPrev)
|
|
{
|
|
pPrev->link = pNode->link;
|
|
}
|
|
|
|
MemFree(pNode);
|
|
}
|
|
|
|
} /* delDeviceChangeNotify */
|
|
|
|
/*
|
|
* onDeviceChangeNotify
|
|
*/
|
|
BOOL onDeviceChangeNotify(UINT Event, DWORD Data)
|
|
{
|
|
BOOL fAllow = TRUE;
|
|
LPDEVICECHANGENOTIFYLIST pNode;
|
|
|
|
__try
|
|
{
|
|
for(pNode = lpDeviceChangeNotifyList; pNode; pNode = pNode->link)
|
|
{
|
|
if(TRUE != pNode->lpNotify(Event, Data))
|
|
{
|
|
fAllow = BROADCAST_QUERY_DENY;
|
|
}
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF(0, "*********************************************************");
|
|
DPF(0, "******** exception during device change notify **********");
|
|
DPF(0, "*********************************************************");
|
|
}
|
|
|
|
return fAllow;
|
|
|
|
} /* delDeviceChangeNotify */
|
|
|
|
/*
|
|
* freeDeviceChangeNotifyList
|
|
*/
|
|
void freeDeviceChangeNotifyList(void)
|
|
{
|
|
LPDEVICECHANGENOTIFYLIST pNext;
|
|
|
|
while(lpDeviceChangeNotifyList)
|
|
{
|
|
pNext = lpDeviceChangeNotifyList->link;
|
|
MemFree(lpDeviceChangeNotifyList);
|
|
lpDeviceChangeNotifyList = pNext;
|
|
}
|
|
|
|
} /* freeDeviceChangeNotifyList */
|
|
#endif /* WIN95 */
|
|
|
|
/*
|
|
* freeAllResources
|
|
*/
|
|
void freeAllResources( void )
|
|
{
|
|
LPHDLLLIST pdll;
|
|
LPHDLLLIST next;
|
|
|
|
freeDCList( (HANDLE) -1 );
|
|
pdll = lpHDLLList;
|
|
while( pdll != NULL )
|
|
{
|
|
while( pdll->dwRefCnt > 0 )
|
|
{
|
|
FreeLibrary( pdll->hdll );
|
|
pdll->dwRefCnt--;
|
|
}
|
|
next = pdll->link;
|
|
MemFree( pdll );
|
|
pdll = next;
|
|
}
|
|
|
|
#ifdef WIN95
|
|
freeDeviceChangeNotifyList();
|
|
#endif
|
|
} /* freeAllResources */
|
|
|
|
/*
|
|
* ThreadProc
|
|
*
|
|
* Open a process and wait for it to terminate
|
|
*/
|
|
VOID ThreadProc( LPVOID *pdata )
|
|
{
|
|
HANDLE hproc;
|
|
DWORD rc;
|
|
LPPROCESSDATA ppd;
|
|
LPPROCESSDATA curr;
|
|
LPPROCESSDATA prev;
|
|
DDHELPDATA hd;
|
|
int i;
|
|
PROCESSDATA pd;
|
|
|
|
ppd = (LPPROCESSDATA) pdata;
|
|
|
|
/*
|
|
* get a handle to the process that attached to DDRAW
|
|
*/
|
|
DPF( 3, "Watchdog thread started for pid %08lx", ppd->pid );
|
|
|
|
hproc = OpenProcess( PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
|
|
FALSE, ppd->pid );
|
|
if( hproc == NULL )
|
|
{
|
|
DPF( 1, "OpenProcess for %08lx failed!", ppd->pid );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
/*
|
|
* wait for process to die
|
|
*/
|
|
rc = WaitForSingleObject( hproc, INFINITE );
|
|
if( rc == WAIT_FAILED )
|
|
{
|
|
DPF( 1, "Wait for process %08lx failed", ppd->pid );
|
|
CloseHandle( hproc );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
/*
|
|
* remove process from the list of watched processes
|
|
*/
|
|
EnterCriticalSection( &pdCSect );
|
|
pd = *ppd;
|
|
curr = lpProcessList;
|
|
prev = NULL;
|
|
while( curr != NULL )
|
|
{
|
|
if( curr == ppd )
|
|
{
|
|
if( prev == NULL )
|
|
{
|
|
lpProcessList = curr->link;
|
|
}
|
|
else
|
|
{
|
|
prev->link = curr->link;
|
|
}
|
|
DPF( 4, "PID %08lx removed from list", ppd->pid );
|
|
MemFree( curr );
|
|
break;
|
|
}
|
|
prev = curr;
|
|
curr = curr->link;
|
|
}
|
|
|
|
if( bNoCallbacks )
|
|
{
|
|
DPF( 1, "No callbacks allowed: leaving thread early" );
|
|
LeaveCriticalSection( &pdCSect );
|
|
CloseHandle( hproc );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
LeaveCriticalSection( &pdCSect );
|
|
|
|
/*
|
|
* tell original caller that process is dead
|
|
*
|
|
* Make a copy to of the process data, and then use that copy.
|
|
* We do this because we will deadlock if we just try to hold it while
|
|
* we call the various apps.
|
|
*/
|
|
for( i=0;i<MAX_CALLBACKS;i++ )
|
|
{
|
|
if( pd.pdata[i].lpNotify != NULL )
|
|
{
|
|
DPF( 3, "Notifying %08lx about process %08lx terminating",
|
|
pd.pdata[i].lpNotify, pd.pid );
|
|
hd.pid = pd.pid;
|
|
|
|
try
|
|
{
|
|
rc = pd.pdata[i].lpNotify( &hd );
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF(0, "*********************************************");
|
|
DPF(0, "******** exception during shutdown **********");
|
|
DPF(0, "******** DDHELP is going to exit **********");
|
|
DPF(0, "*********************************************");
|
|
TerminateProcess(GetCurrentProcess(), 5);
|
|
}
|
|
|
|
/*
|
|
* did it ask us to free our DC list?
|
|
*/
|
|
if( rc )
|
|
{
|
|
freeDCList( pd.pdata[i].req_id );
|
|
}
|
|
}
|
|
}
|
|
CloseHandle( hproc );
|
|
|
|
ExitThread( 0 );
|
|
|
|
} /* ThreadProc */
|
|
|
|
static BOOL bKillNow;
|
|
static BOOL bKillDOSBoxNow;
|
|
|
|
/*
|
|
* ModeSetThreadProc
|
|
*/
|
|
void ModeSetThreadProc( LPVOID pdata )
|
|
{
|
|
DWORD rc;
|
|
MODESETTHREADDATA mstd;
|
|
|
|
#ifdef WIN95
|
|
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
|
|
#endif
|
|
|
|
mstd = *((LPMODESETTHREADDATA)pdata);
|
|
|
|
DPF( 5, "Modeset thread started, proc=%08lx, pdrv=%08lx, hEvent=%08lx",
|
|
mstd.lpProc, mstd.lpDD, mstd.hEvent );
|
|
DPF( 5, "ModeSetThreadProc: hevent = %08lx", mstd.hEvent );
|
|
|
|
/*
|
|
* wait for process to die
|
|
*/
|
|
while( 1 )
|
|
{
|
|
rc = WaitForSingleObject( mstd.hEvent, INFINITE );
|
|
if( rc == WAIT_FAILED )
|
|
{
|
|
DPF( 2, "WAIT_FAILED, Modeset thread terminated" );
|
|
ExitThread( 0 );
|
|
}
|
|
if( bKillNow )
|
|
{
|
|
bKillNow = 0;
|
|
CloseHandle( mstd.hEvent );
|
|
DPF( 4, "Modeset thread now terminated" );
|
|
ExitThread( 0 );
|
|
}
|
|
DPF( 3, "Notifying DirectDraw of modeset!" );
|
|
mstd.lpProc( mstd.lpDD );
|
|
}
|
|
|
|
} /* ModeSetThreadProc */
|
|
|
|
/*
|
|
* DOSBoxThreadProc
|
|
*/
|
|
void DOSBoxThreadProc( LPVOID pdata )
|
|
{
|
|
DWORD rc;
|
|
MODESETTHREADDATA mstd;
|
|
|
|
mstd = *((LPMODESETTHREADDATA)pdata);
|
|
|
|
DPF( 5, "DOS box thread started, proc=%08lx, pdrv=%08lx, hEvent=%08lx",
|
|
mstd.lpProc, mstd.lpDD, mstd.hEvent );
|
|
DPF( 5, "DOSBoxThreadProc: hevent = %08lx", mstd.hEvent );
|
|
|
|
/*
|
|
* wait for process to die
|
|
*/
|
|
while( 1 )
|
|
{
|
|
rc = WaitForSingleObject( mstd.hEvent, INFINITE );
|
|
if( rc == WAIT_FAILED )
|
|
{
|
|
DPF( 2, "WAIT_FAILED, DOS Box thread terminated" );
|
|
ExitThread( 0 );
|
|
}
|
|
if( bKillDOSBoxNow )
|
|
{
|
|
bKillDOSBoxNow = 0;
|
|
CloseHandle( mstd.hEvent );
|
|
DPF( 4, "DOS box thread now terminated" );
|
|
ExitThread( 0 );
|
|
}
|
|
DPF( 3, "Notifying DirectDraw of DOS box!" );
|
|
mstd.lpProc( mstd.lpDD );
|
|
}
|
|
|
|
} /* DOSBoxThreadProc */
|
|
|
|
/*
|
|
* MainWndProc
|
|
*/
|
|
LRESULT __stdcall MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
#ifdef WIN95
|
|
BOOL f;
|
|
|
|
// If we got a message for a WinMM device change, let's convert it
|
|
// into a WM_DEVICECHANGE message with DBT_DEVNODES_CHANGED
|
|
if (message == gumsgWinmmDeviceChange) {
|
|
message = WM_DEVICECHANGE;
|
|
wParam = DBT_DEVNODES_CHANGED;
|
|
}
|
|
#endif
|
|
|
|
switch(message)
|
|
{
|
|
case WM_ENDSESSION:
|
|
/*
|
|
* shoot ourselves in the head
|
|
*/
|
|
if( lParam == FALSE )
|
|
{
|
|
DPF( 4, "WM_ENDSESSION" );
|
|
EnterCriticalSection( &pdCSect );
|
|
DPF( 4, "Setting NO CALLBACKS" );
|
|
bNoCallbacks = TRUE;
|
|
LeaveCriticalSection( &pdCSect );
|
|
}
|
|
else
|
|
{
|
|
DPF( 4, "User logging off" );
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_POWERBROADCAST:
|
|
switch(wParam)
|
|
{
|
|
case PBT_APMSUSPEND:
|
|
DPF(3, "Entering APM suspend mode...");
|
|
SetEvent(hApmSuspendEvent);
|
|
ResetEvent(hApmResumeEvent);
|
|
break;
|
|
|
|
case PBT_APMRESUMESUSPEND:
|
|
case PBT_APMRESUMEAUTOMATIC:
|
|
case PBT_APMRESUMECRITICAL:
|
|
DPF(3, "Leaving APM suspend mode...");
|
|
SetEvent(hApmResumeEvent);
|
|
ResetEvent(hApmSuspendEvent);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
DPF( 4, "WM_DISPLAYCHANGE" );
|
|
if( g_pfnOnDisplayChange )
|
|
(*g_pfnOnDisplayChange)();
|
|
break;
|
|
|
|
#ifdef WIN95
|
|
case WM_DEVICECHANGE:
|
|
DPF(4, "WM_DEVICECHANGE");
|
|
|
|
EnterCriticalSection(&cs);
|
|
f = onDeviceChangeNotify(wParam, lParam);
|
|
LeaveCriticalSection(&cs);
|
|
|
|
if (f != TRUE)
|
|
{
|
|
return f;
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
} /* MainWndProc */
|
|
|
|
/*
|
|
* WindowThreadProc
|
|
*/
|
|
void WindowThreadProc( LPVOID pdata )
|
|
{
|
|
static char szClassName[] = "DDHelpWndClass";
|
|
WNDCLASS cls;
|
|
MSG msg;
|
|
HWND hwnd;
|
|
|
|
/*
|
|
* turn down the heat a little
|
|
*/
|
|
#ifdef WIN95
|
|
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_IDLE );
|
|
|
|
if (!gumsgWinmmDeviceChange) {
|
|
gumsgWinmmDeviceChange = RegisterWindowMessage(WINMMDEVICECHANGEMSGSTRING);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* build class and create window
|
|
*/
|
|
cls.lpszClassName = szClassName;
|
|
cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
cls.hInstance = hInstApp;
|
|
cls.hIcon = NULL;
|
|
cls.hCursor = NULL;
|
|
cls.lpszMenuName = NULL;
|
|
cls.style = 0;
|
|
cls.lpfnWndProc = MainWndProc;
|
|
cls.cbWndExtra = 0;
|
|
cls.cbClsExtra = 0;
|
|
|
|
if( !RegisterClass( &cls ) )
|
|
{
|
|
DPF( 1, "RegisterClass FAILED!" );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
hwnd = CreateWindow( szClassName, szClassName,
|
|
WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstApp, NULL);
|
|
|
|
if( hwnd == NULL )
|
|
{
|
|
DPF( 1, "No monitor window!" );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
/*
|
|
* pump the messages
|
|
*/
|
|
while( GetMessage( &msg, NULL, 0, 0 ) )
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
}
|
|
DPF( 4, "Exiting WindowThreadProc" );
|
|
ExitThread( 1 );
|
|
|
|
} /* WindowThreadProc */
|
|
|
|
//
|
|
// called by WinMain in response to a DDHELPREQ_NEWPID request.
|
|
//
|
|
void WatchNewPid(LPDDHELPDATA phd)
|
|
{
|
|
LPPROCESSDATA ppd;
|
|
BOOL found;
|
|
int i;
|
|
DWORD tid;
|
|
|
|
DPF( 4, "DDHELPREQ_NEWPID" );
|
|
|
|
EnterCriticalSection( &pdCSect );
|
|
ppd = lpProcessList;
|
|
found = FALSE;
|
|
while( ppd != NULL )
|
|
{
|
|
if( ppd->pid == phd->pid )
|
|
{
|
|
DPF( 4, "Have thread for process %08lx already", phd->pid );
|
|
/*
|
|
* look if we already have this callback for this process
|
|
*/
|
|
for( i=0;i<MAX_CALLBACKS;i++ )
|
|
{
|
|
if( ppd->pdata[i].lpNotify == phd->lpNotify )
|
|
{
|
|
DPF( 5, "Notification rtn %08lx already set for pid %08lx",
|
|
phd->lpNotify, phd->pid );
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if( found )
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* we have a new callback for this process
|
|
*/
|
|
for( i=0;i<MAX_CALLBACKS;i++ )
|
|
{
|
|
if( ppd->pdata[i].lpNotify == NULL )
|
|
{
|
|
DPF( 5, "Setting notification rtn %08lx for pid %08lx",
|
|
phd->lpNotify, phd->pid );
|
|
ppd->pdata[i].lpNotify = phd->lpNotify;
|
|
ppd->pdata[i].req_id = phd->req_id;
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if( !found )
|
|
{
|
|
#ifdef DEBUG
|
|
/*
|
|
* this should not happen!
|
|
*/
|
|
DPF( 0, "OUT OF NOTIFICATION ROOM!" );
|
|
DebugBreak(); //_asm int 3;
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
ppd = ppd->link;
|
|
}
|
|
|
|
/*
|
|
* couldn't find anyone waiting on this process, so create
|
|
* a brand spanking new thread
|
|
*/
|
|
if( !found )
|
|
{
|
|
DPF( 3, "Allocating new thread for process %08lx" );
|
|
ppd = MemAlloc( sizeof( PROCESSDATA ) );
|
|
if( ppd != NULL )
|
|
{
|
|
HANDLE h;
|
|
|
|
ppd->link = lpProcessList;
|
|
lpProcessList = ppd;
|
|
ppd->pid = phd->pid;
|
|
ppd->pdata[0].lpNotify = phd->lpNotify;
|
|
ppd->pdata[0].req_id = phd->req_id;
|
|
h = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) ThreadProc,
|
|
(LPVOID)ppd,
|
|
0,
|
|
(LPDWORD)&tid);
|
|
if( h != NULL )
|
|
{
|
|
DPF( 5, "Thread %08lx created, initial callback=%08lx",
|
|
tid, phd->lpNotify );
|
|
CloseHandle( h );
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
DPF( 0, "COULD NOT CREATE HELPER THREAD FOR PID %08lx", phd->pid );
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
DPF( 0, "OUT OF MEMORY CREATING HELPER THREAD FOR PID %08lx", phd->pid );
|
|
#endif
|
|
}
|
|
}
|
|
LeaveCriticalSection( &pdCSect );
|
|
} // WatchNewPid
|
|
|
|
//
|
|
// called by WinMain in response to a DDHELPREQ_STOPWATCHPID request.
|
|
//
|
|
void StopWatchPid(LPDDHELPDATA phd)
|
|
{
|
|
LPPROCESSDATA ppd;
|
|
BOOL found;
|
|
int i;
|
|
|
|
DPF( 4, "DDHELPREQ_STOPWATCHPID" );
|
|
|
|
EnterCriticalSection( &pdCSect );
|
|
ppd = lpProcessList;
|
|
found = FALSE;
|
|
while( ppd != NULL )
|
|
{
|
|
if( ppd->pid == phd->pid )
|
|
{
|
|
/*
|
|
* look if we already have this callback for this process
|
|
*/
|
|
for( i=0;i<MAX_CALLBACKS;i++ )
|
|
{
|
|
if( ppd->pdata[i].lpNotify == phd->lpNotify )
|
|
{
|
|
DPF( 5, "Remove notification rtn %08lx for pid %08lx", phd->lpNotify, phd->pid );
|
|
ppd->pdata[i].lpNotify = NULL;
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if( found )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
ppd = ppd->link;
|
|
}
|
|
|
|
LeaveCriticalSection( &pdCSect );
|
|
} // StopWatchPid
|
|
|
|
/*
|
|
* WinMain
|
|
*/
|
|
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
DWORD tid;
|
|
DWORD rc;
|
|
HANDLE hstartevent;
|
|
HANDLE hstartupevent;
|
|
HANDLE hmutex;
|
|
HANDLE hackevent;
|
|
LPDDHELPDATA phd;
|
|
HANDLE hsharedmem;
|
|
HANDLE h;
|
|
char szSystemDir[1024];
|
|
|
|
/*
|
|
* Set our working directory to the system directory.
|
|
* This prevents us from holding network connections open
|
|
* forever if the first DirectDraw app that we run is across
|
|
* a network connection.
|
|
*/
|
|
GetSystemDirectory(szSystemDir, sizeof(szSystemDir));
|
|
SetCurrentDirectory(szSystemDir);
|
|
|
|
/*
|
|
* when we gotta run, we gotta run baby
|
|
*/
|
|
#ifdef WIN95
|
|
SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS );
|
|
#endif
|
|
|
|
#ifdef WIN95
|
|
/*
|
|
* when we gotta run, we gotta and not let the user see us in
|
|
* the task list.
|
|
*/
|
|
RegisterServiceProcess( 0, RSP_SIMPLE_SERVICE );
|
|
#else
|
|
/*
|
|
* We must guarantee that ddhelp unloads after the last ddraw app,
|
|
* since ctrl-alt-del may have happened while an app held the ddraw
|
|
* lock, and ddhelp needs to clean up orphaned cheap ddraw mutex
|
|
* locks.
|
|
*/
|
|
if ( ! SetProcessShutdownParameters(0x100,SHUTDOWN_NORETRY) )
|
|
{
|
|
DPF(0,"DDHELP.EXE could not set itself to shutdown last!");
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if NEED_WIN16LOCK
|
|
GetpWin16Lock( &lpWin16Lock );
|
|
#endif
|
|
|
|
hInstApp = hInstance;
|
|
|
|
/*
|
|
* create startup event
|
|
*/
|
|
hstartupevent = CreateEvent( NULL, TRUE, FALSE, DDHELP_STARTUP_EVENT_NAME );
|
|
|
|
DPFINIT();
|
|
DPF( 5, "*** DDHELP STARTED, PID=%08lx ***", GetCurrentProcessId() );
|
|
|
|
if( !MemInit() )
|
|
{
|
|
DPF( 1, "Could not init memory manager" );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* create shared memory area
|
|
*/
|
|
hsharedmem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
|
|
PAGE_READWRITE, 0, sizeof( DDHELPDATA ),
|
|
DDHELP_SHARED_NAME );
|
|
if( hsharedmem == NULL )
|
|
{
|
|
DPF( 1, "Could not create file mapping!" );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* create mutex for people who want to use the shared memory area
|
|
*/
|
|
hmutex = CreateMutex( NULL, FALSE, DDHELP_MUTEX_NAME );
|
|
if( hmutex == NULL )
|
|
{
|
|
DPF( 1, "Could not create mutex " DDHELP_MUTEX_NAME );
|
|
CloseHandle( hsharedmem );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* create events
|
|
*/
|
|
hstartevent = CreateEvent( NULL, FALSE, FALSE, DDHELP_EVENT_NAME );
|
|
if( hstartevent == NULL )
|
|
{
|
|
DPF( 1, "Could not create event " DDHELP_EVENT_NAME );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
return 0;
|
|
}
|
|
hackevent = CreateEvent( NULL, FALSE, FALSE, DDHELP_ACK_EVENT_NAME );
|
|
if( hackevent == NULL )
|
|
{
|
|
DPF( 1, "Could not create event " DDHELP_ACK_EVENT_NAME );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
return 0;
|
|
}
|
|
hApmSuspendEvent = CreateEvent( NULL, TRUE, FALSE, DDHELP_APMSUSPEND_EVENT_NAME );
|
|
if( hApmSuspendEvent == NULL )
|
|
{
|
|
DPF( 1, "Could not create event " DDHELP_APMSUSPEND_EVENT_NAME );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
CloseHandle( hackevent );
|
|
return 0;
|
|
}
|
|
hApmResumeEvent = CreateEvent( NULL, TRUE, TRUE, DDHELP_APMRESUME_EVENT_NAME );
|
|
if( hApmResumeEvent == NULL )
|
|
{
|
|
DPF( 1, "Could not create event " DDHELP_APMRESUME_EVENT_NAME );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
CloseHandle( hackevent );
|
|
CloseHandle( hApmSuspendEvent );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Create window so we can get messages
|
|
*/
|
|
h = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) WindowThreadProc,
|
|
NULL,
|
|
0,
|
|
(LPDWORD)&tid );
|
|
if( h == NULL )
|
|
{
|
|
DPF( 1, "Create of WindowThreadProc FAILED!" );
|
|
CloseHandle( hackevent );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
CloseHandle( hApmSuspendEvent );
|
|
CloseHandle( hApmResumeEvent );
|
|
return 0;
|
|
}
|
|
CloseHandle( h );
|
|
|
|
/*
|
|
* serialize access to us
|
|
*/
|
|
memset( &cs, 0, sizeof( cs ) );
|
|
InitializeCriticalSection( &cs );
|
|
|
|
/*
|
|
* serialize access to process data
|
|
*/
|
|
memset( &pdCSect, 0, sizeof( pdCSect ) );
|
|
InitializeCriticalSection( &pdCSect );
|
|
|
|
/*
|
|
* let invoker and anyone else who comes along know we exist
|
|
*/
|
|
SetEvent( hstartupevent );
|
|
|
|
/*
|
|
* loop forever, processing requests
|
|
*/
|
|
while( 1 )
|
|
{
|
|
HANDLE hdll;
|
|
|
|
/*
|
|
* wait to be notified of a request
|
|
*/
|
|
hdll = NULL;
|
|
DPF( 4, "Waiting for next request" );
|
|
rc = WaitForSingleObject( hstartevent, INFINITE );
|
|
if( rc == WAIT_FAILED )
|
|
{
|
|
DPF( 1, "Wait FAILED!!!" );
|
|
continue;
|
|
}
|
|
|
|
EnterCriticalSection( &cs );
|
|
phd = (LPDDHELPDATA) MapViewOfFile( hsharedmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
|
|
if( phd == NULL )
|
|
{
|
|
DPF( 1, "Could not create view of file!" );
|
|
LeaveCriticalSection( &cs );
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* find out what we need to do
|
|
*/
|
|
switch( phd->req )
|
|
{
|
|
case DDHELPREQ_NEWDC:
|
|
DPF( 4, "DDHELPREQ_NEWDC" );
|
|
addDC( phd->fname, phd->isdisp, phd->req_id );
|
|
break;
|
|
case DDHELPREQ_FREEDCLIST:
|
|
DPF( 4, "DDHELPREQ_FREEDCLIST" );
|
|
freeDCList( phd->req_id );
|
|
break;
|
|
case DDHELPREQ_CREATEMODESETTHREAD:
|
|
{
|
|
MODESETTHREADDATA mstd;
|
|
LPTHREADLIST ptl;
|
|
char str[64];
|
|
HANDLE hevent;
|
|
HANDLE h;
|
|
|
|
DPF( 4, "DDHELPREQ_CREATEMODESETTHREAD" );
|
|
mstd.lpProc = phd->lpModeSetNotify;
|
|
mstd.lpDD = phd->pData1;
|
|
wsprintf( str, DDHELP_MODESET_EVENT_NAME, phd->dwData1 );
|
|
DPF( 5, "Trying to Create event \"%s\"", str );
|
|
hevent = CreateEvent( NULL, FALSE, FALSE, str );
|
|
mstd.hEvent = hevent;
|
|
DPF( 5, "hevent = %08lx", hevent );
|
|
|
|
h = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) ModeSetThreadProc,
|
|
(LPVOID) &mstd,
|
|
0,
|
|
(LPDWORD)&tid );
|
|
if( h != NULL )
|
|
{
|
|
DPF( 5, "CREATED MODE SET THREAD %ld", h );
|
|
ptl = MemAlloc( sizeof( THREADLIST ) );
|
|
if( ptl != NULL )
|
|
{
|
|
ptl->hInstance = phd->dwData1;
|
|
ptl->hEvent = hevent;
|
|
ptl->link = lpThreadList;
|
|
lpThreadList = ptl;
|
|
}
|
|
CloseHandle( h );
|
|
}
|
|
break;
|
|
}
|
|
case DDHELPREQ_KILLMODESETTHREAD:
|
|
{
|
|
LPTHREADLIST ptl;
|
|
LPTHREADLIST prev;
|
|
|
|
DPF( 4, "DDHELPREQ_KILLMODESETTHREAD" );
|
|
prev = NULL;
|
|
ptl = lpThreadList;
|
|
while( ptl != NULL )
|
|
{
|
|
if( ptl->hInstance == phd->dwData1 )
|
|
{
|
|
HANDLE h;
|
|
if( prev == NULL )
|
|
{
|
|
lpThreadList = ptl->link;
|
|
}
|
|
else
|
|
{
|
|
prev->link = ptl->link;
|
|
}
|
|
h = ptl->hEvent;
|
|
MemFree( ptl );
|
|
bKillNow = TRUE;
|
|
SetEvent( h );
|
|
break;
|
|
}
|
|
prev = ptl;
|
|
ptl = ptl->link;
|
|
}
|
|
break;
|
|
}
|
|
case DDHELPREQ_CREATEHELPERTHREAD:
|
|
#ifdef WIN95
|
|
if( !bIsActive )
|
|
{
|
|
HANDLE h;
|
|
bIsActive = TRUE;
|
|
h = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) HelperThreadProc,
|
|
NULL,
|
|
0,
|
|
(LPDWORD)&tid);
|
|
if( h == NULL )
|
|
{
|
|
bIsActive = FALSE;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle( h );
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
case DDHELPREQ_NEWPID:
|
|
WatchNewPid(phd);
|
|
break;
|
|
case DDHELPREQ_STOPWATCHPID:
|
|
StopWatchPid(phd);
|
|
break;
|
|
case DDHELPREQ_RETURNHELPERPID:
|
|
DPF( 4, "DDHELPREQ_RETURNHELPERPID" );
|
|
phd->pid = GetCurrentProcessId();
|
|
break;
|
|
case DDHELPREQ_LOADDLL:
|
|
DPF( 4, "DDHELPREQ_LOADDLL" );
|
|
phd->dwReturn = loadDLL( phd->fname, phd->func, phd->context );
|
|
break;
|
|
case DDHELPREQ_FREEDLL:
|
|
DPF( 4, "DDHELPREQ_FREEDDLL" );
|
|
hdll = freeDLL( phd->fname );
|
|
break;
|
|
case DDHELPREQ_KILLATTACHED:
|
|
{
|
|
LPPROCESSDATA ppd;
|
|
HANDLE hproc;
|
|
DPF( 4, "DDHELPREQ_KILLATTACHED" );
|
|
|
|
EnterCriticalSection( &pdCSect );
|
|
ppd = lpProcessList;
|
|
while( ppd != NULL )
|
|
{
|
|
hproc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ppd->pid );
|
|
DPF( 5, "Process %08lx: handle = %08lx", ppd->pid, hproc );
|
|
if( hproc != NULL )
|
|
{
|
|
DPF( 5, "Terminating %08lx", ppd->pid );
|
|
TerminateProcess( hproc, 0 );
|
|
}
|
|
ppd = ppd->link;
|
|
}
|
|
LeaveCriticalSection( &pdCSect );
|
|
break;
|
|
}
|
|
case DDHELPREQ_SUICIDE:
|
|
DPF( 4, "DDHELPREQ_SUICIDE" );
|
|
freeAllResources();
|
|
#ifdef WIN95
|
|
if( INVALID_HANDLE_VALUE != hDSVxd )
|
|
CloseHandle( hDSVxd );
|
|
if( INVALID_HANDLE_VALUE != hDDVxd )
|
|
CloseHandle( hDDVxd );
|
|
#endif /* WIN95 */
|
|
SetEvent( hackevent );
|
|
CloseHandle( hmutex );
|
|
UnmapViewOfFile( phd );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
CloseHandle( hApmSuspendEvent );
|
|
CloseHandle( hApmResumeEvent );
|
|
#ifdef DEBUG
|
|
MemState();
|
|
#endif
|
|
DPF( 4, "Good Night Gracie" );
|
|
TerminateProcess( GetCurrentProcess(), 0 );
|
|
break;
|
|
|
|
case DDHELPREQ_WAVEOPEN:
|
|
{
|
|
#ifdef WIN95
|
|
DWORD dwPriority;
|
|
#endif
|
|
|
|
DPF( 4, "DDHELPREQ_WAVEOPEN" );
|
|
// Due to a possible bug in Win95 mmsystem/mmtask, we can hang
|
|
// if we call waveOutOpen on a REALTIME thread while a sound
|
|
// event is playing. So, we briefly lower our priority to
|
|
// NORMAL while we call this API
|
|
#ifdef WIN95
|
|
dwPriority = GetPriorityClass(GetCurrentProcess());
|
|
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
|
|
#endif
|
|
phd->dwReturn = (DWORD)waveOutOpen(
|
|
(LPHWAVEOUT)(phd->pData1),
|
|
(UINT)(phd->dwData1),
|
|
(LPWAVEFORMATEX)(phd->dwData2),
|
|
0, 0, 0);
|
|
#ifdef WIN95
|
|
SetPriorityClass(GetCurrentProcess(), dwPriority);
|
|
#endif
|
|
|
|
// Some mmsystem wave drivers will program their wave mixer
|
|
// hardware only while the device is open. By doing the
|
|
// following, we can get such drivers to program the hardware
|
|
if (MMSYSERR_NOERROR == phd->dwReturn) {
|
|
MMRESULT mmr;
|
|
DWORD dwVolume;
|
|
|
|
mmr = waveOutGetVolume((HWAVEOUT)(*(LPHWAVEOUT)(phd->pData1)), &dwVolume);
|
|
if (MMSYSERR_NOERROR == mmr) {
|
|
waveOutSetVolume((HWAVEOUT)(*(LPHWAVEOUT)(phd->pData1)), dwVolume);
|
|
}
|
|
}
|
|
DPF( 5, "Wave Open returned %X", phd->dwReturn );
|
|
break;
|
|
}
|
|
case DDHELPREQ_WAVECLOSE:
|
|
DPF( 4, "DDHELPREQ_WAVECLOSE" );
|
|
phd->dwReturn = (DWORD)waveOutClose(
|
|
(HWAVEOUT)(phd->dwData1) );
|
|
break;
|
|
case DDHELPREQ_CREATETIMER:
|
|
DPF( 4, "DDHELPREQ_CREATETIMER proc %X", (phd->pData1) );
|
|
phd->dwReturn = (DWORD)timeSetEvent(
|
|
(UINT)(phd->dwData1), // Delay
|
|
(UINT)(phd->dwData1)/2, // Resolution
|
|
(phd->pData1), // Callback thread proc
|
|
(UINT)(phd->dwData2), // instance data
|
|
TIME_PERIODIC );
|
|
DPF( 5, "Create Timer returned %X", phd->dwReturn );
|
|
break;
|
|
case DDHELPREQ_KILLTIMER:
|
|
DPF( 4, "DDHELPREQ_KILLTIMER %X", phd->dwData1 );
|
|
phd->dwReturn = (DWORD)timeKillEvent( (UINT)phd->dwData1 );
|
|
DPF( 5, "Kill Timer returned %X", phd->dwReturn );
|
|
break;
|
|
|
|
case DDHELPREQ_CREATEDSMIXERTHREAD:
|
|
{
|
|
DWORD tid;
|
|
if (NULL == phd->pData2) phd->pData2 = &tid;
|
|
phd->dwReturn = (ULONG_PTR)CreateThread(NULL, 0, phd->pData1,
|
|
(LPVOID)phd->dwData1,
|
|
(UINT)phd->dwData2,
|
|
(LPDWORD)phd->pData2);
|
|
if (!phd->dwReturn) {
|
|
#ifdef DEBUG
|
|
DPF(0, "pData1 %p (start addr)", phd->pData1);
|
|
DPF(0, "dwData1 %p (thread parm)", phd->dwData1);
|
|
DPF(0, "dwData2 %p (fdwCreate)", phd->dwData2);
|
|
DPF(0, "pData2 %p (lpThreadID)", phd->pData2);
|
|
|
|
DPF(0, "DDHelp: Failed to create mixer thread %lu",
|
|
GetLastError());
|
|
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
case DDHELPREQ_CREATEDSFOCUSTHREAD:
|
|
{
|
|
DWORD tid;
|
|
if (NULL == phd->pData2) phd->pData2 = &tid;
|
|
phd->dwReturn = (ULONG_PTR)CreateThread(NULL, 0, phd->pData1,
|
|
(LPVOID)phd->dwData1,
|
|
(UINT)phd->dwData2,
|
|
(LPDWORD)phd->pData2);
|
|
if (!phd->dwReturn) {
|
|
#ifdef DEBUG
|
|
DPF(0, "pData1 %p (start addr)", phd->pData1);
|
|
DPF(0, "dwData1 %p (thread parm)", phd->dwData1);
|
|
DPF(0, "dwData2 %p (fdwCreate)", phd->dwData2);
|
|
DPF(0, "pData2 %p (lpThreadID)", phd->pData2);
|
|
|
|
DPF(0, "DDHelp: Failed to create sound focus thread %lu",
|
|
GetLastError());
|
|
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DDHELPREQ_CALLDSCLEANUP:
|
|
try
|
|
{
|
|
((LPDSCLEANUP)phd->pData1)(phd->pData2);
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF(0, "*********************************************");
|
|
DPF(0, "**** DDHELPREQ_CALLDSCLEANUP blew up! *******");
|
|
DPF(0, "*********************************************");
|
|
}
|
|
break;
|
|
|
|
#ifdef WIN95
|
|
case DDHELPREQ_GETDSVXDHANDLE:
|
|
phd->dwReturn = getDSVxdHandle();
|
|
break;
|
|
|
|
case DDHELPREQ_GETDDVXDHANDLE:
|
|
phd->dwReturn = getDDVxdHandle();
|
|
break;
|
|
#endif /* WIN95 */
|
|
|
|
case DDHELPREQ_NOTIFYONDISPLAYCHANGE:
|
|
DPF( 4, "DDHELPREQ_NOTIFYONDISPLAYCHANGE" );
|
|
(void *)g_pfnOnDisplayChange = (void *)phd->dwData1;
|
|
break;
|
|
|
|
#ifdef WIN95
|
|
case DDHELPREQ_CREATEDOSBOXTHREAD:
|
|
{
|
|
MODESETTHREADDATA dbtd;
|
|
char str[64];
|
|
HANDLE hevent;
|
|
HANDLE h;
|
|
|
|
DPF( 4, "DDHELPREQ_CREATEDOSBOXTHREAD" );
|
|
dbtd.lpProc = phd->lpModeSetNotify;
|
|
dbtd.lpDD = phd->pData1;
|
|
wsprintf( str, DDHELP_DOSBOX_EVENT_NAME, phd->dwData1 );
|
|
DPF( 5, "Trying to Create event \"%s\"", str );
|
|
hevent = CreateEvent( NULL, FALSE, FALSE, str );
|
|
dbtd.hEvent = hevent;
|
|
DPF( 5, "hevent = %08lx", hevent );
|
|
|
|
h = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) DOSBoxThreadProc,
|
|
(LPVOID) &dbtd,
|
|
0,
|
|
(LPDWORD)&tid );
|
|
if( h != NULL )
|
|
{
|
|
DPF( 5, "CREATED DOS BOX THREAD %ld", h );
|
|
DOSBoxThread.hInstance = phd->dwData1;
|
|
DOSBoxThread.hEvent = hevent;
|
|
CloseHandle( h );
|
|
}
|
|
}
|
|
break;
|
|
case DDHELPREQ_KILLDOSBOXTHREAD:
|
|
{
|
|
DPF( 4, "DDHELPREQ_KILLDOSBOXTHREAD" );
|
|
if( DOSBoxThread.hInstance == phd->dwData1 )
|
|
{
|
|
bKillDOSBoxNow = TRUE;
|
|
SetEvent( DOSBoxThread.hEvent );
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case DDHELPREQ_LOADLIBRARY:
|
|
phd->dwReturn = (ULONG_PTR)LoadLibraryA((LPCSTR)phd->dwData1);
|
|
break;
|
|
|
|
case DDHELPREQ_FREELIBRARY:
|
|
phd->dwReturn = FreeLibrary((HINSTANCE)phd->dwData1);
|
|
break;
|
|
|
|
#ifdef WIN95
|
|
case DDHELPREQ_ADDDEVICECHANGENOTIFY:
|
|
addDeviceChangeNotify(phd->pData1);
|
|
break;
|
|
|
|
case DDHELPREQ_DELDEVICECHANGENOTIFY:
|
|
delDeviceChangeNotify(phd->pData1);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
DPF( 1, "Unknown Request???" );
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* let caller know we've got the news
|
|
*/
|
|
UnmapViewOfFile( phd );
|
|
SetEvent( hackevent );
|
|
LeaveCriticalSection( &cs );
|
|
|
|
/*
|
|
* unload the DLL we were asked to
|
|
*/
|
|
if( hdll != NULL )
|
|
{
|
|
DPF( 4, "Freeing DLL %08lx", hdll );
|
|
FreeLibrary( hdll );
|
|
}
|
|
}
|
|
|
|
#ifdef WIN95
|
|
RegisterServiceProcess( 0, RSP_UNREGISTER_SERVICE );
|
|
#else
|
|
#pragma message("RegisterServiceProcess needs to be taken care of under nt")
|
|
#endif
|
|
|
|
} /* WinMain */
|