Source code of Windows XP (NT5)
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.

607 lines
14 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dplaysvr.c
  6. * Content: dplay winsock shared .exe - allows multiple apps to share
  7. * a single winsock port
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 2/10/97 andyco created it from ddhelp
  12. * 29-jan-98 sohailm added support for stream enum sessions
  13. *
  14. ***************************************************************************/
  15. #ifdef WINNT
  16. #ifdef DBG
  17. #undef DEBUG
  18. #define DEBUG
  19. #endif
  20. #endif
  21. #include <windows.h>
  22. #include "dplaysvr.h"
  23. #include "newdpf.h"
  24. #include "memalloc.h"
  25. #include "dphelp.h"
  26. HANDLE hInstApp;
  27. BOOL bNoCallbacks;
  28. CRITICAL_SECTION gcsCritSection; // the crit section we take in winmain
  29. // this is a global so dphelp can take it before
  30. // forwarding enum requests that come in on its
  31. // receive thread (manbugs 3907)
  32. int gnCSCount; // dplaysvr lock count
  33. /*
  34. * Externs
  35. */
  36. extern RECEIVELIST gReceiveList;
  37. extern FDS gReadfds;
  38. // we watch every dplay process so when it exits we
  39. // make sure it cleaned up...
  40. typedef struct _PROCESSDATA
  41. {
  42. struct _PROCESSDATA *link;
  43. DWORD pid;
  44. } PROCESSDATA, *LPPROCESSDATA;
  45. LPPROCESSDATA lpProcessList; // list of all processes that are registered
  46. // with us
  47. /*
  48. * ThreadProc
  49. *
  50. * Open a process and wait for it to terminate
  51. */
  52. DWORD WINAPI ThreadProc( LPVOID *pdata )
  53. {
  54. HANDLE hproc;
  55. DWORD rc;
  56. LPPROCESSDATA ppd;
  57. LPPROCESSDATA curr;
  58. LPPROCESSDATA prev;
  59. PROCESSDATA pd;
  60. DPHELPDATA hd;
  61. ppd = (LPPROCESSDATA) pdata;
  62. /*
  63. * get a handle to the process that attached to DDRAW
  64. */
  65. DPF( 2, "Watchdog thread started for pid %08lx", ppd->pid );
  66. hproc = OpenProcess( PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
  67. FALSE, ppd->pid );
  68. if( hproc == NULL )
  69. {
  70. DPF( 1, "OpenProcess for %08lx failed!", ppd->pid );
  71. ExitThread( 0 );
  72. }
  73. /*
  74. * wait for process to die
  75. */
  76. rc = WaitForSingleObject( hproc, INFINITE );
  77. if( rc == WAIT_FAILED )
  78. {
  79. DPF( 1, "Wait for process %08lx failed", ppd->pid );
  80. CloseHandle( hproc );
  81. ExitThread( 0 );
  82. }
  83. /*
  84. * remove process from the list of watched processes
  85. */
  86. ENTER_DPLAYSVR();
  87. pd = *ppd;
  88. curr = lpProcessList;
  89. prev = NULL;
  90. while( curr != NULL )
  91. {
  92. if( curr == ppd )
  93. {
  94. if( prev == NULL )
  95. {
  96. lpProcessList = curr->link;
  97. }
  98. else
  99. {
  100. prev->link = curr->link;
  101. }
  102. DPF( 2, "PID %08lx removed from list", ppd->pid );
  103. MemFree( curr );
  104. break;
  105. }
  106. prev = curr;
  107. curr = curr->link;
  108. }
  109. if( bNoCallbacks )
  110. {
  111. DPF( 1, "No callbacks allowed: leaving thread early" );
  112. LEAVE_DPLAYSVR();
  113. CloseHandle( hproc );
  114. ExitThread( 0 );
  115. }
  116. // clean up!
  117. memset(&hd,0,sizeof(hd));
  118. hd.pid = pd.pid;
  119. DPlayHelp_DeleteServer(&hd,TRUE);
  120. LEAVE_DPLAYSVR();
  121. CloseHandle( hproc );
  122. ExitThread( 0 );
  123. return 0;
  124. } /* ThreadProc */
  125. /*
  126. * MainWndProc
  127. */
  128. LONG_PTR __stdcall MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  129. {
  130. switch(message)
  131. {
  132. case WM_ENDSESSION:
  133. /*
  134. * shoot ourselves in the head
  135. */
  136. if( lParam == FALSE )
  137. {
  138. DPF( 3, "WM_ENDSESSION" );
  139. ENTER_DPLAYSVR();
  140. DPF( 1, "Setting NO CALLBACKS" );
  141. bNoCallbacks = TRUE;
  142. LEAVE_DPLAYSVR();
  143. }
  144. else
  145. {
  146. DPF( 3, "User logging off" );
  147. }
  148. break;
  149. }
  150. return DefWindowProc(hWnd, message, wParam, lParam);
  151. } /* MainWndProc */
  152. /*
  153. * WindowThreadProc
  154. */
  155. void WindowThreadProc( LPVOID pdata )
  156. {
  157. static char szClassName[] = "DPlayHelpWndClass";
  158. WNDCLASS cls;
  159. MSG msg;
  160. HWND hwnd;
  161. /*
  162. * build class and create window
  163. */
  164. cls.lpszClassName = szClassName;
  165. cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  166. cls.hInstance = hInstApp;
  167. cls.hIcon = NULL;
  168. cls.hCursor = NULL;
  169. cls.lpszMenuName = NULL;
  170. cls.style = 0;
  171. cls.lpfnWndProc = (WNDPROC)MainWndProc;
  172. cls.cbWndExtra = 0;
  173. cls.cbClsExtra = 0;
  174. if( !RegisterClass( &cls ) )
  175. {
  176. DPF( 1, "RegisterClass FAILED!" );
  177. ExitThread( 0 );
  178. }
  179. hwnd = CreateWindow( szClassName, szClassName,
  180. WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstApp, NULL);
  181. if( hwnd == NULL )
  182. {
  183. DPF( 1, "No monitor window!" );
  184. ExitThread( 0 );
  185. }
  186. /*
  187. * pump the messages
  188. */
  189. while( GetMessage( &msg, NULL, 0, 0 ) )
  190. {
  191. TranslateMessage( &msg );
  192. DispatchMessage( &msg );
  193. }
  194. DPF( 1, "Exiting WindowThreadProc" );
  195. ExitThread( 1 );
  196. } /* WindowThreadProc */
  197. //
  198. // called by by DPlayHelp_AddServer when we get a new process attached.
  199. // we wait for the process to go away, and then make sure it cleaned
  200. // all its registered servers up.
  201. //
  202. void WatchNewPid(LPDPHELPDATA phd)
  203. {
  204. LPPROCESSDATA ppd;
  205. BOOL found;
  206. DWORD tid;
  207. DPF( 1, "watching new pid" );
  208. ENTER_DPLAYSVR();
  209. ppd = lpProcessList;
  210. found = FALSE;
  211. while( ppd != NULL )
  212. {
  213. if( ppd->pid == phd->pid )
  214. {
  215. DPF( 2, "Have thread for process %08lx already", phd->pid );
  216. found = TRUE;
  217. break;
  218. }
  219. ppd = ppd->link;
  220. }
  221. /*
  222. * couldn't find anyone waiting on this process, so create
  223. * a brand spanking new thread
  224. */
  225. if( !found )
  226. {
  227. DPF( 2, "Allocating new thread for process %08lx",phd->pid );
  228. ppd = MemAlloc( sizeof( PROCESSDATA ) );
  229. if( ppd != NULL )
  230. {
  231. HANDLE h;
  232. ppd->link = lpProcessList;
  233. lpProcessList = ppd;
  234. ppd->pid = phd->pid;
  235. h = CreateThread(NULL,
  236. 0,
  237. (LPTHREAD_START_ROUTINE) ThreadProc,
  238. (LPVOID)ppd,
  239. 0,
  240. (LPDWORD)&tid);
  241. if( h != NULL )
  242. {
  243. DPF( 2, "Thread %08lx created",tid);
  244. CloseHandle( h );
  245. }
  246. else
  247. {
  248. #ifdef DEBUG
  249. DPF( 0, "COULD NOT CREATE HELPER THREAD FOR PID %08lx", phd->pid );
  250. DebugBreak(); //_asm int 3;
  251. #endif
  252. }
  253. }
  254. else
  255. {
  256. #ifdef DEBUG
  257. DPF( 0, "OUT OF MEMORY CREATING HELPER THREAD FOR PID %08lx", phd->pid );
  258. DebugBreak(); //_asm int 3;
  259. #endif
  260. }
  261. }
  262. LEAVE_DPLAYSVR();
  263. } // WatchNewPid
  264. typedef DWORD (WINAPI *PFNREGISTERSERVICE)(DWORD,DWORD);
  265. // nt's winbase.h doesn't have these constants - we need them
  266. // so we can compile. taken from \proj\dev\inc\winbase.h
  267. #ifndef RSP_UNREGISTER_SERVICE
  268. #define RSP_UNREGISTER_SERVICE 0x00000000
  269. #endif
  270. #ifndef RSP_SIMPLE_SERVICE
  271. #define RSP_SIMPLE_SERVICE 0x00000001
  272. #endif
  273. // on Win95, we want to call RegisterServiceProcess
  274. // but, it's not available on NT, so we can't import it directly
  275. // here we try to find it dynamically in kernel32. if we find it,
  276. // we call it, otherwise we assume we're on NT and it's not avaible
  277. void MakeMeService()
  278. {
  279. HANDLE hLib;
  280. PFNREGISTERSERVICE pfnRegisterServiceProcess;
  281. hLib = LoadLibrary("kernel32.dll");
  282. if (!hLib)
  283. {
  284. // wacky!
  285. DPF(1,"could not load library kernel32 to register service proc");
  286. return;
  287. }
  288. pfnRegisterServiceProcess = (PFNREGISTERSERVICE)GetProcAddress(hLib,"RegisterServiceProcess");
  289. if (!pfnRegisterServiceProcess)
  290. {
  291. // this is expected on NT
  292. DPF(3,"could not register service process - expected on NT");
  293. FreeLibrary(hLib);
  294. return ;
  295. }
  296. pfnRegisterServiceProcess( 0, RSP_SIMPLE_SERVICE );
  297. FreeLibrary(hLib);
  298. return ;
  299. } // MakeMeService
  300. // on Win95, we want to call RegisterServiceProcess to Unregister
  301. // (see MakeMeService)
  302. void StopServiceProcess()
  303. {
  304. HANDLE hLib;
  305. PFNREGISTERSERVICE pfnRegisterServiceProcess;
  306. hLib = LoadLibrary("kernel32.dll");
  307. if (!hLib)
  308. {
  309. // wacky!
  310. DPF(1,"could not load library kernel32 to register service proc");
  311. return;
  312. }
  313. pfnRegisterServiceProcess = (PFNREGISTERSERVICE)GetProcAddress(hLib,"RegisterServiceProcess");
  314. if (!pfnRegisterServiceProcess)
  315. {
  316. // this is expected on NT
  317. DPF(3,"could not unregister service process - not avail - not tragic");
  318. FreeLibrary(hLib);
  319. return ;
  320. }
  321. // unregistered!
  322. pfnRegisterServiceProcess( 0, RSP_UNREGISTER_SERVICE );
  323. FreeLibrary(hLib);
  324. return ;
  325. } // StopServiceProcess
  326. /*
  327. * WinMain
  328. */
  329. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  330. LPSTR lpCmdLine, int nCmdShow)
  331. {
  332. DWORD tid;
  333. DWORD rc;
  334. HANDLE hstartevent;
  335. HANDLE hstartupevent;
  336. HANDLE hmutex;
  337. HANDLE hackevent;
  338. LPDPHELPDATA phd;
  339. HANDLE hsharedmem;
  340. HANDLE h;
  341. char szSystemDir[1024];
  342. /*
  343. * Set our working directory to the system directory.
  344. * This prevents us from holding network connections open
  345. * forever if the first DirectDraw app that we run is across
  346. * a network connection.
  347. */
  348. GetSystemDirectory(szSystemDir, sizeof(szSystemDir));
  349. SetCurrentDirectory(szSystemDir);
  350. // try to register ourselves as a service so user can't see us
  351. // in task list
  352. MakeMeService();
  353. #if 0
  354. // andyco - not sure if we need this...
  355. /*
  356. * We must guarantee that DPHELP unloads after the last ddraw app,
  357. * since ctrl-alt-del may have happened while an app held the ddraw
  358. * lock, and DPHELP needs to clean up orphaned cheap ddraw mutex
  359. * locks.
  360. */
  361. if ( ! SetProcessShutdownParameters(0x100,SHUTDOWN_NORETRY) )
  362. {
  363. DPF(0,"dplaysvr could not set itself to shutdown last!");
  364. }
  365. #endif
  366. hInstApp = hInstance;
  367. /*
  368. * create startup event
  369. */
  370. hstartupevent = CreateEvent( NULL, TRUE, FALSE, DPHELP_STARTUP_EVENT_NAME );
  371. DPFINIT();
  372. DPF( 2, "*** dplaysvr STARTED, PID=%08lx ***", GetCurrentProcessId() );
  373. if( !MemInit() )
  374. {
  375. DPF( 1, "Could not init memory manager" );
  376. return 0;
  377. }
  378. /*
  379. * create shared memory area
  380. */
  381. hsharedmem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
  382. PAGE_READWRITE, 0, sizeof( DPHELPDATA ),
  383. DPHELP_SHARED_NAME );
  384. if( hsharedmem == NULL )
  385. {
  386. DPF( 1, "Could not create file mapping!" );
  387. return 0;
  388. }
  389. /*
  390. * create mutex for people who want to use the shared memory area
  391. */
  392. hmutex = CreateMutex( NULL, FALSE, DPHELP_MUTEX_NAME );
  393. if( hmutex == NULL )
  394. {
  395. DPF( 1, "Could not create mutex " DPHELP_MUTEX_NAME );
  396. CloseHandle( hsharedmem );
  397. return 0;
  398. }
  399. /*
  400. * create events
  401. */
  402. hstartevent = CreateEvent( NULL, FALSE, FALSE, DPHELP_EVENT_NAME );
  403. if( hstartevent == NULL )
  404. {
  405. DPF( 1, "Could not create event " DPHELP_EVENT_NAME );
  406. CloseHandle( hmutex );
  407. CloseHandle( hsharedmem );
  408. return 0;
  409. }
  410. hackevent = CreateEvent( NULL, FALSE, FALSE, DPHELP_ACK_EVENT_NAME );
  411. if( hackevent == NULL )
  412. {
  413. DPF( 1, "Could not create event " DPHELP_ACK_EVENT_NAME );
  414. CloseHandle( hmutex );
  415. CloseHandle( hsharedmem );
  416. CloseHandle( hstartevent );
  417. return 0;
  418. }
  419. /*
  420. * Create window so we can get messages
  421. */
  422. h = CreateThread(NULL,
  423. 0,
  424. (LPTHREAD_START_ROUTINE) WindowThreadProc,
  425. NULL,
  426. 0,
  427. (LPDWORD)&tid );
  428. if( h == NULL )
  429. {
  430. DPF( 1, "Create of WindowThreadProc FAILED!" );
  431. CloseHandle( hackevent );
  432. CloseHandle( hmutex );
  433. CloseHandle( hsharedmem );
  434. CloseHandle( hstartevent );
  435. return 0;
  436. }
  437. CloseHandle( h );
  438. /*
  439. * serialize access to us
  440. */
  441. INIT_DPLAYSVR_CSECT();
  442. /*
  443. * let invoker and anyone else who comes along know we exist
  444. */
  445. SetEvent( hstartupevent );
  446. /*
  447. * loop forever, processing requests
  448. */
  449. while( 1 )
  450. {
  451. /*
  452. * wait to be notified of a request
  453. */
  454. DPF( 1, "Waiting for next request" );
  455. rc = WaitForSingleObject( hstartevent, INFINITE );
  456. if( rc == WAIT_FAILED )
  457. {
  458. DPF( 1, "Wait FAILED!!!" );
  459. continue;
  460. }
  461. ENTER_DPLAYSVR();
  462. phd = (LPDPHELPDATA) MapViewOfFile( hsharedmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
  463. if( phd == NULL )
  464. {
  465. DPF( 1, "Could not create view of file!" );
  466. LEAVE_DPLAYSVR();
  467. continue;
  468. }
  469. /*
  470. * find out what we need to do
  471. */
  472. switch( phd->req )
  473. {
  474. case DPHELPREQ_SUICIDE:
  475. DPF( 1, "DPHELPREQ_SUICIDE" );
  476. DPlayHelp_FreeServerList();
  477. SetEvent( hackevent );
  478. CloseHandle( hmutex );
  479. UnmapViewOfFile( phd );
  480. CloseHandle( hsharedmem );
  481. CloseHandle( hstartevent );
  482. if (gReceiveList.pConnection)
  483. {
  484. MemFree(gReceiveList.pConnection);
  485. }
  486. if (gReadfds.pfdbigset)
  487. {
  488. MemFree(gReadfds.pfdbigset);
  489. }
  490. FINI_DPLAYSVR_CSECT();
  491. #ifdef DEBUG
  492. MemState();
  493. #endif
  494. DPF( 3, "Good Night Gracie" );
  495. TerminateProcess( GetCurrentProcess(), 0 );
  496. break;
  497. case DPHELPREQ_RETURNHELPERPID:
  498. DPF( 2, "DDHELPREQ_RETURNHELPERPID" );
  499. phd->pid = GetCurrentProcessId();
  500. break;
  501. case DPHELPREQ_DPLAYADDSERVER:
  502. DPF( 2, "DPHELPREQ_DPLAYADDSERVER" );
  503. phd->hr = DPlayHelp_AddServer(phd);
  504. break;
  505. case DPHELPREQ_DPLAYDELETESERVER:
  506. DPF( 2, "DPHELPREQ_DPLAYDELETESERVER" );
  507. DPlayHelp_DeleteServer(phd,FALSE);
  508. break;
  509. default:
  510. DPF( 1, "helper - Unknown Request???" );
  511. break;
  512. }
  513. /*
  514. * let caller know we've got the news
  515. */
  516. UnmapViewOfFile( phd );
  517. SetEvent( hackevent );
  518. LEAVE_DPLAYSVR();
  519. }
  520. StopServiceProcess();
  521. } /* WinMain */