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.

1693 lines
41 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ddhelp.c
  6. * Content: helper app to cleanup after dead processes
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 29-mar-95 craige initial implementation
  11. * 05-apr-95 craige re-worked
  12. * 11-apr-95 craige fixed messed up freeing of DC list
  13. * 12-apr-95 craige only allocate each DC once
  14. * 09-may-95 craige call fn in dll
  15. * 24-jun-95 craige track pids; slay all attached if asked
  16. * 19-jul-95 craige free DC list at DDRAW request
  17. * 20-jul-95 craige internal reorg to prevent thunking during modeset;
  18. * memory allocation bugs
  19. * 15-aug-95 craige bug 538: 1 thread/process being watched
  20. * 02-sep-95 craige bug 795: prevent callbacks at WM_ENDSESSION
  21. * 16-sep-95 craige bug 1117: don't leave view of file mapped always
  22. * 16-sep-95 craige bug 1117: also close thread handles when done!
  23. * 20-sep-95 craige bug 1172: turn off callbacks instead of killing self
  24. * 22-sep-95 craige bug 1117: also don't alloc dll structs unboundedly
  25. * 29-nov-95 angusm added case for creating a sound focus thread
  26. * 12-jul-96 kylej Change ExitProcess to TerminateProcess on exception
  27. * 18-jul-96 andyco added dplayhelp_xxx functions to allow > 1 dplay app to
  28. * host a game on a single machine.
  29. * 25-jul-96 andyco watchnewpid - broke code out of winmain so dplayhelp_addserver
  30. * could call it.
  31. * 2-oct-96 andyco propagated from \orange\ddhelp.2 to \mustard\ddhelp
  32. * 3-oct-96 andyco made the winmain crit section "cs" a global so we can take
  33. * it in dphelps receive thread before forwarding requests
  34. * 12-oct-96 colinmc new service to load the DirectX VXD into DDHELP
  35. * (necessary for the Win16 lock stuff)
  36. * 15-oct-96 toddla multimonitor support (call CreateDC with device name)
  37. * 22-jan-97 kipo return an error code from DPlayHelp_AddServer
  38. * 23-jan-97 dereks added APM notification events
  39. * 27-jan-97 colinmc vxd handling stuff is no longer Win16 specific
  40. * 29-jan-97 colinmc
  41. * 24-feb-97 ketand Add a callback for WM_DISPLAYCHANGE
  42. * 19-mar-97 twillie Exorcized the DPlay Demon from DDHelp
  43. *
  44. ***************************************************************************/
  45. #include "pch.c"
  46. #undef WIN32_LEAN_AND_MEAN
  47. #define WIN32_LEAN_AND_MEAN
  48. #ifdef WIN95
  49. #ifdef _WIN32
  50. #define WINMMDEVICECHANGEMSGSTRINGA "winmm_devicechange"
  51. #define WINMMDEVICECHANGEMSGSTRINGW L"winmm_devicechange"
  52. #ifdef UNICODE
  53. #define WINMMDEVICECHANGEMSGSTRING WINMMDEVICECHANGEMSGSTRINGW
  54. #else
  55. #define WINMMDEVICECHANGEMSGSTRING WINMMDEVICECHANGEMSGSTRINGA
  56. #endif
  57. #else
  58. #define WINMMDEVICECHANGEMSGSTRING "winmm_devicechange"
  59. #endif
  60. #define FILE_FLAG_GLOBAL_HANDLE 0x00800000
  61. WINBASEAPI
  62. DWORD
  63. WINAPI
  64. RegisterServiceProcess(
  65. DWORD dwProcessId,
  66. DWORD dwServiceType
  67. );
  68. #define RSP_UNREGISTER_SERVICE 0x00000000
  69. #define RSP_SIMPLE_SERVICE 0x00000001
  70. #endif
  71. #ifndef WIN95
  72. #ifdef DBG
  73. #undef DEBUG
  74. #define DEBUG
  75. #endif
  76. #endif
  77. //#include <windows.h>
  78. //#include <mmsystem.h>
  79. #include <mmreg.h>
  80. #undef PBT_APMRESUMEAUTOMATIC
  81. #include <pbt.h>
  82. #include <dbt.h>
  83. //#include "ddhelp.h"
  84. #include "ddrawi.h"
  85. #include "dpf.h"
  86. #define NOSHARED
  87. #include "memalloc.h"
  88. #ifdef NEED_WIN16LOCK
  89. extern void _stdcall GetpWin16Lock( LPVOID FAR *);
  90. extern void _stdcall _EnterSysLevel( LPVOID );
  91. extern void _stdcall _LeaveSysLevel( LPVOID );
  92. LPVOID lpWin16Lock;
  93. #endif
  94. HANDLE hInstApp;
  95. extern BOOL bIsActive;
  96. BOOL bHasModeSetThread;
  97. BOOL bNoCallbacks;
  98. extern void HelperThreadProc( LPVOID *pdata );
  99. CRITICAL_SECTION cs; // the crit section we take in winmain
  100. // this is a global so dphelp can take it before
  101. // forwarding enum requests that come in on its
  102. // receive thread (manbugs 3907)
  103. HANDLE hApmSuspendEvent; // Event set when we enter an APM suspension state
  104. HANDLE hApmResumeEvent; // Event set when we leave the above state
  105. #ifdef WIN95
  106. UINT gumsgWinmmDeviceChange = 0; // window message for
  107. // winmm device changes
  108. /*
  109. * Handle to the DirectSound VXD. DDHELP needs its own handle as, on mode
  110. * switches and cleanups DDHELP can invoked DDRAW code that needs to talk
  111. * to the VXD. The VXD is opened on the first request from a client (currently
  112. * only DDRAW) and closed only when DDHELP shuts down.
  113. */
  114. HANDLE hDSVxd = INVALID_HANDLE_VALUE;
  115. HANDLE hDDVxd = INVALID_HANDLE_VALUE;
  116. typedef struct _DEVICECHANGENOTIFYLIST
  117. {
  118. struct _DEVICECHANGENOTIFYLIST *link;
  119. LPDEVICECHANGENOTIFYPROC lpNotify;
  120. } DEVICECHANGENOTIFYLIST, *LPDEVICECHANGENOTIFYLIST;
  121. LPDEVICECHANGENOTIFYLIST lpDeviceChangeNotifyList;
  122. #endif /* WIN95 */
  123. typedef struct HDCLIST
  124. {
  125. struct HDCLIST *link;
  126. HDC hdc;
  127. HANDLE req_id;
  128. char isdisp;
  129. char fname[1];
  130. } HDCLIST, *LPHDCLIST;
  131. static LPHDCLIST lpHDCList;
  132. typedef struct HDLLLIST
  133. {
  134. struct HDLLLIST *link;
  135. HANDLE hdll;
  136. DWORD dwRefCnt;
  137. char fname[1];
  138. } HDLLLIST, *LPHDLLLIST;
  139. static LPHDLLLIST lpHDLLList;
  140. /*
  141. * 8 callbacks: we can use up to 3 currently: ddraw, dsound
  142. */
  143. #define MAX_CALLBACKS 8
  144. typedef struct _PROCESSDATA
  145. {
  146. struct _PROCESSDATA *link;
  147. DWORD pid;
  148. struct
  149. {
  150. LPHELPNOTIFYPROC lpNotify;
  151. HANDLE req_id;
  152. } pdata[MAX_CALLBACKS];
  153. } PROCESSDATA, *LPPROCESSDATA;
  154. LPPROCESSDATA lpProcessList;
  155. CRITICAL_SECTION pdCSect;
  156. typedef struct THREADLIST
  157. {
  158. struct THREADLIST *link;
  159. ULONG_PTR hInstance;
  160. HANDLE hEvent;
  161. } THREADLIST, *LPTHREADLIST;
  162. typedef struct
  163. {
  164. LPVOID lpDD;
  165. LPHELPMODESETNOTIFYPROC lpProc;
  166. HANDLE hEvent;
  167. } MODESETTHREADDATA, *LPMODESETTHREADDATA;
  168. LPTHREADLIST lpThreadList;
  169. THREADLIST DOSBoxThread;
  170. // Who to call when a display change message is sent to the
  171. // DDHELPER's window. This variable is reserved by DDraw.
  172. // This works because DDraw itself is loaded into DDHelper's
  173. // process and so the function will remain valid.
  174. VOID (*g_pfnOnDisplayChange)(void) = NULL;
  175. /*
  176. * freeDCList
  177. *
  178. * Free all DC's that an requestor allocated.
  179. */
  180. void freeDCList( HANDLE req_id )
  181. {
  182. LPHDCLIST pdcl;
  183. LPHDCLIST last;
  184. LPHDCLIST next;
  185. DPF( 4, "Freeing DCList" );
  186. pdcl = lpHDCList;
  187. last = NULL;
  188. while( pdcl != NULL )
  189. {
  190. next = pdcl->link;
  191. if( (pdcl->req_id == req_id) || req_id == (HANDLE) -1 )
  192. {
  193. if( last == NULL )
  194. {
  195. lpHDCList = lpHDCList->link;
  196. }
  197. else
  198. {
  199. last->link = pdcl->link;
  200. }
  201. if( pdcl->isdisp )
  202. {
  203. DPF( 5, " ReleaseDC( NULL, %08lx)", pdcl->hdc );
  204. // ReleaseDC( NULL, pdcl->hdc );
  205. DeleteDC( pdcl->hdc );
  206. DPF( 5, " Back from Release" );
  207. }
  208. else
  209. {
  210. DPF( 5, " DeleteDC( %08lx)", pdcl->hdc );
  211. DeleteDC( pdcl->hdc );
  212. DPF( 5, " Back from DeleteDC" );
  213. }
  214. MemFree( pdcl );
  215. }
  216. else
  217. {
  218. last = pdcl;
  219. }
  220. pdcl = next;
  221. }
  222. if ( req_id == (HANDLE) -1 )
  223. {
  224. DDASSERT (lpHDCList == NULL);
  225. }
  226. DPF( 4, "DCList FREE" );
  227. } /* freeDCList */
  228. /*
  229. * addDC
  230. */
  231. void addDC( char *fname, BOOL isdisp, HANDLE req_id )
  232. {
  233. LPHDCLIST pdcl;
  234. HDC hdc;
  235. UINT u;
  236. pdcl = lpHDCList;
  237. while( pdcl != NULL )
  238. {
  239. if( !_stricmp( fname, pdcl->fname ) )
  240. {
  241. DPF( 4, "DC for %s already obtained (%08lx)", fname, pdcl->hdc );
  242. return;
  243. }
  244. pdcl = pdcl->link;
  245. }
  246. if( isdisp )
  247. {
  248. hdc = CreateDC( "display", NULL, NULL, NULL);
  249. DPF( 4, "CreateDC( \"display\" ) = %08lx", hdc );
  250. }
  251. else
  252. {
  253. DPF( 4, "About to CreateDC( \"%s\" )", fname );
  254. //
  255. // if fname is a device name of the form "\\.\XXXXXX"
  256. // we need to call CreateDC differently
  257. //
  258. u = SetErrorMode( SEM_NOOPENFILEERRORBOX );
  259. if (fname && fname[0] == '\\' && fname[1] == '\\' && fname[2] == '.')
  260. hdc = CreateDC( NULL, fname, NULL, NULL);
  261. else
  262. hdc = CreateDC( fname, NULL, NULL, NULL);
  263. SetErrorMode( u );
  264. }
  265. pdcl = MemAlloc( sizeof( HDCLIST ) + lstrlen( fname ) );
  266. if( pdcl != NULL )
  267. {
  268. pdcl->hdc = hdc;
  269. pdcl->link = lpHDCList;
  270. pdcl->isdisp = (CHAR)isdisp;
  271. pdcl->req_id = req_id;
  272. lstrcpy( pdcl->fname, fname );
  273. lpHDCList = pdcl;
  274. }
  275. } /* addDC */
  276. /*
  277. * loadDLL
  278. */
  279. DWORD loadDLL( LPSTR fname, LPSTR func, DWORD context )
  280. {
  281. HANDLE hdll;
  282. LPHDLLLIST pdll;
  283. DWORD rc = 0;
  284. /*
  285. * load the dll
  286. */
  287. hdll = LoadLibrary( fname );
  288. DPF( 5, "%s: hdll = %08lx", fname, hdll );
  289. if( hdll == NULL )
  290. {
  291. DPF( 1, "Could not load library %s",fname );
  292. return 0;
  293. }
  294. /*
  295. * invoke specified function
  296. */
  297. if( func[0] != 0 )
  298. {
  299. LPDD32BITDRIVERINIT pfunc;
  300. pfunc = (LPVOID) GetProcAddress( hdll, func );
  301. if( pfunc != NULL )
  302. {
  303. rc = pfunc( context );
  304. }
  305. else
  306. {
  307. DPF( 1, "Could not find procedure %s", func );
  308. }
  309. }
  310. else
  311. {
  312. rc = 1;
  313. }
  314. /*
  315. * see if we have recorded this DLL loading already
  316. */
  317. pdll = lpHDLLList;
  318. while( pdll != NULL )
  319. {
  320. if( !lstrcmpi( pdll->fname, fname ) )
  321. {
  322. DPF( 3, "DLL '%s' already loaded", fname );
  323. break;
  324. }
  325. pdll = pdll->link;
  326. }
  327. if( pdll == NULL )
  328. {
  329. pdll = MemAlloc( sizeof( HDLLLIST ) + lstrlen( fname ) );
  330. if( pdll != NULL )
  331. {
  332. pdll->hdll = hdll;
  333. pdll->link = lpHDLLList;
  334. lstrcpy( pdll->fname, fname );
  335. lpHDLLList = pdll;
  336. }
  337. }
  338. if( pdll != NULL )
  339. {
  340. pdll->dwRefCnt++;
  341. }
  342. return rc;
  343. } /* loadDLL */
  344. /*
  345. * freeDLL
  346. */
  347. HANDLE freeDLL( LPSTR fname )
  348. {
  349. LPHDLLLIST pdll;
  350. LPHDLLLIST last;
  351. HANDLE hdll;
  352. pdll = lpHDLLList;
  353. last = NULL;
  354. while( pdll != NULL )
  355. {
  356. if( !lstrcmpi( pdll->fname, fname ) )
  357. {
  358. DPF( 4, "Want to free DLL %s (%08lx)", fname, pdll->hdll );
  359. hdll = pdll->hdll;
  360. if( last == NULL )
  361. {
  362. lpHDLLList = lpHDLLList->link;
  363. }
  364. else
  365. {
  366. last->link = pdll->link;
  367. }
  368. MemFree( pdll );
  369. return hdll;
  370. }
  371. last = pdll;
  372. pdll = pdll->link;
  373. }
  374. return NULL;
  375. } /* freeDLL */
  376. #ifdef WIN95
  377. /*
  378. * return a handle to the DirectSound VXD
  379. */
  380. DWORD getDSVxdHandle( void )
  381. {
  382. if( INVALID_HANDLE_VALUE == hDSVxd )
  383. {
  384. hDSVxd = CreateFile( "\\\\.\\DSOUND.VXD",
  385. GENERIC_WRITE,
  386. FILE_SHARE_WRITE,
  387. NULL,
  388. OPEN_EXISTING,
  389. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_GLOBAL_HANDLE,
  390. NULL );
  391. #ifdef DEBUG
  392. if( INVALID_HANDLE_VALUE == hDSVxd )
  393. DPF( 0, "Could not load the DirectSound VXD" );
  394. #endif /* DEBUG */
  395. }
  396. return (DWORD) hDSVxd;
  397. } /* getDSVxdHandle */
  398. /*
  399. * return a handle to the DirectDraw VXD
  400. */
  401. DWORD getDDVxdHandle( void )
  402. {
  403. if( INVALID_HANDLE_VALUE == hDDVxd )
  404. {
  405. hDDVxd = CreateFile( "\\\\.\\DDRAW.VXD",
  406. GENERIC_WRITE,
  407. FILE_SHARE_WRITE,
  408. NULL,
  409. OPEN_EXISTING,
  410. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_GLOBAL_HANDLE,
  411. NULL );
  412. #ifdef DEBUG
  413. if( INVALID_HANDLE_VALUE == hDDVxd )
  414. DPF( 0, "Could not load the DirectDraw VXD" );
  415. #endif /* DEBUG */
  416. }
  417. return (DWORD) hDDVxd;
  418. } /* getDDVxdHandle */
  419. /*
  420. * addDeviceChangeNotify
  421. */
  422. void addDeviceChangeNotify(LPDEVICECHANGENOTIFYPROC lpNotify)
  423. {
  424. LPDEVICECHANGENOTIFYLIST pNode;
  425. pNode = (LPDEVICECHANGENOTIFYLIST)MemAlloc(sizeof(DEVICECHANGENOTIFYLIST));
  426. if(pNode)
  427. {
  428. pNode->link = lpDeviceChangeNotifyList;
  429. pNode->lpNotify = lpNotify;
  430. lpDeviceChangeNotifyList = pNode;
  431. }
  432. } /* addDeviceChangeNotify */
  433. /*
  434. * delDeviceChangeNotify
  435. */
  436. void delDeviceChangeNotify(LPDEVICECHANGENOTIFYPROC lpNotify)
  437. {
  438. LPDEVICECHANGENOTIFYLIST pNode;
  439. LPDEVICECHANGENOTIFYLIST pPrev;
  440. for(pNode = lpDeviceChangeNotifyList, pPrev = NULL; pNode; pPrev = pNode, pNode = pNode->link)
  441. {
  442. if(lpNotify == pNode->lpNotify)
  443. {
  444. break;
  445. }
  446. }
  447. if(pNode)
  448. {
  449. if(pPrev)
  450. {
  451. pPrev->link = pNode->link;
  452. }
  453. MemFree(pNode);
  454. }
  455. } /* delDeviceChangeNotify */
  456. /*
  457. * onDeviceChangeNotify
  458. */
  459. BOOL onDeviceChangeNotify(UINT Event, DWORD Data)
  460. {
  461. BOOL fAllow = TRUE;
  462. LPDEVICECHANGENOTIFYLIST pNode;
  463. __try
  464. {
  465. for(pNode = lpDeviceChangeNotifyList; pNode; pNode = pNode->link)
  466. {
  467. if(TRUE != pNode->lpNotify(Event, Data))
  468. {
  469. fAllow = BROADCAST_QUERY_DENY;
  470. }
  471. }
  472. }
  473. __except(EXCEPTION_EXECUTE_HANDLER)
  474. {
  475. DPF(0, "*********************************************************");
  476. DPF(0, "******** exception during device change notify **********");
  477. DPF(0, "*********************************************************");
  478. }
  479. return fAllow;
  480. } /* delDeviceChangeNotify */
  481. /*
  482. * freeDeviceChangeNotifyList
  483. */
  484. void freeDeviceChangeNotifyList(void)
  485. {
  486. LPDEVICECHANGENOTIFYLIST pNext;
  487. while(lpDeviceChangeNotifyList)
  488. {
  489. pNext = lpDeviceChangeNotifyList->link;
  490. MemFree(lpDeviceChangeNotifyList);
  491. lpDeviceChangeNotifyList = pNext;
  492. }
  493. } /* freeDeviceChangeNotifyList */
  494. #endif /* WIN95 */
  495. /*
  496. * freeAllResources
  497. */
  498. void freeAllResources( void )
  499. {
  500. LPHDLLLIST pdll;
  501. LPHDLLLIST next;
  502. freeDCList( (HANDLE) -1 );
  503. pdll = lpHDLLList;
  504. while( pdll != NULL )
  505. {
  506. while( pdll->dwRefCnt > 0 )
  507. {
  508. FreeLibrary( pdll->hdll );
  509. pdll->dwRefCnt--;
  510. }
  511. next = pdll->link;
  512. MemFree( pdll );
  513. pdll = next;
  514. }
  515. #ifdef WIN95
  516. freeDeviceChangeNotifyList();
  517. #endif
  518. } /* freeAllResources */
  519. /*
  520. * ThreadProc
  521. *
  522. * Open a process and wait for it to terminate
  523. */
  524. VOID ThreadProc( LPVOID *pdata )
  525. {
  526. HANDLE hproc;
  527. DWORD rc;
  528. LPPROCESSDATA ppd;
  529. LPPROCESSDATA curr;
  530. LPPROCESSDATA prev;
  531. DDHELPDATA hd;
  532. int i;
  533. PROCESSDATA pd;
  534. ppd = (LPPROCESSDATA) pdata;
  535. /*
  536. * get a handle to the process that attached to DDRAW
  537. */
  538. DPF( 3, "Watchdog thread started for pid %08lx", ppd->pid );
  539. hproc = OpenProcess( PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
  540. FALSE, ppd->pid );
  541. if( hproc == NULL )
  542. {
  543. DPF( 1, "OpenProcess for %08lx failed!", ppd->pid );
  544. ExitThread( 0 );
  545. }
  546. /*
  547. * wait for process to die
  548. */
  549. rc = WaitForSingleObject( hproc, INFINITE );
  550. if( rc == WAIT_FAILED )
  551. {
  552. DPF( 1, "Wait for process %08lx failed", ppd->pid );
  553. CloseHandle( hproc );
  554. ExitThread( 0 );
  555. }
  556. /*
  557. * remove process from the list of watched processes
  558. */
  559. EnterCriticalSection( &pdCSect );
  560. pd = *ppd;
  561. curr = lpProcessList;
  562. prev = NULL;
  563. while( curr != NULL )
  564. {
  565. if( curr == ppd )
  566. {
  567. if( prev == NULL )
  568. {
  569. lpProcessList = curr->link;
  570. }
  571. else
  572. {
  573. prev->link = curr->link;
  574. }
  575. DPF( 4, "PID %08lx removed from list", ppd->pid );
  576. MemFree( curr );
  577. break;
  578. }
  579. prev = curr;
  580. curr = curr->link;
  581. }
  582. if( bNoCallbacks )
  583. {
  584. DPF( 1, "No callbacks allowed: leaving thread early" );
  585. LeaveCriticalSection( &pdCSect );
  586. CloseHandle( hproc );
  587. ExitThread( 0 );
  588. }
  589. LeaveCriticalSection( &pdCSect );
  590. /*
  591. * tell original caller that process is dead
  592. *
  593. * Make a copy to of the process data, and then use that copy.
  594. * We do this because we will deadlock if we just try to hold it while
  595. * we call the various apps.
  596. */
  597. for( i=0;i<MAX_CALLBACKS;i++ )
  598. {
  599. if( pd.pdata[i].lpNotify != NULL )
  600. {
  601. DPF( 3, "Notifying %08lx about process %08lx terminating",
  602. pd.pdata[i].lpNotify, pd.pid );
  603. hd.pid = pd.pid;
  604. try
  605. {
  606. rc = pd.pdata[i].lpNotify( &hd );
  607. }
  608. except(EXCEPTION_EXECUTE_HANDLER)
  609. {
  610. DPF(0, "*********************************************");
  611. DPF(0, "******** exception during shutdown **********");
  612. DPF(0, "******** DDHELP is going to exit **********");
  613. DPF(0, "*********************************************");
  614. TerminateProcess(GetCurrentProcess(), 5);
  615. }
  616. /*
  617. * did it ask us to free our DC list?
  618. */
  619. if( rc )
  620. {
  621. freeDCList( pd.pdata[i].req_id );
  622. }
  623. }
  624. }
  625. CloseHandle( hproc );
  626. ExitThread( 0 );
  627. } /* ThreadProc */
  628. static BOOL bKillNow;
  629. static BOOL bKillDOSBoxNow;
  630. /*
  631. * ModeSetThreadProc
  632. */
  633. void ModeSetThreadProc( LPVOID pdata )
  634. {
  635. DWORD rc;
  636. MODESETTHREADDATA mstd;
  637. #ifdef WIN95
  638. SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
  639. #endif
  640. mstd = *((LPMODESETTHREADDATA)pdata);
  641. DPF( 5, "Modeset thread started, proc=%08lx, pdrv=%08lx, hEvent=%08lx",
  642. mstd.lpProc, mstd.lpDD, mstd.hEvent );
  643. DPF( 5, "ModeSetThreadProc: hevent = %08lx", mstd.hEvent );
  644. /*
  645. * wait for process to die
  646. */
  647. while( 1 )
  648. {
  649. rc = WaitForSingleObject( mstd.hEvent, INFINITE );
  650. if( rc == WAIT_FAILED )
  651. {
  652. DPF( 2, "WAIT_FAILED, Modeset thread terminated" );
  653. ExitThread( 0 );
  654. }
  655. if( bKillNow )
  656. {
  657. bKillNow = 0;
  658. CloseHandle( mstd.hEvent );
  659. DPF( 4, "Modeset thread now terminated" );
  660. ExitThread( 0 );
  661. }
  662. DPF( 3, "Notifying DirectDraw of modeset!" );
  663. mstd.lpProc( mstd.lpDD );
  664. }
  665. } /* ModeSetThreadProc */
  666. /*
  667. * DOSBoxThreadProc
  668. */
  669. void DOSBoxThreadProc( LPVOID pdata )
  670. {
  671. DWORD rc;
  672. MODESETTHREADDATA mstd;
  673. mstd = *((LPMODESETTHREADDATA)pdata);
  674. DPF( 5, "DOS box thread started, proc=%08lx, pdrv=%08lx, hEvent=%08lx",
  675. mstd.lpProc, mstd.lpDD, mstd.hEvent );
  676. DPF( 5, "DOSBoxThreadProc: hevent = %08lx", mstd.hEvent );
  677. /*
  678. * wait for process to die
  679. */
  680. while( 1 )
  681. {
  682. rc = WaitForSingleObject( mstd.hEvent, INFINITE );
  683. if( rc == WAIT_FAILED )
  684. {
  685. DPF( 2, "WAIT_FAILED, DOS Box thread terminated" );
  686. ExitThread( 0 );
  687. }
  688. if( bKillDOSBoxNow )
  689. {
  690. bKillDOSBoxNow = 0;
  691. CloseHandle( mstd.hEvent );
  692. DPF( 4, "DOS box thread now terminated" );
  693. ExitThread( 0 );
  694. }
  695. DPF( 3, "Notifying DirectDraw of DOS box!" );
  696. mstd.lpProc( mstd.lpDD );
  697. }
  698. } /* DOSBoxThreadProc */
  699. /*
  700. * MainWndProc
  701. */
  702. LRESULT __stdcall MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  703. {
  704. #ifdef WIN95
  705. BOOL f;
  706. // If we got a message for a WinMM device change, let's convert it
  707. // into a WM_DEVICECHANGE message with DBT_DEVNODES_CHANGED
  708. if (message == gumsgWinmmDeviceChange) {
  709. message = WM_DEVICECHANGE;
  710. wParam = DBT_DEVNODES_CHANGED;
  711. }
  712. #endif
  713. switch(message)
  714. {
  715. case WM_ENDSESSION:
  716. /*
  717. * shoot ourselves in the head
  718. */
  719. if( lParam == FALSE )
  720. {
  721. DPF( 4, "WM_ENDSESSION" );
  722. EnterCriticalSection( &pdCSect );
  723. DPF( 4, "Setting NO CALLBACKS" );
  724. bNoCallbacks = TRUE;
  725. LeaveCriticalSection( &pdCSect );
  726. }
  727. else
  728. {
  729. DPF( 4, "User logging off" );
  730. }
  731. break;
  732. case WM_POWERBROADCAST:
  733. switch(wParam)
  734. {
  735. case PBT_APMSUSPEND:
  736. DPF(3, "Entering APM suspend mode...");
  737. SetEvent(hApmSuspendEvent);
  738. ResetEvent(hApmResumeEvent);
  739. break;
  740. case PBT_APMRESUMESUSPEND:
  741. case PBT_APMRESUMEAUTOMATIC:
  742. case PBT_APMRESUMECRITICAL:
  743. DPF(3, "Leaving APM suspend mode...");
  744. SetEvent(hApmResumeEvent);
  745. ResetEvent(hApmSuspendEvent);
  746. break;
  747. }
  748. break;
  749. case WM_DISPLAYCHANGE:
  750. DPF( 4, "WM_DISPLAYCHANGE" );
  751. if( g_pfnOnDisplayChange )
  752. (*g_pfnOnDisplayChange)();
  753. break;
  754. #ifdef WIN95
  755. case WM_DEVICECHANGE:
  756. DPF(4, "WM_DEVICECHANGE");
  757. EnterCriticalSection(&cs);
  758. f = onDeviceChangeNotify(wParam, lParam);
  759. LeaveCriticalSection(&cs);
  760. if (f != TRUE)
  761. {
  762. return f;
  763. }
  764. break;
  765. #endif
  766. }
  767. return DefWindowProc(hWnd, message, wParam, lParam);
  768. } /* MainWndProc */
  769. /*
  770. * WindowThreadProc
  771. */
  772. void WindowThreadProc( LPVOID pdata )
  773. {
  774. static char szClassName[] = "DDHelpWndClass";
  775. WNDCLASS cls;
  776. MSG msg;
  777. HWND hwnd;
  778. /*
  779. * turn down the heat a little
  780. */
  781. #ifdef WIN95
  782. SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_IDLE );
  783. if (!gumsgWinmmDeviceChange) {
  784. gumsgWinmmDeviceChange = RegisterWindowMessage(WINMMDEVICECHANGEMSGSTRING);
  785. }
  786. #endif
  787. /*
  788. * build class and create window
  789. */
  790. cls.lpszClassName = szClassName;
  791. cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  792. cls.hInstance = hInstApp;
  793. cls.hIcon = NULL;
  794. cls.hCursor = NULL;
  795. cls.lpszMenuName = NULL;
  796. cls.style = 0;
  797. cls.lpfnWndProc = MainWndProc;
  798. cls.cbWndExtra = 0;
  799. cls.cbClsExtra = 0;
  800. if( !RegisterClass( &cls ) )
  801. {
  802. DPF( 1, "RegisterClass FAILED!" );
  803. ExitThread( 0 );
  804. }
  805. hwnd = CreateWindow( szClassName, szClassName,
  806. WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstApp, NULL);
  807. if( hwnd == NULL )
  808. {
  809. DPF( 1, "No monitor window!" );
  810. ExitThread( 0 );
  811. }
  812. /*
  813. * pump the messages
  814. */
  815. while( GetMessage( &msg, NULL, 0, 0 ) )
  816. {
  817. TranslateMessage( &msg );
  818. DispatchMessage( &msg );
  819. }
  820. DPF( 4, "Exiting WindowThreadProc" );
  821. ExitThread( 1 );
  822. } /* WindowThreadProc */
  823. //
  824. // called by WinMain in response to a DDHELPREQ_NEWPID request.
  825. //
  826. void WatchNewPid(LPDDHELPDATA phd)
  827. {
  828. LPPROCESSDATA ppd;
  829. BOOL found;
  830. int i;
  831. DWORD tid;
  832. DPF( 4, "DDHELPREQ_NEWPID" );
  833. EnterCriticalSection( &pdCSect );
  834. ppd = lpProcessList;
  835. found = FALSE;
  836. while( ppd != NULL )
  837. {
  838. if( ppd->pid == phd->pid )
  839. {
  840. DPF( 4, "Have thread for process %08lx already", phd->pid );
  841. /*
  842. * look if we already have this callback for this process
  843. */
  844. for( i=0;i<MAX_CALLBACKS;i++ )
  845. {
  846. if( ppd->pdata[i].lpNotify == phd->lpNotify )
  847. {
  848. DPF( 5, "Notification rtn %08lx already set for pid %08lx",
  849. phd->lpNotify, phd->pid );
  850. found = TRUE;
  851. break;
  852. }
  853. }
  854. if( found )
  855. {
  856. break;
  857. }
  858. /*
  859. * we have a new callback for this process
  860. */
  861. for( i=0;i<MAX_CALLBACKS;i++ )
  862. {
  863. if( ppd->pdata[i].lpNotify == NULL )
  864. {
  865. DPF( 5, "Setting notification rtn %08lx for pid %08lx",
  866. phd->lpNotify, phd->pid );
  867. ppd->pdata[i].lpNotify = phd->lpNotify;
  868. ppd->pdata[i].req_id = phd->req_id;
  869. found = TRUE;
  870. break;
  871. }
  872. }
  873. if( !found )
  874. {
  875. #ifdef DEBUG
  876. /*
  877. * this should not happen!
  878. */
  879. DPF( 0, "OUT OF NOTIFICATION ROOM!" );
  880. DebugBreak(); //_asm int 3;
  881. #endif
  882. }
  883. break;
  884. }
  885. ppd = ppd->link;
  886. }
  887. /*
  888. * couldn't find anyone waiting on this process, so create
  889. * a brand spanking new thread
  890. */
  891. if( !found )
  892. {
  893. DPF( 3, "Allocating new thread for process %08lx" );
  894. ppd = MemAlloc( sizeof( PROCESSDATA ) );
  895. if( ppd != NULL )
  896. {
  897. HANDLE h;
  898. ppd->link = lpProcessList;
  899. lpProcessList = ppd;
  900. ppd->pid = phd->pid;
  901. ppd->pdata[0].lpNotify = phd->lpNotify;
  902. ppd->pdata[0].req_id = phd->req_id;
  903. h = CreateThread(NULL,
  904. 0,
  905. (LPTHREAD_START_ROUTINE) ThreadProc,
  906. (LPVOID)ppd,
  907. 0,
  908. (LPDWORD)&tid);
  909. if( h != NULL )
  910. {
  911. DPF( 5, "Thread %08lx created, initial callback=%08lx",
  912. tid, phd->lpNotify );
  913. CloseHandle( h );
  914. }
  915. else
  916. {
  917. #ifdef DEBUG
  918. DPF( 0, "COULD NOT CREATE HELPER THREAD FOR PID %08lx", phd->pid );
  919. #endif
  920. }
  921. }
  922. else
  923. {
  924. #ifdef DEBUG
  925. DPF( 0, "OUT OF MEMORY CREATING HELPER THREAD FOR PID %08lx", phd->pid );
  926. #endif
  927. }
  928. }
  929. LeaveCriticalSection( &pdCSect );
  930. } // WatchNewPid
  931. //
  932. // called by WinMain in response to a DDHELPREQ_STOPWATCHPID request.
  933. //
  934. void StopWatchPid(LPDDHELPDATA phd)
  935. {
  936. LPPROCESSDATA ppd;
  937. BOOL found;
  938. int i;
  939. DPF( 4, "DDHELPREQ_STOPWATCHPID" );
  940. EnterCriticalSection( &pdCSect );
  941. ppd = lpProcessList;
  942. found = FALSE;
  943. while( ppd != NULL )
  944. {
  945. if( ppd->pid == phd->pid )
  946. {
  947. /*
  948. * look if we already have this callback for this process
  949. */
  950. for( i=0;i<MAX_CALLBACKS;i++ )
  951. {
  952. if( ppd->pdata[i].lpNotify == phd->lpNotify )
  953. {
  954. DPF( 5, "Remove notification rtn %08lx for pid %08lx", phd->lpNotify, phd->pid );
  955. ppd->pdata[i].lpNotify = NULL;
  956. found = TRUE;
  957. break;
  958. }
  959. }
  960. if( found )
  961. {
  962. break;
  963. }
  964. }
  965. ppd = ppd->link;
  966. }
  967. LeaveCriticalSection( &pdCSect );
  968. } // StopWatchPid
  969. /*
  970. * WinMain
  971. */
  972. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  973. LPSTR lpCmdLine, int nCmdShow)
  974. {
  975. DWORD tid;
  976. DWORD rc;
  977. HANDLE hstartevent;
  978. HANDLE hstartupevent;
  979. HANDLE hmutex;
  980. HANDLE hackevent;
  981. LPDDHELPDATA phd;
  982. HANDLE hsharedmem;
  983. HANDLE h;
  984. char szSystemDir[1024];
  985. /*
  986. * Set our working directory to the system directory.
  987. * This prevents us from holding network connections open
  988. * forever if the first DirectDraw app that we run is across
  989. * a network connection.
  990. */
  991. GetSystemDirectory(szSystemDir, sizeof(szSystemDir));
  992. SetCurrentDirectory(szSystemDir);
  993. /*
  994. * when we gotta run, we gotta run baby
  995. */
  996. #ifdef WIN95
  997. SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS );
  998. #endif
  999. #ifdef WIN95
  1000. /*
  1001. * when we gotta run, we gotta and not let the user see us in
  1002. * the task list.
  1003. */
  1004. RegisterServiceProcess( 0, RSP_SIMPLE_SERVICE );
  1005. #else
  1006. /*
  1007. * We must guarantee that ddhelp unloads after the last ddraw app,
  1008. * since ctrl-alt-del may have happened while an app held the ddraw
  1009. * lock, and ddhelp needs to clean up orphaned cheap ddraw mutex
  1010. * locks.
  1011. */
  1012. if ( ! SetProcessShutdownParameters(0x100,SHUTDOWN_NORETRY) )
  1013. {
  1014. DPF(0,"DDHELP.EXE could not set itself to shutdown last!");
  1015. }
  1016. #endif
  1017. #if NEED_WIN16LOCK
  1018. GetpWin16Lock( &lpWin16Lock );
  1019. #endif
  1020. hInstApp = hInstance;
  1021. /*
  1022. * create startup event
  1023. */
  1024. hstartupevent = CreateEvent( NULL, TRUE, FALSE, DDHELP_STARTUP_EVENT_NAME );
  1025. DPFINIT();
  1026. DPF( 5, "*** DDHELP STARTED, PID=%08lx ***", GetCurrentProcessId() );
  1027. if( !MemInit() )
  1028. {
  1029. DPF( 1, "Could not init memory manager" );
  1030. return 0;
  1031. }
  1032. /*
  1033. * create shared memory area
  1034. */
  1035. hsharedmem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
  1036. PAGE_READWRITE, 0, sizeof( DDHELPDATA ),
  1037. DDHELP_SHARED_NAME );
  1038. if( hsharedmem == NULL )
  1039. {
  1040. DPF( 1, "Could not create file mapping!" );
  1041. return 0;
  1042. }
  1043. /*
  1044. * create mutex for people who want to use the shared memory area
  1045. */
  1046. hmutex = CreateMutex( NULL, FALSE, DDHELP_MUTEX_NAME );
  1047. if( hmutex == NULL )
  1048. {
  1049. DPF( 1, "Could not create mutex " DDHELP_MUTEX_NAME );
  1050. CloseHandle( hsharedmem );
  1051. return 0;
  1052. }
  1053. /*
  1054. * create events
  1055. */
  1056. hstartevent = CreateEvent( NULL, FALSE, FALSE, DDHELP_EVENT_NAME );
  1057. if( hstartevent == NULL )
  1058. {
  1059. DPF( 1, "Could not create event " DDHELP_EVENT_NAME );
  1060. CloseHandle( hmutex );
  1061. CloseHandle( hsharedmem );
  1062. return 0;
  1063. }
  1064. hackevent = CreateEvent( NULL, FALSE, FALSE, DDHELP_ACK_EVENT_NAME );
  1065. if( hackevent == NULL )
  1066. {
  1067. DPF( 1, "Could not create event " DDHELP_ACK_EVENT_NAME );
  1068. CloseHandle( hmutex );
  1069. CloseHandle( hsharedmem );
  1070. CloseHandle( hstartevent );
  1071. return 0;
  1072. }
  1073. hApmSuspendEvent = CreateEvent( NULL, TRUE, FALSE, DDHELP_APMSUSPEND_EVENT_NAME );
  1074. if( hApmSuspendEvent == NULL )
  1075. {
  1076. DPF( 1, "Could not create event " DDHELP_APMSUSPEND_EVENT_NAME );
  1077. CloseHandle( hmutex );
  1078. CloseHandle( hsharedmem );
  1079. CloseHandle( hstartevent );
  1080. CloseHandle( hackevent );
  1081. return 0;
  1082. }
  1083. hApmResumeEvent = CreateEvent( NULL, TRUE, TRUE, DDHELP_APMRESUME_EVENT_NAME );
  1084. if( hApmResumeEvent == NULL )
  1085. {
  1086. DPF( 1, "Could not create event " DDHELP_APMRESUME_EVENT_NAME );
  1087. CloseHandle( hmutex );
  1088. CloseHandle( hsharedmem );
  1089. CloseHandle( hstartevent );
  1090. CloseHandle( hackevent );
  1091. CloseHandle( hApmSuspendEvent );
  1092. return 0;
  1093. }
  1094. /*
  1095. * Create window so we can get messages
  1096. */
  1097. h = CreateThread(NULL,
  1098. 0,
  1099. (LPTHREAD_START_ROUTINE) WindowThreadProc,
  1100. NULL,
  1101. 0,
  1102. (LPDWORD)&tid );
  1103. if( h == NULL )
  1104. {
  1105. DPF( 1, "Create of WindowThreadProc FAILED!" );
  1106. CloseHandle( hackevent );
  1107. CloseHandle( hmutex );
  1108. CloseHandle( hsharedmem );
  1109. CloseHandle( hstartevent );
  1110. CloseHandle( hApmSuspendEvent );
  1111. CloseHandle( hApmResumeEvent );
  1112. return 0;
  1113. }
  1114. CloseHandle( h );
  1115. /*
  1116. * serialize access to us
  1117. */
  1118. memset( &cs, 0, sizeof( cs ) );
  1119. InitializeCriticalSection( &cs );
  1120. /*
  1121. * serialize access to process data
  1122. */
  1123. memset( &pdCSect, 0, sizeof( pdCSect ) );
  1124. InitializeCriticalSection( &pdCSect );
  1125. /*
  1126. * let invoker and anyone else who comes along know we exist
  1127. */
  1128. SetEvent( hstartupevent );
  1129. /*
  1130. * loop forever, processing requests
  1131. */
  1132. while( 1 )
  1133. {
  1134. HANDLE hdll;
  1135. /*
  1136. * wait to be notified of a request
  1137. */
  1138. hdll = NULL;
  1139. DPF( 4, "Waiting for next request" );
  1140. rc = WaitForSingleObject( hstartevent, INFINITE );
  1141. if( rc == WAIT_FAILED )
  1142. {
  1143. DPF( 1, "Wait FAILED!!!" );
  1144. continue;
  1145. }
  1146. EnterCriticalSection( &cs );
  1147. phd = (LPDDHELPDATA) MapViewOfFile( hsharedmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
  1148. if( phd == NULL )
  1149. {
  1150. DPF( 1, "Could not create view of file!" );
  1151. LeaveCriticalSection( &cs );
  1152. continue;
  1153. }
  1154. /*
  1155. * find out what we need to do
  1156. */
  1157. switch( phd->req )
  1158. {
  1159. case DDHELPREQ_NEWDC:
  1160. DPF( 4, "DDHELPREQ_NEWDC" );
  1161. addDC( phd->fname, phd->isdisp, phd->req_id );
  1162. break;
  1163. case DDHELPREQ_FREEDCLIST:
  1164. DPF( 4, "DDHELPREQ_FREEDCLIST" );
  1165. freeDCList( phd->req_id );
  1166. break;
  1167. case DDHELPREQ_CREATEMODESETTHREAD:
  1168. {
  1169. MODESETTHREADDATA mstd;
  1170. LPTHREADLIST ptl;
  1171. char str[64];
  1172. HANDLE hevent;
  1173. HANDLE h;
  1174. DPF( 4, "DDHELPREQ_CREATEMODESETTHREAD" );
  1175. mstd.lpProc = phd->lpModeSetNotify;
  1176. mstd.lpDD = phd->pData1;
  1177. wsprintf( str, DDHELP_MODESET_EVENT_NAME, phd->dwData1 );
  1178. DPF( 5, "Trying to Create event \"%s\"", str );
  1179. hevent = CreateEvent( NULL, FALSE, FALSE, str );
  1180. mstd.hEvent = hevent;
  1181. DPF( 5, "hevent = %08lx", hevent );
  1182. h = CreateThread(NULL,
  1183. 0,
  1184. (LPTHREAD_START_ROUTINE) ModeSetThreadProc,
  1185. (LPVOID) &mstd,
  1186. 0,
  1187. (LPDWORD)&tid );
  1188. if( h != NULL )
  1189. {
  1190. DPF( 5, "CREATED MODE SET THREAD %ld", h );
  1191. ptl = MemAlloc( sizeof( THREADLIST ) );
  1192. if( ptl != NULL )
  1193. {
  1194. ptl->hInstance = phd->dwData1;
  1195. ptl->hEvent = hevent;
  1196. ptl->link = lpThreadList;
  1197. lpThreadList = ptl;
  1198. }
  1199. CloseHandle( h );
  1200. }
  1201. break;
  1202. }
  1203. case DDHELPREQ_KILLMODESETTHREAD:
  1204. {
  1205. LPTHREADLIST ptl;
  1206. LPTHREADLIST prev;
  1207. DPF( 4, "DDHELPREQ_KILLMODESETTHREAD" );
  1208. prev = NULL;
  1209. ptl = lpThreadList;
  1210. while( ptl != NULL )
  1211. {
  1212. if( ptl->hInstance == phd->dwData1 )
  1213. {
  1214. HANDLE h;
  1215. if( prev == NULL )
  1216. {
  1217. lpThreadList = ptl->link;
  1218. }
  1219. else
  1220. {
  1221. prev->link = ptl->link;
  1222. }
  1223. h = ptl->hEvent;
  1224. MemFree( ptl );
  1225. bKillNow = TRUE;
  1226. SetEvent( h );
  1227. break;
  1228. }
  1229. prev = ptl;
  1230. ptl = ptl->link;
  1231. }
  1232. break;
  1233. }
  1234. case DDHELPREQ_CREATEHELPERTHREAD:
  1235. #ifdef WIN95
  1236. if( !bIsActive )
  1237. {
  1238. HANDLE h;
  1239. bIsActive = TRUE;
  1240. h = CreateThread(NULL,
  1241. 0,
  1242. (LPTHREAD_START_ROUTINE) HelperThreadProc,
  1243. NULL,
  1244. 0,
  1245. (LPDWORD)&tid);
  1246. if( h == NULL )
  1247. {
  1248. bIsActive = FALSE;
  1249. }
  1250. else
  1251. {
  1252. CloseHandle( h );
  1253. }
  1254. }
  1255. #endif
  1256. break;
  1257. case DDHELPREQ_NEWPID:
  1258. WatchNewPid(phd);
  1259. break;
  1260. case DDHELPREQ_STOPWATCHPID:
  1261. StopWatchPid(phd);
  1262. break;
  1263. case DDHELPREQ_RETURNHELPERPID:
  1264. DPF( 4, "DDHELPREQ_RETURNHELPERPID" );
  1265. phd->pid = GetCurrentProcessId();
  1266. break;
  1267. case DDHELPREQ_LOADDLL:
  1268. DPF( 4, "DDHELPREQ_LOADDLL" );
  1269. phd->dwReturn = loadDLL( phd->fname, phd->func, phd->context );
  1270. break;
  1271. case DDHELPREQ_FREEDLL:
  1272. DPF( 4, "DDHELPREQ_FREEDDLL" );
  1273. hdll = freeDLL( phd->fname );
  1274. break;
  1275. case DDHELPREQ_KILLATTACHED:
  1276. {
  1277. LPPROCESSDATA ppd;
  1278. HANDLE hproc;
  1279. DPF( 4, "DDHELPREQ_KILLATTACHED" );
  1280. EnterCriticalSection( &pdCSect );
  1281. ppd = lpProcessList;
  1282. while( ppd != NULL )
  1283. {
  1284. hproc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ppd->pid );
  1285. DPF( 5, "Process %08lx: handle = %08lx", ppd->pid, hproc );
  1286. if( hproc != NULL )
  1287. {
  1288. DPF( 5, "Terminating %08lx", ppd->pid );
  1289. TerminateProcess( hproc, 0 );
  1290. }
  1291. ppd = ppd->link;
  1292. }
  1293. LeaveCriticalSection( &pdCSect );
  1294. break;
  1295. }
  1296. case DDHELPREQ_SUICIDE:
  1297. DPF( 4, "DDHELPREQ_SUICIDE" );
  1298. freeAllResources();
  1299. #ifdef WIN95
  1300. if( INVALID_HANDLE_VALUE != hDSVxd )
  1301. CloseHandle( hDSVxd );
  1302. if( INVALID_HANDLE_VALUE != hDDVxd )
  1303. CloseHandle( hDDVxd );
  1304. #endif /* WIN95 */
  1305. SetEvent( hackevent );
  1306. CloseHandle( hmutex );
  1307. UnmapViewOfFile( phd );
  1308. CloseHandle( hsharedmem );
  1309. CloseHandle( hstartevent );
  1310. CloseHandle( hApmSuspendEvent );
  1311. CloseHandle( hApmResumeEvent );
  1312. #ifdef DEBUG
  1313. MemState();
  1314. #endif
  1315. DPF( 4, "Good Night Gracie" );
  1316. TerminateProcess( GetCurrentProcess(), 0 );
  1317. break;
  1318. case DDHELPREQ_WAVEOPEN:
  1319. {
  1320. #ifdef WIN95
  1321. DWORD dwPriority;
  1322. #endif
  1323. DPF( 4, "DDHELPREQ_WAVEOPEN" );
  1324. // Due to a possible bug in Win95 mmsystem/mmtask, we can hang
  1325. // if we call waveOutOpen on a REALTIME thread while a sound
  1326. // event is playing. So, we briefly lower our priority to
  1327. // NORMAL while we call this API
  1328. #ifdef WIN95
  1329. dwPriority = GetPriorityClass(GetCurrentProcess());
  1330. SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
  1331. #endif
  1332. phd->dwReturn = (DWORD)waveOutOpen(
  1333. (LPHWAVEOUT)(phd->pData1),
  1334. (UINT)(phd->dwData1),
  1335. (LPWAVEFORMATEX)(phd->dwData2),
  1336. 0, 0, 0);
  1337. #ifdef WIN95
  1338. SetPriorityClass(GetCurrentProcess(), dwPriority);
  1339. #endif
  1340. // Some mmsystem wave drivers will program their wave mixer
  1341. // hardware only while the device is open. By doing the
  1342. // following, we can get such drivers to program the hardware
  1343. if (MMSYSERR_NOERROR == phd->dwReturn) {
  1344. MMRESULT mmr;
  1345. DWORD dwVolume;
  1346. mmr = waveOutGetVolume((HWAVEOUT)(*(LPHWAVEOUT)(phd->pData1)), &dwVolume);
  1347. if (MMSYSERR_NOERROR == mmr) {
  1348. waveOutSetVolume((HWAVEOUT)(*(LPHWAVEOUT)(phd->pData1)), dwVolume);
  1349. }
  1350. }
  1351. DPF( 5, "Wave Open returned %X", phd->dwReturn );
  1352. break;
  1353. }
  1354. case DDHELPREQ_WAVECLOSE:
  1355. DPF( 4, "DDHELPREQ_WAVECLOSE" );
  1356. phd->dwReturn = (DWORD)waveOutClose(
  1357. (HWAVEOUT)(phd->dwData1) );
  1358. break;
  1359. case DDHELPREQ_CREATETIMER:
  1360. DPF( 4, "DDHELPREQ_CREATETIMER proc %X", (phd->pData1) );
  1361. phd->dwReturn = (DWORD)timeSetEvent(
  1362. (UINT)(phd->dwData1), // Delay
  1363. (UINT)(phd->dwData1)/2, // Resolution
  1364. (phd->pData1), // Callback thread proc
  1365. (UINT)(phd->dwData2), // instance data
  1366. TIME_PERIODIC );
  1367. DPF( 5, "Create Timer returned %X", phd->dwReturn );
  1368. break;
  1369. case DDHELPREQ_KILLTIMER:
  1370. DPF( 4, "DDHELPREQ_KILLTIMER %X", phd->dwData1 );
  1371. phd->dwReturn = (DWORD)timeKillEvent( (UINT)phd->dwData1 );
  1372. DPF( 5, "Kill Timer returned %X", phd->dwReturn );
  1373. break;
  1374. case DDHELPREQ_CREATEDSMIXERTHREAD:
  1375. {
  1376. DWORD tid;
  1377. if (NULL == phd->pData2) phd->pData2 = &tid;
  1378. phd->dwReturn = (ULONG_PTR)CreateThread(NULL, 0, phd->pData1,
  1379. (LPVOID)phd->dwData1,
  1380. (UINT)phd->dwData2,
  1381. (LPDWORD)phd->pData2);
  1382. if (!phd->dwReturn) {
  1383. #ifdef DEBUG
  1384. DPF(0, "pData1 %p (start addr)", phd->pData1);
  1385. DPF(0, "dwData1 %p (thread parm)", phd->dwData1);
  1386. DPF(0, "dwData2 %p (fdwCreate)", phd->dwData2);
  1387. DPF(0, "pData2 %p (lpThreadID)", phd->pData2);
  1388. DPF(0, "DDHelp: Failed to create mixer thread %lu",
  1389. GetLastError());
  1390. DebugBreak();
  1391. #endif
  1392. }
  1393. break;
  1394. }
  1395. case DDHELPREQ_CREATEDSFOCUSTHREAD:
  1396. {
  1397. DWORD tid;
  1398. if (NULL == phd->pData2) phd->pData2 = &tid;
  1399. phd->dwReturn = (ULONG_PTR)CreateThread(NULL, 0, phd->pData1,
  1400. (LPVOID)phd->dwData1,
  1401. (UINT)phd->dwData2,
  1402. (LPDWORD)phd->pData2);
  1403. if (!phd->dwReturn) {
  1404. #ifdef DEBUG
  1405. DPF(0, "pData1 %p (start addr)", phd->pData1);
  1406. DPF(0, "dwData1 %p (thread parm)", phd->dwData1);
  1407. DPF(0, "dwData2 %p (fdwCreate)", phd->dwData2);
  1408. DPF(0, "pData2 %p (lpThreadID)", phd->pData2);
  1409. DPF(0, "DDHelp: Failed to create sound focus thread %lu",
  1410. GetLastError());
  1411. DebugBreak();
  1412. #endif
  1413. }
  1414. }
  1415. break;
  1416. case DDHELPREQ_CALLDSCLEANUP:
  1417. try
  1418. {
  1419. ((LPDSCLEANUP)phd->pData1)(phd->pData2);
  1420. }
  1421. except(EXCEPTION_EXECUTE_HANDLER)
  1422. {
  1423. DPF(0, "*********************************************");
  1424. DPF(0, "**** DDHELPREQ_CALLDSCLEANUP blew up! *******");
  1425. DPF(0, "*********************************************");
  1426. }
  1427. break;
  1428. #ifdef WIN95
  1429. case DDHELPREQ_GETDSVXDHANDLE:
  1430. phd->dwReturn = getDSVxdHandle();
  1431. break;
  1432. case DDHELPREQ_GETDDVXDHANDLE:
  1433. phd->dwReturn = getDDVxdHandle();
  1434. break;
  1435. #endif /* WIN95 */
  1436. case DDHELPREQ_NOTIFYONDISPLAYCHANGE:
  1437. DPF( 4, "DDHELPREQ_NOTIFYONDISPLAYCHANGE" );
  1438. (void *)g_pfnOnDisplayChange = (void *)phd->dwData1;
  1439. break;
  1440. #ifdef WIN95
  1441. case DDHELPREQ_CREATEDOSBOXTHREAD:
  1442. {
  1443. MODESETTHREADDATA dbtd;
  1444. char str[64];
  1445. HANDLE hevent;
  1446. HANDLE h;
  1447. DPF( 4, "DDHELPREQ_CREATEDOSBOXTHREAD" );
  1448. dbtd.lpProc = phd->lpModeSetNotify;
  1449. dbtd.lpDD = phd->pData1;
  1450. wsprintf( str, DDHELP_DOSBOX_EVENT_NAME, phd->dwData1 );
  1451. DPF( 5, "Trying to Create event \"%s\"", str );
  1452. hevent = CreateEvent( NULL, FALSE, FALSE, str );
  1453. dbtd.hEvent = hevent;
  1454. DPF( 5, "hevent = %08lx", hevent );
  1455. h = CreateThread(NULL,
  1456. 0,
  1457. (LPTHREAD_START_ROUTINE) DOSBoxThreadProc,
  1458. (LPVOID) &dbtd,
  1459. 0,
  1460. (LPDWORD)&tid );
  1461. if( h != NULL )
  1462. {
  1463. DPF( 5, "CREATED DOS BOX THREAD %ld", h );
  1464. DOSBoxThread.hInstance = phd->dwData1;
  1465. DOSBoxThread.hEvent = hevent;
  1466. CloseHandle( h );
  1467. }
  1468. }
  1469. break;
  1470. case DDHELPREQ_KILLDOSBOXTHREAD:
  1471. {
  1472. DPF( 4, "DDHELPREQ_KILLDOSBOXTHREAD" );
  1473. if( DOSBoxThread.hInstance == phd->dwData1 )
  1474. {
  1475. bKillDOSBoxNow = TRUE;
  1476. SetEvent( DOSBoxThread.hEvent );
  1477. }
  1478. }
  1479. break;
  1480. #endif
  1481. case DDHELPREQ_LOADLIBRARY:
  1482. phd->dwReturn = (ULONG_PTR)LoadLibraryA((LPCSTR)phd->dwData1);
  1483. break;
  1484. case DDHELPREQ_FREELIBRARY:
  1485. phd->dwReturn = FreeLibrary((HINSTANCE)phd->dwData1);
  1486. break;
  1487. #ifdef WIN95
  1488. case DDHELPREQ_ADDDEVICECHANGENOTIFY:
  1489. addDeviceChangeNotify(phd->pData1);
  1490. break;
  1491. case DDHELPREQ_DELDEVICECHANGENOTIFY:
  1492. delDeviceChangeNotify(phd->pData1);
  1493. break;
  1494. #endif
  1495. default:
  1496. DPF( 1, "Unknown Request???" );
  1497. break;
  1498. }
  1499. /*
  1500. * let caller know we've got the news
  1501. */
  1502. UnmapViewOfFile( phd );
  1503. SetEvent( hackevent );
  1504. LeaveCriticalSection( &cs );
  1505. /*
  1506. * unload the DLL we were asked to
  1507. */
  1508. if( hdll != NULL )
  1509. {
  1510. DPF( 4, "Freeing DLL %08lx", hdll );
  1511. FreeLibrary( hdll );
  1512. }
  1513. }
  1514. #ifdef WIN95
  1515. RegisterServiceProcess( 0, RSP_UNREGISTER_SERVICE );
  1516. #else
  1517. #pragma message("RegisterServiceProcess needs to be taken care of under nt")
  1518. #endif
  1519. } /* WinMain */