Home | History | Annotate | Download | only in WinQuake
      1 /*
      2 Copyright (C) 1996-1997 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.c -- Win32 system interface code
     21 
     22 #include "quakedef.h"
     23 #include "winquake.h"
     24 #include "errno.h"
     25 #include "resource.h"
     26 #include "conproc.h"
     27 
     28 #define MINIMUM_WIN_MEMORY		0x0880000
     29 #define MAXIMUM_WIN_MEMORY		0x1000000
     30 
     31 #define CONSOLE_ERROR_TIMEOUT	60.0	// # of seconds to wait on Sys_Error running
     32 										//  dedicated before exiting
     33 #define PAUSE_SLEEP		50				// sleep time on pause or minimization
     34 #define NOT_FOCUS_SLEEP	20				// sleep time when not focus
     35 
     36 int			starttime;
     37 qboolean	ActiveApp, Minimized;
     38 qboolean	WinNT;
     39 
     40 static double		pfreq;
     41 static double		curtime = 0.0;
     42 static double		lastcurtime = 0.0;
     43 static int			lowshift;
     44 qboolean			isDedicated;
     45 static qboolean		sc_return_on_enter = false;
     46 HANDLE				hinput, houtput;
     47 
     48 static char			*tracking_tag = "Clams & Mooses";
     49 
     50 static HANDLE	tevent;
     51 static HANDLE	hFile;
     52 static HANDLE	heventParent;
     53 static HANDLE	heventChild;
     54 
     55 void MaskExceptions (void);
     56 void Sys_InitFloatTime (void);
     57 void Sys_PushFPCW_SetHigh (void);
     58 void Sys_PopFPCW (void);
     59 
     60 volatile int					sys_checksum;
     61 
     62 
     63 /*
     64 ================
     65 Sys_PageIn
     66 ================
     67 */
     68 void Sys_PageIn (void *ptr, int size)
     69 {
     70 	byte	*x;
     71 	int		j, m, n;
     72 
     73 // touch all the memory to make sure it's there. The 16-page skip is to
     74 // keep Win 95 from thinking we're trying to page ourselves in (we are
     75 // doing that, of course, but there's no reason we shouldn't)
     76 	x = (byte *)ptr;
     77 
     78 	for (n=0 ; n<4 ; n++)
     79 	{
     80 		for (m=0 ; m<(size - 16 * 0x1000) ; m += 4)
     81 		{
     82 			sys_checksum += *(int *)&x[m];
     83 			sys_checksum += *(int *)&x[m + 16 * 0x1000];
     84 		}
     85 	}
     86 }
     87 
     88 
     89 /*
     90 ===============================================================================
     91 
     92 FILE IO
     93 
     94 ===============================================================================
     95 */
     96 
     97 #define	MAX_HANDLES		10
     98 FILE	*sys_handles[MAX_HANDLES];
     99 
    100 int		findhandle (void)
    101 {
    102 	int		i;
    103 
    104 	for (i=1 ; i<MAX_HANDLES ; i++)
    105 		if (!sys_handles[i])
    106 			return i;
    107 	Sys_Error ("out of handles");
    108 	return -1;
    109 }
    110 
    111 /*
    112 ================
    113 filelength
    114 ================
    115 */
    116 int filelength (FILE *f)
    117 {
    118 	int		pos;
    119 	int		end;
    120 	int		t;
    121 
    122 	t = VID_ForceUnlockedAndReturnState ();
    123 
    124 	pos = ftell (f);
    125 	fseek (f, 0, SEEK_END);
    126 	end = ftell (f);
    127 	fseek (f, pos, SEEK_SET);
    128 
    129 	VID_ForceLockState (t);
    130 
    131 	return end;
    132 }
    133 
    134 int Sys_FileOpenRead (char *path, int *hndl)
    135 {
    136 	FILE	*f;
    137 	int		i, retval;
    138 	int		t;
    139 
    140 	t = VID_ForceUnlockedAndReturnState ();
    141 
    142 	i = findhandle ();
    143 
    144 	f = fopen(path, "rb");
    145 
    146 	if (!f)
    147 	{
    148 		*hndl = -1;
    149 		retval = -1;
    150 	}
    151 	else
    152 	{
    153 		sys_handles[i] = f;
    154 		*hndl = i;
    155 		retval = filelength(f);
    156 	}
    157 
    158 	VID_ForceLockState (t);
    159 
    160 	return retval;
    161 }
    162 
    163 int Sys_FileOpenWrite (char *path)
    164 {
    165 	FILE	*f;
    166 	int		i;
    167 	int		t;
    168 
    169 	t = VID_ForceUnlockedAndReturnState ();
    170 
    171 	i = findhandle ();
    172 
    173 	f = fopen(path, "wb");
    174 	if (!f)
    175 		Sys_Error ("Error opening %s: %s", path,strerror(errno));
    176 	sys_handles[i] = f;
    177 
    178 	VID_ForceLockState (t);
    179 
    180 	return i;
    181 }
    182 
    183 void Sys_FileClose (int handle)
    184 {
    185 	int		t;
    186 
    187 	t = VID_ForceUnlockedAndReturnState ();
    188 	fclose (sys_handles[handle]);
    189 	sys_handles[handle] = NULL;
    190 	VID_ForceLockState (t);
    191 }
    192 
    193 void Sys_FileSeek (int handle, int position)
    194 {
    195 	int		t;
    196 
    197 	t = VID_ForceUnlockedAndReturnState ();
    198 	fseek (sys_handles[handle], position, SEEK_SET);
    199 	VID_ForceLockState (t);
    200 }
    201 
    202 int Sys_FileRead (int handle, void *dest, int count)
    203 {
    204 	int		t, x;
    205 
    206 	t = VID_ForceUnlockedAndReturnState ();
    207 	x = fread (dest, 1, count, sys_handles[handle]);
    208 	VID_ForceLockState (t);
    209 	return x;
    210 }
    211 
    212 int Sys_FileWrite (int handle, void *data, int count)
    213 {
    214 	int		t, x;
    215 
    216 	t = VID_ForceUnlockedAndReturnState ();
    217 	x = fwrite (data, 1, count, sys_handles[handle]);
    218 	VID_ForceLockState (t);
    219 	return x;
    220 }
    221 
    222 int	Sys_FileTime (char *path)
    223 {
    224 	FILE	*f;
    225 	int		t, retval;
    226 
    227 	t = VID_ForceUnlockedAndReturnState ();
    228 
    229 	f = fopen(path, "rb");
    230 
    231 	if (f)
    232 	{
    233 		fclose(f);
    234 		retval = 1;
    235 	}
    236 	else
    237 	{
    238 		retval = -1;
    239 	}
    240 
    241 	VID_ForceLockState (t);
    242 	return retval;
    243 }
    244 
    245 void Sys_mkdir (char *path)
    246 {
    247 	_mkdir (path);
    248 }
    249 
    250 
    251 /*
    252 ===============================================================================
    253 
    254 SYSTEM IO
    255 
    256 ===============================================================================
    257 */
    258 
    259 /*
    260 ================
    261 Sys_MakeCodeWriteable
    262 ================
    263 */
    264 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
    265 {
    266 	DWORD  flOldProtect;
    267 
    268 	if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
    269    		Sys_Error("Protection change failed\n");
    270 }
    271 
    272 
    273 #ifndef _M_IX86
    274 
    275 void Sys_SetFPCW (void)
    276 {
    277 }
    278 
    279 void Sys_PushFPCW_SetHigh (void)
    280 {
    281 }
    282 
    283 void Sys_PopFPCW (void)
    284 {
    285 }
    286 
    287 void MaskExceptions (void)
    288 {
    289 }
    290 
    291 #endif
    292 
    293 /*
    294 ================
    295 Sys_Init
    296 ================
    297 */
    298 void Sys_Init (void)
    299 {
    300 	LARGE_INTEGER	PerformanceFreq;
    301 	unsigned int	lowpart, highpart;
    302 	OSVERSIONINFO	vinfo;
    303 
    304 	MaskExceptions ();
    305 	Sys_SetFPCW ();
    306 
    307 	if (!QueryPerformanceFrequency (&PerformanceFreq))
    308 		Sys_Error ("No hardware timer available");
    309 
    310 // get 32 out of the 64 time bits such that we have around
    311 // 1 microsecond resolution
    312 	lowpart = (unsigned int)PerformanceFreq.LowPart;
    313 	highpart = (unsigned int)PerformanceFreq.HighPart;
    314 	lowshift = 0;
    315 
    316 	while (highpart || (lowpart > 2000000.0))
    317 	{
    318 		lowshift++;
    319 		lowpart >>= 1;
    320 		lowpart |= (highpart & 1) << 31;
    321 		highpart >>= 1;
    322 	}
    323 
    324 	pfreq = 1.0 / (double)lowpart;
    325 
    326 	Sys_InitFloatTime ();
    327 
    328 	vinfo.dwOSVersionInfoSize = sizeof(vinfo);
    329 
    330 	if (!GetVersionEx (&vinfo))
    331 		Sys_Error ("Couldn't get OS info");
    332 
    333 	if ((vinfo.dwMajorVersion < 4) ||
    334 		(vinfo.dwPlatformId == VER_PLATFORM_WIN32s))
    335 	{
    336 		Sys_Error ("WinQuake requires at least Win95 or NT 4.0");
    337 	}
    338 
    339 	if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
    340 		WinNT = true;
    341 	else
    342 		WinNT = false;
    343 }
    344 
    345 
    346 void Sys_Error (char *error, ...)
    347 {
    348 	va_list		argptr;
    349 	char		text[1024], text2[1024];
    350 	char		*text3 = "Press Enter to exit\n";
    351 	char		*text4 = "***********************************\n";
    352 	char		*text5 = "\n";
    353 	DWORD		dummy;
    354 	double		starttime;
    355 	static int	in_sys_error0 = 0;
    356 	static int	in_sys_error1 = 0;
    357 	static int	in_sys_error2 = 0;
    358 	static int	in_sys_error3 = 0;
    359 
    360 	if (!in_sys_error3)
    361 	{
    362 		in_sys_error3 = 1;
    363 		VID_ForceUnlockedAndReturnState ();
    364 	}
    365 
    366 	va_start (argptr, error);
    367 	vsprintf (text, error, argptr);
    368 	va_end (argptr);
    369 
    370 	if (isDedicated)
    371 	{
    372 		va_start (argptr, error);
    373 		vsprintf (text, error, argptr);
    374 		va_end (argptr);
    375 
    376 		sprintf (text2, "ERROR: %s\n", text);
    377 		WriteFile (houtput, text5, strlen (text5), &dummy, NULL);
    378 		WriteFile (houtput, text4, strlen (text4), &dummy, NULL);
    379 		WriteFile (houtput, text2, strlen (text2), &dummy, NULL);
    380 		WriteFile (houtput, text3, strlen (text3), &dummy, NULL);
    381 		WriteFile (houtput, text4, strlen (text4), &dummy, NULL);
    382 
    383 
    384 		starttime = Sys_FloatTime ();
    385 		sc_return_on_enter = true;	// so Enter will get us out of here
    386 
    387 		while (!Sys_ConsoleInput () &&
    388 				((Sys_FloatTime () - starttime) < CONSOLE_ERROR_TIMEOUT))
    389 		{
    390 		}
    391 	}
    392 	else
    393 	{
    394 	// switch to windowed so the message box is visible, unless we already
    395 	// tried that and failed
    396 		if (!in_sys_error0)
    397 		{
    398 			in_sys_error0 = 1;
    399 			VID_SetDefaultMode ();
    400 			MessageBox(NULL, text, "Quake Error",
    401 					   MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
    402 		}
    403 		else
    404 		{
    405 			MessageBox(NULL, text, "Double Quake Error",
    406 					   MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
    407 		}
    408 	}
    409 
    410 	if (!in_sys_error1)
    411 	{
    412 		in_sys_error1 = 1;
    413 		Host_Shutdown ();
    414 	}
    415 
    416 // shut down QHOST hooks if necessary
    417 	if (!in_sys_error2)
    418 	{
    419 		in_sys_error2 = 1;
    420 		DeinitConProc ();
    421 	}
    422 
    423 	exit (1);
    424 }
    425 
    426 void Sys_Printf (char *fmt, ...)
    427 {
    428 	va_list		argptr;
    429 	char		text[1024];
    430 	DWORD		dummy;
    431 
    432 	if (isDedicated)
    433 	{
    434 		va_start (argptr,fmt);
    435 		vsprintf (text, fmt, argptr);
    436 		va_end (argptr);
    437 
    438 		WriteFile(houtput, text, strlen (text), &dummy, NULL);
    439 	}
    440 }
    441 
    442 void Sys_Quit (void)
    443 {
    444 
    445 	VID_ForceUnlockedAndReturnState ();
    446 
    447 	Host_Shutdown();
    448 
    449 	if (tevent)
    450 		CloseHandle (tevent);
    451 
    452 	if (isDedicated)
    453 		FreeConsole ();
    454 
    455 // shut down QHOST hooks if necessary
    456 	DeinitConProc ();
    457 
    458 	exit (0);
    459 }
    460 
    461 
    462 /*
    463 ================
    464 Sys_FloatTime
    465 ================
    466 */
    467 double Sys_FloatTime (void)
    468 {
    469 	static int			sametimecount;
    470 	static unsigned int	oldtime;
    471 	static int			first = 1;
    472 	LARGE_INTEGER		PerformanceCount;
    473 	unsigned int		temp, t2;
    474 	double				time;
    475 
    476 	Sys_PushFPCW_SetHigh ();
    477 
    478 	QueryPerformanceCounter (&PerformanceCount);
    479 
    480 	temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) |
    481 		   ((unsigned int)PerformanceCount.HighPart << (32 - lowshift));
    482 
    483 	if (first)
    484 	{
    485 		oldtime = temp;
    486 		first = 0;
    487 	}
    488 	else
    489 	{
    490 	// check for turnover or backward time
    491 		if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000))
    492 		{
    493 			oldtime = temp;	// so we can't get stuck
    494 		}
    495 		else
    496 		{
    497 			t2 = temp - oldtime;
    498 
    499 			time = (double)t2 * pfreq;
    500 			oldtime = temp;
    501 
    502 			curtime += time;
    503 
    504 			if (curtime == lastcurtime)
    505 			{
    506 				sametimecount++;
    507 
    508 				if (sametimecount > 100000)
    509 				{
    510 					curtime += 1.0;
    511 					sametimecount = 0;
    512 				}
    513 			}
    514 			else
    515 			{
    516 				sametimecount = 0;
    517 			}
    518 
    519 			lastcurtime = curtime;
    520 		}
    521 	}
    522 
    523 	Sys_PopFPCW ();
    524 
    525     return curtime;
    526 }
    527 
    528 
    529 /*
    530 ================
    531 Sys_InitFloatTime
    532 ================
    533 */
    534 void Sys_InitFloatTime (void)
    535 {
    536 	int		j;
    537 
    538 	Sys_FloatTime ();
    539 
    540 	j = COM_CheckParm("-starttime");
    541 
    542 	if (j)
    543 	{
    544 		curtime = (double) (Q_atof(com_argv[j+1]));
    545 	}
    546 	else
    547 	{
    548 		curtime = 0.0;
    549 	}
    550 
    551 	lastcurtime = curtime;
    552 }
    553 
    554 
    555 char *Sys_ConsoleInput (void)
    556 {
    557 	static char	text[256];
    558 	static int		len;
    559 	INPUT_RECORD	recs[1024];
    560 	int		count;
    561 	int		i, dummy;
    562 	int		ch, numread, numevents;
    563 
    564 	if (!isDedicated)
    565 		return NULL;
    566 
    567 
    568 	for ( ;; )
    569 	{
    570 		if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
    571 			Sys_Error ("Error getting # of console events");
    572 
    573 		if (numevents <= 0)
    574 			break;
    575 
    576 		if (!ReadConsoleInput(hinput, recs, 1, &numread))
    577 			Sys_Error ("Error reading console input");
    578 
    579 		if (numread != 1)
    580 			Sys_Error ("Couldn't read console input");
    581 
    582 		if (recs[0].EventType == KEY_EVENT)
    583 		{
    584 			if (!recs[0].Event.KeyEvent.bKeyDown)
    585 			{
    586 				ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
    587 
    588 				switch (ch)
    589 				{
    590 					case '\r':
    591 						WriteFile(houtput, "\r\n", 2, &dummy, NULL);
    592 
    593 						if (len)
    594 						{
    595 							text[len] = 0;
    596 							len = 0;
    597 							return text;
    598 						}
    599 						else if (sc_return_on_enter)
    600 						{
    601 						// special case to allow exiting from the error handler on Enter
    602 							text[0] = '\r';
    603 							len = 0;
    604 							return text;
    605 						}
    606 
    607 						break;
    608 
    609 					case '\b':
    610 						WriteFile(houtput, "\b \b", 3, &dummy, NULL);
    611 						if (len)
    612 						{
    613 							len--;
    614 						}
    615 						break;
    616 
    617 					default:
    618 						if (ch >= ' ')
    619 						{
    620 							WriteFile(houtput, &ch, 1, &dummy, NULL);
    621 							text[len] = ch;
    622 							len = (len + 1) & 0xff;
    623 						}
    624 
    625 						break;
    626 
    627 				}
    628 			}
    629 		}
    630 	}
    631 
    632 	return NULL;
    633 }
    634 
    635 void Sys_Sleep (void)
    636 {
    637 	Sleep (1);
    638 }
    639 
    640 
    641 void Sys_SendKeyEvents (void)
    642 {
    643     MSG        msg;
    644 
    645 	while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
    646 	{
    647 	// we always update if there are any event, even if we're paused
    648 		scr_skipupdate = 0;
    649 
    650 		if (!GetMessage (&msg, NULL, 0, 0))
    651 			Sys_Quit ();
    652 
    653       	TranslateMessage (&msg);
    654       	DispatchMessage (&msg);
    655 	}
    656 }
    657 
    658 
    659 /*
    660 ==============================================================================
    661 
    662  WINDOWS CRAP
    663 
    664 ==============================================================================
    665 */
    666 
    667 
    668 /*
    669 ==================
    670 WinMain
    671 ==================
    672 */
    673 void SleepUntilInput (int time)
    674 {
    675 
    676 	MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT);
    677 }
    678 
    679 
    680 /*
    681 ==================
    682 WinMain
    683 ==================
    684 */
    685 HINSTANCE	global_hInstance;
    686 int			global_nCmdShow;
    687 char		*argv[MAX_NUM_ARGVS];
    688 static char	*empty_string = "";
    689 HWND		hwnd_dialog;
    690 
    691 
    692 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    693 {
    694     MSG				msg;
    695 	quakeparms_t	parms;
    696 	double			time, oldtime, newtime;
    697 	MEMORYSTATUS	lpBuffer;
    698 	static	char	cwd[1024];
    699 	int				t;
    700 	RECT			rect;
    701 
    702     /* previous instances do not exist in Win32 */
    703     if (hPrevInstance)
    704         return 0;
    705 
    706 	global_hInstance = hInstance;
    707 	global_nCmdShow = nCmdShow;
    708 
    709 	lpBuffer.dwLength = sizeof(MEMORYSTATUS);
    710 	GlobalMemoryStatus (&lpBuffer);
    711 
    712 	if (!GetCurrentDirectory (sizeof(cwd), cwd))
    713 		Sys_Error ("Couldn't determine current directory");
    714 
    715 	if (cwd[Q_strlen(cwd)-1] == '/')
    716 		cwd[Q_strlen(cwd)-1] = 0;
    717 
    718 	parms.basedir = cwd;
    719 	parms.cachedir = NULL;
    720 
    721 	parms.argc = 1;
    722 	argv[0] = empty_string;
    723 
    724 	while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS))
    725 	{
    726 		while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
    727 			lpCmdLine++;
    728 
    729 		if (*lpCmdLine)
    730 		{
    731 			argv[parms.argc] = lpCmdLine;
    732 			parms.argc++;
    733 
    734 			while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
    735 				lpCmdLine++;
    736 
    737 			if (*lpCmdLine)
    738 			{
    739 				*lpCmdLine = 0;
    740 				lpCmdLine++;
    741 			}
    742 
    743 		}
    744 	}
    745 
    746 	parms.argv = argv;
    747 
    748 	COM_InitArgv (parms.argc, parms.argv);
    749 
    750 	parms.argc = com_argc;
    751 	parms.argv = com_argv;
    752 
    753 	isDedicated = (COM_CheckParm ("-dedicated") != 0);
    754 
    755 	if (!isDedicated)
    756 	{
    757 		hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);
    758 
    759 		if (hwnd_dialog)
    760 		{
    761 			if (GetWindowRect (hwnd_dialog, &rect))
    762 			{
    763 				if (rect.left > (rect.top * 2))
    764 				{
    765 					SetWindowPos (hwnd_dialog, 0,
    766 						(rect.left / 2) - ((rect.right - rect.left) / 2),
    767 						rect.top, 0, 0,
    768 						SWP_NOZORDER | SWP_NOSIZE);
    769 				}
    770 			}
    771 
    772 			ShowWindow (hwnd_dialog, SW_SHOWDEFAULT);
    773 			UpdateWindow (hwnd_dialog);
    774 			SetForegroundWindow (hwnd_dialog);
    775 		}
    776 	}
    777 
    778 // take the greater of all the available memory or half the total memory,
    779 // but at least 8 Mb and no more than 16 Mb, unless they explicitly
    780 // request otherwise
    781 	parms.memsize = lpBuffer.dwAvailPhys;
    782 
    783 	if (parms.memsize < MINIMUM_WIN_MEMORY)
    784 		parms.memsize = MINIMUM_WIN_MEMORY;
    785 
    786 	if (parms.memsize < (lpBuffer.dwTotalPhys >> 1))
    787 		parms.memsize = lpBuffer.dwTotalPhys >> 1;
    788 
    789 	if (parms.memsize > MAXIMUM_WIN_MEMORY)
    790 		parms.memsize = MAXIMUM_WIN_MEMORY;
    791 
    792 	if (COM_CheckParm ("-heapsize"))
    793 	{
    794 		t = COM_CheckParm("-heapsize") + 1;
    795 
    796 		if (t < com_argc)
    797 			parms.memsize = Q_atoi (com_argv[t]) * 1024;
    798 	}
    799 
    800 	parms.membase = malloc (parms.memsize);
    801 
    802 	if (!parms.membase)
    803 		Sys_Error ("Not enough memory free; check disk space\n");
    804 
    805 	Sys_PageIn (parms.membase, parms.memsize);
    806 
    807 	tevent = CreateEvent(NULL, FALSE, FALSE, NULL);
    808 
    809 	if (!tevent)
    810 		Sys_Error ("Couldn't create event");
    811 
    812 	if (isDedicated)
    813 	{
    814 		if (!AllocConsole ())
    815 		{
    816 			Sys_Error ("Couldn't create dedicated server console");
    817 		}
    818 
    819 		hinput = GetStdHandle (STD_INPUT_HANDLE);
    820 		houtput = GetStdHandle (STD_OUTPUT_HANDLE);
    821 
    822 	// give QHOST a chance to hook into the console
    823 		if ((t = COM_CheckParm ("-HFILE")) > 0)
    824 		{
    825 			if (t < com_argc)
    826 				hFile = (HANDLE)Q_atoi (com_argv[t+1]);
    827 		}
    828 
    829 		if ((t = COM_CheckParm ("-HPARENT")) > 0)
    830 		{
    831 			if (t < com_argc)
    832 				heventParent = (HANDLE)Q_atoi (com_argv[t+1]);
    833 		}
    834 
    835 		if ((t = COM_CheckParm ("-HCHILD")) > 0)
    836 		{
    837 			if (t < com_argc)
    838 				heventChild = (HANDLE)Q_atoi (com_argv[t+1]);
    839 		}
    840 
    841 		InitConProc (hFile, heventParent, heventChild);
    842 	}
    843 
    844 	Sys_Init ();
    845 
    846 // because sound is off until we become active
    847 	S_BlockSound ();
    848 
    849 	Sys_Printf ("Host_Init\n");
    850 	Host_Init (&parms);
    851 
    852 	oldtime = Sys_FloatTime ();
    853 
    854     /* main window message loop */
    855 	while (1)
    856 	{
    857 		if (isDedicated)
    858 		{
    859 			newtime = Sys_FloatTime ();
    860 			time = newtime - oldtime;
    861 
    862 			while (time < sys_ticrate.value )
    863 			{
    864 				Sys_Sleep();
    865 				newtime = Sys_FloatTime ();
    866 				time = newtime - oldtime;
    867 			}
    868 		}
    869 		else
    870 		{
    871 		// yield the CPU for a little while when paused, minimized, or not the focus
    872 			if ((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing)
    873 			{
    874 				SleepUntilInput (PAUSE_SLEEP);
    875 				scr_skipupdate = 1;		// no point in bothering to draw
    876 			}
    877 			else if (!ActiveApp && !DDActive)
    878 			{
    879 				SleepUntilInput (NOT_FOCUS_SLEEP);
    880 			}
    881 
    882 			newtime = Sys_FloatTime ();
    883 			time = newtime - oldtime;
    884 		}
    885 
    886 		Host_Frame (time);
    887 		oldtime = newtime;
    888 	}
    889 
    890     /* return success of application */
    891     return TRUE;
    892 }
    893 
    894