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
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 */
|