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

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dllinit.c
  6. * Content: DDRAW.DLL initialization
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 20-jan-95 craige initial implementation
  11. * 21-feb-95 craige disconnect anyone who forgot to do it themselves,
  12. * use critical sections on Win95
  13. * 27-feb-95 craige new sync. macros
  14. * 30-mar-95 craige process tracking/cleanup for Win95
  15. * 01-apr-95 craige happy fun joy updated header file
  16. * 12-apr-95 craige debug stuff for csects
  17. * 12-may-95 craige define GUIDs
  18. * 24-jun-95 craige track which processes attach to the DLL
  19. * 25-jun-95 craige one ddraw mutex
  20. * 13-jul-95 craige ENTER_DDRAW is now the win16 lock;
  21. * proper initialization of csects
  22. * 16-jul-95 craige work around weird kernel "feature" of getting a
  23. * process attach of the same process during process detach
  24. * 19-jul-95 craige process detach too much grief; let DDNotify handle it
  25. * 20-jul-95 craige internal reorg to prevent thunking during modeset
  26. * 19-aug-95 davidmay restored call to disconnect thunk from 19-jul change
  27. * 26-sep-95 craige bug 1364: create new csect to avoid dsound deadlock
  28. * 08-dec-95 jeffno For NT, critical section macros expand to use mutexes
  29. * 16-mar-96 colinmc Callback table initialization now happens on process
  30. * attach
  31. * 20-mar-96 colinmc Bug 13341: Made MemState() dump in process detach
  32. * thread safe
  33. * 07-may-96 colinmc Bug 20219: Simultaneous calls to LoadLibrary cause
  34. * a deadlock
  35. * 09-may-96 colinmc Bug 20219 (again): Yes the deadlock again - previous
  36. * fix was not enough.
  37. * 19-jan-97 colinmc AGP support
  38. * 26-jan-97 ketand Kill globals for multi-mon.
  39. * 24-feb-97 ketand Set up callback from DDHelp to update rects.
  40. * 03-mar-97 jeffno Structure name change to avoid conflict w/ ActiveAccessibility
  41. * 13-mar-97 colinmc Bug 6533: Pass uncached flag to VMM correctly
  42. * 31-jul-97 jvanaken Bug 7907: Notify Memphis GDI when ddraw starts up
  43. *
  44. ***************************************************************************/
  45. /*
  46. * unfortunately we have to break our pre-compiled headers to get our
  47. * GUIDS defined...
  48. */
  49. #define INITGUID
  50. #include "ddrawpr.h"
  51. #include <initguid.h>
  52. #ifdef WINNT
  53. #undef IUnknown
  54. #include <objbase.h>
  55. #endif
  56. #include "apphack.h"
  57. #include "aclapi.h"
  58. #ifdef WIN95
  59. int main; // this is so we can avoid calling DllMainCRTStartup
  60. extern BOOL _stdcall thk3216_ThunkConnect32(LPSTR pszDll16,
  61. LPSTR pszDll32,
  62. HINSTANCE hInst,
  63. DWORD dwReason);
  64. extern BOOL _stdcall thk1632_ThunkConnect32(LPSTR pszDll16,
  65. LPSTR pszDll32,
  66. HINSTANCE hInst,
  67. DWORD dwReason);
  68. DWORD _stdcall wWinMain(DWORD a, DWORD b, DWORD c, DWORD d)
  69. {
  70. #ifdef DEBUG
  71. OutputDebugString("WARNING: wWinMain called. \n");
  72. #endif // DEBUG
  73. return 0;
  74. }
  75. #endif
  76. #ifdef USE_CRITSECTS
  77. #define TMPDLLEVENT "__DDRAWDLL_EVENT__"
  78. #endif
  79. #ifndef WIN16_SEPARATE
  80. #ifdef WIN95
  81. #define INITCSINIT() \
  82. ReinitializeCriticalSection( &csInit ); \
  83. MakeCriticalSectionGlobal( &csInit );
  84. #define ENTER_CSINIT() EnterCriticalSection( &csInit )
  85. #define LEAVE_CSINIT() LeaveCriticalSection( &csInit )
  86. extern CRITICAL_SECTION ddcCS;
  87. #define INITCSDDC() \
  88. ReinitializeCriticalSection( &ddcCS ); \
  89. MakeCriticalSectionGlobal( &ddcCS );
  90. #else
  91. #define CSINITMUTEXNAME "InitMutexName"
  92. #define INITCSINIT() \
  93. csInitMutex = CreateMutex(NULL,FALSE,CSINITMUTEXNAME);
  94. #define ENTER_CSINIT() \
  95. WaitForSingleObject(csInitMutex,INFINITE);
  96. #define LEAVE_CSINIT() \
  97. ReleaseMutex(csInitMutex);
  98. #define INITDDC()
  99. #endif
  100. #endif
  101. #ifdef WIN95
  102. #define INITCSWINDLIST() \
  103. ReinitializeCriticalSection( &csWindowList ); \
  104. MakeCriticalSectionGlobal( &csWindowList );
  105. #define INITCSDRIVEROBJECTLIST() \
  106. ReinitializeCriticalSection( &csDriverObjectList ); \
  107. MakeCriticalSectionGlobal( &csDriverObjectList );
  108. #define FINIWINDLIST()
  109. #define FINICSDRIVEROBJECTLIST()
  110. #else
  111. // Each process needs its own handle, so these are not initialised so theyu won't end up in shared mem
  112. HANDLE hDirectDrawMutex=(HANDLE)0;
  113. //This counts recursions into ddraw, so we don't try to do the mode uniqueness thing on recursive entries into ddraw
  114. DWORD gdwRecursionCount=0;
  115. HANDLE hWindowListMutex; //=(HANDLE)0;
  116. HANDLE hDriverObjectListMutex; //=(HANDLE)0;
  117. HANDLE csInitMutex;
  118. DWORD dwNumLockedWhenModeSwitched;
  119. #define WINDOWLISTMUTEXNAME "DDrawWindowListMutex"
  120. #define DRIVEROBJECTLISTMUTEXNAME "DDrawDriverObjectListMutex"
  121. #define INITCSWINDLIST() \
  122. hWindowListMutex = CreateMutex(NULL,FALSE,WINDOWLISTMUTEXNAME);
  123. #define INITCSDRIVEROBJECTLIST() \
  124. hDriverObjectListMutex = CreateMutex(NULL,FALSE,DRIVEROBJECTLISTMUTEXNAME);
  125. #define FINIWINDLIST() CloseHandle(hWindowListMutex);
  126. #define FINICSDRIVEROBJECTLIST() CloseHandle(hDriverObjectListMutex);
  127. #endif //win95
  128. DWORD dwRefCnt=0;
  129. DWORD dwLockCount=0;
  130. DWORD dwFakeCurrPid=0;
  131. DWORD dwGrimReaperPid=0;
  132. LPDDWINDOWINFO lpWindowInfo=0; // the list of WINDOWINFO structures
  133. LPDDRAWI_DIRECTDRAW_LCL lpDriverLocalList=0;
  134. LPDDRAWI_DIRECTDRAW_INT lpDriverObjectList=0;
  135. volatile DWORD dwMarker=0;
  136. /*
  137. * This is the globally maintained list of clippers not owned by any
  138. * DirectDraw object. All clippers created with DirectDrawClipperCreate
  139. * are placed on this list. Those created by IDirectDraw_CreateClipper
  140. * are placed on the clipper list of thier owning DirectDraw object.
  141. *
  142. * The objects on this list are NOT released when an app's DirectDraw
  143. * object is released. They remain alive until explictly released or
  144. * the app. dies.
  145. */
  146. LPDDRAWI_DDRAWCLIPPER_INT lpGlobalClipperList=0;
  147. HINSTANCE hModule=0;
  148. LPATTACHED_PROCESSES lpAttachedProcesses=0;
  149. BOOL bFirstTime=0;
  150. #ifdef DEBUG
  151. int iDLLCSCnt=0;
  152. int iWin16Cnt=0;
  153. #endif
  154. /*
  155. * These variable are so we can handle more than one window in the
  156. * topmost window timer.
  157. */
  158. HWND ghwndTopmostList[MAX_TIMER_HWNDS];
  159. int giTopmostCnt = 0;
  160. /*
  161. * Winnt specific global statics
  162. */
  163. #ifdef WINNT
  164. ULONG uDisplaySettingsUnique=0;
  165. #endif
  166. /*
  167. *Hel globals:
  168. */
  169. // used to count how many drivers are currently using the HEL
  170. DWORD dwHELRefCnt=0;
  171. // keep these around to pass to blitlib. everytime we blt to/from a surface, we
  172. // construct a BITMAPINFO for that surface using gpbmiSrc and gpbmiDest
  173. LPBITMAPINFO gpbmiSrc=0;
  174. LPBITMAPINFO gpbmiDest=0;
  175. #ifdef DEBUG
  176. // these are used by myCreateSurface
  177. int gcSurfMem=0; // surface memory in bytes
  178. int gcSurf=0; // number of surfaces
  179. #endif
  180. DWORD dwHelperPid=0;
  181. #ifdef USE_CHEAP_MUTEX
  182. #ifdef WINNT
  183. #pragma data_seg("share")
  184. #endif
  185. GLOBAL_SHARED_CRITICAL_SECTION CheapMutexCrossProcess={0};
  186. #ifdef WINNT
  187. #pragma data_seg(".data")
  188. #endif
  189. #endif //0
  190. /*
  191. * App compatibility stuff. Moved here from apphack.c
  192. */
  193. BOOL bReloadReg=FALSE;
  194. BOOL bHaveReadReg=FALSE;
  195. LPAPPHACKS lpAppList=NULL;
  196. LPAPPHACKS *lpAppArray=NULL;
  197. DWORD dwAppArraySize=0;
  198. /*
  199. * Global head of DC/Surface association list
  200. * This list is usually very very short, so we take the hit of extra pointers
  201. * just so that we don't have to traverse the entire list of surfaces.
  202. */
  203. DCINFO *g_pdcinfoHead = NULL;
  204. BYTE szDeviceWndClass[] = "DirectDrawDeviceWnd";
  205. /*
  206. * Gamma calibration globals. This determines weather a calibrator exists
  207. * and the handle to the DLL if it's loaded.
  208. */
  209. BOOL bGammaCalibratorExists=FALSE;
  210. BYTE szGammaCalibrator[MAX_PATH]="";
  211. /*
  212. * Optional refresh rate to force for all modes.
  213. */
  214. DWORD dwForceRefreshRate;
  215. /*
  216. * Spinlocks for startup synchronization.
  217. * It's just too hard to use events when NT ddraw is per-process and 9x is cross-
  218. */
  219. DWORD dwSpinStartup=0;
  220. DWORD dwHelperSpinStartup=0;
  221. #ifdef USE_CHEAP_MUTEX
  222. /*
  223. * This is the global variable pointer.
  224. */
  225. GLOBAL_LOCAL_CRITICAL_SECTION CheapMutexPerProcess;
  226. #endif
  227. /*
  228. * These two keep w95help.c happy. They point to the dwHelperPid and hModule entries in the process's
  229. * mapping of the GLOBALS structure.
  230. */
  231. DWORD * pdwHelperPid=&dwHelperPid;
  232. HANDLE * phModule=&hModule;
  233. #ifdef WINNT
  234. /*
  235. * This mutex is owned by the exclusive mode owner
  236. */
  237. HANDLE hExclusiveModeMutex=0;
  238. HANDLE hCheckExclusiveModeMutex=0;
  239. #define EXCLUSIVE_MODE_MUTEX_NAME "__DDrawExclMode__"
  240. #define CHECK_EXCLUSIVE_MODE_MUTEX_NAME "__DDrawCheckExclMode__"
  241. #endif
  242. //#endif
  243. /*
  244. *-------------------------------------------------------------------------
  245. */
  246. #if defined(WIN95) || defined(NT_USES_CRITICAL_SECTION)
  247. static CRITICAL_SECTION DirectDrawCSect;
  248. CSECT_HANDLE lpDDCS;
  249. #endif
  250. /*
  251. * Win95 specific global statics
  252. */
  253. #ifdef WIN95
  254. LPVOID lpWin16Lock;
  255. static CRITICAL_SECTION csInit = {0};
  256. CRITICAL_SECTION csWindowList;
  257. CRITICAL_SECTION csDriverObjectList;
  258. #endif
  259. #define HELPERINITDLLEVENT "__DDRAWDLL_HELPERINIT_EVENT__"
  260. /*
  261. * DllMain
  262. */
  263. BOOL WINAPI DllMain(HINSTANCE hmod, DWORD dwReason, LPVOID lpvReserved)
  264. {
  265. LPATTACHED_PROCESSES lpap;
  266. DWORD pid;
  267. BOOL didhelp;
  268. dwMarker = 0x56414C4D;
  269. pid = GetCurrentProcessId();
  270. switch( dwReason )
  271. {
  272. case DLL_PROCESS_ATTACH:
  273. pdwHelperPid=&dwHelperPid;
  274. phModule=&hModule;
  275. DisableThreadLibraryCalls( hmod );
  276. DPFINIT();
  277. /*
  278. * create the DirectDraw csect
  279. */
  280. DPF( 4, "====> ENTER: DLLMAIN(%08lx): Process Attach: %08lx, tid=%08lx", DllMain,
  281. pid, GetCurrentThreadId() );
  282. #ifdef WIN95
  283. if( lpWin16Lock == NULL )
  284. {
  285. GetpWin16Lock( &lpWin16Lock );
  286. }
  287. #endif
  288. #ifdef USE_CRITSECTS
  289. {
  290. #if defined( WIN16_SEPARATE ) && (defined(WIN95) || defined(NT_USES_CRITICAL_SECTION))
  291. lpDDCS = &DirectDrawCSect;
  292. #endif
  293. /*
  294. * is this the first time?
  295. */
  296. if( FALSE == InterlockedExchange( &bFirstTime, TRUE ) )
  297. {
  298. #ifdef WIN16_SEPARATE
  299. INIT_DDRAW_CSECT();
  300. INITCSWINDLIST();
  301. INITCSDRIVEROBJECTLIST();
  302. ENTER_DDRAW_INDLLMAIN();
  303. #else
  304. INITCSDDC(); // used in DirectDrawCreate
  305. INITCSINIT();
  306. ENTER_CSINIT();
  307. #endif
  308. hModule = hmod;
  309. /*
  310. * This event is signaled when DDHELP has successfully finished
  311. * initializing. Threads other that the very first one to connect
  312. * and the one spawned by DDHELP must wait for this event to
  313. * be signaled as deadlock will result if they run through
  314. * process attach before the DDHELP thread has.
  315. *
  316. * NOTE: The actual deadlock this prevents is pretty unusual so
  317. * if we fail to create this event we will simply continue. Its
  318. * highly unlikely anyone will notice (famous last words).
  319. *
  320. * CMcC
  321. */
  322. /*
  323. * Replaced events with spinlocks to work around a handle leak
  324. */
  325. InterlockedExchange( & dwSpinStartup , 1);
  326. }
  327. /*
  328. * second or later time through, wait for first time to
  329. * finish and then take the csect
  330. */
  331. else
  332. {
  333. /*
  334. * Spin waiting for the first thread to exit the clause above
  335. * This strange construction works around a compiler bug.
  336. * while (dwHelperSpinStartup==1); generates an infinite loop.
  337. */
  338. while (1)
  339. {
  340. if (dwSpinStartup==1)
  341. break;
  342. }
  343. #ifdef WIN16_SEPARATE
  344. #if defined( WINNT )
  345. //Each process needs its own handle in NT
  346. INIT_DDRAW_CSECT();
  347. #endif
  348. ENTER_DDRAW_INDLLMAIN();
  349. #else
  350. ENTER_CSINIT();
  351. #endif
  352. }
  353. }
  354. #endif
  355. #ifdef WINNT
  356. {
  357. SECURITY_ATTRIBUTES sa;
  358. SID_IDENTIFIER_AUTHORITY sia = SECURITY_WORLD_SID_AUTHORITY;
  359. PSID adminSid = 0;
  360. ULONG cbAcl;
  361. PACL acl=0;
  362. PSECURITY_DESCRIPTOR pSD;
  363. BYTE buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  364. BOOL bSecurityGooSucceeded = FALSE;
  365. //Granny's old fashioned LocalAlloc:
  366. BYTE Buffer1[256];
  367. BYTE Buffer2[16];
  368. // Create the SID for world
  369. cbAcl = GetSidLengthRequired(1);
  370. if (cbAcl < sizeof(Buffer2))
  371. {
  372. adminSid = (PSID) Buffer2;
  373. InitializeSid(
  374. adminSid,
  375. &sia,
  376. 1
  377. );
  378. *GetSidSubAuthority(adminSid, 0) = SECURITY_WORLD_RID;
  379. // Create an ACL giving World all access.
  380. cbAcl = sizeof(ACL) +
  381. (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  382. GetLengthSid(adminSid);
  383. if (cbAcl < sizeof(Buffer1))
  384. {
  385. acl = (PACL)&Buffer1;
  386. if (InitializeAcl(
  387. acl,
  388. cbAcl,
  389. ACL_REVISION
  390. ))
  391. {
  392. if (AddAccessAllowedAce(
  393. acl,
  394. ACL_REVISION,
  395. SYNCHRONIZE|MUTANT_QUERY_STATE|DELETE|READ_CONTROL, //|WRITE_OWNER|WRITE_DAC,
  396. adminSid
  397. ))
  398. {
  399. // Create a security descriptor with the above ACL.
  400. pSD = (PSECURITY_DESCRIPTOR)buffer;
  401. if (InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
  402. {
  403. if (SetSecurityDescriptorDacl(pSD, TRUE, acl, FALSE))
  404. {
  405. // Fill in the SECURITY_ATTRIBUTES struct.
  406. sa.nLength = sizeof(sa);
  407. sa.lpSecurityDescriptor = pSD;
  408. sa.bInheritHandle = TRUE;
  409. bSecurityGooSucceeded = TRUE;
  410. }
  411. }
  412. }
  413. }
  414. }
  415. }
  416. // Use the security attributes to create the mutexes
  417. DDASSERT(0 == hExclusiveModeMutex);
  418. hExclusiveModeMutex = CreateMutex(
  419. bSecurityGooSucceeded ? &sa : NULL, //use default access if security goo failed.
  420. FALSE,
  421. EXCLUSIVE_MODE_MUTEX_NAME );
  422. if (0 == hExclusiveModeMutex)
  423. {
  424. hExclusiveModeMutex = OpenMutex(
  425. SYNCHRONIZE|DELETE, // access flag
  426. FALSE, // inherit flag
  427. EXCLUSIVE_MODE_MUTEX_NAME // pointer to mutex-object name
  428. );
  429. }
  430. if( hExclusiveModeMutex == 0 )
  431. {
  432. DPF_ERR("Could not create exclusive mode mutex. exiting" );
  433. #ifdef WIN16_SEPARATE
  434. LEAVE_DDRAW();
  435. #else
  436. LEAVE_CSINIT();
  437. #endif
  438. return FALSE;
  439. }
  440. DDASSERT(0 == hCheckExclusiveModeMutex);
  441. hCheckExclusiveModeMutex = CreateMutex(
  442. bSecurityGooSucceeded ? &sa : NULL, //use default access if security goo failed.
  443. FALSE,
  444. CHECK_EXCLUSIVE_MODE_MUTEX_NAME );
  445. if (0 == hCheckExclusiveModeMutex)
  446. {
  447. hCheckExclusiveModeMutex = OpenMutex(
  448. SYNCHRONIZE|DELETE, // access flag
  449. FALSE, // inherit flag
  450. CHECK_EXCLUSIVE_MODE_MUTEX_NAME // pointer to mutex-object name
  451. );
  452. }
  453. if( hCheckExclusiveModeMutex == 0 )
  454. {
  455. DPF_ERR("Could not create exclusive mode check mutex. exiting" );
  456. CloseHandle( hExclusiveModeMutex );
  457. #ifdef WIN16_SEPARATE
  458. LEAVE_DDRAW();
  459. #else
  460. LEAVE_CSINIT();
  461. #endif
  462. return FALSE;
  463. }
  464. }
  465. #endif
  466. #ifdef WIN95
  467. {
  468. DWORD hpid;
  469. /*
  470. * get the helper process started
  471. */
  472. didhelp = CreateHelperProcess( &hpid );
  473. if( hpid == 0 )
  474. {
  475. DPF( 0, "Could not start helper; exiting" );
  476. #ifdef WIN16_SEPARATE
  477. LEAVE_DDRAW();
  478. #else
  479. LEAVE_CSINIT();
  480. #endif
  481. return FALSE;
  482. }
  483. /*
  484. * You get three kinds of threads coming through
  485. * process attach:
  486. *
  487. * 1) A thread belonging to the first process to
  488. * connect to DDRAW.DLL. This is distinguished as
  489. * it performs lots of one time initialization
  490. * including starting DDHELP and getting DDHELP
  491. * to load its own copy of DDRAW.DLL. Threads
  492. * of this type are identified by didhelp being
  493. * TRUE in their context
  494. * 2) A thread belonging to DDHELP when it loads
  495. * its own copy of DDHELP in response to a
  496. * request from a thread of type 1. Threads of
  497. * this type are identified by having a pid
  498. * which is equal to hpid (DDHELP's pid)
  499. * 3) Any other threads belonging to subsequent
  500. * processes connecting to DDRAW.DLL
  501. *
  502. * As a thread of type 1 causes a thread of type 2
  503. * to enter process attach before it itself has finished
  504. * executing process attach itself we open our selves up
  505. * to lots of deadlock problems if we let threads of
  506. * type 3 through process attach before the other threads
  507. * have completed their work.
  508. *
  509. * Therefore, the rule is that subsequent process
  510. * attachement can only be allowed to execute the
  511. * remainder of process attach if both the type 1
  512. * and type 2 thread have completed their execution
  513. * of process attach. We assure this with a combination
  514. * of the critical section and an event which is signaled
  515. * once DDHELP has initialized. Threads of type 3 MUST
  516. * wait on this event before continuing through the
  517. * process attach code. This is what the following
  518. * code fragment does.
  519. */
  520. /*
  521. * These events have been replaced with spinlocks, since
  522. * the old way leaked events, and it's just too hard to make them work.
  523. */
  524. if( !didhelp && ( pid != hpid ) )
  525. {
  526. {
  527. /*
  528. * NOTE: If we hold the DirectDraw critical
  529. * section when we wait on this event we WILL
  530. * DEADLOCK. Don't do it! Release the critical
  531. * section before and take it again after. This
  532. * guarantees that we won't complete process
  533. * attach before the initial thread and the
  534. * DDHELP thread have exited process attach.
  535. */
  536. #ifdef WIN16_SEPARATE
  537. LEAVE_DDRAW();
  538. #else
  539. LEAVE_CSINIT();
  540. #endif
  541. /*
  542. * This strange construction works around a compiler bug.
  543. * while (dwHelperSpinStartup==1); generates an infinite loop.
  544. */
  545. while (1)
  546. {
  547. if ( dwHelperSpinStartup == 1)
  548. break;
  549. }
  550. #ifdef WIN16_SEPARATE
  551. ENTER_DDRAW_INDLLMAIN();
  552. #else
  553. ENTER_CSINIT();
  554. #endif
  555. }
  556. }
  557. }
  558. /*
  559. * Win95 thunk connection...
  560. */
  561. DPF( 4, "Thunk connects" );
  562. if (!(thk3216_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
  563. DDHAL_APP_DLLNAME,
  564. hmod,
  565. dwReason)))
  566. {
  567. #ifdef WIN16_SEPARATE
  568. LEAVE_DDRAW();
  569. #else
  570. LEAVE_CSINIT();
  571. #endif
  572. DPF( 0, "LEAVING, COULD NOT thk3216_THUNKCONNECT32" );
  573. return FALSE;
  574. }
  575. if (!(thk1632_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
  576. DDHAL_APP_DLLNAME,
  577. hmod,
  578. dwReason)))
  579. {
  580. #ifdef WIN16_SEPARATE
  581. LEAVE_DDRAW();
  582. #else
  583. LEAVE_CSINIT();
  584. #endif
  585. DPF( 0, "LEAVING, COULD NOT thk1632_THUNKCONNECT32" );
  586. return FALSE;
  587. }
  588. /*
  589. * initialize memory used to be done here. Jeffno 960609
  590. */
  591. /*
  592. * signal the new process being added
  593. */
  594. if( didhelp )
  595. {
  596. DPF( 4, "Waiting for DDHELP startup" );
  597. #ifdef WIN16_SEPARATE
  598. LEAVE_DDRAW();
  599. #else
  600. LEAVE_CSINIT();
  601. #endif
  602. if( !WaitForHelperStartup() )
  603. {
  604. /*
  605. * NT Setup loads DDRAW.DLL and sometimes this fails, so we don't
  606. * actually want fail loading the DLL or else setup might fail.
  607. * Instead, we will suceed the load but then fail any other ddraw
  608. * calls.
  609. */
  610. DPF( 0, "WaitForHelperStartup FAILED - disabling DDRAW" );
  611. dwHelperPid = 0;
  612. return TRUE;
  613. }
  614. HelperLoadDLL( DDHAL_APP_DLLNAME, NULL, 0 );
  615. /*
  616. * For now, only call this on a multi-monitor system because
  617. * it does cause a behavior change and we aren't able to
  618. * provide adequate test covereage in the DX5 timeframe.
  619. */
  620. if( IsMultiMonitor() )
  621. {
  622. HelperSetOnDisplayChangeNotify( (void *)&UpdateAllDeviceRects);
  623. }
  624. #ifdef WIN16_SEPARATE
  625. ENTER_DDRAW_INDLLMAIN();
  626. #else
  627. ENTER_CSINIT();
  628. #endif
  629. /*
  630. * As we were the first process through we now signal
  631. * the completion of DDHELP initialization. This will
  632. * release any subsequent threads waiting to complete
  633. * process attach.
  634. *
  635. * NOTE: Threads waiting on this event will not immediately
  636. * run process attach to completion as they will immediately
  637. * try to take the DirectDraw critical section which we hold.
  638. * Thus, they will not be allowed to continue until we have
  639. * released the critical section just prior to existing
  640. * below.
  641. */
  642. InterlockedExchange( & dwHelperSpinStartup , 1);
  643. }
  644. SignalNewProcess( pid, DDNotify );
  645. #endif //w95
  646. /*
  647. * We call MemInit here in order to guarantee that MemInit is called for
  648. * the first time on ddhelp's process. Why? Glad you asked. On wx86
  649. * (NT's 486 emulator) controlled instances of ddraw apps, we get a fault
  650. * whenever the ddraw app exits. This is because the app creates the RTL
  651. * heap inside a view of a file mapping which gets uncomitted (rightly)
  652. * when the app calls MemFini on exit. In this scenario, imagehlp.dll has
  653. * also created a heap, and calls a ntdll function which attempts to walk
  654. * the list of heaps, which requires a peek at the ddraw app's heap which
  655. * has been mapped out. Krunch.
  656. * We can't destroy the heap on MemFini because of the following scenario:
  657. * App A starts, creates heap. App b starts, maps a view of heap. App A
  658. * terminates, destroys heap. App b tries to use destroyed heap. Krunch
  659. * Jeffno 960609
  660. */
  661. if( dwRefCnt == 0 )
  662. {
  663. if ( !MemInit() )
  664. {
  665. #ifdef WINNT
  666. CloseHandle( hExclusiveModeMutex );
  667. CloseHandle( hCheckExclusiveModeMutex );
  668. #endif
  669. #ifdef WIN16_SEPARATE
  670. LEAVE_DDRAW();
  671. #else
  672. LEAVE_CSINIT();
  673. #endif
  674. DPF( 0,"LEAVING, COULD NOT MemInit");
  675. return FALSE;
  676. }
  677. #ifdef WIN95
  678. /*
  679. * The Memphis version of GDI calls into DirectDraw, but GDI
  680. * needs to be notified that DirectDraw has actually loaded.
  681. * (While GDI could check for itself to see whether ddraw.dll
  682. * has loaded, this would be sloooooow if it hasn't yet.)
  683. * The code below executes when ddraw.dll first starts up.
  684. */
  685. {
  686. HANDLE h;
  687. VOID (WINAPI *p)();
  688. h = LoadLibrary("msimg32.dll"); // GDI DLL
  689. if (h)
  690. {
  691. p = (VOID(WINAPI *)())GetProcAddress(h, "vSetDdrawflag");
  692. if (p)
  693. { // vSetDdrawflag is a private call to
  694. (*p)(); // signal GDI that DDraw has loaded
  695. }
  696. FreeLibrary(h);
  697. }
  698. }
  699. #endif //WIN95
  700. }
  701. dwRefCnt++;
  702. /*
  703. * remember this process (moved this below MemInit when it moved -Jeffno 960609
  704. */
  705. lpap = MemAlloc( sizeof( ATTACHED_PROCESSES ) );
  706. if( lpap != NULL )
  707. {
  708. lpap->lpLink = lpAttachedProcesses;
  709. lpap->dwPid = pid;
  710. #ifdef WINNT
  711. lpap->dwNTToldYet=0;
  712. #endif
  713. lpAttachedProcesses = lpap;
  714. }
  715. /*
  716. * Initialize callback tables for this process.
  717. */
  718. InitCallbackTables();
  719. #ifdef WIN16_SEPARATE
  720. LEAVE_DDRAW();
  721. #else
  722. LEAVE_CSINIT();
  723. #endif
  724. DPF( 4, "====> EXIT: DLLMAIN(%08lx): Process Attach: %08lx", DllMain,
  725. pid );
  726. break;
  727. case DLL_PROCESS_DETACH:
  728. DPF( 4, "====> ENTER: DLLMAIN(%08lx): Process Detach %08lx, tid=%08lx",
  729. DllMain, pid, GetCurrentThreadId() );
  730. /*
  731. * disconnect from thunk, even if other cleanup code commented out...
  732. */
  733. #ifdef WIN95
  734. thk3216_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
  735. DDHAL_APP_DLLNAME,
  736. hmod,
  737. dwReason);
  738. thk1632_ThunkConnect32(DDHAL_DRIVER_DLLNAME,
  739. DDHAL_APP_DLLNAME,
  740. hmod,
  741. dwReason);
  742. #endif
  743. #ifdef WINNT //win NT needs to close file mapping handle for each process
  744. FreeAppHackData();
  745. RemoveProcessFromDLL(pid);
  746. FINI_DDRAW_CSECT(); //Cheap mutexes need to close semaphore handle for each process
  747. MemFini();
  748. DDASSERT(0 != hExclusiveModeMutex);
  749. CloseHandle( hCheckExclusiveModeMutex );
  750. CloseHandle( hExclusiveModeMutex );
  751. FINIWINDLIST();
  752. FINICSDRIVEROBJECTLIST();
  753. #endif
  754. DPF( 4, "====> EXIT: DLLMAIN(%08lx): Process Detach %08lx",
  755. DllMain, pid );
  756. break;
  757. /*
  758. * we don't ever want to see thread attach/detach
  759. */
  760. #ifdef DEBUG
  761. case DLL_THREAD_ATTACH:
  762. DPF( 4, "THREAD_ATTACH");
  763. break;
  764. case DLL_THREAD_DETACH:
  765. DPF( 4,"THREAD_DETACH");
  766. break;
  767. #endif
  768. default:
  769. break;
  770. }
  771. return TRUE;
  772. } /* DllMain */
  773. /*
  774. * RemoveProcessFromDLL
  775. *
  776. * Find & remove a pid from the list.
  777. * Assumes ddlock taken
  778. */
  779. BOOL RemoveProcessFromDLL( DWORD pid )
  780. {
  781. LPATTACHED_PROCESSES lpap;
  782. LPATTACHED_PROCESSES prev;
  783. lpap = lpAttachedProcesses;
  784. prev = NULL;
  785. while( lpap != NULL )
  786. {
  787. if( lpap->dwPid == pid )
  788. {
  789. if( prev == NULL )
  790. {
  791. lpAttachedProcesses = lpap->lpLink;
  792. }
  793. else
  794. {
  795. prev->lpLink = lpap->lpLink;
  796. }
  797. MemFree( lpap );
  798. DPF( 5, "Removing process %08lx from list", pid );
  799. return TRUE;
  800. }
  801. prev = lpap;
  802. lpap = lpap->lpLink;
  803. }
  804. DPF( 5, "Process %08lx not in DLL list", pid );
  805. return FALSE;
  806. } /* RemoveProcessFromDLL */