1 /*
2 * sys_win.c -- Windows system interface code
3 * $Id: sys_win.c 6015 2018-02-21 17:30:51Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 * Copyright (C) 2005-2012 O.Sezer <sezero@users.sourceforge.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "quakedef.h"
25 #include "winquake.h"
26 #include <mmsystem.h>
27 #include "resource.h"
28 #include "debuglog.h"
29
30
31 // heapsize: minimum 16mb, standart 32 mb, max is 96 mb.
32 // -heapsize argument will abide by these min/max settings
33 // unless the -forcemem argument is used
34 #define MIN_MEM_ALLOC 0x1000000
35 #define STD_MEM_ALLOC 0x2000000
36 #define MAX_MEM_ALLOC 0x6000000
37
38 #define CONSOLE_ERROR_TIMEOUT 60.0 /* # of seconds to wait on Sys_Error running dedicated before exiting */
39 #define PAUSE_SLEEP 50 /* sleep time on pause or minimization */
40 #define NOT_FOCUS_SLEEP 20 /* sleep time when not focus */
41
42 cvar_t sys_nostdout = {"sys_nostdout", "0", CVAR_NONE};
43 cvar_t sys_throttle = {"sys_throttle", "0.02", CVAR_ARCHIVE};
44
45 qboolean ActiveApp, Minimized;
46 qboolean Win95, Win95old, WinNT, WinVista;
47
48 qboolean isDedicated;
49
50 #define TIME_WRAP_VALUE (~(DWORD)0)
51 static DWORD starttime;
52 static qboolean sc_return_on_enter = false;
53 static HANDLE hinput, houtput;
54
55 static HANDLE tevent;
56
57 static volatile int sys_checksum;
58
59
60 /*
61 ================
62 Sys_PageIn
63 ================
64 */
Sys_PageIn(void * ptr,int size)65 static void Sys_PageIn (void *ptr, int size)
66 {
67 byte *x;
68 int m, n;
69
70 // touch all the memory to make sure it's there. The 16-page skip is to
71 // keep Win 95 from thinking we're trying to page ourselves in (we are
72 // doing that, of course, but there's no reason we shouldn't)
73 x = (byte *)ptr;
74
75 for (n = 0; n < 4; n++)
76 {
77 for (m = 0; m < (size - 16 * 0x1000); m += 4)
78 {
79 sys_checksum += *(int *)&x[m];
80 sys_checksum += *(int *)&x[m + 16 * 0x1000];
81 }
82 }
83 }
84
85
86 /*
87 ===============================================================================
88
89 FILE IO
90
91 ===============================================================================
92 */
93
Sys_mkdir(const char * path,qboolean crash)94 int Sys_mkdir (const char *path, qboolean crash)
95 {
96 if (CreateDirectory(path, NULL) != 0)
97 return 0;
98 if (GetLastError() == ERROR_ALREADY_EXISTS)
99 return 0;
100 if (crash)
101 Sys_Error("Unable to create directory %s", path);
102 return -1;
103 }
104
Sys_rmdir(const char * path)105 int Sys_rmdir (const char *path)
106 {
107 if (RemoveDirectory(path) != 0)
108 return 0;
109 return -1;
110 }
111
Sys_unlink(const char * path)112 int Sys_unlink (const char *path)
113 {
114 if (DeleteFile(path) != 0)
115 return 0;
116 return -1;
117 }
118
Sys_rename(const char * oldp,const char * newp)119 int Sys_rename (const char *oldp, const char *newp)
120 {
121 if (MoveFile(oldp, newp) != 0)
122 return 0;
123 return -1;
124 }
125
Sys_filesize(const char * path)126 long Sys_filesize (const char *path)
127 {
128 HANDLE fh;
129 WIN32_FIND_DATA data;
130 long size;
131
132 fh = FindFirstFile(path, &data);
133 if (fh == INVALID_HANDLE_VALUE)
134 return -1;
135 FindClose(fh);
136 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
137 return -1;
138 // we're not dealing with gigabytes of files.
139 // size should normally smaller than INT_MAX.
140 // size = (data.nFileSizeHigh * (MAXDWORD + 1)) + data.nFileSizeLow;
141 size = (long) data.nFileSizeLow;
142 return size;
143 }
144
145 #ifndef INVALID_FILE_ATTRIBUTES
146 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
147 #endif
Sys_FileType(const char * path)148 int Sys_FileType (const char *path)
149 {
150 DWORD result = GetFileAttributes(path);
151
152 if (result == INVALID_FILE_ATTRIBUTES)
153 return FS_ENT_NONE;
154 if (result & FILE_ATTRIBUTE_DIRECTORY)
155 return FS_ENT_DIRECTORY;
156
157 return FS_ENT_FILE;
158 }
159
Sys_CopyFile(const char * frompath,const char * topath)160 int Sys_CopyFile (const char *frompath, const char *topath)
161 {
162 /* 3rd param: whether to fail if 'topath' already exists */
163 if (CopyFile(frompath, topath, FALSE) != 0)
164 return 0;
165 return -1;
166 }
167
168 /*
169 =================================================
170 simplified findfirst/findnext implementation:
171 Sys_FindFirstFile and Sys_FindNextFile return
172 filenames only, not a dirent struct. this is
173 what we presently need in this engine.
174 =================================================
175 */
176 static HANDLE findhandle = INVALID_HANDLE_VALUE;
177 static WIN32_FIND_DATA finddata;
178 static char findstr[MAX_OSPATH];
179
Sys_FindFirstFile(const char * path,const char * pattern)180 const char *Sys_FindFirstFile (const char *path, const char *pattern)
181 {
182 if (findhandle != INVALID_HANDLE_VALUE)
183 Sys_Error ("Sys_FindFirst without FindClose");
184 q_snprintf (findstr, sizeof(findstr), "%s/%s", path, pattern);
185 findhandle = FindFirstFile(findstr, &finddata);
186 if (findhandle == INVALID_HANDLE_VALUE)
187 return NULL;
188 if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
189 return Sys_FindNextFile();
190 return finddata.cFileName;
191 }
192
Sys_FindNextFile(void)193 const char *Sys_FindNextFile (void)
194 {
195 if (findhandle == INVALID_HANDLE_VALUE)
196 return NULL;
197 while (FindNextFile(findhandle, &finddata) != 0)
198 {
199 if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
200 continue;
201 return finddata.cFileName;
202 }
203 return NULL;
204 }
205
Sys_FindClose(void)206 void Sys_FindClose (void)
207 {
208 if (findhandle != INVALID_HANDLE_VALUE)
209 {
210 FindClose(findhandle);
211 findhandle = INVALID_HANDLE_VALUE;
212 }
213 }
214
215
216 /*
217 ===============================================================================
218
219 SYSTEM IO
220
221 ===============================================================================
222 */
223
224 /*
225 ================
226 Sys_MakeCodeWriteable
227 ================
228 */
229 #if id386 && !defined(GLQUAKE)
Sys_MakeCodeWriteable(unsigned long startaddr,unsigned long length)230 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
231 {
232 DWORD flOldProtect;
233 //@@@ copy on write or just read-write?
234 if (!VirtualProtect((LPVOID)startaddr, length, PAGE_EXECUTE_READWRITE, &flOldProtect))
235 Sys_Error("Protection change failed\n");
236 }
237 #endif /* id386, !GLQUAKE */
238
239
240 /*
241 ================
242 Sys_SetDPIAware
243 ================
244 */
245 typedef enum { dpi_unaware = 0, dpi_system_aware = 1, dpi_monitor_aware = 2 } dpi_awareness;
246 typedef BOOL (WINAPI *SetProcessDPIAwareFunc)();
247 typedef HRESULT (WINAPI *SetProcessDPIAwarenessFunc)(dpi_awareness value);
248
Sys_SetDPIAware(void)249 static void Sys_SetDPIAware (void)
250 {
251 HMODULE hUser32, hShcore;
252 SetProcessDPIAwarenessFunc setDPIAwareness;
253 SetProcessDPIAwareFunc setDPIAware;
254
255 /* We do not handle the OS scaling our window. Call
256 * SetProcessDpiAwareness() or SetProcessDPIAware()
257 * to opt out of scaling.
258 */
259 hShcore = LoadLibraryA ("Shcore.dll");
260 hUser32 = LoadLibraryA ("user32.dll");
261 setDPIAwareness = (SetProcessDPIAwarenessFunc) (hShcore ? GetProcAddress (hShcore, "SetProcessDpiAwareness") : NULL);
262 setDPIAware = (SetProcessDPIAwareFunc) (hUser32 ? GetProcAddress (hUser32, "SetProcessDPIAware") : NULL);
263
264 if (setDPIAwareness) /* Windows 8.1+ */
265 setDPIAwareness (dpi_monitor_aware);
266 else if (setDPIAware) /* Vista, Win7 or 8.0 */
267 setDPIAware ();
268
269 if (hShcore)
270 FreeLibrary (hShcore);
271 if (hUser32)
272 FreeLibrary (hUser32);
273 }
274
275 /*
276 ================
277 Sys_Init
278 ================
279 */
Sys_Init(void)280 static void Sys_Init (void)
281 {
282 OSVERSIONINFO vinfo;
283
284 vinfo.dwOSVersionInfoSize = sizeof(vinfo);
285
286 if (!GetVersionEx (&vinfo))
287 Sys_Error ("Couldn't get OS info");
288
289 if ((vinfo.dwMajorVersion < 4) ||
290 (vinfo.dwPlatformId == VER_PLATFORM_WIN32s))
291 {
292 Sys_Error ("%s requires at least Win95 or NT 4.0", ENGINE_NAME);
293 }
294
295 if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
296 {
297 WinNT = true;
298 if (vinfo.dwMajorVersion >= 6)
299 WinVista = true;
300 }
301 else
302 {
303 WinNT = false; /* Win9x or WinME */
304 if ((vinfo.dwMajorVersion == 4) && (vinfo.dwMinorVersion == 0))
305 {
306 Win95 = true;
307 /* Win95-gold or Win95A can't switch bpp automatically */
308 if (vinfo.szCSDVersion[1] != 'C' && vinfo.szCSDVersion[1] != 'B')
309 Win95old = true;
310 }
311 }
312
313 if (!isDedicated)
314 Sys_SetDPIAware ();
315
316 timeBeginPeriod (1); /* 1 ms timer precision */
317 starttime = timeGetTime ();
318
319 /* do we really need these with opengl ?? */
320 MaskExceptions ();
321 Sys_SetFPCW ();
322 }
323
324
325 #define ERROR_PREFIX "\nFATAL ERROR: "
Sys_Error(const char * error,...)326 void Sys_Error (const char *error, ...)
327 {
328 va_list argptr;
329 char text[MAX_PRINTMSG];
330 const char text2[] = ERROR_PREFIX;
331 const char text3[] = "\n";
332 const char text4[] = "\nPress Enter to exit\n";
333 DWORD dummy;
334 double err_begin;
335
336 host_parms->errstate++;
337
338 va_start (argptr, error);
339 q_vsnprintf (text, sizeof (text), error, argptr);
340 va_end (argptr);
341
342 if (con_debuglog)
343 {
344 LOG_Print (ERROR_PREFIX);
345 LOG_Print (text);
346 LOG_Print ("\n\n");
347 }
348
349 Host_Shutdown ();
350
351 if (isDedicated)
352 {
353 WriteFile (houtput, text2, strlen(text2), &dummy, NULL);
354 WriteFile (houtput, text, strlen(text), &dummy, NULL);
355 WriteFile (houtput, text3, strlen(text3), &dummy, NULL);
356 WriteFile (houtput, text4, strlen(text4), &dummy, NULL);
357
358 err_begin = Sys_DoubleTime ();
359 sc_return_on_enter = true; /* so Enter will get us out of here */
360 while (!Sys_ConsoleInput () &&
361 ((Sys_DoubleTime () - err_begin) < CONSOLE_ERROR_TIMEOUT))
362 {
363 }
364 }
365 else
366 {
367 MessageBox(NULL, text, ENGINE_NAME " Error", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
368 }
369
370 exit (1);
371 }
372
Sys_PrintTerm(const char * msgtxt)373 void Sys_PrintTerm (const char *msgtxt)
374 {
375 DWORD dummy;
376
377 if (isDedicated)
378 {
379 if (sys_nostdout.integer)
380 return;
381
382 WriteFile(houtput, msgtxt, strlen(msgtxt), &dummy, NULL);
383 }
384 }
385
Sys_Quit(void)386 void Sys_Quit (void)
387 {
388 Host_Shutdown();
389
390 if (tevent)
391 CloseHandle (tevent);
392
393 if (isDedicated)
394 FreeConsole ();
395
396 exit (0);
397 }
398
399
400 /*
401 ================
402 Sys_DoubleTime
403 ================
404 */
Sys_DoubleTime(void)405 double Sys_DoubleTime (void)
406 {
407 DWORD now, passed;
408
409 now = timeGetTime();
410 if (now < starttime) /* wrapped? */
411 {
412 passed = TIME_WRAP_VALUE - starttime;
413 passed += now;
414 }
415 else
416 {
417 passed = now - starttime;
418 }
419
420 return (passed == 0) ? 0.0 : (passed / 1000.0);
421 }
422
Sys_DateTimeString(char * buf)423 char *Sys_DateTimeString (char *buf)
424 {
425 static char strbuf[24];
426 SYSTEMTIME st;
427 int val;
428
429 if (!buf) buf = strbuf;
430
431 GetLocalTime(&st);
432
433 val = st.wMonth;
434 buf[0] = val / 10 + '0';
435 buf[1] = val % 10 + '0';
436 buf[2] = '/';
437 val = st.wDay;
438 buf[3] = val / 10 + '0';
439 buf[4] = val % 10 + '0';
440 buf[5] = '/';
441 val = st.wYear / 100;
442 buf[6] = val / 10 + '0';
443 buf[7] = val % 10 + '0';
444 val = st.wYear % 100;
445 buf[8] = val / 10 + '0';
446 buf[9] = val % 10 + '0';
447
448 buf[10] = ' ';
449
450 val = st.wHour;
451 buf[11] = val / 10 + '0';
452 buf[12] = val % 10 + '0';
453 buf[13] = ':';
454 val = st.wMinute;
455 buf[14] = val / 10 + '0';
456 buf[15] = val % 10 + '0';
457 buf[16] = ':';
458 val = st.wSecond;
459 buf[17] = val / 10 + '0';
460 buf[18] = val % 10 + '0';
461
462 buf[19] = '\0';
463
464 return buf;
465 }
466
467
Sys_ConsoleInput(void)468 const char *Sys_ConsoleInput (void)
469 {
470 static char con_text[256];
471 static int textlen;
472 INPUT_RECORD recs[1024];
473 int ch;
474 DWORD dummy, numread, numevents;
475
476 for ( ;; )
477 {
478 if (GetNumberOfConsoleInputEvents(hinput, &numevents) == 0)
479 Sys_Error ("Error getting # of console events");
480
481 if (! numevents)
482 break;
483
484 if (ReadConsoleInput(hinput, recs, 1, &numread) == 0)
485 Sys_Error ("Error reading console input");
486
487 if (numread != 1)
488 Sys_Error ("Couldn't read console input");
489
490 if (recs[0].EventType == KEY_EVENT)
491 {
492 if (recs[0].Event.KeyEvent.bKeyDown == FALSE)
493 {
494 ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
495
496 switch (ch)
497 {
498 case '\r':
499 WriteFile(houtput, "\r\n", 2, &dummy, NULL);
500 if (textlen != 0)
501 {
502 con_text[textlen] = 0;
503 textlen = 0;
504 return con_text;
505 }
506 else if (sc_return_on_enter)
507 {
508 /* special case to allow exiting
509 from the error handler on Enter */
510 con_text[0] = '\r';
511 textlen = 0;
512 return con_text;
513 }
514
515 break;
516
517 case '\b':
518 WriteFile(houtput, "\b \b", 3, &dummy, NULL);
519 if (textlen != 0)
520 textlen--;
521
522 break;
523
524 default:
525 if (ch >= ' ')
526 {
527 WriteFile(houtput, &ch, 1, &dummy, NULL);
528 con_text[textlen] = ch;
529 textlen = (textlen + 1) & 0xff;
530 }
531
532 break;
533 }
534 }
535 }
536 }
537
538 return NULL;
539 }
540
Sys_Sleep(unsigned long msecs)541 void Sys_Sleep (unsigned long msecs)
542 {
543 Sleep (msecs);
544 }
545
546
Sys_SendKeyEvents(void)547 void Sys_SendKeyEvents (void)
548 {
549 MSG msg;
550
551 while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
552 {
553 // we always update if there are any event, even if we're paused
554 scr_skipupdate = 0;
555
556 if (!GetMessage (&msg, NULL, 0, 0))
557 Sys_Quit ();
558 TranslateMessage (&msg);
559 DispatchMessage (&msg);
560 }
561 }
562
563 #define MAX_CLIPBOARDTXT MAXCMDLINE /* 256 */
Sys_GetClipboardData(void)564 char *Sys_GetClipboardData (void)
565 {
566 char *data = NULL;
567 char *cliptext;
568
569 if (OpenClipboard(NULL) != 0)
570 {
571 HANDLE hClipboardData;
572
573 if ((hClipboardData = GetClipboardData(CF_TEXT)) != NULL)
574 {
575 cliptext = (char *) GlobalLock(hClipboardData);
576 if (cliptext != NULL)
577 {
578 size_t size = GlobalSize(hClipboardData) + 1;
579 /* this is intended for simple small text copies
580 * such as an ip address, etc: do chop the size
581 * here, otherwise we may experience Z_Malloc()
582 * failures and all other not-oh-so-fun stuff. */
583 size = q_min(MAX_CLIPBOARDTXT, size);
584 data = (char *) Z_Malloc(size, Z_MAINZONE);
585 q_strlcpy (data, cliptext, size);
586 GlobalUnlock (hClipboardData);
587 }
588 }
589 CloseClipboard ();
590 }
591 return data;
592 }
593
594
Sys_GetBasedir(char * argv0,char * dst,size_t dstsize)595 static int Sys_GetBasedir (char *argv0, char *dst, size_t dstsize)
596 {
597 char *tmp;
598 size_t rc;
599
600 rc = GetCurrentDirectory(dstsize, dst);
601 if (rc == 0 || rc > dstsize)
602 return -1;
603
604 tmp = dst;
605 while (*tmp != 0)
606 tmp++;
607 while (*tmp == 0 && tmp != dst)
608 {
609 --tmp;
610 if (tmp != dst && (*tmp == '/' || *tmp == '\\'))
611 *tmp = 0;
612 }
613
614 return 0;
615 }
616
617 /*
618 ==============================================================================
619
620 WINDOWS CRAP
621
622 ==============================================================================
623 */
624
625
626 /*
627 ==================
628 SleepUntilInput
629 ==================
630 */
SleepUntilInput(unsigned long msecs)631 static void SleepUntilInput (unsigned long msecs)
632 {
633 MsgWaitForMultipleObjects(1, &tevent, FALSE, msecs, QS_ALLINPUT);
634 }
635
636
PrintVersion(void)637 static void PrintVersion (void)
638 {
639 Sys_Printf ("Hammer of Thyrion, release %s (%s)\n", HOT_VERSION_STR, HOT_VERSION_REL_DATE);
640 Sys_Printf ("running on %s engine %4.2f (%s)\n", ENGINE_NAME, ENGINE_VERSION, PLATFORM_STRING);
641 Sys_Printf ("More info / sending bug reports: http://uhexen2.sourceforge.net\n");
642 }
643
644 /*
645 ==================
646 WinMain
647 ==================
648 */
649 HINSTANCE global_hInstance;
650 int global_nCmdShow;
651 #if !defined(NO_SPLASHES)
652 HWND hwnd_dialog;
653 #endif /* NO_SPLASHES */
654 static char *argv[MAX_NUM_ARGVS];
655 static char cwd[1024];
656 static char prog[MAX_PATH];
657 static quakeparms_t parms;
658
Sys_CreateInitSplash(HINSTANCE hInstance)659 static void Sys_CreateInitSplash (HINSTANCE hInstance)
660 {
661 #if !defined(NO_SPLASHES)
662 RECT rect;
663
664 hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);
665 if (!hwnd_dialog)
666 return;
667
668 if (GetWindowRect (hwnd_dialog, &rect))
669 {
670 if (rect.left > (rect.top * 2))
671 {
672 SetWindowPos (hwnd_dialog, 0,
673 (rect.left / 2) - ((rect.right - rect.left) / 2),
674 rect.top, 0, 0,
675 SWP_NOZORDER | SWP_NOSIZE);
676 }
677 }
678
679 ShowWindow (hwnd_dialog, SW_SHOWDEFAULT);
680 UpdateWindow (hwnd_dialog);
681 SetForegroundWindow (hwnd_dialog);
682 #endif /* NO_SPLASHES */
683 }
684
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)685 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
686 {
687 int i;
688 double time, oldtime, newtime;
689 MEMORYSTATUS lpBuffer;
690
691 /* previous instances do not exist in Win32 */
692 if (hPrevInstance)
693 return 0;
694
695 global_hInstance = hInstance;
696 global_nCmdShow = nCmdShow;
697
698 lpBuffer.dwLength = sizeof(MEMORYSTATUS);
699 GlobalMemoryStatus (&lpBuffer);
700 /* Maximum of 2GiB to work around signed int */
701 if (lpBuffer.dwAvailPhys > 0x7FFFFFFF)
702 lpBuffer.dwAvailPhys = 0x7FFFFFFF;
703 if (lpBuffer.dwTotalPhys > 0x7FFFFFFF)
704 lpBuffer.dwTotalPhys = 0x7FFFFFFF;
705
706 memset (&parms, 0, sizeof(parms));
707 parms.basedir = cwd;
708 parms.userdir = cwd; /* no userdir on win32 */
709 parms.errstate = 0;
710 host_parms = &parms; /* initialize the host params */
711
712 memset (cwd, 0, sizeof(cwd));
713 if (Sys_GetBasedir(NULL, cwd, sizeof(cwd)) != 0)
714 Sys_Error ("Couldn't determine current directory");
715
716 parms.argc = 1;
717 argv[0] = prog;
718 if (GetModuleFileName(NULL, prog, sizeof(prog)) == 0)
719 prog[0] = '\0';
720 else prog[MAX_PATH - 1] = '\0';
721
722 while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS))
723 {
724 while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
725 lpCmdLine++;
726
727 if (*lpCmdLine)
728 {
729 argv[parms.argc] = lpCmdLine;
730 parms.argc++;
731
732 while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
733 lpCmdLine++;
734
735 if (*lpCmdLine)
736 {
737 *lpCmdLine = 0;
738 lpCmdLine++;
739 }
740 }
741 }
742
743 parms.argv = argv;
744
745 isDedicated = (COM_CheckParm ("-dedicated") != 0);
746 if (isDedicated)
747 {
748 if (!AllocConsole ())
749 {
750 isDedicated = false; /* so that we have a graphical error dialog */
751 Sys_Error ("Couldn't create dedicated server console");
752 }
753 hinput = GetStdHandle (STD_INPUT_HANDLE);
754 houtput = GetStdHandle (STD_OUTPUT_HANDLE);
755 if (hinput == INVALID_HANDLE_VALUE ||
756 houtput == INVALID_HANDLE_VALUE ||
757 hinput == NULL || houtput == NULL)
758 {
759 isDedicated = false; /* so that we have a graphical error dialog */
760 Sys_Error ("Couldn't retrieve server console handles");
761 }
762
763 PrintVersion();
764 }
765
766 LOG_Init (&parms);
767
768 Sys_Printf("basedir is: %s\n", parms.basedir);
769 Sys_Printf("userdir is: %s\n", parms.userdir);
770
771 COM_ValidateByteorder ();
772
773 if (!isDedicated)
774 Sys_CreateInitSplash (global_hInstance);
775
776 // take the greater of all the available memory or half the total memory,
777 // but at least 16 Mb and no more than 32 Mb, unless they explicitly
778 // request otherwise
779 parms.memsize = lpBuffer.dwAvailPhys;
780
781 if (parms.memsize < MIN_MEM_ALLOC)
782 parms.memsize = MIN_MEM_ALLOC;
783
784 if (parms.memsize < (int) (lpBuffer.dwTotalPhys >> 1))
785 parms.memsize = (int) (lpBuffer.dwTotalPhys >> 1);
786
787 if (parms.memsize > STD_MEM_ALLOC)
788 parms.memsize = STD_MEM_ALLOC;
789
790 if (isDedicated)
791 parms.memsize = MIN_MEM_ALLOC;
792
793 i = COM_CheckParm ("-heapsize");
794 if (i && i < com_argc-1)
795 {
796 parms.memsize = atoi (com_argv[i+1]) * 1024;
797
798 if ((parms.memsize > MAX_MEM_ALLOC) && !(COM_CheckParm ("-forcemem")))
799 parms.memsize = MAX_MEM_ALLOC;
800 else if ((parms.memsize < MIN_MEM_ALLOC) && !(COM_CheckParm ("-forcemem")))
801 parms.memsize = MIN_MEM_ALLOC;
802 }
803
804 parms.membase = malloc (parms.memsize);
805
806 if (!parms.membase)
807 Sys_Error ("Insufficient memory.\n");
808
809 if (COM_CheckParm("-nopagein") == 0)
810 {
811 Sys_PageIn (parms.membase, parms.memsize);
812 }
813
814 tevent = CreateEvent(NULL, FALSE, FALSE, NULL);
815 if (!tevent)
816 Sys_Error ("Couldn't create event");
817
818 Sys_Init ();
819
820 Host_Init();
821
822 oldtime = Sys_DoubleTime ();
823
824 /* main window message loop */
825 while (1)
826 {
827 if (isDedicated)
828 {
829 newtime = Sys_DoubleTime ();
830 time = newtime - oldtime;
831
832 while (time < sys_ticrate.value )
833 {
834 Sleep (1);
835 newtime = Sys_DoubleTime ();
836 time = newtime - oldtime;
837 }
838
839 Host_Frame (time);
840 oldtime = newtime;
841 }
842 else
843 {
844 /* yield the CPU for a little while when paused, minimized or not focused */
845 if ((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing)
846 {
847 SleepUntilInput (PAUSE_SLEEP);
848 scr_skipupdate = 1; /* no point in bothering to draw */
849 }
850 else if (!ActiveApp && !DDActive)
851 {
852 SleepUntilInput (NOT_FOCUS_SLEEP);
853 scr_skipupdate = 1; /* no point in bothering to draw */
854 }
855
856 newtime = Sys_DoubleTime ();
857 time = newtime - oldtime;
858
859 Host_Frame (time);
860
861 if (time < sys_throttle.value)
862 Sleep (1);
863
864 oldtime = newtime;
865 }
866 }
867
868 return 0;
869 }
870
871