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