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