1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 // sys_win.h
21 
22 #define _WINNT_VER 0x5
23 
24 #include "../qcommon/qcommon.h"
25 #include "winquake.h"
26 #include "resource.h"
27 #include <errno.h>
28 #include <float.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <direct.h>
32 #include <io.h>
33 #include <conio.h>
34 #include <process.h>
35 #include <dbghelp.h>
36 #include <Richedit.h>
37 
38 #ifdef USE_OPENSSL
39 #define OPENSSLEXPORT __cdecl
40 #include <openssl/sha.h>
41 #endif
42 
43 #ifdef USE_CURL
44 #define CURL_STATICLIB
45 #define CURL_HIDDEN_SYMBOLS
46 #define CURL_EXTERN_SYMBOL
47 #define CURL_CALLING_CONVENTION __cdecl
48 #include <curl/curl.h>
49 #endif
50 
51 #include "../win32/conproc.h"
52 
53 int SV_CountPlayers (void);
54 
55 //#define DEMO
56 
57 #ifdef DEDICATED_ONLY
58 qboolean	 global_Service = false;
59 #endif
60 
61 HMODULE hSh32 = NULL;
62 FARPROC procShell_NotifyIcon = NULL;
63 NOTIFYICONDATA pNdata;
64 
65 cvar_t	*win_priority;
66 //cvar_t	*win_disablewinkey;
67 
68 qboolean s_win95;
69 
70 int			starttime;
71 int			ActiveApp;
72 qboolean	Minimized;
73 
74 HWND		hwnd_Server;
75 
76 #ifndef NO_SERVER
77 #ifdef USE_PYROADMIN
78 extern netadr_t netaddress_pyroadmin;
79 #endif
80 static HANDLE		hinput, houtput;
81 BOOL	oldStyleConsole = FALSE;
82 #endif
83 
84 uint32	sys_msg_time;
85 uint32	sys_frame_time;
86 
87 #ifdef USE_PYROADMIN
88 extern		cvar_t	*pyroadminport;
89 #endif
90 
91 cvar_t		*win_disableexceptionhandler = &uninitialized_cvar;
92 cvar_t		*win_silentexceptionhandler = &uninitialized_cvar;
93 cvar_t		*sys_fpu_bits = &uninitialized_cvar;
94 
95 //static HANDLE		qwclsemaphore;
96 
97 #define	MAX_NUM_ARGVS	128
98 int			argc;
99 char		*argv[MAX_NUM_ARGVS];
100 
101 //cvar_t	*win_priority;
102 
103 sizebuf_t	console_buffer;
104 byte		console_buff[16384];
105 
106 //r1: service support
107 #ifdef DEDICATED_ONLY
108 SERVICE_STATUS          MyServiceStatus;
109 SERVICE_STATUS_HANDLE   MyServiceStatusHandle;
110 #endif
111 
112 //original game command line
113 char	cmdline[4096];
114 char	bname[MAX_QPATH];
115 
116 /*
117 ===============================================================================
118 
119 SYSTEM IO
120 
121 ===============================================================================
122 */
123 
Sys_FileLength(const char * path)124 int Sys_FileLength (const char *path)
125 {
126 	WIN32_FILE_ATTRIBUTE_DATA	fileData;
127 
128 	if (GetFileAttributesEx (path, GetFileExInfoStandard, &fileData))
129 		return (int)fileData.nFileSizeLow;
130 	else
131 		return -1;
132 }
133 
134 void VID_Restart_f (void);
135 void S_Init (int fullInit);
Sys_Error(const char * error,...)136 NORETURN void Sys_Error (const char *error, ...)
137 {
138 	va_list		argptr;
139 	char		text[1024];
140 	int			ret;
141 
142 #ifndef DEDICATED_ONLY
143 	if (cl_hwnd && IsWindow (cl_hwnd))
144 		DestroyWindow (cl_hwnd);
145 #endif
146 
147 	Qcommon_Shutdown ();
148 
149 	va_start (argptr, error);
150 	vsnprintf (text, sizeof(text)-1, error, argptr);
151 	va_end (argptr);
152 
153 	text[sizeof(text)-1] = 0;
154 
155 	if (strlen(text) < 900)
156 		strcat (text, "\r\n\r\nWould you like to debug? (DEVELOPERS ONLY!)\n");
157 
158 rebox:;
159 
160 	ret = MessageBox(NULL, text, "Quake II Fatal Error", MB_ICONEXCLAMATION | MB_YESNO);
161 
162 	if (ret == IDYES)
163 	{
164 		ret = MessageBox(NULL, "Please attach your debugger now to prevent the built in exception handler from catching the breakpoint. When ready, press Yes to cause a breakpoint or No to cancel.", "Quake II Fatal Error", MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2);
165 		if (ret == IDYES)
166 		{
167 #ifndef _DEBUG
168 			if (!IsDebuggerPresent ())
169 			{
170 				ExitProcess (0x1d107);
171 			}
172 #endif
173 			Sys_DebugBreak ();
174 		}
175 		else
176 		{
177 			goto rebox;
178 		}
179 	}
180 
181 	ExitProcess (0xDEAD);
182 }
183 
Sys_Quit(void)184 void Sys_Quit (void)
185 {
186 	timeEndPeriod( 1 );
187 
188 #ifndef DEDICATED_ONLY
189 	CL_Shutdown();
190 #endif
191 
192 	Qcommon_Shutdown ();
193 
194     // Cleanup before shutdown
195     //UnhookWindowsHookEx( g_hKeyboardHook );
196 
197 	if (procShell_NotifyIcon)
198 		procShell_NotifyIcon (NIM_DELETE, &pNdata);
199 
200 	if (hSh32)
201 		FreeLibrary (hSh32);
202 
203 #ifdef DEDICATED_ONLY
204 	if (!global_Service)
205 #endif
206 		//exit (0);
207 		ExitProcess (0);
208 }
209 
WinError(void)210 void WinError (void)
211 {
212 	LPVOID lpMsgBuf;
213 
214 	FormatMessage(
215 		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
216 		NULL,
217 		GetLastError(),
218 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
219 		(LPTSTR) &lpMsgBuf,
220 		0,
221 		NULL
222 	);
223 
224 	// Display the string.
225 	MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
226 
227 	// Free the buffer.
228 	LocalFree( lpMsgBuf );
229 }
230 
231 #ifdef DEDICATED_ONLY
232 
Sys_ServiceCtrlHandler(DWORD Opcode)233 void EXPORT Sys_ServiceCtrlHandler (DWORD Opcode)
234 {
235     switch(Opcode)
236     {
237         case SERVICE_CONTROL_STOP:
238 			// Do whatever it takes to stop here.
239 			MyServiceStatus.dwWin32ExitCode = 0;
240             MyServiceStatus.dwCurrentState  = SERVICE_STOPPED;
241             MyServiceStatus.dwCheckPoint    = 0;
242             MyServiceStatus.dwWaitHint      = 0;
243 
244             SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus);
245 
246 			Com_Quit();
247             return;
248     }
249 
250     // Send current status.
251     SetServiceStatus (MyServiceStatusHandle,  &MyServiceStatus);
252 }
253 
Sys_ServiceStart(DWORD argc,LPTSTR * argv)254 void EXPORT Sys_ServiceStart (DWORD argc, LPTSTR *argv)
255 {
256     MyServiceStatus.dwServiceType        = SERVICE_WIN32;
257     MyServiceStatus.dwCurrentState       = SERVICE_START_PENDING;
258     MyServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP;
259     MyServiceStatus.dwWin32ExitCode      = 0;
260     MyServiceStatus.dwServiceSpecificExitCode = 0;
261     MyServiceStatus.dwCheckPoint         = 0;
262     MyServiceStatus.dwWaitHint           = 0;
263 
264     MyServiceStatusHandle = RegisterServiceCtrlHandler(
265         argv[0],
266         (LPHANDLER_FUNCTION)Sys_ServiceCtrlHandler);
267 
268     if (MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
269         return;
270 
271     // Initialization complete - report running status.
272     MyServiceStatus.dwCurrentState       = SERVICE_RUNNING;
273     MyServiceStatus.dwCheckPoint         = 0;
274     MyServiceStatus.dwWaitHint           = 0;
275 
276     SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus);
277 
278 	WinMain (0, NULL, cmdline, 0);
279 
280     return;
281 }
282 
main(void)283 int EXPORT main(void)
284 {
285     SERVICE_TABLE_ENTRY   DispatchTable[] =
286     {
287         { "R1Q2", (LPSERVICE_MAIN_FUNCTION)Sys_ServiceStart      },
288         { NULL,              NULL          }
289     };
290 
291     if (!StartServiceCtrlDispatcher( DispatchTable))
292 		return 1;
293 
294 	return 0;
295 }
296 
297 //================================================================
298 
Sys_InstallService(char * servername,char * cmdline)299 void Sys_InstallService(char *servername, char *cmdline)
300 {
301 	SC_HANDLE schService, schSCManager;
302 
303 	char srvName[MAX_OSPATH];
304 	char srvDispName[MAX_OSPATH];
305 	char lpszBinaryPathName[2048];
306 
307 	GetModuleFileName(NULL, lpszBinaryPathName, sizeof(lpszBinaryPathName));
308 
309 	while (*cmdline != ' ') {
310 		cmdline++;
311 	}
312 
313 	cmdline++;
314 
315 	strcat (lpszBinaryPathName, " -service ");
316 	strcat (lpszBinaryPathName, cmdline);
317 
318 	Com_sprintf (srvDispName, sizeof(srvDispName), "Quake II - %s", servername);
319 	Com_sprintf (srvName, sizeof(srvName), "R1Q2(%s)", servername);
320 
321 	schSCManager = OpenSCManager(
322 		NULL,                    // local machine
323 		NULL,                    // ServicesActive database
324 		SC_MANAGER_ALL_ACCESS);  // full access rights
325 
326 	if (schSCManager == NULL) {
327 		Com_Printf ("OpenSCManager FAILED. GetLastError = %d\n", LOG_GENERAL, GetLastError());
328 		return;
329 	}
330 
331     schService = CreateService(
332         schSCManager,              // SCManager database
333         srvName,				   // name of service
334         srvDispName,           // service name to display
335         SERVICE_ALL_ACCESS,        // desired access
336         SERVICE_WIN32_OWN_PROCESS, // service type
337         SERVICE_AUTO_START,      // start type
338         SERVICE_ERROR_NORMAL,      // error control type
339         lpszBinaryPathName,        // service's binary
340         NULL,                      // no load ordering group
341         NULL,                      // no tag identifier
342         NULL,                      // no dependencies
343         NULL,                      // LocalSystem account
344         NULL);                     // no password
345 
346     if (schService == NULL)
347 	{
348         Com_Printf ("CreateService FAILED. GetLastError = %d\n", LOG_GENERAL, GetLastError());
349 	}
350 	else
351 	{
352         Com_Printf ("CreateService SUCCESS.\n", LOG_GENERAL);
353 		CloseServiceHandle(schService);
354 	}
355 
356 	CloseServiceHandle (schSCManager);
357 }
358 
Sys_DeleteService(char * servername)359 void Sys_DeleteService (char *servername)
360 {
361 	SC_HANDLE schService, schSCManager;
362 	char srvName[MAX_OSPATH];
363 
364 	snprintf (srvName, sizeof(srvName)-1, "R1Q2(%s)", servername);
365 	//strcpy (srvName, servername);
366 
367 	schSCManager = OpenSCManager(
368 		NULL,                    // local machine
369 		NULL,                    // ServicesActive database
370 		SC_MANAGER_ALL_ACCESS);  // full access rights
371 
372 	if (schSCManager == NULL) {
373 		Com_Printf ("OpenSCManager FAILED. GetLastError = %d\n", LOG_GENERAL, GetLastError());
374 		return;
375 	}
376 
377     schService = OpenService(
378         schSCManager,       // SCManager database
379         srvName,       // name of service
380         DELETE);            // only need DELETE access
381 
382     if (schService == NULL) {
383         Com_Printf ("OpenService FAILED. GetLastError = %d\n", LOG_GENERAL, GetLastError());
384 	} else {
385 		DeleteService(schService);
386 		CloseServiceHandle(schService);
387 		Com_Printf ("DeleteService SUCCESS.\n", LOG_GENERAL);
388 	}
389 
390 	CloseServiceHandle (schSCManager);
391 }
392 #endif
393 
Sys_EnableTray(void)394 void Sys_EnableTray (void)
395 {
396 	memset (&pNdata, 0, sizeof(pNdata));
397 
398 	pNdata.cbSize = sizeof(NOTIFYICONDATA);
399 	pNdata.hWnd = hwnd_Server;
400 	pNdata.uID = 0;
401 	pNdata.uCallbackMessage = WM_USER + 4;
402 	GetWindowText (hwnd_Server, pNdata.szTip, sizeof(pNdata.szTip)-1);
403 	pNdata.hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE(IDI_ICON2));
404 	pNdata.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
405 
406 	hSh32 = LoadLibrary ("shell32.dll");
407 	procShell_NotifyIcon = GetProcAddress (hSh32, "Shell_NotifyIcon");
408 
409 	procShell_NotifyIcon (NIM_ADD, &pNdata);
410 
411 	Com_Printf ("Minimize to tray enabled.\n", LOG_GENERAL);
412 }
413 
Sys_DisableTray(void)414 void Sys_DisableTray (void)
415 {
416 	ShowWindow (hwnd_Server, SW_RESTORE);
417 	procShell_NotifyIcon (NIM_DELETE, &pNdata);
418 
419 	if (hSh32)
420 		FreeLibrary (hSh32);
421 
422 	procShell_NotifyIcon = NULL;
423 
424 	Com_Printf ("Minimize to tray disabled.\n", LOG_GENERAL);
425 }
426 
Sys_Minimize(void)427 void Sys_Minimize (void)
428 {
429 	SendMessage (hwnd_Server, WM_ACTIVATE, MAKELONG(WA_INACTIVE,1), 0);
430 }
431 
432 #ifndef NO_SERVER
Sys_SetWindowText(char * buff)433 void Sys_SetWindowText (char *buff)
434 {
435 #ifdef DEDICATED_ONLY
436 	if (!global_Service)
437 #endif
438 		SetWindowText (hwnd_Server, buff);
439 }
440 
ServerWindowProcCommandExecute(void)441 void ServerWindowProcCommandExecute (void)
442 {
443 	int			ret;
444 	char		buff[1024];
445 
446 	*(DWORD *)&buff = sizeof(buff)-2;
447 
448 	ret = (int)SendDlgItemMessage (hwnd_Server, IDC_COMMAND, EM_GETLINE, 1, (LPARAM)buff);
449 	if (!ret)
450 		return;
451 
452 	buff[ret] = '\n';
453 	buff[ret+1] = '\0';
454 	Sys_ConsoleOutput (buff);
455 	//Cmd_ExecuteString (buff);
456 	Cbuf_AddText (buff);
457 	SendDlgItemMessage (hwnd_Server, IDC_COMMAND, WM_SETTEXT, 0, (LPARAM)"");
458 }
459 
Sys_UpdateConsoleBuffer(void)460 void Sys_UpdateConsoleBuffer (void)
461 {
462 #ifdef DEDICATED_ONLY
463 	if (global_Service)
464 		return;
465 #endif
466 
467 	if (console_buffer.cursize)
468 	{
469 		int len;
470 
471 		/*buflen = console_buffer.cursize + 1024;
472 
473 		if (consoleBufferPointer + buflen >= sizeof(consoleFullBuffer))
474 		{
475 			int		moved;
476 			char	*p = consoleFullBuffer + buflen;
477 			char	*q;
478 
479 			while (p[0] && p[0] != '\n')
480 				p++;
481 			p++;
482 			q = (consoleFullBuffer + buflen);
483 			moved = (buflen + (int)(p - q));
484 			memmove (consoleFullBuffer, consoleFullBuffer + moved, consoleBufferPointer - moved);
485 			consoleBufferPointer -= moved;
486 			consoleFullBuffer[consoleBufferPointer] = '\0';
487 		}
488 
489 		memcpy (consoleFullBuffer+consoleBufferPointer, console_buffer.data, console_buffer.cursize);
490 		consoleBufferPointer += (console_buffer.cursize - 1);*/
491 
492 		SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
493 		SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_REPLACESEL, 0, (LPARAM)console_buffer.data);
494 
495 		while ((len = (int)SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_GETLINECOUNT, 0, 0)) > 1000)
496 		{
497 			int	line_length;
498 			line_length = (int)SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_LINELENGTH, 0, 0);
499 
500 			SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_SETSEL, 0, line_length + 1);
501 			SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_REPLACESEL, 0, (LPARAM)"");
502 		}
503 
504 		SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
505 		SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, WM_VSCROLL, SB_BOTTOM, 0);
506 
507 		SZ_Clear (&console_buffer);
508 	}
509 }
510 
511 //================================================================
512 
ServerWindowProcCommand(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)513 LRESULT ServerWindowProcCommand(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
514 {
515 	UINT idItem = LOWORD(wParam);
516 	UINT wNotifyCode = HIWORD(wParam);
517 	//HWND hwndCtl = (HWND) lParam;
518 
519 	switch (idItem) {
520 		case IDOK:
521 			switch (wNotifyCode) {
522 				case BN_CLICKED:
523 					ServerWindowProcCommandExecute();
524 					break;
525 			}
526 	}
527 
528 	return FALSE;
529 }
530 
ServerWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)531 LRESULT CALLBACK ServerWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
532 {
533 	//UINT idItem = LOWORD(wParam);
534 
535 	switch (message) {
536 		case WM_COMMAND:
537 			return ServerWindowProcCommand(hwnd, message, wParam, lParam);
538 		case WM_ENDSESSION:
539 			Cbuf_AddText ("quit exiting due to Windows shutdown.\n");
540 			return TRUE;
541 		case WM_CLOSE:
542 #ifdef DEDICATED_ONLY
543 			if (!global_Service)
544 #endif
545 			{
546 				if (SV_CountPlayers()) {
547 					int ays = MessageBox (hwnd_Server, "There are still players on the server! Really shut it down?", "WARNING!", MB_YESNO + MB_ICONEXCLAMATION);
548 					if (ays == IDNO)
549 						return TRUE;
550 				}
551 			}
552 			Cbuf_AddText ("quit terminated by local request.\n");
553 			break;
554 		case WM_ACTIVATE:
555 			{
556 				int minimized = (BOOL)HIWORD(wParam);
557 
558 				Minimized = minimized;
559 				if (procShell_NotifyIcon)
560 				{
561 					if (minimized && LOWORD(wParam) == WA_INACTIVE)
562 					{
563 						Minimized = true;
564 						ShowWindow (hwnd_Server, SW_HIDE);
565 						return FALSE;
566 					}
567 				}
568 				return DefWindowProc (hwnd, message, wParam, lParam);
569 			}
570 		case WM_USER + 4:
571 			if (lParam == WM_LBUTTONDBLCLK) {
572 				ShowWindow (hwnd_Server, SW_RESTORE);
573 				SetForegroundWindow (hwnd_Server);
574 				SetFocus (GetDlgItem (hwnd_Server, IDC_COMMAND));
575 			}
576 			return FALSE;
577 	}
578 
579 	return FALSE;
580 }
581 #endif
582 
_priority_changed(cvar_t * cvar,char * ov,char * nv)583 void _priority_changed (cvar_t *cvar, char *ov, char *nv)
584 {
585 	//r1: let dedicated servers eat the cpu if needed
586 	switch (cvar->intvalue)
587 	{
588 		case -2:
589 			SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);
590 			break;
591 #ifdef BELOW_NORMAL_PRIORITY_CLASS
592 		case -1:
593 			SetPriorityClass (GetCurrentProcess (), BELOW_NORMAL_PRIORITY_CLASS);
594 			break;
595 #endif
596 		case 0:
597 			SetPriorityClass (GetCurrentProcess (), NORMAL_PRIORITY_CLASS);
598 			break;
599 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
600 		case 1:
601 			SetPriorityClass (GetCurrentProcess (), ABOVE_NORMAL_PRIORITY_CLASS);
602 			break;
603 #endif
604 		case 2:
605 			SetPriorityClass (GetCurrentProcess (), HIGH_PRIORITY_CLASS);
606 			break;
607 		default:
608 			Com_Printf ("Unknown priority class %d.\n", LOG_GENERAL, cvar->intvalue);
609 			Cvar_Set (cvar->name, ov);
610 			break;
611 	}
612 }
613 
614 //CRITICAL_SECTION consoleCrit;
615 
Sys_AcquireConsoleMutex(void)616 void Sys_AcquireConsoleMutex (void)
617 {
618 	//EnterCriticalSection (&consoleCrit);
619 }
620 
Sys_ReleaseConsoleMutex(void)621 void Sys_ReleaseConsoleMutex (void)
622 {
623 	//LeaveCriticalSection (&consoleCrit);
624 }
625 
Sys_InitConsoleMutex(void)626 void Sys_InitConsoleMutex (void)
627 {
628 	//InitializeCriticalSection (&consoleCrit);
629 }
630 
Sys_FreeConsoleMutex(void)631 void Sys_FreeConsoleMutex (void)
632 {
633 	//DeleteCriticalSection (&consoleCrit);
634 }
635 
636 qboolean os_winxp = false;
637 
638 /*
639 ================
640 Sys_Init
641 ================
642 */
Sys_Init(void)643 void Sys_Init (void)
644 {
645 	OSVERSIONINFO	vinfo;
646 
647 	timeBeginPeriod( 1 );
648 
649 	//initializes base time
650 	Sys_Milliseconds ();
651 
652 	vinfo.dwOSVersionInfoSize = sizeof(vinfo);
653 
654 	if (!GetVersionEx (&vinfo))
655 		Sys_Error ("Couldn't get OS info");
656 
657 	if (vinfo.dwMajorVersion < 4)
658 		Sys_Error ("Quake2 requires windows version 4 or greater");
659 	if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)
660 		Sys_Error ("Quake2 doesn't run on Win32s");
661 	else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
662 		s_win95 = true;
663 
664 #ifndef DEDICATED_ONLY
665 	if (vinfo.dwMajorVersion >= 5)
666 		os_winxp = true;
667 #endif
668 
669 #ifndef NO_SERVER
670 
671 	if (dedicated->intvalue)
672 	{
673 		HICON hIcon;
674 		BOOL hide = FALSE;
675 
676 		int i;
677 
678 		for (i = 1; i < argc; i++)
679 		{
680 			if (!strcmp (argv[i], "-hideconsole"))
681 			{
682 				hide = TRUE;
683 			}
684 			else if (!strcmp (argv[i], "-oldconsole"))
685 			{
686 #ifdef DEDICATED_ONLY
687 				if (global_Service)
688 					Sys_Error ("-oldconsole and service mode are incompatible");
689 #endif
690 				oldStyleConsole = TRUE;
691 				break;
692 			}
693 			else if (!Q_stricmp (argv[i], "-HCHILD") || !Q_stricmp (argv[i], "-HPARENT") || !Q_stricmp (argv[i], "-HFILE"))
694 			{
695 				//for gamehost compatibility
696 				oldStyleConsole = TRUE;
697 			}
698 		}
699 
700 		if (oldStyleConsole)
701 		{
702 			if (!AllocConsole ())
703 				Sys_Error ("Couldn't create dedicated server console");
704 			hinput = GetStdHandle (STD_INPUT_HANDLE);
705 			houtput = GetStdHandle (STD_OUTPUT_HANDLE);
706 
707 			// let QHOST hook in
708 			InitConProc (argc, argv);
709 		}
710 		else
711 		{
712 #ifdef DEDICATED_ONLY
713 			if (!global_Service)
714 #endif
715 			{
716 				if (!LoadLibrary ("Riched20"))
717 					Sys_Error ("Couldn't load RICHED20.DLL. GetLastError() = %d", GetLastError());
718 
719 				hwnd_Server = CreateDialog (global_hInstance, MAKEINTRESOURCE(IDD_SERVER_GUI), NULL, (DLGPROC)ServerWindowProc);
720 
721 				if (!hwnd_Server)
722 					Sys_Error ("Couldn't create dedicated server window. GetLastError() = %d", GetLastError());
723 
724 				if (hide)
725 					ShowWindow (hwnd_Server, SW_HIDE);
726 
727 				SendDlgItemMessage (hwnd_Server, IDC_CONSOLE, EM_SETREADONLY, TRUE, 0);
728 
729 				SZ_Init (&console_buffer, console_buff, sizeof(console_buff));
730 				console_buffer.allowoverflow = true;
731 
732 				//memset (consoleFullBuffer, 0, sizeof(consoleFullBuffer));
733 
734 				hIcon = (HICON)LoadImage(   global_hInstance,
735 											MAKEINTRESOURCE(IDI_ICON2),
736 											IMAGE_ICON,
737 											GetSystemMetrics(SM_CXSMICON),
738 											GetSystemMetrics(SM_CYSMICON),
739 											0);
740 
741 				//FIXME: if compiled with ICL, this icon turns into the win32 'info' icon (???)
742 				if(hIcon)
743 					SendMessage(hwnd_Server, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
744 
745 				SetFocus (GetDlgItem (hwnd_Server, IDC_COMMAND));
746 			}
747 		}
748 	}
749 	else
750 	{
751 		// Initialization
752 	}
753 
754 	Sys_InitConsoleMutex ();
755 
756 #ifndef _DEBUG
757 	sys_fpu_bits = Cvar_Get ("sys_fpu_bits", "2", CVAR_NOSET);
758 #else
759 	sys_fpu_bits = Cvar_Get ("sys_fpu_bits", "2", 0);
760 #endif
761 
762 	//Cmd_AddCommand ("win_priority", Sys_SetQ2Priority);
763 	win_priority = Cvar_Get ("win_priority", "0", 0);
764 	win_priority->changed = _priority_changed;
765 	win_priority->changed (win_priority, "0", win_priority->string);
766 	win_disableexceptionhandler = Cvar_Get ("win_disableexceptionhandler", "0", 0);
767 	win_silentexceptionhandler = Cvar_Get ("win_silentexceptionhandler", "0", 0);
768 #endif
769 }
770 
771 #ifndef NO_SERVER
772 static char	console_text[1024];
773 static int	console_textlen;
774 
775 /*
776 ================
777 Sys_ConsoleInput
778 ================
779 */
Sys_ConsoleInput(void)780 char *Sys_ConsoleInput (void)
781 {
782 	Sys_UpdateConsoleBuffer ();
783 
784 	if (!oldStyleConsole)
785 	{
786 		return NULL;
787 	}
788 	else
789 	{
790 		INPUT_RECORD	recs[1024];
791 		int		dummy;
792 		int		ch, numread, numevents;
793 
794 		if (!dedicated || !dedicated->intvalue)
795 			return NULL;
796 
797 		for ( ;; )
798 		{
799 			if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
800 				Sys_Error ("Error getting # of console events");
801 
802 			if (numevents <= 0)
803 				break;
804 
805 			if (!ReadConsoleInput(hinput, recs, 1, &numread))
806 				Sys_Error ("Error reading console input");
807 
808 			if (numread != 1)
809 				Sys_Error ("Couldn't read console input");
810 
811 			if (recs[0].EventType == KEY_EVENT)
812 			{
813 				if (!recs[0].Event.KeyEvent.bKeyDown)
814 				{
815 					ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
816 
817 					switch (ch)
818 					{
819 						case '\r':
820 							WriteFile(houtput, "\r\n", 2, &dummy, NULL);
821 
822 							if (console_textlen)
823 							{
824 								if (console_textlen >= sizeof(console_text)-1)
825 								{
826 									Com_Printf ("Sys_ConsoleInput: Line too long, discarded.\n", LOG_SERVER);
827 									return NULL;
828 								}
829 								console_text[console_textlen] = 0;
830 								console_textlen = 0;
831 								return console_text;
832 							}
833 							break;
834 
835 						case '\b':
836 							if (console_textlen)
837 							{
838 								console_textlen--;
839 								WriteFile(houtput, "\b \b", 3, &dummy, NULL);
840 							}
841 							break;
842 
843 						default:
844 							if (ch >= ' ')
845 							{
846 								if (console_textlen < sizeof(console_text)-2)
847 								{
848 									WriteFile(houtput, &ch, 1, &dummy, NULL);
849 									console_text[console_textlen] = ch;
850 									console_textlen++;
851 								}
852 							}
853 
854 							break;
855 
856 					}
857 				}
858 			}
859 		}
860 		return NULL;
861 	}
862 }
863 
Sys_ConsoleOutputOld(const char * string)864 void Sys_ConsoleOutputOld (const char *string)
865 {
866 	int			dummy;
867 	char		text[256];
868 	char		cleanstring[2048];
869 	const char	*p;
870 	char		*s;
871 
872 	p = string;
873 	s = cleanstring;
874 
875 	while (p[0])
876 	{
877 		if (p[0] == '\n')
878 		{
879 			*s++ = '\r';
880 		}
881 
882 		//r1: strip high bits here
883 		*s = (p[0]) & 127;
884 
885 		if (s[0] >= 32 || s[0] == '\n' || s[0] == '\t')
886 			s++;
887 
888 		p++;
889 
890 		if ((s - cleanstring) >= sizeof(cleanstring)-2)
891 		{
892 			*s++ = '\n';
893 			break;
894 		}
895 	}
896 	s[0] = '\0';
897 
898 	if (console_textlen)
899 	{
900 		text[0] = '\r';
901 		memset(&text[1], ' ', console_textlen);
902 		text[console_textlen+1] = '\r';
903 		text[console_textlen+2] = 0;
904 		WriteFile(houtput, text, console_textlen+2, &dummy, NULL);
905 	}
906 
907 	WriteFile(houtput, cleanstring, (DWORD)strlen(cleanstring), &dummy, NULL);
908 
909 	if (console_textlen)
910 		WriteFile(houtput, console_text, console_textlen, &dummy, NULL);
911 }
912 
913 /*
914 ================
915 Sys_ConsoleOutput
916 
917 Print text to the dedicated console
918 ================
919 */
Sys_ConsoleOutput(const char * string)920 void Sys_ConsoleOutput (const char *string)
921 {
922 	char text[2048];
923 	const char *p;
924 	char *s;
925 	//int n = 0;
926 
927 	if (!dedicated->intvalue)
928 		return;
929 
930 	if (oldStyleConsole)
931 	{
932 		Sys_ConsoleOutputOld (string);
933 		return;
934 	}
935 
936 #ifdef DEDICATED_ONLY
937 	if (global_Service)
938 		return;
939 #endif
940 
941 	//r1: no output for services, non dedicated and not before buffer is initialized.
942 	if (!console_buffer.maxsize)
943 		return;
944 
945 	Sys_AcquireConsoleMutex();
946 
947 #ifdef USE_PYROADMIN
948 	if (pyroadminport->intvalue)
949 	{
950 		int len;
951 		char buff[1152];
952 		len = Com_sprintf (buff, sizeof(buff), "line\n%s", string);
953 		Netchan_OutOfBand (NS_SERVER, &netaddress_pyroadmin, len, (byte *)buff);
954 	}
955 #endif
956 
957 	p = string;
958 	s = text;
959 
960 	while (p[0])
961 	{
962 		if (p[0] == '\n')
963 		{
964 			*s++ = '\r';
965 		}
966 
967 		//r1: strip high bits here
968 		*s = (p[0]) & 127;
969 
970 		if (s[0] >= 32 || s[0] == '\n' || s[0] == '\t')
971 			s++;
972 
973 		p++;
974 
975 		if ((s - text) >= sizeof(text)-2)
976 		{
977 			*s++ = '\n';
978 			break;
979 		}
980 	}
981 	s[0] = '\0';
982 
983 	//MessageBox (NULL, text, "hi", MB_OK);
984 	//if (console_buffer.cursize + strlen(text)+2 > console_buffer.maxsize)
985 	SZ_Print (&console_buffer, text);
986 	Sys_ReleaseConsoleMutex();
987 }
988 
989 #endif
990 
Sys_Sleep(int msec)991 void Sys_Sleep (int msec)
992 {
993 	Sleep (msec);
994 }
995 
996 /*
997 ================
998 Sys_SendKeyEvents
999 
1000 Send Key_Event calls
1001 ================
1002 */
1003 #ifndef DEDICATED_ONLY
Sys_SendKeyEvents(void)1004 void Sys_SendKeyEvents (void)
1005 {
1006 	if (g_pKeyboard)
1007 	{
1008 		IN_ReadKeyboard ();
1009 	}
1010 	else
1011 	{
1012 		MSG        msg;
1013 
1014 		//Com_Printf ("sske\n", LOG_GENERAL);
1015 
1016 		//while (GetInputState())
1017 		while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1018 		{
1019 			//if (GetMessage (&msg, NULL, 0, 0) == -1)
1020 				//Com_Quit ();
1021 			sys_msg_time = msg.time;
1022       		TranslateMessage (&msg);
1023       		DispatchMessage (&msg);
1024 		}
1025 	}
1026 
1027 	// grab frame time
1028 	sys_frame_time = timeGetTime();	// FIXME: should this be at start?
1029 }
1030 #endif
1031 
1032 /*
1033 ================
1034 Sys_GetClipboardData
1035 
1036 ================
1037 */
Sys_GetClipboardData(void)1038 char *Sys_GetClipboardData( void )
1039 {
1040 	char *data = NULL;
1041 	char *cliptext;
1042 
1043 	if ( OpenClipboard( NULL ) != 0 )
1044 	{
1045 		HANDLE hClipboardData;
1046 
1047 		if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 )
1048 		{
1049 			if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 )
1050 			{
1051 				data = malloc( GlobalSize( hClipboardData ) + 1 );
1052 				strcpy( data, cliptext );
1053 				GlobalUnlock( hClipboardData );
1054 			}
1055 		}
1056 		CloseClipboard();
1057 	}
1058 	return data;
1059 }
1060 
1061 /*
1062 ==============================================================================
1063 
1064  WINDOWS CRAP
1065 
1066 ==============================================================================
1067 */
1068 
1069 /*
1070 =================
1071 Sys_AppActivate
1072 =================
1073 */
Sys_AppActivate(void)1074 void Sys_AppActivate (void)
1075 {
1076 #ifndef DEDICATED_ONLY
1077 	ShowWindow ( cl_hwnd, SW_RESTORE);
1078 	SetForegroundWindow ( cl_hwnd );
1079 #endif
1080 }
1081 
1082 /*
1083 ========================================================================
1084 
1085 GAME DLL
1086 
1087 ========================================================================
1088 */
1089 #ifndef NO_SERVER
1090 static HINSTANCE	game_library;
1091 
1092 /*
1093 =================
1094 Sys_UnloadGame
1095 =================
1096 */
Sys_UnloadGame(void)1097 void Sys_UnloadGame (void)
1098 {
1099 	if (!FreeLibrary (game_library))
1100 		Sys_Error ("FreeLibrary failed for game library (%d)", GetLastError());
1101 	game_library = NULL;
1102 }
1103 
1104 /*
1105 =================
1106 Sys_GetGameAPI
1107 
1108 Loads the game dll
1109 =================
1110 */
Sys_GetGameAPI(void * parms,int baseq2DLL)1111 void *Sys_GetGameAPI (void *parms, int baseq2DLL)
1112 {
1113 	void	*(IMPORT *GetGameAPI) (void *);
1114 	char	newname[MAX_OSPATH];
1115 	char	name[MAX_OSPATH];
1116 	char	*path;
1117 	char	cwd[MAX_OSPATH];
1118 	FILE	*newExists;
1119 
1120 #if defined _M_IX86
1121 	const char gamename[] = "gamex86.dll";
1122 
1123 #ifdef NDEBUG
1124 	const char debugdir[] = "release";
1125 #else
1126 	const char debugdir[] = "debug";
1127 #endif
1128 
1129 #elif defined _M_ALPHA
1130 	const char gamename[] = "gameaxp.dll";
1131 
1132 #ifdef NDEBUG
1133 	const char debugdir[] = "releaseaxp";
1134 #else
1135 	const char debugdir[] = "debugaxp";
1136 #endif
1137 
1138 #elif defined _WIN64
1139 
1140 	const char gamename[] = "gamex86_64.dll";
1141 
1142 #ifdef NDEBUG
1143 	const char debugdir[] = "release";
1144 #else
1145 	const char debugdir[] = "debug";
1146 #endif
1147 
1148 #else
1149 #error Don't know what kind of dynamic objects to use for this architecture.
1150 #endif
1151 
1152 	if (game_library)
1153 		Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
1154 
1155 	// check the current debug directory first for development purposes
1156 	_getcwd (cwd, sizeof(cwd));
1157 	Com_sprintf (newname, sizeof(newname), "%s/%s/%s.new", cwd, debugdir, gamename);
1158 	Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename);
1159 	newExists = fopen (newname, "rb");
1160 	if (newExists)
1161 	{
1162 		Com_DPrintf ("%s.new found, moving to %s...\n", gamename, gamename);
1163 		fclose (newExists);
1164 		remove (name);
1165 		rename (newname, name);
1166 	}
1167 	game_library = LoadLibrary ( name );
1168 	if (game_library)
1169 	{
1170 		Com_DPrintf ("LoadLibrary (%s)\n", name);
1171 	}
1172 	else
1173 	{
1174 #ifdef _DEBUG
1175 		// check the current directory for other development purposes
1176 		Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename);
1177 		Com_sprintf (newname, sizeof(newname), "%s/%s.new", cwd, gamename);
1178 		newExists = fopen (newname, "rb");
1179 		if (newExists)
1180 		{
1181 			Com_DPrintf ("%s.new found, moving to %s...\n", gamename, gamename);
1182 			fclose (newExists);
1183 			remove (name);
1184 			rename (newname, name);
1185 		}
1186 		game_library = LoadLibrary ( name );
1187 		if (game_library)
1188 		{
1189 			Com_DPrintf ("LoadLibrary (%s)\n", name);
1190 		}
1191 		else
1192 #endif
1193 		{
1194 			// now run through the search paths
1195 			if (baseq2DLL)
1196 			{
1197 				Com_sprintf (name, sizeof(name), "./" BASEDIRNAME "/%s", gamename);
1198 				game_library = LoadLibrary (name);
1199 			}
1200 			else
1201 			{
1202 				path = NULL;
1203 				for (;;)
1204 				{
1205 					path = FS_NextPath (path);
1206 					if (!path)
1207 						return NULL;		// couldn't find one anywhere
1208 					Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
1209 					Com_sprintf (newname, sizeof(newname), "%s/%s.new", path, gamename);
1210 					newExists = fopen (newname, "rb");
1211 					if (newExists)
1212 					{
1213 						Com_DPrintf ("%s.new found, moving to %s...\n", gamename, gamename);
1214 						fclose (newExists);
1215 						remove (name);
1216 						rename (newname, name);
1217 					}
1218 					game_library = LoadLibrary (name);
1219 					if (game_library)
1220 					{
1221 						Com_DPrintf ("LoadLibrary (%s)\n",name);
1222 						break;
1223 					}
1224 					else
1225 						Com_DPrintf ("LoadLibrary (%s) = %d\n", name, GetLastError());
1226 				}
1227 			}
1228 		}
1229 	}
1230 
1231 	if (!game_library)
1232 		return NULL;
1233 
1234 	//if (!Sys_CheckFPUStatus())
1235 	//	Com_Printf ("\2WARNING: The FPU control word was changed after loading %s!\n", LOG_GENERAL, name);
1236 
1237 	GetGameAPI = (void *(IMPORT *)(void *))GetProcAddress (game_library, "GetGameAPI");
1238 	if (!GetGameAPI)
1239 	{
1240 		Sys_UnloadGame ();
1241 		return NULL;
1242 	}
1243 
1244 	return GetGameAPI (parms);
1245 }
1246 #endif
1247 
1248 //=======================================================================
1249 
1250 
1251 /*
1252 ==================
1253 ParseCommandLine
1254 
1255 ==================
1256 */
ParseCommandLine(LPSTR lpCmdLine)1257 void ParseCommandLine (LPSTR lpCmdLine)
1258 {
1259 	char *p;
1260 
1261 	argc = 1;
1262 	argv[0] = "exe";
1263 
1264 	GetModuleFileName (NULL, bname, sizeof(bname)-1);
1265 	p = strrchr (bname, '\\');
1266 	if (p)
1267 		binary_name = p + 1;
1268 	else
1269 		binary_name = bname;
1270 
1271 	while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
1272 	{
1273 		while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
1274 			lpCmdLine++;
1275 
1276 		if (*lpCmdLine)
1277 		{
1278 			argv[argc] = lpCmdLine;
1279 			argc++;
1280 
1281 			while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
1282 				lpCmdLine++;
1283 
1284 			if (*lpCmdLine)
1285 			{
1286 				*lpCmdLine = 0;
1287 				lpCmdLine++;
1288 			}
1289 
1290 		}
1291 	}
1292 }
1293 
1294 /*#ifndef NO_SERVER
1295 void QuakeMain (void)
1296 {
1297 	int				time, oldtime, newtime;
1298 
1299 	oldtime = Sys_Milliseconds ();
1300 
1301 	_controlfp( _PC_24, _MCW_PC );
1302 
1303 	for (;;)
1304 	{
1305 		if (Minimized || dedicated->intvalue)
1306 			Sleep (1);
1307 
1308 		do
1309 		{
1310 			newtime = Sys_Milliseconds ();
1311 			time = newtime - oldtime;
1312 		} while (time < 1);
1313 
1314 		Qcommon_Frame (time);
1315 
1316 		oldtime = newtime;
1317 	}
1318 }
1319 #endif*/
1320 
FixWorkingDirectory(void)1321 void FixWorkingDirectory (void)
1322 {
1323 	int		i;
1324 	char	*p;
1325 	char	curDir[MAX_PATH];
1326 
1327 	GetModuleFileName (NULL, curDir, sizeof(curDir)-1);
1328 
1329 	p = strrchr (curDir, '\\');
1330 	p[0] = 0;
1331 
1332 	for (i = 1; i < argc; i++)
1333 	{
1334 		if (!strcmp (argv[i], "-nopathcheck"))
1335 			goto skipPathCheck;
1336 
1337 		if (!strcmp (argv[i], "-nocwdcheck"))
1338 			return;
1339 	}
1340 
1341 	if (strlen(curDir) > (MAX_OSPATH - MAX_QPATH))
1342 		Sys_Error ("Current path is too long. Please move your Quake II installation to a shorter path.");
1343 
1344 skipPathCheck:
1345 
1346 	SetCurrentDirectory (curDir);
1347 }
1348 
1349 #ifdef ANTICHEAT
1350 #ifndef DEDICATED_ONLY
1351 /*
1352 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
1353 
1354 BOOL IsWow64()
1355 {
1356     BOOL bIsWow64 = FALSE;
1357 	LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("KERNEL32"),"IsWow64Process");
1358 
1359     if (NULL != fnIsWow64Process)
1360     {
1361         fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
1362     }
1363     return bIsWow64;
1364 }*/
1365 
1366 typedef struct
1367 {
1368 	void (*Check) (void);
1369 } anticheat_export_t;
1370 
1371 anticheat_export_t *anticheat;
1372 
1373 typedef VOID * (*FNINIT) (VOID);
1374 
Sys_GetAntiCheatAPI(void)1375 int Sys_GetAntiCheatAPI (void)
1376 {
1377 	qboolean			updated = false;
1378 	HMODULE				hAC;
1379 	static FNINIT		init = NULL;
1380 
1381 	//windows version check
1382 	if (s_win95)
1383 	{
1384 		Com_Printf ("ERROR: Anticheat requires Windows 2000/XP/2003/Vista.\n", LOG_GENERAL);
1385 		return 0;
1386 	}
1387 
1388 	/*if (IsWow64())
1389 	{
1390 		Com_Printf ("ERROR: Anticheat is currently incompatible with 64 bit Windows.\n", LOG_GENERAL);
1391 		return 0;
1392 	}*/
1393 
1394 	//already loaded, just reinit
1395 	if (anticheat)
1396 	{
1397 		anticheat = (anticheat_export_t *)init ();
1398 		if (!anticheat)
1399 			return 0;
1400 		return 1;
1401 	}
1402 
1403 reInit:
1404 
1405 #if defined(_DEBUG)
1406 	hAC = LoadLibrary ("anticheatd");
1407 #else
1408 	hAC = LoadLibrary ("anticheat");
1409 #endif
1410 	if (!hAC)
1411 		return 0;
1412 
1413 	//this should never fail unless the anticheat.dll is bad
1414 	if (!init)
1415 	{
1416 		init = (FNINIT)GetProcAddress (hAC, "Initialize");
1417 		if (!init)
1418 			Sys_Error ("Couldn't GetProcAddress Initialize on anticheat.dll!\r\n\r\nPlease check you are using a valid anticheat.dll from http://antiche.at/");
1419 	}
1420 
1421 	anticheat = (anticheat_export_t *)init ();
1422 
1423 	if (!updated && !anticheat)
1424 	{
1425 		updated = true;
1426 		FreeLibrary (hAC);
1427 		hAC = NULL;
1428 		init = NULL;
1429 		goto reInit;
1430 	}
1431 
1432 	if (!anticheat)
1433 		return 0;
1434 
1435 	//if (!Sys_CheckFPUStatus ())
1436 	//	Com_Printf ("\2WARNING: The FPU control word has changed after loading anticheat!\n", LOG_GENERAL);
1437 
1438 	return 1;
1439 }
1440 #endif
1441 #endif
1442 
1443 typedef BOOL (WINAPI *ENUMERATELOADEDMODULES64) (HANDLE hProcess, PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback, PVOID UserContext);
1444 typedef DWORD (WINAPI *SYMSETOPTIONS) (DWORD SymOptions);
1445 typedef BOOL (WINAPI *SYMINITIALIZE) (HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess);
1446 typedef BOOL (WINAPI *SYMCLEANUP) (HANDLE hProcess);
1447 typedef BOOL (WINAPI *STACKWALK64) (
1448 								DWORD MachineType,
1449 								HANDLE hProcess,
1450 								HANDLE hThread,
1451 								LPSTACKFRAME64 StackFrame,
1452 								PVOID ContextRecord,
1453 								PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
1454 								PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
1455 								PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
1456 								PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
1457 								);
1458 
1459 typedef PVOID	(WINAPI *SYMFUNCTIONTABLEACCESS64) (HANDLE hProcess, DWORD64 AddrBase);
1460 typedef DWORD64 (WINAPI *SYMGETMODULEBASE64) (HANDLE hProcess, DWORD64 dwAddr);
1461 typedef BOOL	(WINAPI *SYMFROMADDR) (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol);
1462 typedef BOOL	(WINAPI *SYMGETMODULEINFO64) (HANDLE hProcess, DWORD64 dwAddr, PIMAGEHLP_MODULE64 ModuleInfo);
1463 
1464 typedef DWORD64 (WINAPI *SYMLOADMODULE64) (HANDLE hProcess, HANDLE hFile, PSTR ImageName, PSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll);
1465 
1466 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP) (
1467 	HANDLE hProcess,
1468 	DWORD ProcessId,
1469 	HANDLE hFile,
1470 	MINIDUMP_TYPE DumpType,
1471 	PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
1472 	PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
1473 	PMINIDUMP_CALLBACK_INFORMATION CallbackParam
1474 	);
1475 
1476 typedef HINSTANCE (WINAPI *SHELLEXECUTEA) (HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd);
1477 
1478 SYMGETMODULEINFO64	fnSymGetModuleInfo64;
1479 SYMLOADMODULE64		fnSymLoadModule64;
1480 
1481 typedef BOOL (WINAPI *VERQUERYVALUE) (const LPVOID pBlock, LPTSTR lpSubBlock, PUINT lplpBuffer, PUINT puLen);
1482 typedef DWORD (WINAPI *GETFILEVERSIONINFOSIZE) (LPTSTR lptstrFilename, LPDWORD lpdwHandle);
1483 typedef BOOL (WINAPI *GETFILEVERSIONINFO) (LPTSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
1484 
1485 VERQUERYVALUE			fnVerQueryValue;
1486 GETFILEVERSIONINFOSIZE	fnGetFileVersionInfoSize;
1487 GETFILEVERSIONINFO		fnGetFileVersionInfo;
1488 BOOL					versionedGL = FALSE;
1489 
EnumerateLoadedModulesProcDump(PSTR ModuleName,DWORD64 ModuleBase,ULONG ModuleSize,PVOID UserContext)1490 BOOL CALLBACK EnumerateLoadedModulesProcDump (PSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext)
1491 {
1492 	VS_FIXEDFILEINFO *fileVersion;
1493 	BYTE	*verInfo;
1494 	DWORD	dummy, len;
1495 	FILE	*fhReport = (FILE *)UserContext;
1496 	CHAR	verString[32];
1497 	CHAR	lowered[MAX_PATH];
1498 
1499 	Q_strncpy (lowered, ModuleName, sizeof(lowered)-1);
1500 	strlwr (lowered);
1501 
1502 	if (fnGetFileVersionInfo && fnVerQueryValue && fnGetFileVersionInfoSize)
1503 	{
1504 		if (len = (fnGetFileVersionInfoSize (ModuleName, &dummy)))
1505 		{
1506 			verInfo = LocalAlloc (LPTR, len);
1507 			if (fnGetFileVersionInfo (ModuleName, dummy, len, verInfo))
1508 			{
1509 				if (fnVerQueryValue (verInfo, "\\", (LPVOID)&fileVersion, &dummy))
1510 				{
1511 					if (strstr (lowered, "ref_gl"))
1512 						versionedGL = TRUE;
1513 					sprintf (verString, "%d.%d.%d.%d", HIWORD(fileVersion->dwFileVersionMS), LOWORD(fileVersion->dwFileVersionMS), HIWORD(fileVersion->dwFileVersionLS), LOWORD(fileVersion->dwFileVersionLS));
1514 				}
1515 				else
1516 				{
1517 					strcpy (verString, "unknown");
1518 				}
1519 			}
1520 			else
1521 			{
1522 				strcpy (verString, "unknown");
1523 			}
1524 
1525 			LocalFree (verInfo);
1526 		}
1527 		else
1528 		{
1529 			strcpy (verString, "unknown");
1530 		}
1531 	}
1532 	else
1533 	{
1534 		strcpy (verString, "unknown");
1535 	}
1536 
1537 #ifdef _M_AMD64
1538 	fprintf (fhReport, "[0x%16I64X - 0x%16I64X] %s (%lu bytes, version %s)\r\n", ModuleBase, ModuleBase + (DWORD64)ModuleSize, ModuleName, ModuleSize, verString);
1539 #else
1540 	fprintf (fhReport, "[0x%08I64X - 0x%08I64X] %s (%lu bytes, version %s)\r\n", ModuleBase, ModuleBase + (DWORD64)ModuleSize, ModuleName, ModuleSize, verString);
1541 #endif
1542 	return TRUE;
1543 }
1544 
EnumerateLoadedModulesProcSymInfo(PSTR ModuleName,DWORD64 ModuleBase,ULONG ModuleSize,PVOID UserContext)1545 BOOL CALLBACK EnumerateLoadedModulesProcSymInfo (PSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext)
1546 {
1547 	IMAGEHLP_MODULE64	symInfo = {0};
1548 	FILE				*fhReport = (FILE *)UserContext;
1549 	//CHAR				szImageName[512];
1550 	PCHAR				symType;
1551 
1552 	symInfo.SizeOfStruct = sizeof(symInfo);
1553 
1554 	if (fnSymGetModuleInfo64 (GetCurrentProcess(), ModuleBase, &symInfo))
1555 	{
1556 		//WideCharToMultiByte (CP_UTF8, 0, symInfo.LoadedImageName, -1, szImageName, sizeof(szImageName), 0, NULL);
1557 
1558 		switch (symInfo.SymType)
1559 		{
1560 		case SymCoff:
1561 			symType = "COFF";
1562 			break;
1563 		case SymCv:
1564 			symType = "CV";
1565 			break;
1566 		case SymExport:
1567 			symType = "Export";
1568 			break;
1569 		case SymPdb:
1570 			symType = "PDB";
1571 			break;
1572 		case SymNone:
1573 			symType = "No";
1574 			break;
1575 		default:
1576 			symType = "Unknown";
1577 			break;
1578 		}
1579 
1580 		fprintf (fhReport, "%s, %s symbols loaded.\r\n", symInfo.LoadedImageName, symType);
1581 	}
1582 	else
1583 	{
1584 		int i = GetLastError ();
1585 		fprintf (fhReport, "%s, couldn't check symbols (error %d, DBGHELP.DLL too old?)\r\n", ModuleName, i);
1586 	}
1587 
1588 	return TRUE;
1589 }
1590 
1591 CHAR	szModuleName[MAX_PATH];
1592 
EnumerateLoadedModulesProcInfo(PSTR ModuleName,DWORD64 ModuleBase,ULONG ModuleSize,PVOID UserContext)1593 BOOL CALLBACK EnumerateLoadedModulesProcInfo (PSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext)
1594 {
1595 	DWORD64	addr = (DWORD64)UserContext;
1596 	if (addr > ModuleBase && addr < ModuleBase + ModuleSize)
1597 	{
1598 		strncpy (szModuleName, ModuleName, sizeof(szModuleName)-1);
1599 		return FALSE;
1600 	}
1601 	return TRUE;
1602 }
1603 
1604 #ifdef USE_CURL
R1Q2UploadProgress(void * clientp,double dltotal,double dlnow,double ultotal,double ulnow)1605 static int EXPORT R1Q2UploadProgress (void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
1606 {
1607 	char	progressBuff[512];
1608 	DWORD	len, ret;
1609 	double	speed;
1610 	int		percent;
1611 
1612 	if (ultotal <= 0)
1613 		return 0;
1614 
1615 	curl_easy_getinfo ((CURL *)clientp, CURLINFO_SPEED_UPLOAD, &speed);
1616 
1617 	percent = (int)((ulnow / ultotal)*100.0f);
1618 
1619 	len = snprintf (progressBuff, sizeof(progressBuff)-1, "[%d%%] %g / %g bytes, %g bytes/sec.\n", percent, ulnow, ultotal, speed);
1620 	WriteConsole(GetStdHandle (STD_OUTPUT_HANDLE), progressBuff, len, &ret, NULL);
1621 
1622 	snprintf (progressBuff, sizeof(progressBuff)-1, "[%d%%] R1Q2 Crash Dump Uploader", percent);
1623 	SetConsoleTitle (progressBuff);
1624 
1625 	return 0;
1626 }
1627 
1628 #ifndef DEDICATED_ONLY
1629 extern cvar_t	*cl_http_proxy;
1630 #endif
R1Q2UploadCrashDump(LPCSTR crashDump,LPCSTR crashText)1631 VOID R1Q2UploadCrashDump (LPCSTR crashDump, LPCSTR crashText)
1632 {
1633 	struct curl_httppost* post = NULL;
1634 	struct curl_httppost* last = NULL;
1635 
1636 	CURL	*curl;
1637 
1638 	DWORD	lenDmp;
1639 	DWORD	lenTxt;
1640 	DWORD	ret;
1641 
1642 	BOOL	console = FALSE;
1643 
1644 	__try
1645 	{
1646 		lenDmp = Sys_FileLength (crashDump);
1647 		lenTxt = Sys_FileLength (crashText);
1648 
1649 		if (lenTxt == -1)
1650 			return;
1651 
1652 		if (AllocConsole ())
1653 			console = TRUE;
1654 
1655 		SetConsoleTitle ("R1Q2 Crash Dump Uploader");
1656 
1657 		if (console)
1658 			WriteConsole(GetStdHandle (STD_OUTPUT_HANDLE), "Connecting...\n", 14, &ret, NULL);
1659 
1660 		curl = curl_easy_init ();
1661 
1662 		/* Add simple file section */
1663 		if (lenDmp > 0)
1664 			curl_formadd (&post, &last, CURLFORM_PTRNAME, "minidump", CURLFORM_FILE, crashDump, CURLFORM_END);
1665 
1666 		curl_formadd (&post, &last, CURLFORM_PTRNAME, "report", CURLFORM_FILE, crashText, CURLFORM_END);
1667 
1668 		/* Set the form info */
1669 		curl_easy_setopt (curl, CURLOPT_HTTPPOST, post);
1670 
1671 #ifndef DEDICATED_ONLY
1672 		if (cl_http_proxy)
1673 			curl_easy_setopt (curl, CURLOPT_PROXY, cl_http_proxy->string);
1674 #endif
1675 
1676 		//curl_easy_setopt (curl, CURLOPT_UPLOAD, 1);
1677 		if (console)
1678 		{
1679 			curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, R1Q2UploadProgress);
1680 			curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, curl);
1681 			curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0);
1682 		}
1683 		else
1684 		{
1685 			curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1);
1686 		}
1687 
1688 		curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1);
1689 		curl_easy_setopt (curl, CURLOPT_USERAGENT, R1Q2_VERSION_STRING);
1690 		curl_easy_setopt (curl, CURLOPT_URL, "http://www.r1ch.net/stuff/r1q2/receiveCrashDump.php");
1691 
1692 		if (curl_easy_perform (curl) != CURLE_OK)
1693 		{
1694 			if (!win_silentexceptionhandler->intvalue)
1695 				MessageBox (NULL, "An error occured while trying to upload the crash dump. Please post it manually on the R1Q2 forums.", "Upload Error", MB_ICONEXCLAMATION | MB_OK);
1696 		}
1697 		else
1698 		{
1699 			if (!win_silentexceptionhandler->intvalue)
1700 			{
1701 				long response;
1702 
1703 				if (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response) == CURLE_OK)
1704 				{
1705 					if (response == 202)
1706 					{
1707 						MessageBox (NULL, "Upload completed, however the server reports that you are using an out of date R1Q2 version. Crash reports from old versions are not as likely to be investigated as the problem may already have been fixed. Please update your R1Q2 using the R1Q2Updater.", "Upload Complete", MB_ICONEXCLAMATION | MB_OK);
1708 					}
1709 					else if (response == 200)
1710 					{
1711 						MessageBox (NULL, "Upload completed. Thanks for submitting your crash report!\n\nIf you would like feedback on the cause of this crash, please post a brief note on the R1Q2 forums describing what you were doing at the time the exception occured. If possible, please also attach the R1Q2CrashLog.txt file.", "Upload Complete", MB_ICONINFORMATION | MB_OK);
1712 					}
1713 					else
1714 					{
1715 						MessageBox (NULL, "Upload failed, HTTP error.", "Upload Failed", MB_ICONEXCLAMATION | MB_OK);
1716 					}
1717 				}
1718 			}
1719 		}
1720 	}
1721 	__except (EXCEPTION_EXECUTE_HANDLER)
1722 	{
1723 		if (!win_silentexceptionhandler->intvalue)
1724 			MessageBox (NULL, "An exception occured while trying to upload the crash dump. Please post it manually on the R1Q2 forums.", "Upload Error", MB_ICONEXCLAMATION | MB_OK);
1725 	}
1726 
1727 	if (console)
1728 		FreeConsole ();
1729 }
1730 #endif
1731 
IsOpenGLValid(VOID)1732 BOOL IsOpenGLValid (VOID)
1733 {
1734 	HMODULE	hOpenGL;
1735 
1736 	hOpenGL = GetModuleHandle ("OPENGL32");
1737 	if (hOpenGL)
1738 	{
1739 		CHAR	openglPath[MAX_PATH];
1740 		CHAR	systemPath[MAX_PATH];
1741 
1742 		GetModuleFileName (hOpenGL, openglPath, sizeof(openglPath)-1);
1743 		GetSystemDirectory (systemPath, sizeof(systemPath)-1);
1744 
1745 		strlwr (openglPath);
1746 		strlwr (systemPath);
1747 
1748 		if (strstr (openglPath, systemPath))
1749 			return TRUE;
1750 	}
1751 
1752 	return FALSE;
1753 }
1754 
R1Q2ExceptionHandler(DWORD exceptionCode,LPEXCEPTION_POINTERS exceptionInfo)1755 DWORD R1Q2ExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo)
1756 {
1757 	FILE	*fhReport;
1758 
1759 	HANDLE	hProcess;
1760 
1761 	HMODULE	hDbgHelp, hVersion;
1762 
1763 	MINIDUMP_EXCEPTION_INFORMATION miniInfo;
1764 	STACKFRAME64	frame = {0};
1765 	CONTEXT			context = *exceptionInfo->ContextRecord;
1766 	SYMBOL_INFO		*symInfo;
1767 	DWORD64			fnOffset;
1768 	CHAR			tempPath[MAX_PATH];
1769 	CHAR			dumpPath[MAX_PATH];
1770 	OSVERSIONINFOEX	osInfo;
1771 	SYSTEMTIME		timeInfo;
1772 
1773 	ENUMERATELOADEDMODULES64	fnEnumerateLoadedModules64;
1774 	SYMSETOPTIONS				fnSymSetOptions;
1775 	SYMINITIALIZE				fnSymInitialize;
1776 	STACKWALK64					fnStackWalk64;
1777 	SYMFUNCTIONTABLEACCESS64	fnSymFunctionTableAccess64;
1778 	SYMGETMODULEBASE64			fnSymGetModuleBase64;
1779 	SYMFROMADDR					fnSymFromAddr;
1780 	SYMCLEANUP					fnSymCleanup;
1781 	MINIDUMPWRITEDUMP			fnMiniDumpWriteDump;
1782 
1783 	DWORD						ret, i;
1784 	DWORD64						InstructionPtr;
1785 
1786 	BOOL						wantUpload = TRUE;
1787 
1788 	CHAR						searchPath[MAX_PATH], *p, *gameMsg;
1789 
1790 	if (win_disableexceptionhandler->intvalue == 2)
1791 		return EXCEPTION_EXECUTE_HANDLER;
1792 	else if (win_disableexceptionhandler->intvalue)
1793 		return EXCEPTION_CONTINUE_SEARCH;
1794 
1795 #ifndef DEDICATED_ONLY
1796 	ShowCursor (TRUE);
1797 	if (cl_hwnd)
1798 		DestroyWindow (cl_hwnd);
1799 #else
1800 	if (hwnd_Server)
1801 		EnableWindow (hwnd_Server, FALSE);
1802 #endif
1803 
1804 #ifdef _DEBUG
1805 	ret = MessageBox (NULL, "EXCEPTION_CONTINUE_SEARCH?", "Unhandled Exception", MB_ICONERROR | MB_YESNO);
1806 	if (ret == IDYES)
1807 		return EXCEPTION_CONTINUE_SEARCH;
1808 #endif
1809 
1810 #ifndef _DEBUG
1811 	if (IsDebuggerPresent ())
1812 		return EXCEPTION_CONTINUE_SEARCH;
1813 #endif
1814 
1815 	hDbgHelp = LoadLibrary ("DBGHELP");
1816 	hVersion = LoadLibrary ("VERSION");
1817 
1818 	if (!hDbgHelp)
1819 	{
1820 		if (!win_silentexceptionhandler->intvalue)
1821 			MessageBox (NULL, PRODUCTNAME " has encountered an unhandled exception and must be terminated. No crash report could be generated since R1Q2 failed to load DBGHELP.DLL. Please obtain DBGHELP.DLL and place it in your R1Q2 directory to enable crash dump generation.", "Unhandled Exception", MB_OK | MB_ICONEXCLAMATION);
1822 		return EXCEPTION_CONTINUE_SEARCH;
1823 	}
1824 
1825 	if (hVersion)
1826 	{
1827 		fnVerQueryValue = (VERQUERYVALUE)GetProcAddress (hVersion, "VerQueryValueA");
1828 		fnGetFileVersionInfo = (GETFILEVERSIONINFO)GetProcAddress (hVersion, "GetFileVersionInfoA");
1829 		fnGetFileVersionInfoSize = (GETFILEVERSIONINFOSIZE)GetProcAddress (hVersion, "GetFileVersionInfoSizeA");
1830 	}
1831 
1832 	fnEnumerateLoadedModules64 = (ENUMERATELOADEDMODULES64)GetProcAddress (hDbgHelp, "EnumerateLoadedModules64");
1833 	fnSymSetOptions = (SYMSETOPTIONS)GetProcAddress (hDbgHelp, "SymSetOptions");
1834 	fnSymInitialize = (SYMINITIALIZE)GetProcAddress (hDbgHelp, "SymInitialize");
1835 	fnSymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESS64)GetProcAddress (hDbgHelp, "SymFunctionTableAccess64");
1836 	fnSymGetModuleBase64 = (SYMGETMODULEBASE64)GetProcAddress (hDbgHelp, "SymGetModuleBase64");
1837 	fnStackWalk64 = (STACKWALK64)GetProcAddress (hDbgHelp, "StackWalk64");
1838 	fnSymFromAddr = (SYMFROMADDR)GetProcAddress (hDbgHelp, "SymFromAddr");
1839 	fnSymCleanup = (SYMCLEANUP)GetProcAddress (hDbgHelp, "SymCleanup");
1840 	fnSymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress (hDbgHelp, "SymGetModuleInfo64");
1841 	//fnSymLoadModule64 = (SYMLOADMODULE64)GetProcAddress (hDbgHelp, "SymLoadModule64");
1842 	fnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress (hDbgHelp, "MiniDumpWriteDump");
1843 
1844 	if (!fnEnumerateLoadedModules64 || !fnSymSetOptions || !fnSymInitialize || !fnSymFunctionTableAccess64 ||
1845 		!fnSymGetModuleBase64 || !fnStackWalk64 || !fnSymFromAddr || !fnSymCleanup || !fnSymGetModuleInfo64)// ||
1846 		//!fnSymLoadModule64)
1847 	{
1848 		FreeLibrary (hDbgHelp);
1849 		if (hVersion)
1850 			FreeLibrary (hVersion);
1851 		MessageBox (NULL, PRODUCTNAME " has encountered an unhandled exception and must be terminated. No crash report could be generated since the version of DBGHELP.DLL in use is too old. Please obtain an up-to-date DBGHELP.DLL and place it in your R1Q2 directory to enable crash dump generation.", "Unhandled Exception", MB_OK | MB_ICONEXCLAMATION);
1852 		return EXCEPTION_CONTINUE_SEARCH;
1853 	}
1854 
1855 	if (!win_silentexceptionhandler->intvalue)
1856 		ret = MessageBox (NULL, PRODUCTNAME " has encountered an unhandled exception and must be terminated. Would you like to generate a crash report?", "Unhandled Exception", MB_ICONEXCLAMATION | MB_YESNO);
1857 	else
1858 		ret = IDYES;
1859 
1860 	if (ret == IDNO)
1861 	{
1862 		FreeLibrary (hDbgHelp);
1863 		if (hVersion)
1864 			FreeLibrary (hVersion);
1865 		return EXCEPTION_CONTINUE_SEARCH;
1866 	}
1867 
1868 	hProcess = GetCurrentProcess();
1869 
1870 	fnSymSetOptions (SYMOPT_UNDNAME | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_ANYTHING);
1871 
1872 	GetModuleFileName (NULL, searchPath, sizeof(searchPath));
1873 	p = strrchr (searchPath, '\\');
1874 	if (p) p[0] = 0;
1875 
1876 	GetSystemTime (&timeInfo);
1877 
1878 	i = 1;
1879 
1880 	for (;;)
1881 	{
1882 		snprintf (tempPath, sizeof(tempPath)-1, "%s\\R1Q2CrashLog%.4d-%.2d-%.2d%_%d.txt", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, i);
1883 		if (Sys_FileLength (tempPath) == -1)
1884 			break;
1885 		i++;
1886 	}
1887 
1888 	fhReport = fopen (tempPath, "wb");
1889 
1890 	if (!fhReport)
1891 	{
1892 		FreeLibrary (hDbgHelp);
1893 		if (hVersion)
1894 			FreeLibrary (hVersion);
1895 		return EXCEPTION_CONTINUE_SEARCH;
1896 	}
1897 
1898 #ifdef _DEBUG
1899 	//strcat (searchPath, ";c:\\websyms");
1900 #endif
1901 
1902 	fnSymInitialize (hProcess, searchPath, TRUE);
1903 
1904 #ifdef _DEBUG
1905 	GetModuleFileName (NULL, searchPath, sizeof(searchPath));
1906 	p = strrchr (searchPath, '\\');
1907 	if (p) p[0] = 0;
1908 #endif
1909 
1910 
1911 #ifdef _M_AMD64
1912 	InstructionPtr = context.Rip;
1913 	frame.AddrPC.Offset = InstructionPtr;
1914 	frame.AddrFrame.Offset = context.Rbp;
1915 	frame.AddrStack.Offset = context.Rsp;
1916 #else
1917 	InstructionPtr = context.Eip;
1918 	frame.AddrPC.Offset = InstructionPtr;
1919 	frame.AddrFrame.Offset = context.Ebp;
1920 	frame.AddrStack.Offset = context.Esp;
1921 #endif
1922 
1923 	frame.AddrFrame.Mode = AddrModeFlat;
1924 	frame.AddrPC.Mode = AddrModeFlat;
1925 	frame.AddrStack.Mode = AddrModeFlat;
1926 
1927 	symInfo = LocalAlloc (LPTR, sizeof(*symInfo) + 128);
1928 	symInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
1929 	symInfo->MaxNameLen = 128;
1930 	fnOffset = 0;
1931 
1932 	memset (&osInfo, 0, sizeof(osInfo));
1933 	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
1934 
1935 	if (!GetVersionEx ((OSVERSIONINFO *)&osInfo))
1936 	{
1937 		osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1938 		GetVersionEx ((OSVERSIONINFO *)&osInfo);
1939 	}
1940 
1941 	strcpy (szModuleName, "<unknown>");
1942 	fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)InstructionPtr);
1943 
1944 	strlwr (szModuleName);
1945 
1946 	if (strstr (szModuleName, "gamex86.dll"))
1947 	{
1948 		gameMsg =
1949 			"It is very likely that the Game DLL you are using for the mod you run is at fault.\r\n"
1950 			"Please send this crash report to the author(s) of the mod you are running.";
1951 		wantUpload = FALSE;
1952 	}
1953 	else if (strstr (szModuleName, "ref_soft.dll"))
1954 	{
1955 		gameMsg =
1956 			"It is very likely that the software renderer (ref_soft) is at fault. Software\r\n"
1957 			"rendering in Q2 has always been unreliable. If possible, please use OpenGL to avoid\r\n"
1958 			"crashes. Consider using the modified ref_soft.dll available on the r1ch.net forums to\r\n"
1959 			"fix some small bugs if you are not using it already.";
1960 		wantUpload = FALSE;
1961 	}
1962 	else if (strstr (szModuleName, "opengl32.dll"))
1963 	{
1964 		if (!IsOpenGLValid ())
1965 		{
1966 			gameMsg =
1967 				"You have an OPENGL32.DLL file in your Quake II folder. This is overriding the correct\r\n"
1968 				"DLL from your Windows system folder. Delete the OPENGL32.DLL in your Quake II folder to\r\n"
1969 				"ensure the correct version of OPENGL is loaded.";
1970 			wantUpload = FALSE;
1971 		}
1972 		else
1973 		{
1974 			gameMsg =
1975 				"This crash occured in OpenGL. Make sure you are using the latest video drivers and\r\n"
1976 				"the latest version of R1GL. If you are using software mode, consider switching to\r\n"
1977 				"OpenGL for better performance.";
1978 		}
1979 	}
1980 	else if (strstr (szModuleName, "ref_gl.dll") && !versionedGL)
1981 	{
1982 		gameMsg =
1983 			"This crash occured in ref_gl and you aren't using R1GL. It is unlikely that\r\n"
1984 			"this crash can be fixed. Consider switching to R1GL for improved crash\r\n"
1985 			"reporting, speed and stability. The original ref_gl has known crash bugs that\r\n"
1986 			"cannot be fixed so you will continue to crash unless you use R1GL.";
1987 		wantUpload = FALSE;
1988 	}
1989 	else if (strstr (szModuleName, "r1q2.exe") || strstr (szModuleName, "ref_r1gl.dll") || strstr (szModuleName, "dedicated.exe"))
1990 	{
1991 #ifdef USE_CURL
1992 		gameMsg =
1993 		"Since this crash appears to be inside R1Q2 or R1GL, it would be very helpful\r\n"
1994 		"if when prompted, you submitted the crash report to r1ch.net. This will aid in\r\n"
1995 		"finding the fault that caused this exception.";
1996 #else
1997 		gameMsg =
1998 		"\r\nSince this crash appears to be inside R1Q2 or R1GL, it would be very helpful\r\n"
1999 		"if you submitted the crash report to r1ch.net forums. This will aid in finding\r\n"
2000 		"the fault that caused this exception.";
2001 #endif
2002 	}
2003 	else
2004 	{
2005 		gameMsg =
2006 		"Please note, unless you are using both R1Q2 and R1GL, any crashes will be much\r\n"
2007 		"harder to diagnose. If you are still using ref_gl, please consider using R1GL for\r\n"
2008 		"an accurate crash report.";
2009 	}
2010 
2011 #ifdef USE_CURL
2012 	fprintf (fhReport,
2013 		PRODUCTNAME " encountered an unhandled exception and has terminated. If you are able to\r\n"
2014 		"reproduce this crash, please submit the crash report to r1ch.net when prompted or\r\n"
2015 		"post this file and the crash dump .dmp file (if available) on the R1Q2 forums at\r\n"
2016 		"http://www.r1ch.net/forum/index.php?board=8.0\r\n"
2017 		"\r\n"
2018 		"     PLEASE MAKE SURE YOU ARE USING THE LATEST VERSIONS OF R1Q2/R1GL/ETC!\r\n"
2019 		"\r\n"
2020 		"This crash appears to have occured in the '%s' module.\r\n%s\r\n\r\n", szModuleName, gameMsg);
2021 #else
2022 	fprintf (fhReport,
2023 		PRODUCTNAME " encountered an unhandled exception and has terminated. If you are able to\r\n"
2024 		"reproduce this crash, please submit the crash report on the R1Q2 forums at\r\n"
2025 		"http://www.r1ch.net/forum/index.php?board=8.0 - include this .txt file and the\r\n"
2026 		".dmp file (if available)\r\n"
2027 		"\r\n"
2028 		"This crash appears to have occured in the '%s' module.%s\r\n\r\n", szModuleName, gameMsg);
2029 #endif
2030 
2031 	fprintf (fhReport, "**** UNHANDLED EXCEPTION: %x\r\nFault address: %I64p (%s)\r\n", exceptionCode, InstructionPtr, szModuleName);
2032 
2033 	fprintf (fhReport, PRODUCTNAME " module: %s(%s) (Version: %s)\r\n", binary_name, R1BINARY, R1Q2_VERSION_STRING);
2034 	fprintf (fhReport, "Windows version: %d.%d (Build %d) %s\r\n\r\n", osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, osInfo.szCSDVersion);
2035 
2036 	fprintf (fhReport, "Symbol information:\r\n");
2037 	fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcSymInfo, (VOID *)fhReport);
2038 
2039 	fprintf (fhReport, "\r\nEnumerate loaded modules:\r\n");
2040 	fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcDump, (VOID *)fhReport);
2041 
2042 	fprintf (fhReport, "\r\nStack trace:\r\n");
2043 	fprintf (fhReport, "Stack    EIP      Arg0     Arg1     Arg2     Arg3     Address\r\n");
2044 	while (fnStackWalk64 (IMAGE_FILE_MACHINE_I386, hProcess, GetCurrentThread(), &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL))
2045 	{
2046 		strcpy (szModuleName, "<unknown>");
2047 		fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)frame.AddrPC.Offset);
2048 		strlwr (szModuleName);
2049 
2050 		p = strrchr (szModuleName, '\\');
2051 		if (p)
2052 		{
2053 			p++;
2054 		}
2055 		else
2056 		{
2057 			p = szModuleName;
2058 		}
2059 
2060 		if (strstr (p, "ref_gl.dll") && !versionedGL)
2061 		{
2062 			gameMsg =
2063 				"This crash occured in ref_gl and you aren't using R1GL. It is unlikely that "
2064 				"this crash can be fixed. Consider switching to R1GL for improved stability, speed "
2065 				"and crash reporting capabilities. The original ref_gl has known crash bugs that "
2066 				"cannot be fixed so you will continue to crash unless you use R1GL.";
2067 			wantUpload = FALSE;
2068 		}
2069 		else if (strstr (p, "ref_ncgl.dll"))
2070 		{
2071 			gameMsg =
2072 				"This crash occured in ref_ncgl.dll. It is unlikely that this crash can be fixed. "
2073 				"Consider switching to R1GL for improved stability, speed and crash reporting capabilities. "
2074 				"NoCheat GL has known crash bugs that are not fixed so you will continue to crash unless you "
2075 				"use R1GL.";
2076 			wantUpload = FALSE;
2077 		}
2078 		else if (strstr (p, "atioglxx.dll") || strstr (p, "atioglx2.dll"))
2079 		{
2080 			gameMsg =
2081 				"This crash occured in the ATI GL drivers. The ATI drivers are optimized in such "
2082 				"a way that makes debugging very difficult. Please make sure you are using the latest "
2083 				"ATI drivers and that you do not have any OPENGL32.DLL or ATIOGLXX.DLL files in your Q2 "
2084 				"folder.";
2085 			wantUpload = FALSE;
2086 		}
2087 		else if (strstr (p, "opengl32.dll"))
2088 		{
2089 			if (!IsOpenGLValid ())
2090 			{
2091 				gameMsg =
2092 					"You have an OPENGL32.DLL file in your Quake II folder. This is overriding the correct "
2093 					"DLL from your Windows system folder. Delete the OPENGL32.DLL in your Quake II folder to "
2094 					"ensure the correct version of OPENGL is loaded.";
2095 				wantUpload = FALSE;
2096 			}
2097 		}
2098 
2099 #ifdef _M_AMD64
2100 		if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
2101 		{
2102 			fprintf (fhReport, "%16I64X %16I64X %16I64X %16I64X %16I64X %16I64X %s!%s+0x%I64x\r\n", frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, symInfo->Name, fnOffset);
2103 		}
2104 		else
2105 		{
2106 			fprintf (fhReport, "%16I64X %16I64X %16I64X %16I64X %16I64X %16I64X %s!0x%I64x\r\n", frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, frame.AddrPC.Offset);
2107 		}
2108 #else
2109 		if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
2110 		{
2111 			fprintf (fhReport, "%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!%s+0x%I64x\r\n", frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, symInfo->Name, fnOffset);
2112 		}
2113 		else
2114 		{
2115 			fprintf (fhReport, "%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!0x%I64x\r\n", frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, frame.AddrPC.Offset);
2116 		}
2117 #endif
2118 	}
2119 
2120 	if (fnMiniDumpWriteDump)
2121 	{
2122 		HANDLE	hFile;
2123 
2124 		GetTempPath (sizeof(dumpPath)-16, dumpPath);
2125 		strcat (dumpPath, "R1Q2CrashDump.dmp");
2126 
2127 		hFile = CreateFile (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2128 		if (hFile != INVALID_HANDLE_VALUE)
2129 		{
2130 			miniInfo.ClientPointers = TRUE;
2131 			miniInfo.ExceptionPointers = exceptionInfo;
2132 			miniInfo.ThreadId = GetCurrentThreadId ();
2133 			if (fnMiniDumpWriteDump (hProcess, GetCurrentProcessId(), hFile, MiniDumpWithIndirectlyReferencedMemory|MiniDumpWithDataSegs, &miniInfo, NULL, NULL))
2134 			{
2135 #ifndef NO_ZLIB
2136 				FILE	*fh;
2137 #endif
2138 				CHAR	zPath[MAX_PATH];
2139 
2140 				CloseHandle (hFile);
2141 #ifndef NO_ZLIB
2142 				fh = fopen (dumpPath, "rb");
2143 				if (fh)
2144 				{
2145 
2146 					BYTE	buff[0xFFFF];
2147 					size_t	len;
2148 					gzFile	gz;
2149 
2150 					snprintf (zPath, sizeof(zPath)-1, "%s\\R1Q2CrashLog%.4d-%.2d-%.2d_%d.dmp.gz", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, i);
2151 					gz = gzopen (zPath, "wb");
2152 					if (gz)
2153 					{
2154 						while ((len = fread (buff, 1, sizeof(buff), fh)) > 0)
2155 						{
2156 							gzwrite (gz, buff, (unsigned int)len);
2157 						}
2158 						gzclose (gz);
2159 						fclose (fh);
2160 					}
2161 				}
2162 #else
2163 				snprintf (zPath, sizeof(zPath)-1, "%s\\R1Q2CrashLog%.4d-%.2d-%.2d_%d.dmp", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, i);
2164 				CopyFile (dumpPath, zPath, FALSE);
2165 #endif
2166 				DeleteFile (dumpPath);
2167 				strcpy (dumpPath, zPath);
2168 				fprintf (fhReport, "\r\nA minidump was saved to %s.\r\nPlease include this file when posting a crash report.\r\n", dumpPath);
2169 			}
2170 			else
2171 			{
2172 				CloseHandle (hFile);
2173 				DeleteFile (dumpPath);
2174 			}
2175 		}
2176 	}
2177 	else
2178 	{
2179 		fprintf (fhReport, "\r\nA minidump could not be created. Minidumps are only available on Windows XP or later.\r\n");
2180 	}
2181 
2182 	fclose (fhReport);
2183 
2184 	LocalFree (symInfo);
2185 
2186 	fnSymCleanup (hProcess);
2187 
2188 	if (!win_silentexceptionhandler->intvalue)
2189 	{
2190 		HMODULE shell;
2191 		shell = LoadLibrary ("SHELL32");
2192 		if (shell)
2193 		{
2194 			SHELLEXECUTEA fncOpen = (SHELLEXECUTEA)GetProcAddress (shell, "ShellExecuteA");
2195 			if (fncOpen)
2196                 fncOpen (NULL, NULL, tempPath, NULL, searchPath, SW_SHOWDEFAULT);
2197 
2198 			FreeLibrary (shell);
2199 		}
2200 	}
2201 
2202 #ifdef USE_CURL
2203 	if (wantUpload)
2204 	{
2205 		if (!win_silentexceptionhandler->intvalue)
2206 			ret = MessageBox (NULL, "Would you like to upload this crash report to r1ch.net to help improve R1Q2? If you are able to reproduce this crash, please do not submit multiple reports as this will only delay processing.\r\n\r\nIf you would like feedback on this crash, please post the crash report and .dmp file on the r1ch.net forums.", "Unhandled Exception", MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
2207 		else
2208 			ret = IDYES;
2209 
2210 		if (ret == IDYES)
2211 			R1Q2UploadCrashDump (dumpPath, tempPath);
2212 	}
2213 	else
2214 	{
2215 		CHAR message[1024], *s;
2216 		strcpy (message, "Crash analysis:\r\n\r\n");
2217 		strcat (message, gameMsg);
2218 		s = message + sizeof("Crash analysis:\r\n\r\n");
2219 		while (s[0])
2220 		{
2221 			if (s[0] == '\n')
2222 				s[0] = ' ';
2223 			else if (s[0] == '\r')
2224 				s[0] = ' ';
2225 			s++;
2226 		}
2227 
2228 		MessageBox (NULL, message, "Unhandled Exception", MB_OK | MB_ICONEXCLAMATION);
2229 	}
2230 #endif
2231 
2232 	FreeLibrary (hDbgHelp);
2233 	if (hVersion)
2234 		FreeLibrary (hVersion);
2235 
2236 	return EXCEPTION_EXECUTE_HANDLER;
2237 }
2238 
2239 #ifndef DEDICATED_ONLY
2240 
2241 char	sys_url_location[1024];
2242 
Sys_ShellExec(const char * cmd)2243 void Sys_ShellExec (const char *cmd)
2244 {
2245 	HMODULE shell;
2246 	shell = LoadLibrary ("SHELL32");
2247 	if (shell)
2248 	{
2249 		SHELLEXECUTEA fncOpen = (SHELLEXECUTEA)GetProcAddress (shell, "ShellExecuteA");
2250 		if (fncOpen)
2251             fncOpen (NULL, NULL, cmd, NULL, NULL, SW_SHOWDEFAULT);
2252 
2253 		FreeLibrary (shell);
2254 	}
2255 }
2256 
Sys_OpenURL(void)2257 void Sys_OpenURL (void)
2258 {
2259 	Sys_ShellExec (sys_url_location);
2260 }
2261 
Sys_UpdateURLMenu(const char * s)2262 void Sys_UpdateURLMenu (const char *s)
2263 {
2264 	HMENU	menu;
2265 	CHAR	title[80];
2266 	CHAR	*dots;
2267 
2268 	GetSystemMenu (cl_hwnd, TRUE);
2269 
2270 	if (strlen (s) > 64)
2271 		dots = "...";
2272 	else
2273 		dots = "";
2274 
2275 	strncpy (sys_url_location, s, sizeof(sys_url_location)-1);
2276 
2277 	Com_sprintf (title, sizeof(title), "Open \"%.64s%s\"", s, dots);
2278 
2279 	menu = GetSystemMenu (cl_hwnd, FALSE);
2280 	InsertMenu (menu, 0,  MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
2281 	InsertMenu (menu, 0,  MF_BYPOSITION, 1234, title);
2282 }
2283 #endif
2284 
2285 const __int64 nano100SecInWeek= (__int64)10000000*60*60*24*7;
2286 const __int64 nano100SecInDay = (__int64)10000000*60*60*24;
2287 const __int64 nano100SecInHour= (__int64)10000000*60*60;
2288 const __int64 nano100SecInMin = (__int64)10000000*60;
2289 const __int64 nano100SecInSec = (__int64)10000000;
2290 
Sys_ProcessTimes_f(void)2291 void Sys_ProcessTimes_f (void)
2292 {
2293 	FILETIME		createTime, exitTime, kernelTime, userTime;
2294 	__int64			total, tmp;
2295 	DWORD			days, hours, mins;
2296 	double			seconds;
2297 
2298 	GetProcessTimes (GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
2299 
2300 	total = *(__int64 *)&kernelTime;
2301 
2302 	tmp = total / nano100SecInDay;
2303 	days = (DWORD)tmp;
2304 	total -= tmp * nano100SecInDay;
2305 
2306 	tmp = total / nano100SecInHour;
2307 	hours = (DWORD)tmp;
2308 	total -= tmp * nano100SecInHour;
2309 
2310 	tmp = total / nano100SecInMin;
2311 	mins = (DWORD)tmp;
2312 	total -= tmp * nano100SecInMin;
2313 
2314 	seconds = (double)total / (double)nano100SecInSec;
2315 
2316 	Com_Printf ("%ud %uh %um %gs kernel\n", LOG_GENERAL, days, hours, mins, seconds);
2317 
2318 	total = *(__int64 *)&userTime;
2319 
2320 	tmp = total / nano100SecInDay;
2321 	days = (DWORD)tmp;
2322 	total -= tmp * nano100SecInDay;
2323 
2324 	tmp = total / nano100SecInHour;
2325 	hours = (DWORD)tmp;
2326 	total -= tmp * nano100SecInHour;
2327 
2328 	tmp = total / nano100SecInMin;
2329 	mins = (DWORD)tmp;
2330 	total -= tmp * nano100SecInMin;
2331 
2332 	seconds = (double)total / (double)nano100SecInSec;
2333 
2334 	Com_Printf ("%ud %uh %um %gs user\n", LOG_GENERAL, days, hours, mins, seconds);
2335 }
2336 
2337 static unsigned int badspins, goodspins;
2338 
Sys_Spinstats_f(void)2339 void Sys_Spinstats_f (void)
2340 {
2341 	Com_Printf ("%u fast spins, %u slow spins, %.2f%% slow.\n", LOG_GENERAL, goodspins, badspins, ((float)badspins / (float)(goodspins+badspins)) * 100.0f);
2342 }
2343 
2344 #ifdef _M_IX86
2345 
Sys_GetFPUStatus(void)2346 __declspec(naked) unsigned short Sys_GetFPUStatus (void)
2347 {
2348 	__asm
2349 	{
2350 		xor eax, eax
2351 		push eax
2352 		mov eax, esp
2353 		fnstcw dword ptr [eax]
2354 		pop eax
2355 		ret
2356 	}
2357 }
2358 
Sys_SetFPU(byte bits)2359 void Sys_SetFPU (byte bits)
2360 {
2361 	__asm
2362 	{
2363 		xor eax, eax
2364 		push eax
2365 		mov eax, esp
2366 		mov ecx, eax
2367 		fnstcw word ptr [eax]
2368 		mov eax, [eax]
2369 		and ah, 0f0h
2370 		or  ah, bits          ; RTZ/truncate/chop mode, 24 bit precision
2371 		mov [ecx], eax
2372 		fldcw word ptr [ecx]
2373 		pop eax
2374 	}
2375 }
2376 
2377 //FPU should be round to nearest, 24 bit precision.
2378 //3.20 = 0x007f
Sys_CheckFPUStatus(void)2379 qboolean Sys_CheckFPUStatus (void)
2380 {
2381 	static unsigned short	last_word = 0;
2382 	unsigned short	fpu_control_word;
2383 
2384 	fpu_control_word = Sys_GetFPUStatus ();
2385 
2386 	Com_DPrintf ("Sys_CheckFPUStatus: rounding %d, precision %d\n", (fpu_control_word >> 10) & 3, (fpu_control_word >> 8) & 3);
2387 
2388 	//check rounding (10) and precision (8) are set properly
2389 	/*if (((fpu_control_word >> 10) & 3) != 3 ||
2390 		((fpu_control_word >> 8) & 3) != 0)
2391 	{
2392 		if (fpu_control_word != last_word)
2393 		{
2394 			Com_Printf ("\2WARNING: The FPU control word was modified by some external force to rounding %d, precision %d. Resetting.\n", LOG_GENERAL, (fpu_control_word >> 10) & 3, (fpu_control_word >> 8) & 3);
2395 			Sys_SetFPU (sys_fpu_bits->intvalue);
2396 			fpu_control_word = Sys_GetFPUStatus ();
2397 			last_word = fpu_control_word;
2398 			return false;
2399 		}
2400 	}*/
2401 
2402 	last_word = fpu_control_word;
2403 	return true;
2404 }
2405 #endif
2406 
2407 /*
2408 ==================
2409 WinMain
2410 
2411 ==================
2412 */
2413 HINSTANCE	global_hInstance;
2414 
2415 //#define FLOAT2INTCAST(f)(*((int *)(&f)))
2416 //#define FLOAT_GT_ZERO(f) (FLOAT2INTCAST(f) > 0)
2417 
2418 extern cvar_t	*sys_loopstyle;
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)2419 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
2420 {
2421 #ifndef NO_SERVER
2422 //	unsigned int	handle;
2423 #endif
2424     MSG				msg;
2425 	unsigned int	time, oldtime, newtime;
2426 	int				spins;
2427 
2428 	badspins = goodspins = 0;
2429 
2430     /* previous instances do not exist in Win32 */
2431     if (hPrevInstance)
2432         return 0;
2433 
2434 	if (hInstance)
2435 		strncpy (cmdline, lpCmdLine, sizeof(cmdline)-1);
2436 
2437 	global_hInstance = hInstance;
2438 
2439 	ParseCommandLine (lpCmdLine);
2440 
2441 	//r1ch: always change to our directory (ugh)
2442 	FixWorkingDirectory ();
2443 
2444 	//hInstance is empty when we are back here with service code
2445 #ifdef DEDICATED_ONLY
2446 	if (hInstance && argc > 1)
2447 	{
2448 		if (!strcmp(argv[1], "-service"))
2449 		{
2450 			global_Service = true;
2451 			return main ();
2452 		}
2453 	}
2454 #endif
2455 
2456 
2457 	__try
2458 	{
2459 		Sys_SetFPU (sys_fpu_bits->intvalue);
2460 		Sys_CheckFPUStatus ();
2461 
2462 		Qcommon_Init (argc, argv);
2463 
2464 #ifndef _M_AMD64
2465 		//_controlfp( _PC_24, _MCW_PC );
2466 #endif
2467 
2468 		oldtime = Sys_Milliseconds ();
2469 		/* main window message loop */
2470 		for (;;)
2471 		{
2472 			// if at a full screen console, don't update unless needed
2473 			//if (Minimized
2474 	/*#ifndef NO_SERVER
2475 				|| (dedicated->intvalue)
2476 	#endif*/
2477 			//)
2478 			//{
2479 			//	Sleep (1);
2480 			//}
2481 
2482 			/*while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
2483 			{
2484 				//if (GetMessage (&msg, NULL, 0, 0) == -1)
2485 				//	Com_Quit ();
2486 				sys_msg_time = msg.time;
2487 
2488 	#ifndef NO_SERVER
2489 				if (!hwnd_Server || !IsDialogMessage(hwnd_Server, &msg))
2490 				{
2491 	#endif
2492 					TranslateMessage (&msg);
2493    					DispatchMessage (&msg);
2494 	#ifndef NO_SERVER
2495 				}
2496 	#endif
2497 			}*/
2498 
2499 			if (dedicated->intvalue && sys_loopstyle->intvalue)
2500 			{
2501 				while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
2502 				{
2503 					//if (GetMessage (&msg, NULL, 0, 0) == -1)
2504 					//	Com_Quit ();
2505 					sys_msg_time = msg.time;
2506 
2507 		#ifndef NO_SERVER
2508 					if (!hwnd_Server || !IsDialogMessage(hwnd_Server, &msg))
2509 					{
2510 		#endif
2511 						TranslateMessage (&msg);
2512 						DispatchMessage (&msg);
2513 		#ifndef NO_SERVER
2514 					}
2515 		#endif
2516 				}
2517 				newtime = Sys_Milliseconds ();
2518 				time = newtime - oldtime;
2519 				spins = 0;
2520 			}
2521 			else
2522 			{
2523 				spins = 0;
2524 				do
2525 				{
2526 					while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
2527 					{
2528 						//if (GetMessage (&msg, NULL, 0, 0) == -1)
2529 						//	Com_Quit ();
2530 						sys_msg_time = msg.time;
2531 
2532 			#ifndef NO_SERVER
2533 						if (!hwnd_Server || !IsDialogMessage(hwnd_Server, &msg))
2534 						{
2535 			#endif
2536 							TranslateMessage (&msg);
2537    							DispatchMessage (&msg);
2538 			#ifndef NO_SERVER
2539 						}
2540 			#endif
2541 					}
2542 					newtime = Sys_Milliseconds ();
2543 					time = newtime - oldtime;
2544 					if (!time)
2545 						Sleep (0);
2546 					spins ++;
2547 				} while (0 && time < 1);
2548 			}
2549 
2550 			if (spins > 500)
2551 				badspins++;
2552 			else
2553 				goodspins++;
2554 
2555 			Sys_SetFPU (sys_fpu_bits->intvalue);
2556 			//Sys_CheckFPUStatus ();
2557 			Qcommon_Frame (time);
2558 
2559 			oldtime = newtime;
2560 		}
2561 	}
2562 	__except (R1Q2ExceptionHandler(GetExceptionCode(), GetExceptionInformation()))
2563 	{
2564 		return 1;
2565 	}
2566 
2567 	return 0;
2568 }
2569