Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

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 }