Leaked source code of windows server 2003
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.
 
 
 
 
 
 

913 lines
29 KiB

/*==========================================================================
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
*
* File: dllinit.c
* Content: DDRAW.DLL initialization
* History:
* Date By Reason
* ==== == ======
* 20-jan-95 craige initial implementation
* 21-feb-95 craige disconnect anyone who forgot to do it themselves,
* use critical sections on Win95
* 27-feb-95 craige new sync. macros
* 30-mar-95 craige process tracking/cleanup for Win95
* 01-apr-95 craige happy fun joy updated header file
* 12-apr-95 craige debug stuff for csects
* 12-may-95 craige define GUIDs
* 24-jun-95 craige track which processes attach to the DLL
* 25-jun-95 craige one ddraw mutex
* 13-jul-95 craige ENTER_DDRAW is now the win16 lock;
* proper initialization of csects
* 16-jul-95 craige work around weird kernel "feature" of getting a
* process attach of the same process during process detach
* 19-jul-95 craige process detach too much grief; let DDNotify handle it
* 20-jul-95 craige internal reorg to prevent thunking during modeset
* 19-aug-95 davidmay restored call to disconnect thunk from 19-jul change
* 26-sep-95 craige bug 1364: create new csect to avoid dsound deadlock
* 08-dec-95 jeffno For NT, critical section macros expand to use mutexes
* 16-mar-96 colinmc Callback table initialization now happens on process
* attach
* 20-mar-96 colinmc Bug 13341: Made MemState() dump in process detach
* thread safe
* 07-may-96 colinmc Bug 20219: Simultaneous calls to LoadLibrary cause
* a deadlock
* 09-may-96 colinmc Bug 20219 (again): Yes the deadlock again - previous
* fix was not enough.
* 19-jan-97 colinmc AGP support
* 26-jan-97 ketand Kill globals for multi-mon.
* 24-feb-97 ketand Set up callback from DDHelp to update rects.
* 03-mar-97 jeffno Structure name change to avoid conflict w/ ActiveAccessibility
* 13-mar-97 colinmc Bug 6533: Pass uncached flag to VMM correctly
* 31-jul-97 jvanaken Bug 7907: Notify Memphis GDI when ddraw starts up
*
***************************************************************************/
/*
* unfortunately we have to break our pre-compiled headers to get our
* GUIDS defined...
*/
#define INITGUID
#include "ddrawpr.h"
#include <initguid.h>
#ifdef WINNT
#undef IUnknown
#include <objbase.h>
#endif
#include "apphack.h"
#include "aclapi.h"
#ifdef WIN95
int main; // this is so we can avoid calling DllMainCRTStartup
extern BOOL _stdcall thk3216_ThunkConnect32(LPSTR pszDll16,
LPSTR pszDll32,
HINSTANCE hInst,
DWORD dwReason);
extern BOOL _stdcall thk1632_ThunkConnect32(LPSTR pszDll16,
LPSTR pszDll32,
HINSTANCE hInst,
DWORD dwReason);
DWORD _stdcall wWinMain(DWORD a, DWORD b, DWORD c, DWORD d)
{
#ifdef DEBUG
OutputDebugString("WARNING: wWinMain called. \n");
#endif // DEBUG
return 0;
}
#endif
#ifdef USE_CRITSECTS
#define TMPDLLEVENT "__DDRAWDLL_EVENT__"
#endif
#ifndef WIN16_SEPARATE
#ifdef WIN95
#define INITCSINIT() \
ReinitializeCriticalSection( &csInit ); \
MakeCriticalSectionGlobal( &csInit );
#define ENTER_CSINIT() EnterCriticalSection( &csInit )
#define LEAVE_CSINIT() LeaveCriticalSection( &csInit )
extern CRITICAL_SECTION ddcCS;
#define INITCSDDC() \
ReinitializeCriticalSection( &ddcCS ); \
MakeCriticalSectionGlobal( &ddcCS );
#else
#define CSINITMUTEXNAME "InitMutexName"
#define INITCSINIT() \
csInitMutex = CreateMutex(NULL,FALSE,CSINITMUTEXNAME);
#define ENTER_CSINIT() \
WaitForSingleObject(csInitMutex,INFINITE);
#define LEAVE_CSINIT() \
ReleaseMutex(csInitMutex);
#define INITDDC()
#endif
#endif
#ifdef WIN95
#define INITCSWINDLIST() \
ReinitializeCriticalSection( &csWindowList ); \
MakeCriticalSectionGlobal( &csWindowList );
#define INITCSDRIVEROBJECTLIST() \
ReinitializeCriticalSection( &csDriverObjectList ); \
MakeCriticalSectionGlobal( &csDriverObjectList );
#define FINIWINDLIST()
#define FINICSDRIVEROBJECTLIST()
#else
// Each process needs its own handle, so these are not initialised so theyu won't end up in shared mem
HANDLE hDirectDrawMutex=(HANDLE)0;
//This counts recursions into ddraw, so we don't try to do the mode uniqueness thing on recursive entries into ddraw
DWORD gdwRecursionCount=0;
HANDLE hWindowListMutex; //=(HANDLE)0;
HANDLE hDriverObjectListMutex; //=(HANDLE)0;
HANDLE csInitMutex;
DWORD dwNumLockedWhenModeSwitched;
#define WINDOWLISTMUTEXNAME "DDrawWindowListMutex"
#define DRIVEROBJECTLISTMUTEXNAME "DDrawDriverObjectListMutex"
#define INITCSWINDLIST() \
hWindowListMutex = CreateMutex(NULL,FALSE,WINDOWLISTMUTEXNAME);
#define INITCSDRIVEROBJECTLIST() \
hDriverObjectListMutex = CreateMutex(NULL,FALSE,DRIVEROBJECTLISTMUTEXNAME);
#define FINIWINDLIST() CloseHandle(hWindowListMutex);
#define FINICSDRIVEROBJECTLIST() CloseHandle(hDriverObjectListMutex);
#endif //win95
DWORD dwRefCnt=0;
DWORD dwLockCount=0;
DWORD dwFakeCurrPid=0;
DWORD dwGrimReaperPid=0;
LPDDWINDOWINFO lpWindowInfo=0; // the list of WINDOWINFO structures
LPDDRAWI_DIRECTDRAW_LCL lpDriverLocalList=0;
LPDDRAWI_DIRECTDRAW_INT lpDriverObjectList=0;
volatile DWORD dwMarker=0;
/*
* This is the globally maintained list of clippers not owned by any
* DirectDraw object. All clippers created with DirectDrawClipperCreate
* are placed on this list. Those created by IDirectDraw_CreateClipper
* are placed on the clipper list of thier owning DirectDraw object.
*
* The objects on this list are NOT released when an app's DirectDraw
* object is released. They remain alive until explictly released or
* the app. dies.
*/
LPDDRAWI_DDRAWCLIPPER_INT lpGlobalClipperList=0;
HINSTANCE hModule=0;
LPATTACHED_PROCESSES lpAttachedProcesses=0;
BOOL bFirstTime=0;
#ifdef DEBUG
int iDLLCSCnt=0;
int iWin16Cnt=0;
#endif
/*
* These variable are so we can handle more than one window in the
* topmost window timer.
*/
HWND ghwndTopmostList[MAX_TIMER_HWNDS];
int giTopmostCnt = 0;
/*
* Winnt specific global statics
*/
#ifdef WINNT
ULONG uDisplaySettingsUnique=0;
#endif
/*
*Hel globals:
*/
// used to count how many drivers are currently using the HEL
DWORD dwHELRefCnt=0;
// keep these around to pass to blitlib. everytime we blt to/from a surface, we
// construct a BITMAPINFO for that surface using gpbmiSrc and gpbmiDest
LPBITMAPINFO gpbmiSrc=0;
LPBITMAPINFO gpbmiDest=0;
#ifdef DEBUG
// these are used by myCreateSurface
int gcSurfMem=0; // surface memory in bytes
int gcSurf=0; // number of surfaces
#endif
DWORD dwHelperPid=0;
#ifdef USE_CHEAP_MUTEX
#ifdef WINNT
#pragma data_seg("share")
#endif
GLOBAL_SHARED_CRITICAL_SECTION CheapMutexCrossProcess={0};
#ifdef WINNT
#pragma data_seg(".data")
#endif
#endif //0
/*
* App compatibility stuff. Moved here from apphack.c
*/
BOOL bReloadReg=FALSE;
BOOL bHaveReadReg=FALSE;
LPAPPHACKS lpAppList=NULL;
LPAPPHACKS *lpAppArray=NULL;
DWORD dwAppArraySize=0;
/*
* Global head of DC/Surface association list
* This list is usually very very short, so we take the hit of extra pointers
* just so that we don't have to traverse the entire list of surfaces.
*/
DCINFO *g_pdcinfoHead = NULL;
BYTE szDeviceWndClass[] = "DirectDrawDeviceWnd";
/*
* Gamma calibration globals. This determines weather a calibrator exists
* and the handle to the DLL if it's loaded.
*/
BOOL bGammaCalibratorExists=FALSE;
BYTE szGammaCalibrator[MAX_PATH]="";
/*
* Optional refresh rate to force for all modes.
*/
DWORD dwForceRefreshRate;
/*
* Spinlocks for startup synchronization.
* It's just too hard to use events when NT ddraw is per-process and 9x is cross-
*/
DWORD dwSpinStartup=0;
DWORD dwHelperSpinStartup=0;
#ifdef USE_CHEAP_MUTEX
/*
* This is the global variable pointer.
*/
GLOBAL_LOCAL_CRITICAL_SECTION CheapMutexPerProcess;
#endif
/*
* These two keep w95help.c happy. They point to the dwHelperPid and hModule entries in the process's
* mapping of the GLOBALS structure.
*/
DWORD * pdwHelperPid=&dwHelperPid;
HANDLE * phModule=&hModule;
#ifdef WINNT
/*
* This mutex is owned by the exclusive mode owner
*/
HANDLE hExclusiveModeMutex=0;
HANDLE hCheckExclusiveModeMutex=0;
#define EXCLUSIVE_MODE_MUTEX_NAME "__DDrawExclMode__"
#define CHECK_EXCLUSIVE_MODE_MUTEX_NAME "__DDrawCheckExclMode__"
#endif
//#endif
/*
*-------------------------------------------------------------------------
*/
#if defined(WIN95) || defined(NT_USES_CRITICAL_SECTION)
static CRITICAL_SECTION DirectDrawCSect;
CSECT_HANDLE lpDDCS;
#endif
/*
* Win95 specific global statics
*/
#ifdef WIN95
LPVOID lpWin16Lock;
static CRITICAL_SECTION csInit = {0};
CRITICAL_SECTION csWindowList;
CRITICAL_SECTION csDriverObjectList;
#endif
#define HELPERINITDLLEVENT "__DDRAWDLL_HELPERINIT_EVENT__"
/*
* DllMain
*/
BOOL WINAPI DllMain(HINSTANCE hmod, DWORD dwReason, LPVOID lpvReserved)
{
LPATTACHED_PROCESSES lpap;
DWORD pid;
BOOL didhelp;
dwMarker = 0x56414C4D;
pid = GetCurrentProcessId();
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
pdwHelperPid=&dwHelperPid;
phModule=&hModule;
DisableThreadLibraryCalls( hmod );
DPFINIT();
/*
* create the DirectDraw csect
*/
DPF( 4, "====> ENTER: DLLMAIN(%08lx): Process Attach: %08lx, tid=%08lx", DllMain,
pid, GetCurrentThreadId() );
#ifdef WIN95
if( lpWin16Lock == NULL )
{
GetpWin16Lock( &lpWin16Lock );
}
#endif
#ifdef USE_CRITSECTS
{
#if defined( WIN16_SEPARATE ) && (defined(WIN95) || defined(NT_USES_CRITICAL_SECTION))
lpDDCS = &DirectDrawCSect;
#endif
/*
* is this the first time?
*/
if( FALSE == InterlockedExchange( &bFirstTime, TRUE ) )
{
#ifdef WIN16_SEPARATE
INIT_DDRAW_CSECT();
INITCSWINDLIST();
INITCSDRIVEROBJECTLIST();
ENTER_DDRAW_INDLLMAIN();
#else
INITCSDDC(); // used in DirectDrawCreate
INITCSINIT();
ENTER_CSINIT();
#endif
hModule = hmod;
/*
* This event is signaled when DDHELP has successfully finished
* initializing. Threads other that the very first one to connect
* and the one spawned by DDHELP must wait for this event to
* be signaled as deadlock will result if they run through
* process attach before the DDHELP thread has.
*
* NOTE: The actual deadlock this prevents is pretty unusual so
* if we fail to create this event we will simply continue. Its
* highly unlikely anyone will notice (famous last words).
*
* CMcC
*/
/*
* Replaced events with spinlocks to work around a handle leak
*/
InterlockedExchange( & dwSpinStartup , 1);
}
/*
* second or later time through, wait for first time to
* finish and then take the csect
*/
else
{
/*
* Spin waiting for the first thread to exit the clause above
* This strange construction works around a compiler bug.
* while (dwHelperSpinStartup==1); generates an infinite loop.
*/
while (1)
{
if (dwSpinStartup==1)
break;
}
#ifdef WIN16_SEPARATE
#if defined( WINNT )
//Each process needs its own handle in NT
INIT_DDRAW_CSECT();
#endif
ENTER_DDRAW_INDLLMAIN();
#else
ENTER_CSINIT();
#endif
}
}
#endif
#ifdef WINNT
{
SECURITY_ATTRIBUTES sa;
SID_IDENTIFIER_AUTHORITY sia = SECURITY_WORLD_SID_AUTHORITY;
PSID adminSid = 0;
ULONG cbAcl;
PACL acl=0;
PSECURITY_DESCRIPTOR pSD;
BYTE buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
BOOL bSecurityGooSucceeded = FALSE;
//Granny's old fashioned LocalAlloc:
BYTE Buffer1[256];
BYTE Buffer2[16];
// Create the SID for world
cbAcl = GetSidLengthRequired(1);
if (cbAcl < sizeof(Buffer2))
{
adminSid = (PSID) Buffer2;
InitializeSid(
adminSid,
&sia,
1
);
*GetSidSubAuthority(adminSid, 0) = SECURITY_WORLD_RID;
// Create an ACL giving World all access.
cbAcl = sizeof(ACL) +
(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
GetLengthSid(adminSid);
if (cbAcl < sizeof(Buffer1))
{
acl = (PACL)&Buffer1;
if (InitializeAcl(
acl,
cbAcl,
ACL_REVISION
))
{
if (AddAccessAllowedAce(
acl,
ACL_REVISION,
SYNCHRONIZE|MUTANT_QUERY_STATE|DELETE|READ_CONTROL, //|WRITE_OWNER|WRITE_DAC,
adminSid
))
{
// Create a security descriptor with the above ACL.
pSD = (PSECURITY_DESCRIPTOR)buffer;
if (InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
if (SetSecurityDescriptorDacl(pSD, TRUE, acl, FALSE))
{
// Fill in the SECURITY_ATTRIBUTES struct.
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = TRUE;
bSecurityGooSucceeded = TRUE;
}
}
}
}
}
}
// Use the security attributes to create the mutexes
DDASSERT(0 == hExclusiveModeMutex);
hExclusiveModeMutex = CreateMutex(
bSecurityGooSucceeded ? &sa : NULL, //use default access if security goo failed.
FALSE,
EXCLUSIVE_MODE_MUTEX_NAME );
if (0 == hExclusiveModeMutex)
{
hExclusiveModeMutex = OpenMutex(
SYNCHRONIZE|DELETE, // access flag
FALSE, // inherit flag
EXCLUSIVE_MODE_MUTEX_NAME // pointer to mutex-object name
);
}
if( hExclusiveModeMutex == 0 )
{
DPF_ERR("Could not create exclusive mode mutex. exiting" );
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
return FALSE;
}
DDASSERT(0 == hCheckExclusiveModeMutex);
hCheckExclusiveModeMutex = CreateMutex(
bSecurityGooSucceeded ? &sa : NULL, //use default access if security goo failed.
FALSE,
CHECK_EXCLUSIVE_MODE_MUTEX_NAME );
if (0 == hCheckExclusiveModeMutex)
{
hCheckExclusiveModeMutex = OpenMutex(
SYNCHRONIZE|DELETE, // access flag
FALSE, // inherit flag
CHECK_EXCLUSIVE_MODE_MUTEX_NAME // pointer to mutex-object name
);
}
if( hCheckExclusiveModeMutex == 0 )
{
DPF_ERR("Could not create exclusive mode check mutex. exiting" );
CloseHandle( hExclusiveModeMutex );
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
return FALSE;
}
}
#endif
#ifdef WIN95
{
DWORD hpid;
/*
* get the helper process started
*/
didhelp = CreateHelperProcess( &hpid );
if( hpid == 0 )
{
DPF( 0, "Could not start helper; exiting" );
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
return FALSE;
}
/*
* You get three kinds of threads coming through
* process attach:
*
* 1) A thread belonging to the first process to
* connect to DDRAW.DLL. This is distinguished as
* it performs lots of one time initialization
* including starting DDHELP and getting DDHELP
* to load its own copy of DDRAW.DLL. Threads
* of this type are identified by didhelp being
* TRUE in their context
* 2) A thread belonging to DDHELP when it loads
* its own copy of DDHELP in response to a
* request from a thread of type 1. Threads of
* this type are identified by having a pid
* which is equal to hpid (DDHELP's pid)
* 3) Any other threads belonging to subsequent
* processes connecting to DDRAW.DLL
*
* As a thread of type 1 causes a thread of type 2
* to enter process attach before it itself has finished
* executing process attach itself we open our selves up
* to lots of deadlock problems if we let threads of
* type 3 through process attach before the other threads
* have completed their work.
*
* Therefore, the rule is that subsequent process
* attachement can only be allowed to execute the
* remainder of process attach if both the type 1
* and type 2 thread have completed their execution
* of process attach. We assure this with a combination
* of the critical section and an event which is signaled
* once DDHELP has initialized. Threads of type 3 MUST
* wait on this event before continuing through the
* process attach code. This is what the following
* code fragment does.
*/
/*
* These events have been replaced with spinlocks, since
* the old way leaked events, and it's just too hard to make them work.
*/
if( !didhelp && ( pid != hpid ) )
{
{
/*
* NOTE: If we hold the DirectDraw critical
* section when we wait on this event we WILL
* DEADLOCK. Don't do it! Release the critical
* section before and take it again after. This
* guarantees that we won't complete process
* attach before the initial thread and the
* DDHELP thread have exited process attach.
*/
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
/*
* This strange construction works around a compiler bug.
* while (dwHelperSpinStartup==1); generates an infinite loop.
*/
while (1)
{
if ( dwHelperSpinStartup == 1)
break;
}
#ifdef WIN16_SEPARATE
ENTER_DDRAW_INDLLMAIN();
#else
ENTER_CSINIT();
#endif
}
}
}
/*
* Win95 thunk connection...
*/
DPF( 4, "Thunk connects" );
if (!(thk3216_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
DDHAL_APP_DLLNAME,
hmod,
dwReason)))
{
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
DPF( 0, "LEAVING, COULD NOT thk3216_THUNKCONNECT32" );
return FALSE;
}
if (!(thk1632_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
DDHAL_APP_DLLNAME,
hmod,
dwReason)))
{
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
DPF( 0, "LEAVING, COULD NOT thk1632_THUNKCONNECT32" );
return FALSE;
}
/*
* initialize memory used to be done here. Jeffno 960609
*/
/*
* signal the new process being added
*/
if( didhelp )
{
DPF( 4, "Waiting for DDHELP startup" );
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
if( !WaitForHelperStartup() )
{
/*
* NT Setup loads DDRAW.DLL and sometimes this fails, so we don't
* actually want fail loading the DLL or else setup might fail.
* Instead, we will suceed the load but then fail any other ddraw
* calls.
*/
DPF( 0, "WaitForHelperStartup FAILED - disabling DDRAW" );
dwHelperPid = 0;
return TRUE;
}
HelperLoadDLL( DDHAL_APP_DLLNAME, NULL, 0 );
/*
* For now, only call this on a multi-monitor system because
* it does cause a behavior change and we aren't able to
* provide adequate test covereage in the DX5 timeframe.
*/
if( IsMultiMonitor() )
{
HelperSetOnDisplayChangeNotify( (void *)&UpdateAllDeviceRects);
}
#ifdef WIN16_SEPARATE
ENTER_DDRAW_INDLLMAIN();
#else
ENTER_CSINIT();
#endif
/*
* As we were the first process through we now signal
* the completion of DDHELP initialization. This will
* release any subsequent threads waiting to complete
* process attach.
*
* NOTE: Threads waiting on this event will not immediately
* run process attach to completion as they will immediately
* try to take the DirectDraw critical section which we hold.
* Thus, they will not be allowed to continue until we have
* released the critical section just prior to existing
* below.
*/
InterlockedExchange( & dwHelperSpinStartup , 1);
}
SignalNewProcess( pid, DDNotify );
#endif //w95
/*
* We call MemInit here in order to guarantee that MemInit is called for
* the first time on ddhelp's process. Why? Glad you asked. On wx86
* (NT's 486 emulator) controlled instances of ddraw apps, we get a fault
* whenever the ddraw app exits. This is because the app creates the RTL
* heap inside a view of a file mapping which gets uncomitted (rightly)
* when the app calls MemFini on exit. In this scenario, imagehlp.dll has
* also created a heap, and calls a ntdll function which attempts to walk
* the list of heaps, which requires a peek at the ddraw app's heap which
* has been mapped out. Krunch.
* We can't destroy the heap on MemFini because of the following scenario:
* App A starts, creates heap. App b starts, maps a view of heap. App A
* terminates, destroys heap. App b tries to use destroyed heap. Krunch
* Jeffno 960609
*/
if( dwRefCnt == 0 )
{
if ( !MemInit() )
{
#ifdef WINNT
CloseHandle( hExclusiveModeMutex );
CloseHandle( hCheckExclusiveModeMutex );
#endif
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
DPF( 0,"LEAVING, COULD NOT MemInit");
return FALSE;
}
#ifdef WIN95
/*
* The Memphis version of GDI calls into DirectDraw, but GDI
* needs to be notified that DirectDraw has actually loaded.
* (While GDI could check for itself to see whether ddraw.dll
* has loaded, this would be sloooooow if it hasn't yet.)
* The code below executes when ddraw.dll first starts up.
*/
{
HANDLE h;
VOID (WINAPI *p)();
h = LoadLibrary("msimg32.dll"); // GDI DLL
if (h)
{
p = (VOID(WINAPI *)())GetProcAddress(h, "vSetDdrawflag");
if (p)
{ // vSetDdrawflag is a private call to
(*p)(); // signal GDI that DDraw has loaded
}
FreeLibrary(h);
}
}
#endif //WIN95
}
dwRefCnt++;
/*
* remember this process (moved this below MemInit when it moved -Jeffno 960609
*/
lpap = MemAlloc( sizeof( ATTACHED_PROCESSES ) );
if( lpap != NULL )
{
lpap->lpLink = lpAttachedProcesses;
lpap->dwPid = pid;
#ifdef WINNT
lpap->dwNTToldYet=0;
#endif
lpAttachedProcesses = lpap;
}
/*
* Initialize callback tables for this process.
*/
InitCallbackTables();
#ifdef WIN16_SEPARATE
LEAVE_DDRAW();
#else
LEAVE_CSINIT();
#endif
DPF( 4, "====> EXIT: DLLMAIN(%08lx): Process Attach: %08lx", DllMain,
pid );
break;
case DLL_PROCESS_DETACH:
DPF( 4, "====> ENTER: DLLMAIN(%08lx): Process Detach %08lx, tid=%08lx",
DllMain, pid, GetCurrentThreadId() );
/*
* disconnect from thunk, even if other cleanup code commented out...
*/
#ifdef WIN95
thk3216_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
DDHAL_APP_DLLNAME,
hmod,
dwReason);
thk1632_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
DDHAL_APP_DLLNAME,
hmod,
dwReason);
#endif
#ifdef WINNT //win NT needs to close file mapping handle for each process
FreeAppHackData();
RemoveProcessFromDLL(pid);
FINI_DDRAW_CSECT(); //Cheap mutexes need to close semaphore handle for each process
MemFini();
DDASSERT(0 != hExclusiveModeMutex);
CloseHandle( hCheckExclusiveModeMutex );
CloseHandle( hExclusiveModeMutex );
FINIWINDLIST();
FINICSDRIVEROBJECTLIST();
#endif
DPF( 4, "====> EXIT: DLLMAIN(%08lx): Process Detach %08lx",
DllMain, pid );
break;
/*
* we don't ever want to see thread attach/detach
*/
#ifdef DEBUG
case DLL_THREAD_ATTACH:
DPF( 4, "THREAD_ATTACH");
break;
case DLL_THREAD_DETACH:
DPF( 4,"THREAD_DETACH");
break;
#endif
default:
break;
}
return TRUE;
} /* DllMain */
/*
* RemoveProcessFromDLL
*
* Find & remove a pid from the list.
* Assumes ddlock taken
*/
BOOL RemoveProcessFromDLL( DWORD pid )
{
LPATTACHED_PROCESSES lpap;
LPATTACHED_PROCESSES prev;
lpap = lpAttachedProcesses;
prev = NULL;
while( lpap != NULL )
{
if( lpap->dwPid == pid )
{
if( prev == NULL )
{
lpAttachedProcesses = lpap->lpLink;
}
else
{
prev->lpLink = lpap->lpLink;
}
MemFree( lpap );
DPF( 5, "Removing process %08lx from list", pid );
return TRUE;
}
prev = lpap;
lpap = lpap->lpLink;
}
DPF( 5, "Process %08lx not in DLL list", pid );
return FALSE;
} /* RemoveProcessFromDLL */