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 
21 #include "win_local.h"
22 #include "net.h"
23 #include "q_field.h"
24 #include "q_list.h"
25 #include "prompt.h"
26 #include <mmsystem.h>
27 #ifdef DEDICATED_ONLY
28 #include <winsvc.h>
29 #endif
30 #ifdef USE_DBGHELP
31 #include <dbghelp.h>
32 #endif
33 #include "version.h"
34 
35 #define USE_SLEEP
36 
37 #ifndef DEDICATED_ONLY
38 #if !( defined REF_HARD_LINKED ) && !( defined UI_HARD_LINKED )
39 #define USE_MODULES
40 void Sys_ListModules_f( void );
41 #endif
42 #endif
43 
44 sysAPI_t	sys;
45 
46 static cvar_t		*sys_debugdir;
47 
48 #ifndef _WIN32_WCE
49 #define MAX_CONSOLE_INPUT_EVENTS	16
50 
51 static cvar_t		*sys_viewlog;
52 
53 static HANDLE		hinput = INVALID_HANDLE_VALUE;
54 static HANDLE		houtput = INVALID_HANDLE_VALUE;
55 
56 static commandPrompt_t	sys_con;
57 static int				sys_hidden;
58 static CONSOLE_SCREEN_BUFFER_INFO	sbinfo;
59 static qboolean			gotConsole;
60 static qboolean			errorEntered;
61 static qboolean			shouldExit;
62 #endif /* !_WIN32_WCE */
63 
64 #ifdef DEDICATED_ONLY
65 static SERVICE_STATUS_HANDLE	statusHandle;
66 static SERVICE_STATUS			serviceStatus;
67 #endif
68 
69 #ifdef USE_SLEEP
70 static HANDLE		hSocketEvent;
71 #endif
72 
73 HINSTANCE	hGlobalInstance;
74 
75 static qboolean winnt;
76 
77 static char		currentDirectory[MAX_OSPATH];
78 
79 #define SystemTimeToQTime( qtime, systime )			\
80 	( qtime )->tm_sec = ( systime )->wSecond;		\
81 	( qtime )->tm_min = ( systime )->wMinute;		\
82 	( qtime )->tm_hour = ( systime )->wHour;		\
83 	( qtime )->tm_mday = ( systime )->wDay;			\
84 	( qtime )->tm_mon = ( systime )->wMonth;		\
85 	( qtime )->tm_year = ( systime )->wYear;		\
86 	( qtime )->tm_wday = ( systime )->wDayOfWeek;	\
87 	( qtime )->tm_yday = -1;						\
88 	( qtime )->tm_isdst = -1;
89 
90 
91 
92 /*
93 ===============================================================================
94 
95 SYSTEM IO
96 
97 ===============================================================================
98 */
99 
Sys_DebugBreak(void)100 void Sys_DebugBreak( void ) {
101 	DebugBreak();
102 }
103 
104 /*
105 ================
106 Sys_Printf
107 ================
108 */
Sys_Printf(const char * fmt,...)109 void Sys_Printf( const char *fmt, ... ) {
110 	va_list		argptr;
111 	char		msg[MAXPRINTMSG];
112 
113 	va_start( argptr, fmt );
114 	Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
115 	va_end( argptr );
116 
117     Sys_ConsoleOutput( msg );
118 }
119 
120 /*
121 ================
122 Sys_Error
123 ================
124 */
Sys_Error(const char * error,...)125 void Sys_Error( const char *error, ... ) {
126 	va_list		argptr;
127 	char		text[MAXPRINTMSG];
128 
129 	va_start( argptr, error );
130 	Q_vsnprintf( text, sizeof( text ), error, argptr );
131 	va_end( argptr );
132 
133 #ifndef _WIN32_WCE
134 	errorEntered = qtrue;
135 #endif
136 
137 	Sys_Printf( S_COLOR_RED "********************\n"
138                             "FATAL: %s\n"
139                             "********************\n", text );
140 #ifdef DEDICATED_ONLY
141 	if( !statusHandle )
142 #endif
143 	{
144 #ifndef _WIN32_WCE
145 		if( gotConsole ) {
146 			Sleep( INFINITE );
147 		}
148 #endif
149 
150 		MessageBoxA( NULL, text, APPLICATION " Fatal Error", MB_ICONERROR | MB_OK );
151 	}
152 
153 	exit( 1 );
154 }
155 
156 /*
157 ================
158 Sys_Quit
159 ================
160 */
Sys_Quit(void)161 void Sys_Quit( void ) {
162 	timeEndPeriod( 1 );
163 
164 #if !(defined _WIN32_WCE) && !(defined DEDICATED_ONLY)
165 	if( dedicated && dedicated->integer )
166 		FreeConsole();
167 #endif
168 
169 #ifdef DEDICATED_ONLY
170 	if( !statusHandle )
171 #endif
172 		exit( 0 );
173 }
174 
175 #ifndef _WIN32_WCE
176 
Sys_HideInput(void)177 static void Sys_HideInput( void ) {
178 	DWORD		dummy;
179 	int i;
180 
181 	if( !sys_hidden ) {
182 		for( i = 0; i <= sys_con.inputLine.cursorPos; i++ ) {
183 			WriteFile( houtput, "\b \b", 3, &dummy, NULL );
184 		}
185 	}
186 	sys_hidden++;
187 }
188 
Sys_ShowInput(void)189 static void Sys_ShowInput( void ) {
190 	DWORD		dummy;
191 	int i;
192 
193 	if( !sys_hidden ) {
194 		Com_EPrintf( "Sys_ShowInput: not hidden\n" );
195 		return;
196 	}
197 
198 	sys_hidden--;
199 	if( !sys_hidden ) {
200 		WriteFile( houtput, "]", 1, &dummy, NULL );
201 		for( i = 0; i < sys_con.inputLine.cursorPos; i++ ) {
202 			WriteFile( houtput, &sys_con.inputLine.text[i], 1, &dummy, NULL );
203 		}
204 	}
205 }
206 
207 /*
208 ================
209 Sys_ConsoleInput
210 ================
211 */
Sys_ConsoleInput(void)212 char *Sys_ConsoleInput( void ) {
213 	INPUT_RECORD	recs[MAX_CONSOLE_INPUT_EVENTS];
214 	DWORD		dummy;
215 	int		ch;
216 	DWORD numread, numevents;
217 	int i;
218 	inputField_t *f;
219 	char *s;
220 
221 	if( hinput == INVALID_HANDLE_VALUE ) {
222 		return NULL;
223 	}
224 
225 	if( !gotConsole ) {
226 		return NULL;
227 	}
228 
229 	f = &sys_con.inputLine;
230 	while( 1 ) {
231 		if( !GetNumberOfConsoleInputEvents( hinput, &numevents ) ) {
232 			Com_EPrintf( "Error %lu getting number of console events.\n"
233 				"Console IO disabled.\n", GetLastError() );
234 			gotConsole = qfalse;
235 			return NULL;
236 		}
237 
238 		if( numevents <= 0 )
239 			break;
240 		if( numevents > MAX_CONSOLE_INPUT_EVENTS ) {
241 		    numevents = MAX_CONSOLE_INPUT_EVENTS;
242 		}
243 
244 		if( !ReadConsoleInput( hinput, recs, numevents, &numread ) ) {
245 			Com_EPrintf( "Error %lu reading console input.\n"
246 				"Console IO disabled.\n", GetLastError() );
247 			gotConsole = qfalse;
248 			return NULL;
249 		}
250 
251 		for( i = 0; i < numread; i++ ) {
252 			if( recs[i].EventType == WINDOW_BUFFER_SIZE_EVENT ) {
253 				sys_con.widthInChars = recs[i].Event.WindowBufferSizeEvent.dwSize.X;
254 				continue;
255 			}
256 			if( recs[i].EventType != KEY_EVENT ) {
257 				continue;
258 			}
259 
260 			if( !recs[i].Event.KeyEvent.bKeyDown ) {
261 				continue;
262 			}
263 
264 			switch( recs[i].Event.KeyEvent.wVirtualKeyCode ) {
265 			case VK_UP:
266 				Sys_HideInput();
267 				Prompt_HistoryUp( &sys_con );
268 				Sys_ShowInput();
269 				break;
270 			case VK_DOWN:
271 				Sys_HideInput();
272 				Prompt_HistoryDown( &sys_con );
273 				Sys_ShowInput();
274 				break;
275 			case VK_RETURN:
276 				Sys_HideInput();
277 				s = Prompt_Action( &sys_con );
278 				if( s ) {
279 					if( *s == '\\' || *s == '/' ) {
280 						s++;
281 					}
282 					Sys_Printf( "]%s\n", s );
283 				} else {
284 					WriteFile( houtput, "\n", 2, &dummy, NULL );
285 				}
286 				Sys_ShowInput();
287 				return s;
288 			case VK_BACK:
289 				if( f->cursorPos ) {
290 					f->cursorPos--;
291 					f->text[f->cursorPos] = 0;
292 					WriteFile( houtput, "\b \b", 3, &dummy, NULL );
293 				}
294 				break;
295 			case VK_TAB:
296 				Sys_HideInput();
297 				Prompt_CompleteCommand( &sys_con, qfalse );
298 				f->cursorPos = strlen( f->text );
299 				Sys_ShowInput();
300 				break;
301 			default:
302 				ch = recs[i].Event.KeyEvent.uChar.AsciiChar;
303 				if( ch < 32 ) {
304 					break;
305 				}
306 				if( f->cursorPos < sizeof( f->text ) - 1 ) {
307 					WriteFile( houtput, &ch, 1, &dummy, NULL );
308 					f->text[f->cursorPos] = ch;
309 					f->text[f->cursorPos+1] = 0;
310 					f->cursorPos++;
311 				}
312 				break;
313 			}
314 		}
315 	}
316 
317 	return NULL;
318 }
319 
320 #define FOREGROUND_BLACK	0
321 #define FOREGROUND_WHITE	(FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED)
322 
323 static WORD textColors[8] = {
324 	FOREGROUND_BLACK,
325 	FOREGROUND_RED,
326 	FOREGROUND_GREEN,
327 	FOREGROUND_RED|FOREGROUND_GREEN,
328 	FOREGROUND_BLUE,
329 	FOREGROUND_BLUE|FOREGROUND_GREEN,
330 	FOREGROUND_RED|FOREGROUND_BLUE,
331 	FOREGROUND_WHITE
332 };
333 
334 /*
335 ================
336 Sys_ConsoleOutput
337 
338 Print text to the dedicated console
339 ================
340 */
Sys_ConsoleOutput(const char * string)341 void Sys_ConsoleOutput( const char *string ) {
342 	DWORD		dummy;
343 	char	text[MAXPRINTMSG];
344 	char *maxp, *p;
345 	int length;
346 	WORD attr, w;
347 	int c;
348 
349 	if( houtput == INVALID_HANDLE_VALUE ) {
350 		return;
351 	}
352 
353 	if( !gotConsole ) {
354 		p = text;
355 		maxp = text + sizeof( text ) - 1;
356 		while( *string ) {
357 			if( Q_IsColorString( string ) ) {
358 				string += 2;
359 				continue;
360 			}
361 			*p++ = *string++ & 127;
362 			if( p == maxp ) {
363 				break;
364 			}
365 		}
366 
367 		*p = 0;
368 
369 		length = p - text;
370 		WriteFile( houtput, text, length, &dummy, NULL );
371 		return;
372 	}
373 
374 	Sys_HideInput();
375 
376 	attr = sbinfo.wAttributes & ~FOREGROUND_WHITE;
377 
378 	while( *string ) {
379 		if( Q_IsColorString( string ) ) {
380 			c = string[1];
381 			string += 2;
382 			if( c == COLOR_ALT ) {
383 				w = attr | FOREGROUND_GREEN;
384 			} else if( c == COLOR_RESET ) {
385 				w = sbinfo.wAttributes;
386 			} else {
387 				w = attr | textColors[ ColorIndex( c ) ];
388 			}
389 			SetConsoleTextAttribute( houtput, w );
390 			continue;
391 		}
392 
393 		p = text;
394 		maxp = text + sizeof( text ) - 1;
395 		do {
396 			*p++ = *string++ & 127;
397 			if( p == maxp ) {
398 				break;
399 			}
400 		} while( *string && !Q_IsColorString( string ) );
401 
402 		*p = 0;
403 
404 		length = p - text;
405 		WriteFile( houtput, text, length, &dummy, NULL );
406 	}
407 
408 	SetConsoleTextAttribute( houtput, sbinfo.wAttributes );
409 
410 	Sys_ShowInput();
411 }
412 
Sys_ConsoleCtrlHandler(DWORD dwCtrlType)413 static BOOL WINAPI Sys_ConsoleCtrlHandler( DWORD dwCtrlType ) {
414 	if( errorEntered ) {
415 		exit( 1 );
416 	}
417 	/* 32 bit writes are guranteed to be atomic */
418 	shouldExit = qtrue;
419 	return TRUE;
420 }
421 
Sys_ConsoleInit(void)422 static void Sys_ConsoleInit( void ) {
423 	DWORD mode;
424 
425 #ifdef DEDICATED_ONLY
426 	if( statusHandle ) {
427 		return;
428 	}
429 #else
430 	if( !AllocConsole() ) {
431 		Com_EPrintf( "Couldn't create system console.\n"
432 			"Console IO disabled.\n" );
433 		return;
434 	}
435 #endif
436 
437 	hinput = GetStdHandle( STD_INPUT_HANDLE );
438 	houtput = GetStdHandle( STD_OUTPUT_HANDLE );
439 	if( !GetConsoleScreenBufferInfo( houtput, &sbinfo ) ) {
440 		Com_EPrintf( "Couldn't get console buffer info.\n"
441 			"Console IO disabled.\n" );
442 		return;
443 	}
444 
445 	SetConsoleTitle( "q2pro console" );
446 	SetConsoleCtrlHandler( Sys_ConsoleCtrlHandler, TRUE );
447 	GetConsoleMode( hinput, &mode );
448 	mode |= ENABLE_WINDOW_INPUT;
449 	SetConsoleMode( hinput, mode );
450 	sys_con.widthInChars = sbinfo.dwSize.X;
451 	sys_con.Printf = Sys_Printf;
452 	gotConsole = qtrue;
453 
454 	Com_Printf( "System console initialized (%d cols, %d rows).\n",
455 		sbinfo.dwSize.X, sbinfo.dwSize.Y );
456 }
457 
458 #else /* !_WIN32_WCE */
459 
Sys_ConsoleInput(void)460 char *Sys_ConsoleInput( void ) {
461 	return NULL;
462 }
463 
Sys_ConsoleOutput(const char * string)464 void Sys_ConsoleOutput( const char *string ) {
465 	printf( "%s", string );
466 }
467 
468 #endif /* _WIN32_WCE */
469 
470 /*
471 ===============================================================================
472 
473 SERVICE CONTROL
474 
475 ===============================================================================
476 */
477 
478 #ifdef DEDICATED_ONLY
479 
Sys_InstallService_f(void)480 static void Sys_InstallService_f( void ) {
481 	char servicePath[256];
482 	char serviceName[1024];
483 	SC_HANDLE scm, service;
484 	DWORD error, length;
485 	char *commandline;
486 
487 	if( Cmd_Argc() < 3 ) {
488 		Com_Printf( "Usage: %s <servicename> <+command> [...]\n"
489 			"Example: %s test +set net_port 27910 +map q2dm1\n",
490 				Cmd_Argv( 0 ), Cmd_Argv( 0 ) );
491 		return;
492 	}
493 
494 	scm = OpenSCManager( NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS );
495 	if( !scm ) {
496 		error = GetLastError();
497 		if( error == ERROR_ACCESS_DENIED ) {
498 			Com_Printf( "Insufficient privileges for opening Service Control Manager.\n" );
499 		} else {
500 			Com_EPrintf( "%#lx opening Service Control Manager.\n", error );
501 		}
502 		return;
503 	}
504 
505 	Com_sprintf( serviceName, sizeof( serviceName ), "Q2PRO - %s", Cmd_Argv( 1 ) );
506 
507 	length = GetModuleFileName( NULL, servicePath, MAX_PATH );
508 	if( !length ) {
509 		error = GetLastError();
510 		Com_EPrintf( "%#lx getting module file name.\n", error );
511 		goto fail;
512 	}
513 	commandline = Cmd_RawArgsFrom( 2 );
514 	if( length + strlen( commandline ) + 10 > sizeof( servicePath ) - 1 ) {
515 		Com_Printf( "Oversize service command line.\n" );
516 		goto fail;
517 	}
518 	strcpy( servicePath + length, " -service " );
519 	strcpy( servicePath + length + 10, commandline );
520 
521 	service = CreateService(
522 			scm,
523 			serviceName,
524 			serviceName,
525 			SERVICE_START,
526 			SERVICE_WIN32_OWN_PROCESS,
527 			SERVICE_AUTO_START,
528 			SERVICE_ERROR_IGNORE,
529 			servicePath,
530 			NULL,
531 			NULL,
532 			NULL,
533 			NULL,
534 			NULL );
535 
536 	if( !service ) {
537 		error = GetLastError();
538 		if( error == ERROR_SERVICE_EXISTS || error == ERROR_DUPLICATE_SERVICE_NAME ) {
539 			Com_Printf( "Service already exists.\n" );
540 		} else {
541 			Com_EPrintf( "%#lx creating service.\n", error );
542 		}
543 		goto fail;
544 	}
545 
546 	Com_Printf( "Service created successfully.\n" );
547 
548 	CloseServiceHandle( service );
549 
550 fail:
551 	CloseServiceHandle( scm );
552 }
553 
Sys_DeleteService_f(void)554 static void Sys_DeleteService_f( void ) {
555 	char serviceName[256];
556 	SC_HANDLE scm, service;
557 	DWORD error;
558 
559 	if( Cmd_Argc() < 2 ) {
560 		Com_Printf( "Usage: %s <servicename>\n", Cmd_Argv( 0 ) );
561 		return;
562 	}
563 
564 	scm = OpenSCManager( NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS );
565 	if( !scm ) {
566 		error = GetLastError();
567 		if( error == ERROR_ACCESS_DENIED ) {
568 			Com_Printf( "Insufficient privileges for opening Service Control Manager.\n" );
569 		} else {
570 			Com_EPrintf( "%#lx opening Service Control Manager.\n", error );
571 		}
572 		return;
573 	}
574 
575 	Com_sprintf( serviceName, sizeof( serviceName ), "Q2PRO - %s", Cmd_Argv( 1 ) );
576 
577 	service = OpenService(
578 			scm,
579 			serviceName,
580 			DELETE );
581 
582 	if( !service ) {
583 		error = GetLastError();
584 		if( error == ERROR_SERVICE_DOES_NOT_EXIST ) {
585 			Com_Printf( "Service doesn't exist.\n" );
586 		} else {
587 			Com_EPrintf( "%#lx opening service.\n", error );
588 		}
589 		goto fail;
590 	}
591 
592 	if( !DeleteService( service ) ) {
593 		error = GetLastError();
594 		if( error == ERROR_SERVICE_MARKED_FOR_DELETE ) {
595 			Com_Printf( "Service has already been marked for deletion.\n" );
596 		} else {
597 			Com_EPrintf( "%#lx deleting service.\n", error );
598 		}
599 	} else {
600 		Com_Printf( "Service deleted successfully.\n" );
601 	}
602 
603 	CloseServiceHandle( service );
604 
605 fail:
606 	CloseServiceHandle( scm );
607 }
608 
609 #endif
610 
611 /*
612 ===============================================================================
613 
614 HUNK
615 
616 ===============================================================================
617 */
618 
619 #ifdef _WIN32_WCE
620 
621 static int		hunkcount;
622 static int		highwaterMark;
623 
Hunk_Init(int maxsize)624 void Hunk_Init( int maxsize ) {
625 	hunkmaxsize = ( maxsize + 4095 ) & ~4095;
626 	membase = VirtualAlloc( NULL, hunkmaxsize, MEM_RESERVE, PAGE_NOACCESS );
627 	if( !membase ) {
628 		Com_Error( ERR_FATAL,
629             "VirtualAlloc reserve %d bytes failed. GetLastError() = %lu",
630 			maxsize, GetLastError() );
631 	}
632 }
633 
Hunk_Shutdown(void)634 void Hunk_Shutdown( void ) {
635 	if( membase ) {
636 		if( !VirtualFree( membase, 0, MEM_RELEASE ) ) {
637 			Com_Error( ERR_FATAL, "VirtualFree failed. GetLastError() = %lu",
638 				GetLastError() );
639 		}
640 	}
641 	highwaterMark = 0;
642 	cursize = 0;
643 	hunkmaxsize = 0;
644 }
645 
Hunk_Flush(void)646 void Hunk_Flush( void ) {
647 	cursize = 0;
648 }
649 
Hunk_Begin(int maxsize)650 void *Hunk_Begin( int maxsize ) {
651 	return ( void * )( membase + cursize );
652 }
653 
Hunk_Alloc(int size)654 void *Hunk_Alloc( int size ) {
655 	void	*buf;
656 
657 	// round to cacheline
658 	size = ( size + 31 ) & ~ 31;
659 
660 	cursize += size;
661 	if( cursize > hunkmaxsize ) {
662 		Com_Error( ERR_FATAL, "Hunk_Alloc: couldn't allocate %d bytes", size );
663 	}
664 
665 	if( highwaterMark < cursize ) {
666 		// commit pages as needed
667 		buf = VirtualAlloc( membase, cursize, MEM_COMMIT, PAGE_READWRITE );
668 		if( !buf ) {
669 			Com_Error( ERR_FATAL,
670 				"VirtualAlloc commit %d bytes failed. GetLastError() = %lu",
671 				cursize, GetLastError() );
672 		}
673 		highwaterMark = cursize;
674 	}
675 
676 	return ( void * )( membase + cursize - size );
677 }
678 
Hunk_End(void)679 int Hunk_End( void ) {
680 	hunkcount++;
681 	return cursize;
682 }
683 
Hunk_Free(void * base)684 void Hunk_Free( void *base ) {
685 	hunkcount--;
686 
687 	if( hunkcount == 0 ) {
688 		cursize = 0;
689 	}
690 }
691 
692 #else
693 
Hunk_Begin(mempool_t * pool,int maxsize)694 void Hunk_Begin( mempool_t *pool, int maxsize ) {
695 	// reserve a huge chunk of memory, but don't commit any yet
696 	pool->cursize = 0;
697 	pool->maxsize = ( maxsize + 4095 ) & ~4095;
698 	pool->base = VirtualAlloc( NULL, pool->maxsize, MEM_RESERVE, PAGE_NOACCESS );
699 	if( !pool->base ) {
700 		Com_Error( ERR_FATAL,
701             "VirtualAlloc reserve %d bytes failed. GetLastError() = %lu",
702 			pool->maxsize, GetLastError() );
703 	}
704 }
705 
Hunk_Alloc(mempool_t * pool,int size)706 void *Hunk_Alloc( mempool_t *pool, int size ) {
707 	void	*buf;
708 
709 	// round to cacheline
710 	size = ( size + 31 ) & ~ 31;
711 
712 	pool->cursize += size;
713 	if( pool->cursize > pool->maxsize )
714 		Com_Error( ERR_FATAL, "Hunk_Alloc: couldn't allocate %d bytes", size );
715 
716 	// commit pages as needed
717 	buf = VirtualAlloc( pool->base, pool->cursize, MEM_COMMIT, PAGE_READWRITE );
718 	if( !buf ) {
719 		Com_Error( ERR_FATAL,
720             "VirtualAlloc commit %d bytes failed. GetLastError() = %lu",
721 			pool->cursize, GetLastError() );
722 	}
723 
724 	return ( void * )( pool->base + pool->cursize - size );
725 }
726 
Hunk_End(mempool_t * pool)727 void Hunk_End( mempool_t *pool ) {
728 }
729 
Hunk_Free(mempool_t * pool)730 void Hunk_Free( mempool_t *pool ) {
731 	if( pool->base ) {
732 		if( !VirtualFree( pool->base, 0, MEM_RELEASE ) ) {
733 			Com_Error( ERR_FATAL, "VirtualFree failed. GetLastError() = %lu",
734 				GetLastError() );
735 		}
736 	}
737 
738 	memset( pool, 0, sizeof( pool ) );
739 }
740 
741 #endif
742 
743 /*
744 ===============================================================================
745 
746 MISC
747 
748 ===============================================================================
749 */
750 
751 /*
752 ================
753 Sys_Milliseconds
754 ================
755 */
Sys_Milliseconds(void)756 int Sys_Milliseconds( void ) {
757 	static uint32		base;
758 	static qboolean	initialized = qfalse;
759 	int	curtime;
760 
761 	if( !initialized ) {
762 		// let base retain 16 bits of effectively random data
763 		base = timeGetTime() & 0xffff0000;
764 		initialized = qtrue;
765 	}
766 	curtime = timeGetTime() - base;
767 
768 	return curtime;
769 }
770 
Sys_Realtime(void)771 uint32 Sys_Realtime( void ) {
772 	return timeGetTime();
773 }
774 
775 /*
776 ================
777 Sys_Sleep
778 
779 Sleep for specified amount of time until there are pending
780 events in our thread queue or incoming network packets.
781 ================
782 */
Sys_Sleep(uint32 msec)783 void Sys_Sleep( uint32 msec ) {
784 #ifdef USE_SLEEP
785 	DWORD result;
786 
787 	if( dedicated->integer ) {
788 		result = WaitForSingleObject( hSocketEvent, msec );
789 	} else {
790 		result = MsgWaitForMultipleObjects( 1, &hSocketEvent, FALSE, msec, QS_ALLEVENTS );
791 	}
792 	if( result == WAIT_FAILED ) {
793 		Sys_Error( "Sys_Sleep failed" );
794 	}
795 	if( result == WAIT_OBJECT_0 ) {
796 		ResetEvent( hSocketEvent );
797 	}
798 #endif
799 }
800 
801 /*
802 ================
803 Sys_Mkdir
804 ================
805 */
Sys_Mkdir(const char * path)806 void Sys_Mkdir( const char *path ) {
807 	CreateDirectoryA( path, NULL );
808 }
809 
Sys_RemoveFile(const char * path)810 qboolean Sys_RemoveFile( const char *path ) {
811 	if( !DeleteFileA( path ) ) {
812 		return qfalse;
813 	}
814 	return qtrue;
815 }
816 
Sys_RenameFile(const char * from,const char * to)817 qboolean Sys_RenameFile( const char *from, const char *to ) {
818 	if( !MoveFileA( from, to ) ) {
819 		return qfalse;
820 	}
821 	return qtrue;
822 }
823 
824 /*
825 ================
826 Sys_GetFileInfo
827 ================
828 */
Sys_GetFileInfo(const char * path,fsFileInfo_t * info)829 qboolean Sys_GetFileInfo( const char *path, fsFileInfo_t *info ) {
830 	WIN32_FILE_ATTRIBUTE_DATA	data;
831 	SYSTEMTIME	systemTime;
832 	BOOL bSuccess;
833 
834 	bSuccess = GetFileAttributesExA( path, GetFileExInfoStandard, &data );
835 	if( !bSuccess ) {
836 		return qfalse;
837 	}
838 
839 	if( !info ) {
840 		return qtrue;
841 	}
842 
843 	info->fileSize = data.nFileSizeLow;
844 
845 	bSuccess = FileTimeToSystemTime( &data.ftCreationTime, &systemTime );
846 	if( !bSuccess ) {
847 		return qfalse;
848 	}
849 	SystemTimeToQTime( &info->timeCreate, &systemTime );
850 
851 	bSuccess = FileTimeToSystemTime( &data.ftLastWriteTime, &systemTime );
852 	if( !bSuccess ) {
853 		return qfalse;
854 	}
855 	SystemTimeToQTime( &info->timeModify, &systemTime );
856 
857 	return qtrue;
858 }
859 
860 /*
861 ================
862 Sys_GetClipboardData
863 
864 ================
865 */
Sys_GetClipboardData(void)866 char *Sys_GetClipboardData( void ) {
867 	char *data = NULL;
868 	char *cliptext;
869 
870 	if( OpenClipboard( NULL ) != FALSE ) {
871 		HANDLE hClipboardData;
872 
873 		if( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != NULL ) {
874 			if( ( cliptext = GlobalLock( hClipboardData ) ) != NULL ) {
875 				data = Z_CopyString( cliptext );
876 				GlobalUnlock( hClipboardData );
877 			}
878 		}
879 		CloseClipboard();
880 	}
881 	return data;
882 }
883 
884 /*
885 ================
886 Sys_SetClipboardData
887 
888 ================
889 */
Sys_SetClipboardData(const char * data)890 void Sys_SetClipboardData( const char *data ) {
891 	char *cliptext;
892 	int	length;
893 
894 	if( OpenClipboard( NULL ) != FALSE ) {
895 		HANDLE hClipboardData;
896 
897 		length = strlen( data );
898 		hClipboardData = GlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE, length + 1 );
899 
900 		if( SetClipboardData( CF_TEXT, hClipboardData ) != NULL ) {
901 			if( ( cliptext = GlobalLock( hClipboardData ) ) != NULL ) {
902 				strcpy( cliptext, data );
903 				cliptext[length] = 0;
904 				GlobalUnlock( hClipboardData );
905 			}
906 		}
907 		CloseClipboard();
908 	}
909 }
910 
911 
912 /*
913 ================
914 Sys_FillAPI
915 ================
916 */
Sys_FillAPI(sysAPI_t * api)917 void Sys_FillAPI( sysAPI_t *api ) {
918 	api->Milliseconds = Sys_Milliseconds;
919 	api->GetClipboardData = Sys_GetClipboardData;
920 	api->SetClipboardData = Sys_SetClipboardData;
921 	api->HunkBegin = Hunk_Begin;
922 	api->HunkAlloc = Hunk_Alloc;
923     api->HunkEnd = Hunk_End;
924 	api->HunkFree = Hunk_Free;
925 }
926 
927 /*
928 ================
929 Sys_Init
930 ================
931 */
Sys_Init(void)932 void Sys_Init( void ) {
933 	OSVERSIONINFO	vinfo;
934 
935 	timeBeginPeriod( 1 );
936 
937 	vinfo.dwOSVersionInfoSize = sizeof( vinfo );
938 
939 	if( !GetVersionEx( &vinfo ) ) {
940 		Sys_Error( "Couldn't get OS info" );
941 	}
942 
943 	winnt = qtrue;
944 	if( vinfo.dwMajorVersion < 4 ) {
945 		Sys_Error( APPLICATION " requires windows version 4 or greater" );
946 	}
947 	if( vinfo.dwPlatformId == VER_PLATFORM_WIN32s ) {
948 		Sys_Error( APPLICATION " doesn't run on Win32s" );
949 	} else if( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) {
950 		if( vinfo.dwMinorVersion == 0 ) {
951 			Sys_Error( APPLICATION " doesn't run on Win95" );
952 		}
953 		winnt = qfalse;
954 	}
955 
956 	sys_debugdir = Cvar_Get( "sys_debugdir", "", CVAR_NOSET );
957 
958 	Cvar_Get( "sys_hinstance", va( "0x%x", ( UINT_PTR )hGlobalInstance ),
959             CVAR_ROM );
960 	Cvar_Get( "sys_winnt", va( "%i", winnt ), CVAR_ROM );
961 
962 #ifdef USE_MODULES
963 	Cmd_AddCommand( "listmodules", Sys_ListModules_f );
964 #endif
965 
966 #ifdef DEDICATED_ONLY
967 	Cmd_AddCommand( "installservice", Sys_InstallService_f );
968 	Cmd_AddCommand( "deleteservice", Sys_DeleteService_f );
969 #endif
970 
971 #ifdef _WIN32_WCE
972 	{
973 		MEMORYSTATUS   memInfo;
974 
975 		memInfo.dwLength = sizeof( memInfo );
976 		GlobalMemoryStatus( &memInfo );
977 
978 		Com_Printf( "Total RAM: %d, free: %d, used: %d",
979 			memInfo.dwTotalPhys, memInfo.dwAvailPhys, memInfo.dwTotalPhys - memInfo.dwAvailPhys );
980 
981 	}
982 #else
983 	sys_viewlog = Cvar_Get( "sys_viewlog", "0", CVAR_NOSET );
984 
985 	houtput = GetStdHandle( STD_OUTPUT_HANDLE );
986 
987 	if( dedicated->integer || sys_viewlog->integer ) {
988 		Sys_ConsoleInit();
989 	}
990 #endif /* !_WIN32_WCE */
991 
992 #ifdef USE_SLEEP
993 	hSocketEvent = WSACreateEvent();
994 #endif
995 
996 	Sys_FillAPI( &sys );
997 }
998 
999 /*
1000 ===============================================================================
1001 
1002 NETWORKING
1003 
1004 ===============================================================================
1005 */
1006 
1007 /*
1008 ====================
1009 Sys_NetErrorString
1010 ====================
1011 */
Sys_NetErrorString(void)1012 char *Sys_NetErrorString( void ) {
1013 	int		code;
1014 	char	*s;
1015 
1016 	code = WSAGetLastError();
1017 
1018 	switch( code ) {
1019 	case S_OK: s = "NO ERROR"; break;
1020 	default: s = "UNKNOWN ERROR"; break;
1021 
1022 #define MAPERR( x )		case x: s = #x; break;
1023 
1024 	MAPERR( WSAEINTR )
1025 	MAPERR( WSAEBADF )
1026 	MAPERR( WSAEACCES )
1027 	MAPERR( WSAEFAULT )
1028 	MAPERR( WSAEINVAL )
1029 	MAPERR( WSAEMFILE )
1030 	MAPERR( WSAEWOULDBLOCK )
1031 	MAPERR( WSAEINPROGRESS )
1032 	MAPERR( WSAEALREADY )
1033 	MAPERR( WSAENOTSOCK )
1034 	MAPERR( WSAEDESTADDRREQ )
1035 	MAPERR( WSAEMSGSIZE )
1036 	MAPERR( WSAEPROTOTYPE )
1037 	MAPERR( WSAENOPROTOOPT )
1038 	MAPERR( WSAEPROTONOSUPPORT )
1039 	MAPERR( WSAESOCKTNOSUPPORT )
1040 	MAPERR( WSAEOPNOTSUPP )
1041 	MAPERR( WSAEPFNOSUPPORT )
1042 	MAPERR( WSAEAFNOSUPPORT )
1043 	MAPERR( WSAEADDRINUSE )
1044 	MAPERR( WSAEADDRNOTAVAIL )
1045 	MAPERR( WSAENETDOWN )
1046 	MAPERR( WSAENETUNREACH )
1047 	MAPERR( WSAENETRESET )
1048 	MAPERR( WSAECONNABORTED )
1049 	MAPERR( WSAECONNRESET )
1050 	MAPERR( WSAENOBUFS )
1051 	MAPERR( WSAEISCONN )
1052 	MAPERR( WSAENOTCONN )
1053 	MAPERR( WSAESHUTDOWN )
1054 	MAPERR( WSAETOOMANYREFS )
1055 	MAPERR( WSAETIMEDOUT )
1056 	MAPERR( WSAECONNREFUSED )
1057 	MAPERR( WSAELOOP )
1058 	MAPERR( WSAENAMETOOLONG )
1059 	MAPERR( WSAEHOSTDOWN )
1060 	MAPERR( WSAEHOSTUNREACH )
1061 	MAPERR( WSAENOTEMPTY )
1062 	MAPERR( WSAEPROCLIM )
1063 	MAPERR( WSAEUSERS )
1064 	MAPERR( WSAEDQUOT )
1065 	MAPERR( WSAESTALE )
1066 	MAPERR( WSAEREMOTE )
1067 	MAPERR( WSASYSNOTREADY )
1068 	MAPERR( WSAVERNOTSUPPORTED )
1069 	MAPERR( WSANOTINITIALISED )
1070 	MAPERR( WSAEDISCON )
1071 	MAPERR( WSAENOMORE )
1072 	MAPERR( WSAECANCELLED )
1073 	MAPERR( WSAEINVALIDPROCTABLE )
1074 	MAPERR( WSAEINVALIDPROVIDER )
1075 	MAPERR( WSAEPROVIDERFAILEDINIT )
1076 	MAPERR( WSASYSCALLFAILURE )
1077 	MAPERR( WSASERVICE_NOT_FOUND )
1078 	MAPERR( WSATYPE_NOT_FOUND )
1079 	MAPERR( WSA_E_NO_MORE )
1080 	MAPERR( WSA_E_CANCELLED )
1081 	MAPERR( WSAEREFUSED )
1082 	MAPERR( WSAHOST_NOT_FOUND )
1083 	MAPERR( WSATRY_AGAIN )
1084 	MAPERR( WSANO_RECOVERY )
1085 	MAPERR( WSANO_DATA )
1086 	}
1087 
1088 #undef MAPERR
1089 
1090 	return s;
1091 }
1092 
1093 /*
1094 ====================
1095 Sys_IPSocket
1096 ====================
1097 */
Sys_IPSocket(const char * net_interface,int port)1098 SOCKET Sys_IPSocket( const char *net_interface, int port ) {
1099 	SOCKET				newsocket;
1100 	struct sockaddr_in	address;
1101 	qboolean			_true = qtrue;
1102 	int					i = 1;
1103 	int					err;
1104 
1105 	if( !net_interface || !net_interface[0] ) {
1106 		net_interface = "localhost";
1107 	}
1108 
1109 	Com_Printf( "Opening IP socket: %s:%i\n", net_interface, port );
1110 
1111 	if( ( newsocket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
1112 		err = WSAGetLastError();
1113 		if( err != WSAEAFNOSUPPORT )
1114 			Com_WPrintf( "UDP_OpenSocket: socket: %s", Sys_NetErrorString() );
1115 		return INVALID_SOCKET;
1116 	}
1117 
1118 	// make it non-blocking
1119 	if( ioctlsocket( newsocket, FIONBIO, (u_long *)&_true ) == SOCKET_ERROR ) {
1120 		Com_WPrintf( "UDP_OpenSocket: ioctl FIONBIO: %s\n", Sys_NetErrorString() );
1121 		goto fail;
1122 	}
1123 
1124 	// make it broadcast capable
1125 	if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof( i ) ) == SOCKET_ERROR ) {
1126 		Com_WPrintf( "UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", Sys_NetErrorString() );
1127 		goto fail;
1128 	}
1129 
1130 	if( !Q_stricmp( net_interface, "localhost" ) ) {
1131 		address.sin_addr.s_addr = INADDR_ANY;
1132 	} else {
1133 		NET_StringToSockaddr( net_interface, (struct sockaddr *)&address );
1134 	}
1135 
1136 	if( port == PORT_ANY ) {
1137 		address.sin_port = 0;
1138 	} else {
1139 		address.sin_port = htons( (u_short)port );
1140 	}
1141 
1142 	address.sin_family = AF_INET;
1143 
1144 	if( bind( newsocket, (void *)&address, sizeof( address ) ) == SOCKET_ERROR ) {
1145 		Com_WPrintf( "UDP_OpenSocket: bind: %s\n", Sys_NetErrorString() );
1146 		goto fail;
1147 	}
1148 
1149 #ifdef USE_SLEEP
1150 	if( WSAEventSelect( newsocket, hSocketEvent, FD_READ ) == SOCKET_ERROR ) {
1151 		Com_WPrintf( "UDP_OpenSocket: WSAEventSelect: %s\n", Sys_NetErrorString() );
1152 		goto fail;
1153 	}
1154 #endif
1155 
1156 	return newsocket;
1157 
1158 fail:
1159 	closesocket( newsocket );
1160 	return INVALID_SOCKET;
1161 }
1162 
1163 /*
1164 ====================
1165 Sys_CloseSocket
1166 ====================
1167 */
Sys_CloseSocket(SOCKET sock)1168 void Sys_CloseSocket( SOCKET sock ) {
1169 	closesocket( sock );
1170 }
1171 
1172 /*
1173 ====================
1174 Sys_InitNetworking
1175 ====================
1176 */
Sys_InitNetworking(void)1177 qboolean Sys_InitNetworking( void ) {
1178 	WSADATA		winsockdata;
1179 	int		r;
1180 	char *errmsg;
1181 
1182 	r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
1183 	if( r ) {
1184 		errmsg = va( "Winsock initialization failed, returned %i", r );
1185 		if( dedicated->integer ) {
1186 			Com_Error( ERR_FATAL, "%s", errmsg );
1187 		}
1188 
1189 		Com_WPrintf( "%s\n", errmsg );
1190 		return qfalse;
1191 	}
1192 
1193 	Com_Printf( "Winsock Initialized\n" );
1194 
1195 	return qtrue;
1196 }
1197 
1198 /*
1199 ====================
1200 Sys_ShutdownNetworking
1201 ====================
1202 */
Sys_ShutdownNetworking(void)1203 void Sys_ShutdownNetworking( void ) {
1204 	WSACleanup();
1205 }
1206 
1207 /*
1208 ========================================================================
1209 
1210 DLL LOADING
1211 
1212 ========================================================================
1213 */
1214 
1215 #ifdef USE_MODULES
1216 
1217 typedef struct sysModule_s {
1218 	listElem_t	elem;
1219 	void *handle;
1220 	moduleEntry_t entry;
1221 	int refCount;
1222 	char name[1];
1223 } sysModule_t;
1224 
1225 static list_t sys_moduleList;
1226 
1227 /*
1228 =================
1229 Sys_FreeModule
1230 =================
1231 */
Sys_FreeModule(void * handle)1232 void Sys_FreeModule( void *handle ) {
1233 	sysModule_t *module = ( sysModule_t * )handle;
1234 
1235 	if( module ) {
1236 		if( --module->refCount < 1 ) {
1237 			if( module->refCount < 0 ) {
1238 				Com_Error( ERR_FATAL, "Sys_FreeModule: freed a freed module" );
1239 			}
1240 			if( !FreeLibrary( module->handle ) ) {
1241 				Com_Error( ERR_FATAL, "Sys_FreeModule: FreeLibrary failed" );
1242 			}
1243 			List_DeleteElem( module );
1244 			Z_Free( module );
1245 		}
1246 	}
1247 }
1248 
1249 /*
1250 =================
1251 Sys_LoadModule
1252 =================
1253 */
Sys_LoadModule(const char * name,void ** handle)1254 moduleEntry_t Sys_LoadModule( const char *name, void **handle ) {
1255 	HMODULE		hModule;
1256 	moduleEntry_t moduleEntry;
1257 	char	fullname[MAX_OSPATH];
1258 	sysModule_t *module;
1259 	listElem_t *elem;
1260 
1261 	for( elem = sys_moduleList.first; elem; elem = elem->next ) {
1262 		module = ( sysModule_t * )elem;
1263 		if( !strcmp( module->name, name ) ) {
1264 			break;
1265 		}
1266 	}
1267 
1268 	if( elem != NULL ) {
1269 		module->refCount++;
1270 		*handle = ( void * )module;
1271 		return module->entry;
1272 	}
1273 
1274 	*handle = NULL;
1275 	hModule = NULL;
1276 
1277 	// check the current debug directory first for development purposes
1278 	if( sys_debugdir->string[0] ) {
1279 		Com_sprintf( fullname, sizeof( fullname ), "%s\\%s.dll", sys_debugdir->string, name );
1280 		hModule = LoadLibraryA( fullname );
1281 		if( !hModule ) {
1282 			Com_DPrintf(
1283                 "Sys_LoadModule( %s ): LoadLibrary failed with error %lu\n",
1284 				fullname, GetLastError() );
1285 		}
1286 	}
1287 
1288 	if( !hModule ) {
1289 		// check the baseq2pro directory
1290 		Com_sprintf( fullname, sizeof( fullname ), "%s\\"INITDIRNAME"\\%s.dll",
1291 			Cvar_VariableString( "basedir" ), name );
1292 		hModule = LoadLibraryA( fullname );
1293 		if( !hModule ) {
1294 			Com_DPrintf(
1295                 "Sys_LoadModule( %s ): LoadLibrary failed with error %lu\n",
1296 				fullname, GetLastError() );
1297 			return NULL;
1298 		}
1299 	}
1300 
1301 	moduleEntry = ( void * )GetProcAddress( hModule, __TEXT( "moduleEntry" ) );
1302 	if( !moduleEntry ) {
1303 		Com_DPrintf(
1304             "Sys_LoadModule( %s ): GetProcAddress failed with error %lu\n",
1305 			fullname, GetLastError() );
1306 		FreeLibrary( hModule );
1307 		return NULL;
1308 	}
1309 
1310 	Com_DPrintf( "Sys_LoadModule( %s ) succeeded\n", fullname );
1311 
1312 	module = Z_Malloc( sizeof( *module ) + strlen( name ) );
1313 	module->refCount = 1;
1314 	module->handle = hModule;
1315 	module->entry = moduleEntry;
1316 	strcpy( module->name, name );
1317 	List_Append( &sys_moduleList, module );
1318 
1319 	*handle = module;
1320 
1321 	return moduleEntry;
1322 }
1323 
1324 /*
1325 =================
1326 Sys_ListModules_f
1327 =================
1328 */
Sys_ListModules_f(void)1329 void Sys_ListModules_f( void ) {
1330 	listElem_t *elem;
1331 	sysModule_t *module;
1332 	moduleInfo_t info;
1333 	int numElems;
1334 
1335 	numElems = 0;
1336 	for( elem = sys_moduleList.first; elem; elem = elem->next ) {
1337 		module = ( sysModule_t * )elem;
1338 
1339 		Com_Printf( "Module  : %s\n", module->name );
1340 		Com_Printf( "RefCount: %i\n", module->refCount );
1341 
1342 		if( !module->entry( MQ_GETINFO, &info ) ) {
1343 			Com_EPrintf( "Couldn't get module info\n" );
1344 			continue;
1345 		}
1346 
1347 		Com_Printf( "Name    : %s\n", info.fullname );
1348 		Com_Printf( "Author  : %s\n", info.author );
1349 		Com_Printf( "\n" );
1350 		numElems++;
1351 	}
1352 
1353 	Com_Printf( "----------------\n" );
1354 	Com_Printf( "%i total modules\n", numElems );
1355 }
1356 
1357 #endif /* USE_MODULES */
1358 
1359 //=======================================================================
1360 
1361 static HMODULE	gameLibrary;
1362 
1363 #ifdef ARM
1364 #define GAMELIB		"gamearmv4.dll"
1365 #else
1366 #define GAMELIB		"gamex86.dll"
1367 #endif
1368 
1369 /*
1370 =================
1371 Sys_FreeGameLibrary
1372 =================
1373 */
Sys_FreeGameLibrary(void)1374 void Sys_FreeGameLibrary( void ) {
1375 	if( !gameLibrary ) {
1376 		return;
1377 	}
1378 	if( !FreeLibrary( gameLibrary ) ) {
1379 		Com_Error( ERR_FATAL, "Sys_FreeGameLibrary failed!" );
1380 	}
1381 	gameLibrary = NULL;
1382 }
1383 
1384 /*
1385 =================
1386 Sys_LoadLibrary
1387 =================
1388 */
Sys_LoadGameLibrary(void * parms)1389 void *Sys_LoadGameLibrary( void *parms ) {
1390 	void	*(*GetAPI)( void * );
1391 	char	fullname[MAX_OSPATH];
1392 	char	*path;
1393 #ifdef NDEBUG
1394 	const char *debugdir = "release";
1395 #else
1396 	const char *debugdir = "debug";
1397 #endif
1398 
1399 	if( gameLibrary ) {
1400 		Sys_FreeGameLibrary();
1401 	}
1402 
1403 	// check the current debug directory first for development purposes
1404 	if( sys_debugdir->string[0] ) {
1405 		Com_sprintf( fullname, sizeof( fullname ), "%s\\"GAMELIB, sys_debugdir->string );
1406 	} else {
1407 		Com_sprintf( fullname, sizeof( fullname ), "%s\\%s\\"GAMELIB, currentDirectory, debugdir );
1408 	}
1409 
1410 	gameLibrary = LoadLibraryA( fullname );
1411 	if( !gameLibrary ) {
1412 #if 0//ndef NDEBUG
1413 		Com_DPrintf( "Sys_LoadLibrary( %s ) failed with error %d\n", fullname, GetLastError() );
1414 
1415 		// check the current directory for other development purposes
1416 		Com_sprintf( fullname, sizeof( fullname ), "%s\\"GAMELIB, currentDirectory );
1417 		hModule = LoadLibraryA( fullname );
1418 		if( !hModule )
1419 #endif
1420 		{
1421 			Com_DPrintf( "Sys_LoadLibrary( %s ) failed with error %lu\n",
1422                     fullname, GetLastError() );
1423 			// now run through the search paths
1424 			path = NULL;
1425 			while( 1 ) {
1426 				path = FS_NextPath( path );
1427 				if( !path ) {
1428 					break;		// couldn't find one anywhere
1429 				}
1430 				Com_sprintf( fullname, sizeof( fullname ), "%s\\"GAMELIB, path );
1431 				gameLibrary = LoadLibraryA( fullname );
1432 				if( gameLibrary ) {
1433 					break;
1434 				}
1435 				Com_DPrintf( "Sys_LoadLibrary( %s ) failed with error %lu\n",
1436                         fullname, GetLastError() );
1437 			}
1438 		}
1439 	}
1440 
1441 	if( !gameLibrary ) {
1442 		return NULL;
1443 	}
1444 
1445 	GetAPI = ( void * )GetProcAddress( gameLibrary, __TEXT( "GetGameAPI" ) );
1446 	if( !GetAPI ) {
1447 		Com_DPrintf( "Sys_LoadLibrary( %s ) failed with error %lu\n",
1448                 fullname, GetLastError() );
1449 		Sys_FreeGameLibrary();
1450 		return NULL;
1451 	}
1452 
1453 	Com_DPrintf( "Sys_LoadLibrary( %s ) succeeded\n", fullname );
1454 
1455 	return GetAPI( parms );
1456 }
1457 
1458 //=======================================================================
1459 
Sys_FindInfoToExtraInfo(WIN32_FIND_DATAA * findInfo,fsFileInfo_t * info)1460 static qboolean Sys_FindInfoToExtraInfo( WIN32_FIND_DATAA *findInfo, fsFileInfo_t *info ) {
1461 	SYSTEMTIME	systemTime;
1462 	BOOL	bSuccess;
1463 
1464 	info->fileSize = findInfo->nFileSizeLow;
1465 
1466 	bSuccess = FileTimeToSystemTime( &findInfo->ftCreationTime, &systemTime );
1467 	if( !bSuccess ) {
1468 		return qfalse;
1469 	}
1470 	SystemTimeToQTime( &info->timeCreate, &systemTime );
1471 
1472 	bSuccess = FileTimeToSystemTime( &findInfo->ftLastWriteTime, &systemTime );
1473 	if( !bSuccess ) {
1474 		return qfalse;
1475 	}
1476 	SystemTimeToQTime( &info->timeModify, &systemTime );
1477 
1478 	return qtrue;
1479 }
1480 
1481 /*
1482 =================
1483 Sys_ListFilteredFiles
1484 =================
1485 */
Sys_ListFilteredFiles(char ** listedFiles,int * count,const char * path,const char * filter,uint32 flags,int length)1486 static void Sys_ListFilteredFiles( char **listedFiles, int *count, const char *path,
1487 								  const char *filter, uint32 flags, int length )
1488 {
1489 	WIN32_FIND_DATAA	findInfo;
1490 	HANDLE		findHandle;
1491 	char	findPath[MAX_OSPATH];
1492 	char	dirPath[MAX_OSPATH];
1493 	fsFileInfo_t	info;
1494 	char	*name;
1495 
1496 	if( *count >= MAX_LISTED_FILES ) {
1497 		return;
1498 	}
1499 
1500 	Com_sprintf( findPath, sizeof( findPath ), "%s\\*", path );
1501 
1502 	findHandle = FindFirstFileA( findPath, &findInfo );
1503 	if( findHandle == INVALID_HANDLE_VALUE ) {
1504 		return;
1505 	}
1506 
1507 	do {
1508 		if( !strcmp( findInfo.cFileName, "." ) || !strcmp( findInfo.cFileName, ".." ) ) {
1509 			continue;
1510 		}
1511 
1512 		if( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
1513 			Com_sprintf( dirPath, sizeof( dirPath ), "%s\\%s", path, findInfo.cFileName );
1514 			Sys_ListFilteredFiles( listedFiles, count, dirPath, filter, flags, length );
1515 		}
1516 
1517 		if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) {
1518 			if( !( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
1519 				continue;
1520 			}
1521 		} else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) {
1522 			if( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
1523 				continue;
1524 			}
1525 		}
1526 
1527 		Com_sprintf( dirPath, sizeof( dirPath ), "%s\\%s", path, findInfo.cFileName );
1528 		if( !FS_WildCmp( filter, dirPath + length ) ) {
1529 			continue;
1530 		}
1531 
1532 		name = ( flags & FS_SEARCH_SAVEPATH ) ? dirPath + length : findInfo.cFileName;
1533 
1534 		if( flags & FS_SEARCH_EXTRAINFO ) {
1535 			Sys_FindInfoToExtraInfo( &findInfo, &info );
1536 			listedFiles[( *count )++] = FS_CopyExtraInfo( name, &info );
1537 		} else {
1538 			listedFiles[( *count )++] = Z_CopyString( name );
1539 		}
1540 
1541 	} while( *count < MAX_LISTED_FILES && FindNextFileA( findHandle, &findInfo ) != FALSE );
1542 
1543 	FindClose( findHandle );
1544 
1545 }
1546 
1547 /*
1548 =================
1549 Sys_ListFiles
1550 =================
1551 */
Sys_ListFiles(const char * rawPath,const char * extension,uint32 flags,int * numFiles)1552 char **Sys_ListFiles( const char *rawPath, const char *extension, uint32 flags, int *numFiles ) {
1553 	WIN32_FIND_DATAA	findInfo;
1554 	HANDLE		findHandle;
1555 	char	path[MAX_OSPATH];
1556 	char	findPath[MAX_OSPATH];
1557 	char	*listedFiles[MAX_LISTED_FILES];
1558 	int		count;
1559 	char	**list;
1560 	int		i, length;
1561 	fsFileInfo_t	info;
1562 	char	*name;
1563 
1564 	count = 0;
1565 
1566 	if( numFiles ) {
1567 		*numFiles = 0;
1568 	}
1569 
1570 	Q_strncpyz( path, rawPath, sizeof( path ) );
1571 	Com_ReplaceSeparators( path, '\\' );
1572 
1573 	if( flags & FS_SEARCH_BYFILTER ) {
1574 		length = strlen( path );
1575         if( !length ) {
1576             return NULL;
1577         }
1578 		Q_strncpyz( findPath, extension, sizeof( findPath ) );
1579 		Com_ReplaceSeparators( findPath, '\\' );
1580 		Sys_ListFilteredFiles( listedFiles, &count, path, findPath, flags, length + 1 );
1581 	} else {
1582 		if( extension ) {
1583 			if( *extension == '.' ) {
1584 				extension++;
1585 			}
1586 			Com_sprintf( findPath, sizeof( findPath ), "%s\\*.%s", path, extension );
1587 		} else {
1588 			Com_sprintf( findPath, sizeof( findPath ), "%s\\*", path );
1589 		}
1590 
1591 		findHandle = FindFirstFileA( findPath, &findInfo );
1592 		if( findHandle == INVALID_HANDLE_VALUE ) {
1593 			return NULL;
1594 		}
1595 
1596 		do {
1597 			if( !strcmp( findInfo.cFileName, "." ) || !strcmp( findInfo.cFileName, ".." ) ) {
1598 				continue;
1599 			}
1600 
1601 			if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) {
1602 				if( !( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
1603 					continue;
1604 				}
1605 			} else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) {
1606 				if( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
1607 					continue;
1608 				}
1609 			}
1610 
1611 			name = ( flags & FS_SEARCH_SAVEPATH ) ? va( "%s\\%s", path, findInfo.cFileName ) : findInfo.cFileName;
1612 
1613 			if( flags & FS_SEARCH_EXTRAINFO ) {
1614 				Sys_FindInfoToExtraInfo( &findInfo, &info );
1615 				listedFiles[count++] = FS_CopyExtraInfo( name, &info );
1616 			} else {
1617 				listedFiles[count++] = Z_CopyString( name );
1618 			}
1619 		} while( count < MAX_LISTED_FILES && FindNextFileA( findHandle, &findInfo ) != FALSE );
1620 
1621 		FindClose( findHandle );
1622 	}
1623 
1624 	if( !count ) {
1625 		return NULL;
1626 	}
1627 
1628 	if( !( flags & FS_SEARCH_NOSORT ) ) {
1629 		qsort( listedFiles, count, sizeof( listedFiles[0] ), SortStrcmp );
1630 	}
1631 
1632 	// reformat filenames back to quake filesystem style
1633 	list = Z_Malloc( sizeof( char * ) * ( count + 1 ) );
1634 	for( i = 0; i < count; i++ ) {
1635 		name = listedFiles[i];
1636 		Q_strlwr( name );
1637 		Com_ReplaceSeparators( name, '/' );
1638 		list[i] = name;
1639 	}
1640 	list[count] = NULL;
1641 
1642 	if( numFiles ) {
1643 		*numFiles = count;
1644 	}
1645 
1646 	return list;
1647 }
1648 
1649 /*
1650 =================
1651 Sys_FreeFileList
1652 =================
1653 */
Sys_FreeFileList(char ** list)1654 void Sys_FreeFileList( char **list ) {
1655 	char **p;
1656 
1657 	if( !list ) {
1658 		Com_Error( ERR_FATAL, "Sys_FreeFileList: NULL" );
1659 	}
1660 
1661 	p = list;
1662 	while( *p ) {
1663 		Z_Free( *p++ );
1664 	}
1665 
1666 	Z_Free( list );
1667 }
1668 
1669 /*
1670 =================
1671 Sys_GetCurrentDirectory
1672 =================
1673 */
Sys_GetCurrentDirectory(void)1674 char *Sys_GetCurrentDirectory( void ) {
1675 	return currentDirectory;
1676 }
1677 
1678 //=======================================================================
1679 
1680 #ifdef _WIN32_WCE
1681 
1682 DWORD WINAPI GetCurrentDirectoryA( DWORD nBufferLength, LPSTR lpBuffer );
1683 
1684 /*
1685 ==================
1686 WinMain
1687 
1688 ==================
1689 */
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)1690 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) {
1691 	/* previous instances do not exist in Win32 */
1692 	if( hPrevInstance ) {
1693 		return 1;
1694 	}
1695 
1696 	if( !GetCurrentDirectoryA( sizeof( currentDirectory ) - 1, currentDirectory ) ) {
1697 		return 1;
1698 	}
1699 
1700 	hGlobalInstance = hInstance;
1701 
1702 	Qcommon_Init( "" );
1703 
1704     /* main program loop */
1705 	while( 1 ) {
1706 		Qcommon_Frame();
1707 	}
1708 
1709 	// never gets here
1710     return 0;
1711 }
1712 
1713 #else
1714 
1715 #ifdef USE_ANTICHEAT
1716 
1717 typedef BOOL (WINAPI *ISWOW64PROCESS)( HANDLE, PBOOL );
1718 typedef PVOID (*FNINIT)( VOID );
1719 
1720 PRIVATE PVOID anticheatApi;
1721 PRIVATE FNINIT anticheatInit;
1722 PRIVATE HMODULE anticheatHandle;
1723 PRIVATE ISWOW64PROCESS pIsWow64Process;
1724 
1725 //
1726 // r1ch.net anticheat support
1727 //
Sys_GetAntiCheatAPI(void)1728 qboolean Sys_GetAntiCheatAPI( void ) {
1729 	qboolean updated = qfalse;
1730     BOOL bIsWow64 = FALSE;
1731 
1732 	//already loaded, just reinit
1733 	if( anticheatInit ) {
1734 		anticheatApi = anticheatInit();
1735 		if( !anticheatApi ) {
1736 	        Com_Printf( S_COLOR_RED "Anticheat failed to reinitialize!\n" );
1737             FreeLibrary( anticheatHandle );
1738             anticheatHandle = NULL;
1739             anticheatInit = NULL;
1740 			return qfalse;
1741         }
1742 		return qtrue;
1743 	}
1744 
1745 	//windows version check
1746 	if( !winnt ) {
1747 		Com_Printf( S_COLOR_YELLOW
1748 			"Anticheat requires Windows 2000/XP/2003.\n" );
1749 		return qfalse;
1750 	}
1751 
1752     if( !pIsWow64Process ) {
1753         pIsWow64Process = ( ISWOW64PROCESS )GetProcAddress(
1754             GetModuleHandle( "kernel32" ), "IsWow64Process" );
1755     }
1756     if( pIsWow64Process ) {
1757         pIsWow64Process( GetCurrentProcess(), &bIsWow64 );
1758         if( bIsWow64 ) {
1759             Com_Printf( S_COLOR_YELLOW
1760 				"Anticheat is incompatible with 64 bit Windows.\n" );
1761             return qfalse;
1762         }
1763     }
1764 
1765 reInit:
1766 	anticheatHandle = LoadLibrary( "anticheat" );
1767 	if( !anticheatHandle ) {
1768 		Com_Printf( S_COLOR_RED "Anticheat failed to load.\n" );
1769 		return qfalse;
1770     }
1771 
1772 	//this should never fail unless the anticheat.dll is bad
1773     anticheatInit = ( FNINIT )GetProcAddress(
1774             anticheatHandle, "Initialize" );
1775     if( !anticheatInit ) {
1776         Com_Printf( S_COLOR_RED "Couldn't get API of anticheat.dll!\n"
1777                     "Please check you are using a valid "
1778                     "anticheat.dll from http://antiche.at/" );
1779         FreeLibrary( anticheatHandle );
1780         anticheatHandle = NULL;
1781         return qfalse;
1782     }
1783 
1784 	anticheatApi = anticheatInit();
1785 	if( anticheatApi ) {
1786         return qtrue; // succeeded
1787     }
1788 
1789     FreeLibrary( anticheatHandle );
1790     anticheatHandle = NULL;
1791     anticheatInit = NULL;
1792     if( !updated ) {
1793         updated = qtrue;
1794         goto reInit;
1795     }
1796 
1797 	Com_Printf( S_COLOR_RED "Anticheat failed to initialize.\n" );
1798 
1799     return qfalse;
1800 }
1801 
1802 #endif /* USE_ANTICHEAT */
1803 
1804 #ifdef USE_DBGHELP
1805 
1806 typedef DWORD (WINAPI *SETSYMOPTIONS)( DWORD );
1807 typedef BOOL (WINAPI *SYMGETMODULEINFO)( HANDLE, DWORD, PIMAGEHLP_MODULE );
1808 typedef BOOL (WINAPI *SYMINITIALIZE)( HANDLE, PSTR, BOOL );
1809 typedef BOOL (WINAPI *SYMCLEANUP)( HANDLE );
1810 typedef BOOL (WINAPI *ENUMERATELOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID );
1811 typedef BOOL (WINAPI *STACKWALK)( DWORD, HANDLE, HANDLE, LPSTACKFRAME, PVOID,
1812 	PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE,
1813 	PTRANSLATE_ADDRESS_ROUTINE );
1814 typedef BOOL (WINAPI *SYMFROMADDR)( HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO );
1815 typedef PVOID (WINAPI *SYMFUNCTIONTABLEACCESS)( HANDLE, DWORD );
1816 typedef DWORD (WINAPI *SYMGETMODULEBASE)( HANDLE, DWORD );
1817 
1818 typedef HINSTANCE (WINAPI *SHELLEXECUTE)( HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT );
1819 
1820 PRIVATE SETSYMOPTIONS pSymSetOptions;
1821 PRIVATE SYMGETMODULEINFO pSymGetModuleInfo;
1822 PRIVATE SYMINITIALIZE pSymInitialize;
1823 PRIVATE SYMCLEANUP pSymCleanup;
1824 PRIVATE ENUMERATELOADEDMODULES pEnumerateLoadedModules;
1825 PRIVATE STACKWALK pStackWalk;
1826 PRIVATE SYMFROMADDR pSymFromAddr;
1827 PRIVATE SYMFUNCTIONTABLEACCESS pSymFunctionTableAccess;
1828 PRIVATE SYMGETMODULEBASE pSymGetModuleBase;
1829 PRIVATE SHELLEXECUTE pShellExecute;
1830 
1831 PRIVATE HANDLE processHandle, threadHandle;
1832 
1833 PRIVATE FILE *crashReport;
1834 
1835 PRIVATE CHAR moduleName[MAX_PATH];
1836 
EnumModulesCallback(PSTR ModuleName,ULONG ModuleBase,ULONG ModuleSize,PVOID UserContext)1837 PRIVATE BOOL CALLBACK EnumModulesCallback(
1838 	PSTR  ModuleName,
1839 	ULONG ModuleBase,
1840 	ULONG ModuleSize,
1841 	PVOID UserContext )
1842 {
1843 	IMAGEHLP_MODULE moduleInfo;
1844 	DWORD pc = ( DWORD )UserContext;
1845 	BYTE buffer[4096];
1846 	PBYTE data;
1847 	UINT numBytes;
1848 	VS_FIXEDFILEINFO *info;
1849 	char version[64];
1850 	char *symbols;
1851 
1852 	strcpy( version, "unknown" );
1853 	if( GetFileVersionInfo( ModuleName, 0, sizeof( buffer ), buffer ) ) {
1854 		if( VerQueryValue( buffer, "\\", &data, &numBytes ) ) {
1855 			info = ( VS_FIXEDFILEINFO * )data;
1856 			Com_sprintf( version, sizeof( version ), "%u.%u.%u.%u",
1857 				HIWORD( info->dwFileVersionMS ),
1858 				LOWORD( info->dwFileVersionMS ),
1859 				HIWORD( info->dwFileVersionLS ),
1860 				LOWORD( info->dwFileVersionLS ) );
1861 		}
1862 	}
1863 
1864 	symbols = "failed";
1865 	moduleInfo.SizeOfStruct = sizeof( moduleInfo );
1866 	if( pSymGetModuleInfo( processHandle, ModuleBase, &moduleInfo ) ) {
1867 		ModuleName = moduleInfo.ModuleName;
1868 		switch( moduleInfo.SymType ) {
1869 			case SymCoff: symbols = "COFF"; break;
1870 			case SymExport: symbols = "export"; break;
1871 			case SymNone: symbols = "none"; break;
1872 			case SymPdb: symbols = "PDB"; break;
1873 			default: symbols = "unknown"; break;
1874 		}
1875 	}
1876 
1877 	fprintf( crashReport, "%08x %08x %s (version %s, symbols %s) ",
1878 		ModuleBase, ModuleBase + ModuleSize, ModuleName, version, symbols );
1879 	if( pc >= ModuleBase && pc < ModuleBase + ModuleSize ) {
1880 		Q_strncpyz( moduleName, ModuleName, sizeof( moduleName ) );
1881 		fprintf( crashReport, "*\n" );
1882 	} else {
1883 		fprintf( crashReport, "\n" );
1884 	}
1885 
1886 	return TRUE;
1887 }
1888 
Sys_ExceptionHandler(DWORD exceptionCode,LPEXCEPTION_POINTERS exceptionInfo)1889 PRIVATE DWORD Sys_ExceptionHandler( DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo ) {
1890 	STACKFRAME stackFrame;
1891 	PCONTEXT context;
1892 	SYMBOL_INFO *symbol;
1893 	int count, ret, i;
1894 	DWORD64 offset;
1895 	BYTE buffer[sizeof( SYMBOL_INFO ) + 256 - 1];
1896 	IMAGEHLP_MODULE moduleInfo;
1897 	char path[MAX_PATH];
1898 	char execdir[MAX_PATH];
1899 	char *p;
1900 	HMODULE helpModule, shellModule;
1901 	SYSTEMTIME systemTime;
1902 	static char *monthNames[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1903 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1904 	OSVERSIONINFO	vinfo;
1905 
1906 #ifndef DEDICATED_ONLY
1907 #ifdef REF_HARD_LINKED
1908 #ifdef SOFTWARE_RENDERER
1909 	SWimp_FatalShutdown();
1910 #else
1911 	GLimp_FatalShutdown();
1912 #endif
1913 #else
1914 	GLimp_FatalShutdown();
1915 	SWimp_FatalShutdown();
1916 #endif
1917 #endif
1918 
1919 	ret = MessageBox( NULL, APPLICATION " has encountered an unhandled "
1920 		"exception and needs to be terminated.\n"
1921 		"Would you like to generate a crash report?",
1922 		"Unhandled Exception",
1923 		MB_ICONERROR|MB_YESNO );
1924 	if( ret == IDNO ) {
1925 		return EXCEPTION_CONTINUE_SEARCH;
1926 	}
1927 
1928 	helpModule = LoadLibrary( "dbghelp.dll" );
1929 	if( !helpModule ) {
1930 		return EXCEPTION_CONTINUE_SEARCH;
1931 	}
1932 
1933 #define GPA( x, y )															\
1934 	do {																	\
1935 		p ## y = ( x )GetProcAddress( helpModule, #y );						\
1936 		if( !p ## y ) {														\
1937 			return EXCEPTION_CONTINUE_SEARCH;								\
1938 		}																	\
1939 	} while( 0 )
1940 
1941 	GPA( SETSYMOPTIONS, SymSetOptions );
1942 	GPA( SYMGETMODULEINFO, SymGetModuleInfo );
1943 	GPA( SYMCLEANUP, SymCleanup );
1944 	GPA( SYMINITIALIZE, SymInitialize );
1945 	GPA( ENUMERATELOADEDMODULES, EnumerateLoadedModules );
1946 	GPA( STACKWALK, StackWalk );
1947 	GPA( SYMFROMADDR, SymFromAddr );
1948 	GPA( SYMFUNCTIONTABLEACCESS, SymFunctionTableAccess );
1949 	GPA( SYMGETMODULEBASE, SymGetModuleBase );
1950 
1951 	pSymSetOptions( SYMOPT_LOAD_ANYTHING|SYMOPT_DEBUG|SYMOPT_FAIL_CRITICAL_ERRORS );
1952 	processHandle = GetCurrentProcess();
1953 	threadHandle = GetCurrentThread();
1954 
1955 	GetModuleFileName( NULL, execdir, sizeof( execdir ) - 1 );
1956 	execdir[sizeof( execdir ) - 1] = 0;
1957 	p = strrchr( execdir, '\\' );
1958 	if( p ) {
1959 		*p = 0;
1960 	}
1961 
1962 	GetSystemTime( &systemTime );
1963 
1964 	for( i = 0; i < 100; i++ ) {
1965 		Com_sprintf( path, sizeof( path ), "%s\\Q2PRO_CrashReport%02d.txt", execdir, i );
1966 		if( !Sys_GetFileInfo( path, NULL ) ) {
1967 			break;
1968 		}
1969 	}
1970 	crashReport = fopen( path, "w" );
1971 	if( !crashReport ) {
1972 		return EXCEPTION_CONTINUE_SEARCH;
1973 	}
1974 
1975 	pSymInitialize( processHandle, execdir, TRUE );
1976 
1977 	fprintf( crashReport, "Crash report generated %s %u %u, %02u:%02u:%02u UTC\n",
1978 		monthNames[systemTime.wMonth % 12], systemTime.wDay, systemTime.wYear,
1979 		systemTime.wHour, systemTime.wMinute, systemTime.wSecond );
1980 	fprintf( crashReport, "by " APPLICATION " " VERSION ", built " __DATE__", " __TIME__ "\n" );
1981 
1982 	vinfo.dwOSVersionInfoSize = sizeof( vinfo );
1983 	if( GetVersionEx( &vinfo ) ) {
1984 		fprintf( crashReport, "\nWindows version: %u.%u (build %u) %s\n",
1985 			vinfo.dwMajorVersion, vinfo.dwMinorVersion, vinfo.dwBuildNumber, vinfo.szCSDVersion );
1986 	}
1987 
1988 	strcpy( moduleName, "unknown" );
1989 
1990 	context = exceptionInfo->ContextRecord;
1991 
1992 	fprintf( crashReport, "\nLoaded modules:\n" );
1993 	pEnumerateLoadedModules( processHandle, EnumModulesCallback, ( PVOID )context->Eip );
1994 
1995 	fprintf( crashReport, "\nException information:\n" );
1996 	fprintf( crashReport, "Code: %08x\n", exceptionCode );
1997 	fprintf( crashReport, "Address: %08x (%s)\n",
1998 		context->Eip, moduleName );
1999 
2000 	fprintf( crashReport, "\nThread context:\n" );
2001 	fprintf( crashReport, "EIP: %08x EBP: %08x ESP: %08x\n",
2002 		context->Eip, context->Ebp, context->Esp );
2003 	fprintf( crashReport, "EAX: %08x EBX: %08x ECX: %08x\n",
2004 		context->Eax, context->Ebx, context->Ecx );
2005 	fprintf( crashReport, "EDX: %08x ESI: %08x EDI: %08x\n",
2006 		context->Edx, context->Esi, context->Edi );
2007 
2008 	memset( &stackFrame, 0, sizeof( stackFrame ) );
2009 	stackFrame.AddrPC.Offset = context->Eip;
2010 	stackFrame.AddrPC.Mode = AddrModeFlat;
2011 	stackFrame.AddrFrame.Offset = context->Ebp;
2012 	stackFrame.AddrFrame.Mode = AddrModeFlat;
2013 	stackFrame.AddrStack.Offset = context->Esp;
2014 	stackFrame.AddrStack.Mode = AddrModeFlat;
2015 
2016 	fprintf( crashReport, "\nStack trace:\n" );
2017 	count = 0;
2018 	symbol = ( SYMBOL_INFO * )buffer;
2019 	symbol->SizeOfStruct = sizeof( *symbol );
2020 	symbol->MaxNameLen = 256;
2021 	while( pStackWalk( IMAGE_FILE_MACHINE_I386,
2022 		processHandle,
2023 		threadHandle,
2024 		&stackFrame,
2025 		context,
2026 		NULL,
2027 		pSymFunctionTableAccess,
2028 		pSymGetModuleBase,
2029 		NULL ) )
2030 	{
2031 		fprintf( crashReport, "%d: %08x %08x %08x %08x ",
2032 			count,
2033 			stackFrame.Params[0],
2034 			stackFrame.Params[1],
2035 			stackFrame.Params[2],
2036 			stackFrame.Params[3] );
2037 
2038 		moduleInfo.SizeOfStruct = sizeof( moduleInfo );
2039 		if( pSymGetModuleInfo( processHandle, stackFrame.AddrPC.Offset, &moduleInfo ) ) {
2040 			if( moduleInfo.SymType != SymNone && moduleInfo.SymType != SymExport &&
2041 				pSymFromAddr( processHandle, stackFrame.AddrPC.Offset, &offset, symbol ) )
2042 			{
2043 				fprintf( crashReport, "%s!%s+%#x\n",
2044 					moduleInfo.ModuleName,
2045 					symbol->Name, offset );
2046 			} else {
2047 				fprintf( crashReport, "%s!%#x\n",
2048 					moduleInfo.ModuleName,
2049 					stackFrame.AddrPC.Offset );
2050 			}
2051 		} else {
2052 			fprintf( crashReport, "%#x\n",
2053 				stackFrame.AddrPC.Offset );
2054 		}
2055 		count++;
2056 	}
2057 
2058 	fclose( crashReport );
2059 
2060 	shellModule = LoadLibrary( "shell32.dll" );
2061 	if( shellModule ) {
2062 		pShellExecute = ( SHELLEXECUTE )GetProcAddress( shellModule, "ShellExecuteA" );
2063 		if( pShellExecute ) {
2064 			pShellExecute( NULL, "open", path, NULL, execdir, SW_SHOW );
2065 		}
2066 	}
2067 
2068 	pSymCleanup( processHandle );
2069 
2070 	ExitProcess( 1 );
2071 	return EXCEPTION_CONTINUE_SEARCH;
2072 }
2073 
2074 #if 0
2075 EXCEPTION_DISPOSITION _ExceptionHandler(
2076 	EXCEPTION_RECORD *ExceptionRecord,
2077 	void *EstablisherFrame,
2078 	CONTEXT *ContextRecord,
2079 	void *DispatcherContext )
2080 {
2081 	return ExceptionContinueSearch;
2082 }
2083 
2084 #ifndef __GNUC__
2085 #define __try1( handler )	__asm { \
2086 	__asm push handler \
2087 	__asm push fs:[0] \
2088 	__asm mov fs:0, esp \
2089 }
2090 #define __except1	__asm { \
2091 	__asm mov eax, [esp] \
2092 	__asm mov fs:[0], eax \
2093 	__asm add esp, 8 \
2094 }
2095 #endif
2096 #endif
2097 
2098 #endif /* USE_DBGHELP */
2099 
2100 /*
2101 ==================
2102 WinMain
2103 
2104 ==================
2105 */
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)2106 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
2107 	/* previous instances do not exist in Win32 */
2108 	if( hPrevInstance ) {
2109 		return 1;
2110 	}
2111 
2112 #ifdef DEDICATED_ONLY
2113 	if( !GetModuleFileName( NULL, currentDirectory, sizeof( currentDirectory ) - 1 ) ) {
2114 		return 1;
2115 	}
2116 	currentDirectory[sizeof( currentDirectory ) - 1] = 0;
2117 	{
2118 		char *p = strrchr( currentDirectory, '\\' );
2119 		if( p ) {
2120 			*p = 0;
2121 		}
2122 		if( !SetCurrentDirectory( currentDirectory ) ) {
2123 			return 1;
2124 		}
2125 	}
2126 #else
2127 	if( !GetCurrentDirectory( sizeof( currentDirectory ) - 1, currentDirectory ) ) {
2128 		return 1;
2129 	}
2130 	currentDirectory[sizeof( currentDirectory ) - 1] = 0;
2131 #endif
2132 
2133 	hGlobalInstance = hInstance;
2134 
2135 #ifdef USE_DBGHELP
2136 #ifdef _MSC_VER
2137 	__try {
2138 #else
2139 	__try1( Sys_ExceptionHandler );
2140 #endif
2141 #endif /* USE_DBGHELP */
2142 
2143 	Qcommon_Init( lpCmdLine );
2144 
2145 	/* main program loop */
2146 	while( !shouldExit ) {
2147 		Qcommon_Frame();
2148 	}
2149 
2150 	Com_Quit();
2151 
2152 #ifdef USE_DBGHELP
2153 #ifdef _MSC_VER
2154 	} __except( Sys_ExceptionHandler( GetExceptionCode(), GetExceptionInformation() ) ) {
2155 		return 1;
2156 	}
2157 #else
2158 	__except1;
2159 #endif
2160 #endif /* USE_DBGHELP */
2161 
2162 	// never gets here
2163     return 0;
2164 }
2165 
2166 #ifdef DEDICATED_ONLY
2167 
ServiceHandler(DWORD fdwControl)2168 static VOID WINAPI ServiceHandler( DWORD fdwControl ) {
2169 	if( fdwControl != SERVICE_CONTROL_STOP ) {
2170 		return;
2171 	}
2172 
2173 	Com_Quit();
2174 
2175 	serviceStatus.dwCurrentState = SERVICE_STOPPED;
2176 	serviceStatus.dwControlsAccepted = 0;
2177 	SetServiceStatus( statusHandle, &serviceStatus );
2178 }
2179 
2180 
ServiceMain(DWORD argc,LPTSTR * argv)2181 static VOID WINAPI ServiceMain( DWORD argc, LPTSTR *argv ) {
2182 	statusHandle = RegisterServiceCtrlHandler( APPLICATION, ServiceHandler );
2183 	if( !statusHandle ) {
2184 		return;
2185 	}
2186 
2187 	memset( &serviceStatus, 0, sizeof( serviceStatus ) );
2188 	serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
2189 	serviceStatus.dwCurrentState = SERVICE_RUNNING;
2190 	serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
2191 	SetServiceStatus( statusHandle, &serviceStatus );
2192 
2193 	WinMain( GetModuleHandle( NULL ), NULL, GetCommandLineA(), 0 );
2194 }
2195 
2196 static SERVICE_TABLE_ENTRY serviceTable[] = {
2197 	{ APPLICATION, ServiceMain },
2198 	{ NULL, NULL }
2199 };
2200 
2201 /*
2202 ==================
2203 main
2204 
2205 ==================
2206 */
main(int argc,char ** argv)2207 int main( int argc, char **argv ) {
2208 	int i;
2209 
2210 	for( i = 1; i < argc; i++ ) {
2211 		if( !strcmp( argv[i], "-service" ) ) {
2212 			goto service;
2213 		}
2214 	}
2215 
2216 	return WinMain( GetModuleHandle( NULL ), NULL, GetCommandLineA(), 0 );
2217 
2218 service:
2219 	if( !StartServiceCtrlDispatcher( serviceTable ) ) {
2220 		if( GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ) {
2221 			return WinMain( GetModuleHandle( NULL ), NULL, GetCommandLineA(), 0 );
2222 		}
2223 		return 1;
2224 	}
2225 
2226 	return 0;
2227 }
2228 
2229 #endif
2230 
2231 #endif
2232 
2233