sys_win.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // sys_win.h
  16. #include "../qcommon/qcommon.h"
  17. #include "winquake.h"
  18. #include "resource.h"
  19. #include <errno.h>
  20. #include <float.h>
  21. #include <fcntl.h>
  22. #include <stdio.h>
  23. #include <direct.h>
  24. #include <io.h>
  25. #include <conio.h>
  26. #include "../win32/conproc.h"
  27. #define MINIMUM_WIN_MEMORY 0x0a00000
  28. #define MAXIMUM_WIN_MEMORY 0x1000000
  29. //#define DEMO
  30. qboolean s_win95;
  31. int starttime;
  32. int ActiveApp;
  33. qboolean Minimized;
  34. static HANDLE hinput, houtput;
  35. unsigned sys_msg_time;
  36. unsigned sys_frame_time;
  37. static HANDLE qwclsemaphore;
  38. #define MAX_NUM_ARGVS 128
  39. int argc;
  40. char *argv[MAX_NUM_ARGVS];
  41. /*
  42. ===============================================================================
  43. SYSTEM IO
  44. ===============================================================================
  45. */
  46. void Sys_Error (char *error, ...)
  47. {
  48. va_list argptr;
  49. char text[1024];
  50. CL_Shutdown ();
  51. Qcommon_Shutdown ();
  52. va_start (argptr, error);
  53. vsprintf (text, error, argptr);
  54. va_end (argptr);
  55. MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
  56. if (qwclsemaphore)
  57. CloseHandle (qwclsemaphore);
  58. // shut down QHOST hooks if necessary
  59. DeinitConProc ();
  60. exit (1);
  61. }
  62. void Sys_Quit (void)
  63. {
  64. timeEndPeriod( 1 );
  65. CL_Shutdown();
  66. Qcommon_Shutdown ();
  67. CloseHandle (qwclsemaphore);
  68. if (dedicated && dedicated->value)
  69. FreeConsole ();
  70. // shut down QHOST hooks if necessary
  71. DeinitConProc ();
  72. exit (0);
  73. }
  74. void WinError (void)
  75. {
  76. LPVOID lpMsgBuf;
  77. FormatMessage(
  78. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  79. NULL,
  80. GetLastError(),
  81. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  82. (LPTSTR) &lpMsgBuf,
  83. 0,
  84. NULL
  85. );
  86. // Display the string.
  87. MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
  88. // Free the buffer.
  89. LocalFree( lpMsgBuf );
  90. }
  91. //================================================================
  92. /*
  93. ================
  94. Sys_ScanForCD
  95. ================
  96. */
  97. char *Sys_ScanForCD (void)
  98. {
  99. static char cddir[MAX_OSPATH];
  100. static qboolean done;
  101. #ifndef DEMO
  102. char drive[4];
  103. FILE *f;
  104. char test[MAX_QPATH];
  105. if (done) // don't re-check
  106. return cddir;
  107. // no abort/retry/fail errors
  108. SetErrorMode (SEM_FAILCRITICALERRORS);
  109. drive[0] = 'c';
  110. drive[1] = ':';
  111. drive[2] = '\\';
  112. drive[3] = 0;
  113. done = true;
  114. // scan the drives
  115. for (drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++)
  116. {
  117. // where activision put the stuff...
  118. sprintf (cddir, "%sinstall\\data", drive);
  119. sprintf (test, "%sinstall\\data\\quake2.exe", drive);
  120. f = fopen(test, "r");
  121. if (f)
  122. {
  123. fclose (f);
  124. if (GetDriveType (drive) == DRIVE_CDROM)
  125. return cddir;
  126. }
  127. }
  128. #endif
  129. cddir[0] = 0;
  130. return NULL;
  131. }
  132. /*
  133. ================
  134. Sys_CopyProtect
  135. ================
  136. */
  137. void Sys_CopyProtect (void)
  138. {
  139. #ifndef DEMO
  140. char *cddir;
  141. cddir = Sys_ScanForCD();
  142. if (!cddir[0])
  143. Com_Error (ERR_FATAL, "You must have the Quake2 CD in the drive to play.");
  144. #endif
  145. }
  146. //================================================================
  147. /*
  148. ================
  149. Sys_Init
  150. ================
  151. */
  152. void Sys_Init (void)
  153. {
  154. OSVERSIONINFO vinfo;
  155. #if 0
  156. // allocate a named semaphore on the client so the
  157. // front end can tell if it is alive
  158. // mutex will fail if semephore already exists
  159. qwclsemaphore = CreateMutex(
  160. NULL, /* Security attributes */
  161. 0, /* owner */
  162. "qwcl"); /* Semaphore name */
  163. if (!qwclsemaphore)
  164. Sys_Error ("QWCL is already running on this system");
  165. CloseHandle (qwclsemaphore);
  166. qwclsemaphore = CreateSemaphore(
  167. NULL, /* Security attributes */
  168. 0, /* Initial count */
  169. 1, /* Maximum count */
  170. "qwcl"); /* Semaphore name */
  171. #endif
  172. timeBeginPeriod( 1 );
  173. vinfo.dwOSVersionInfoSize = sizeof(vinfo);
  174. if (!GetVersionEx (&vinfo))
  175. Sys_Error ("Couldn't get OS info");
  176. if (vinfo.dwMajorVersion < 4)
  177. Sys_Error ("Quake2 requires windows version 4 or greater");
  178. if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)
  179. Sys_Error ("Quake2 doesn't run on Win32s");
  180. else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
  181. s_win95 = true;
  182. if (dedicated->value)
  183. {
  184. if (!AllocConsole ())
  185. Sys_Error ("Couldn't create dedicated server console");
  186. hinput = GetStdHandle (STD_INPUT_HANDLE);
  187. houtput = GetStdHandle (STD_OUTPUT_HANDLE);
  188. // let QHOST hook in
  189. InitConProc (argc, argv);
  190. }
  191. }
  192. static char console_text[256];
  193. static int console_textlen;
  194. /*
  195. ================
  196. Sys_ConsoleInput
  197. ================
  198. */
  199. char *Sys_ConsoleInput (void)
  200. {
  201. INPUT_RECORD recs[1024];
  202. int dummy;
  203. int ch, numread, numevents;
  204. if (!dedicated || !dedicated->value)
  205. return NULL;
  206. for ( ;; )
  207. {
  208. if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
  209. Sys_Error ("Error getting # of console events");
  210. if (numevents <= 0)
  211. break;
  212. if (!ReadConsoleInput(hinput, recs, 1, &numread))
  213. Sys_Error ("Error reading console input");
  214. if (numread != 1)
  215. Sys_Error ("Couldn't read console input");
  216. if (recs[0].EventType == KEY_EVENT)
  217. {
  218. if (!recs[0].Event.KeyEvent.bKeyDown)
  219. {
  220. ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
  221. switch (ch)
  222. {
  223. case '\r':
  224. WriteFile(houtput, "\r\n", 2, &dummy, NULL);
  225. if (console_textlen)
  226. {
  227. console_text[console_textlen] = 0;
  228. console_textlen = 0;
  229. return console_text;
  230. }
  231. break;
  232. case '\b':
  233. if (console_textlen)
  234. {
  235. console_textlen--;
  236. WriteFile(houtput, "\b \b", 3, &dummy, NULL);
  237. }
  238. break;
  239. default:
  240. if (ch >= ' ')
  241. {
  242. if (console_textlen < sizeof(console_text)-2)
  243. {
  244. WriteFile(houtput, &ch, 1, &dummy, NULL);
  245. console_text[console_textlen] = ch;
  246. console_textlen++;
  247. }
  248. }
  249. break;
  250. }
  251. }
  252. }
  253. }
  254. return NULL;
  255. }
  256. /*
  257. ================
  258. Sys_ConsoleOutput
  259. Print text to the dedicated console
  260. ================
  261. */
  262. void Sys_ConsoleOutput (char *string)
  263. {
  264. int dummy;
  265. char text[256];
  266. if (!dedicated || !dedicated->value)
  267. return;
  268. if (console_textlen)
  269. {
  270. text[0] = '\r';
  271. memset(&text[1], ' ', console_textlen);
  272. text[console_textlen+1] = '\r';
  273. text[console_textlen+2] = 0;
  274. WriteFile(houtput, text, console_textlen+2, &dummy, NULL);
  275. }
  276. WriteFile(houtput, string, strlen(string), &dummy, NULL);
  277. if (console_textlen)
  278. WriteFile(houtput, console_text, console_textlen, &dummy, NULL);
  279. }
  280. /*
  281. ================
  282. Sys_SendKeyEvents
  283. Send Key_Event calls
  284. ================
  285. */
  286. void Sys_SendKeyEvents (void)
  287. {
  288. MSG msg;
  289. while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  290. {
  291. if (!GetMessage (&msg, NULL, 0, 0))
  292. Sys_Quit ();
  293. sys_msg_time = msg.time;
  294. TranslateMessage (&msg);
  295. DispatchMessage (&msg);
  296. }
  297. // grab frame time
  298. sys_frame_time = timeGetTime(); // FIXME: should this be at start?
  299. }
  300. /*
  301. ================
  302. Sys_GetClipboardData
  303. ================
  304. */
  305. char *Sys_GetClipboardData( void )
  306. {
  307. char *data = NULL;
  308. char *cliptext;
  309. if ( OpenClipboard( NULL ) != 0 )
  310. {
  311. HANDLE hClipboardData;
  312. if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 )
  313. {
  314. if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 )
  315. {
  316. data = malloc( GlobalSize( hClipboardData ) + 1 );
  317. strcpy( data, cliptext );
  318. GlobalUnlock( hClipboardData );
  319. }
  320. }
  321. CloseClipboard();
  322. }
  323. return data;
  324. }
  325. /*
  326. ==============================================================================
  327. WINDOWS CRAP
  328. ==============================================================================
  329. */
  330. /*
  331. =================
  332. Sys_AppActivate
  333. =================
  334. */
  335. void Sys_AppActivate (void)
  336. {
  337. ShowWindow ( cl_hwnd, SW_RESTORE);
  338. SetForegroundWindow ( cl_hwnd );
  339. }
  340. /*
  341. ========================================================================
  342. GAME DLL
  343. ========================================================================
  344. */
  345. static HINSTANCE game_library;
  346. /*
  347. =================
  348. Sys_UnloadGame
  349. =================
  350. */
  351. void Sys_UnloadGame (void)
  352. {
  353. if (!FreeLibrary (game_library))
  354. Com_Error (ERR_FATAL, "FreeLibrary failed for game library");
  355. game_library = NULL;
  356. }
  357. /*
  358. =================
  359. Sys_GetGameAPI
  360. Loads the game dll
  361. =================
  362. */
  363. void *Sys_GetGameAPI (void *parms)
  364. {
  365. void *(*GetGameAPI) (void *);
  366. char name[MAX_OSPATH];
  367. char *path;
  368. char cwd[MAX_OSPATH];
  369. #if defined _M_IX86
  370. const char *gamename = "gamex86.dll";
  371. #ifdef NDEBUG
  372. const char *debugdir = "release";
  373. #else
  374. const char *debugdir = "debug";
  375. #endif
  376. #elif defined _M_ALPHA
  377. const char *gamename = "gameaxp.dll";
  378. #ifdef NDEBUG
  379. const char *debugdir = "releaseaxp";
  380. #else
  381. const char *debugdir = "debugaxp";
  382. #endif
  383. #endif
  384. if (game_library)
  385. Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
  386. // check the current debug directory first for development purposes
  387. _getcwd (cwd, sizeof(cwd));
  388. Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename);
  389. game_library = LoadLibrary ( name );
  390. if (game_library)
  391. {
  392. Com_DPrintf ("LoadLibrary (%s)\n", name);
  393. }
  394. else
  395. {
  396. // check the current directory for other development purposes
  397. Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename);
  398. game_library = LoadLibrary ( name );
  399. if (game_library)
  400. {
  401. Com_DPrintf ("LoadLibrary (%s)\n", name);
  402. }
  403. else
  404. {
  405. // now run through the search paths
  406. path = NULL;
  407. while (1)
  408. {
  409. path = FS_NextPath (path);
  410. if (!path)
  411. return NULL; // couldn't find one anywhere
  412. Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
  413. game_library = LoadLibrary (name);
  414. if (game_library)
  415. {
  416. Com_DPrintf ("LoadLibrary (%s)\n",name);
  417. break;
  418. }
  419. }
  420. }
  421. }
  422. GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI");
  423. if (!GetGameAPI)
  424. {
  425. Sys_UnloadGame ();
  426. return NULL;
  427. }
  428. return GetGameAPI (parms);
  429. }
  430. //=======================================================================
  431. /*
  432. ==================
  433. ParseCommandLine
  434. ==================
  435. */
  436. void ParseCommandLine (LPSTR lpCmdLine)
  437. {
  438. argc = 1;
  439. argv[0] = "exe";
  440. while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
  441. {
  442. while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
  443. lpCmdLine++;
  444. if (*lpCmdLine)
  445. {
  446. argv[argc] = lpCmdLine;
  447. argc++;
  448. while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
  449. lpCmdLine++;
  450. if (*lpCmdLine)
  451. {
  452. *lpCmdLine = 0;
  453. lpCmdLine++;
  454. }
  455. }
  456. }
  457. }
  458. /*
  459. ==================
  460. WinMain
  461. ==================
  462. */
  463. HINSTANCE global_hInstance;
  464. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  465. {
  466. MSG msg;
  467. int time, oldtime, newtime;
  468. char *cddir;
  469. /* previous instances do not exist in Win32 */
  470. if (hPrevInstance)
  471. return 0;
  472. global_hInstance = hInstance;
  473. ParseCommandLine (lpCmdLine);
  474. // if we find the CD, add a +set cddir xxx command line
  475. cddir = Sys_ScanForCD ();
  476. if (cddir && argc < MAX_NUM_ARGVS - 3)
  477. {
  478. int i;
  479. // don't override a cddir on the command line
  480. for (i=0 ; i<argc ; i++)
  481. if (!strcmp(argv[i], "cddir"))
  482. break;
  483. if (i == argc)
  484. {
  485. argv[argc++] = "+set";
  486. argv[argc++] = "cddir";
  487. argv[argc++] = cddir;
  488. }
  489. }
  490. Qcommon_Init (argc, argv);
  491. oldtime = Sys_Milliseconds ();
  492. /* main window message loop */
  493. while (1)
  494. {
  495. // if at a full screen console, don't update unless needed
  496. if (Minimized || (dedicated && dedicated->value) )
  497. {
  498. Sleep (1);
  499. }
  500. while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  501. {
  502. if (!GetMessage (&msg, NULL, 0, 0))
  503. Com_Quit ();
  504. sys_msg_time = msg.time;
  505. TranslateMessage (&msg);
  506. DispatchMessage (&msg);
  507. }
  508. do
  509. {
  510. newtime = Sys_Milliseconds ();
  511. time = newtime - oldtime;
  512. } while (time < 1);
  513. // Con_Printf ("time:%5.2f - %5.2f = %5.2f\n", newtime, oldtime, time);
  514. // _controlfp( ~( _EM_ZERODIVIDE /*| _EM_INVALID*/ ), _MCW_EM );
  515. _controlfp( _PC_24, _MCW_PC );
  516. Qcommon_Frame (time);
  517. oldtime = newtime;
  518. }
  519. // never gets here
  520. return TRUE;
  521. }