vkQuake2 doxygen  1.0 dev
sys_win.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2018-2019 Krzysztof Kondrak
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 // sys_win.h
22 
23 #include "../qcommon/qcommon.h"
24 #include "winquake.h"
25 #include "resource.h"
26 #include <errno.h>
27 #include <float.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <direct.h>
31 #include <io.h>
32 #include <conio.h>
33 #include "../win32/conproc.h"
34 
35 #define MINIMUM_WIN_MEMORY 0x0a00000
36 #define MAXIMUM_WIN_MEMORY 0x1000000
37 
38 //#define DEMO
39 
41 
45 
46 static HANDLE hinput, houtput;
47 
48 unsigned sys_msg_time;
49 unsigned sys_frame_time;
50 
51 
52 static HANDLE qwclsemaphore;
53 
54 #define MAX_NUM_ARGVS 128
55 int argc;
57 
58 
59 /*
60 ===============================================================================
61 
62 SYSTEM IO
63 
64 ===============================================================================
65 */
66 
67 
68 void Sys_Error (char *error, ...)
69 {
70  va_list argptr;
71  char text[1024];
72 
73  CL_Shutdown ();
75 
76  va_start (argptr, error);
77  vsnprintf (text, 1024, error, argptr);
78  va_end (argptr);
79 
80  MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
81 
82  if (qwclsemaphore)
83  CloseHandle (qwclsemaphore);
84 
85 // shut down QHOST hooks if necessary
86  DeinitConProc ();
87 
88  exit (1);
89 }
90 
91 void Sys_Quit (void)
92 {
93  timeEndPeriod( 1 );
94 
95  CL_Shutdown();
97  CloseHandle (qwclsemaphore);
98  if (dedicated && dedicated->value)
99  FreeConsole ();
100 #ifdef WIN_DEBUG_CONSOLE
101  else
102  FreeConsole();
103 #endif
104 
105 // shut down QHOST hooks if necessary
106  DeinitConProc ();
107 
108  exit (0);
109 }
110 
111 
112 void WinError (void)
113 {
114  LPVOID lpMsgBuf;
115 
116  FormatMessage(
117  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
118  NULL,
119  GetLastError(),
120  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
121  (LPTSTR) &lpMsgBuf,
122  0,
123  NULL
124  );
125 
126  // Display the string.
127  MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
128 
129  // Free the buffer.
130  LocalFree( lpMsgBuf );
131 }
132 
133 //================================================================
134 
135 
136 /*
137 ================
138 Sys_ScanForCD
139 
140 ================
141 */
142 char *Sys_ScanForCD (void)
143 {
144  static char cddir[MAX_OSPATH];
145  static qboolean done;
146 #ifndef DEMO
147  char drive[4];
148  FILE *f;
149  char test[MAX_QPATH];
150 
151  if (done) // don't re-check
152  return cddir;
153 
154  // no abort/retry/fail errors
155  SetErrorMode (SEM_FAILCRITICALERRORS);
156 
157  drive[0] = 'c';
158  drive[1] = ':';
159  drive[2] = '\\';
160  drive[3] = 0;
161 
162  done = true;
163 
164  // scan the drives
165  for (drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++)
166  {
167  // where activision put the stuff...
168  sprintf (cddir, "%sinstall\\data", drive);
169  sprintf (test, "%sinstall\\data\\quake2.exe", drive);
170  f = fopen(test, "r");
171  if (f)
172  {
173  fclose (f);
174  if (GetDriveType (drive) == DRIVE_CDROM)
175  return cddir;
176  }
177  }
178 #endif
179 
180  cddir[0] = 0;
181 
182  return NULL;
183 }
184 
185 /*
186 ================
187 Sys_CopyProtect
188 
189 ================
190 */
191 void Sys_CopyProtect (void)
192 {
193 #ifndef DEMO
194  char *cddir;
195 
196  cddir = Sys_ScanForCD();
197  if (!cddir[0])
198  Com_Error (ERR_FATAL, "You must have the Quake2 CD in the drive to play.");
199 #endif
200 }
201 
202 /*
203 ================
204 Sys_SetDPIAwareness
205 
206 ================
207 */
209 typedef BOOL(WINAPI *SetProcessDPIAwareFunc)();
211 
213 {
214  HMODULE hShcore = LoadLibraryA("Shcore.dll");
215  HMODULE hUser32 = LoadLibraryA("user32.dll");
216  SetProcessDPIAwarenessFunc setProcDPIAwareness = (SetProcessDPIAwarenessFunc)(hShcore ? GetProcAddress(hShcore, "SetProcessDpiAwareness") : NULL);
217  SetProcessDPIAwareFunc setProcDPIAware = (SetProcessDPIAwareFunc)(hUser32 ? GetProcAddress(hUser32, "SetProcessDPIAware") : NULL);
218 
219  if (setProcDPIAwareness) /* Windows 8.1+ */
220  setProcDPIAwareness(dpi_monitor_aware);
221  else if (setProcDPIAware) /* Windows Vista-8.0 */
222  setProcDPIAware();
223 
224  if (hShcore)
225  FreeLibrary(hShcore);
226  if (hUser32)
227  FreeLibrary(hUser32);
228 }
229 
230 //================================================================
231 
232 
233 /*
234 ================
235 Sys_Init
236 ================
237 */
238 void Sys_Init (void)
239 {
240  OSVERSIONINFO vinfo;
241 
242  timeBeginPeriod( 1 );
243 
244  vinfo.dwOSVersionInfoSize = sizeof(vinfo);
245 
246  if (!GetVersionEx (&vinfo))
247  Sys_Error ("Couldn't get OS info");
248 
249  if (vinfo.dwMajorVersion < 4)
250  Sys_Error ("Quake2 requires windows version 4 or greater");
251  if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)
252  Sys_Error ("Quake2 doesn't run on Win32s");
253  else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
254  s_win95 = true;
255 
256  if (dedicated->value)
257  {
258  if (!AllocConsole ())
259  Sys_Error ("Couldn't create dedicated server console");
260  hinput = GetStdHandle (STD_INPUT_HANDLE);
261  houtput = GetStdHandle (STD_OUTPUT_HANDLE);
262 
263  // let QHOST hook in
264  InitConProc (argc, argv);
265  }
266 #ifdef WIN_DEBUG_CONSOLE
267  else
268  {
269  AllocConsole();
270  SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), 0x07);
271  DeleteMenu(GetSystemMenu(GetConsoleWindow(), false), SC_CLOSE, MF_BYCOMMAND);
272  freopen("CONOUT$", "w", stderr);
273  }
274 #endif
275 
276  // enable DPI awareness
278 }
279 
280 
281 static char console_text[256];
282 static int console_textlen;
283 
284 /*
285 ================
286 Sys_ConsoleInput
287 ================
288 */
289 char *Sys_ConsoleInput (void)
290 {
291  INPUT_RECORD recs[1024];
292  int dummy;
293  int ch, numread, numevents;
294 
295  if (!dedicated || !dedicated->value)
296  return NULL;
297 
298 
299  for ( ;; )
300  {
301  if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
302  Sys_Error ("Error getting # of console events");
303 
304  if (numevents <= 0)
305  break;
306 
307  if (!ReadConsoleInput(hinput, recs, 1, &numread))
308  Sys_Error ("Error reading console input");
309 
310  if (numread != 1)
311  Sys_Error ("Couldn't read console input");
312 
313  if (recs[0].EventType == KEY_EVENT)
314  {
315  if (!recs[0].Event.KeyEvent.bKeyDown)
316  {
317  ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
318 
319  switch (ch)
320  {
321  case '\r':
322  WriteFile(houtput, "\r\n", 2, &dummy, NULL);
323 
324  if (console_textlen)
325  {
327  console_textlen = 0;
328  return console_text;
329  }
330  break;
331 
332  case '\b':
333  if (console_textlen)
334  {
335  console_textlen--;
336  WriteFile(houtput, "\b \b", 3, &dummy, NULL);
337  }
338  break;
339 
340  default:
341  if (ch >= ' ')
342  {
343  if (console_textlen < sizeof(console_text)-2)
344  {
345  WriteFile(houtput, &ch, 1, &dummy, NULL);
347  console_textlen++;
348  }
349  }
350 
351  break;
352 
353  }
354  }
355  }
356  }
357 
358  return NULL;
359 }
360 
361 
362 /*
363 ================
364 Sys_ConsoleOutput
365 
366 Print text to the dedicated console
367 ================
368 */
369 void Sys_ConsoleOutput (char *string)
370 {
371  int dummy;
372  char text[256];
373 
374  if (!dedicated || !dedicated->value)
375  {
376 #ifdef WIN_DEBUG_CONSOLE
377  fputs(string, stderr);
378  OutputDebugString(string);
379 #endif
380  return;
381  }
382 
383  if (console_textlen)
384  {
385  text[0] = '\r';
386  memset(&text[1], ' ', console_textlen);
387  text[console_textlen+1] = '\r';
388  text[console_textlen+2] = 0;
389  WriteFile(houtput, text, console_textlen+2, &dummy, NULL);
390  }
391 
392  WriteFile(houtput, string, (DWORD)strlen(string), &dummy, NULL);
393 
394  if (console_textlen)
395  WriteFile(houtput, console_text, console_textlen, &dummy, NULL);
396 }
397 
398 
399 /*
400 ================
401 Sys_SendKeyEvents
402 
403 Send Key_Event calls
404 ================
405 */
406 void Sys_SendKeyEvents (void)
407 {
408  MSG msg;
409 
410  while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
411  {
412  if (!GetMessage (&msg, NULL, 0, 0))
413  Sys_Quit ();
414  sys_msg_time = msg.time;
415  TranslateMessage (&msg);
416  DispatchMessage (&msg);
417  }
418 
419  // grab frame time
420  sys_frame_time = timeGetTime(); // FIXME: should this be at start?
421 }
422 
423 
424 
425 /*
426 ================
427 Sys_GetClipboardData
428 
429 ================
430 */
431 char *Sys_GetClipboardData( void )
432 {
433  char *data = NULL;
434  char *cliptext;
435 
436  if ( OpenClipboard( NULL ) != 0 )
437  {
438  HANDLE hClipboardData;
439 
440  if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 )
441  {
442  if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 )
443  {
444  data = malloc( GlobalSize( hClipboardData ) + 1 );
445  strcpy( data, cliptext );
446  GlobalUnlock( hClipboardData );
447  }
448  }
449  CloseClipboard();
450  }
451  return data;
452 }
453 
454 /*
455 ==============================================================================
456 
457  WINDOWS CRAP
458 
459 ==============================================================================
460 */
461 
462 /*
463 =================
464 Sys_AppActivate
465 =================
466 */
467 void Sys_AppActivate (void)
468 {
469  ShowWindow ( cl_hwnd, SW_RESTORE);
470  SetForegroundWindow ( cl_hwnd );
471 }
472 
473 /*
474 ========================================================================
475 
476 GAME DLL
477 
478 ========================================================================
479 */
480 
481 static HINSTANCE game_library;
482 
483 /*
484 =================
485 Sys_UnloadGame
486 =================
487 */
488 void Sys_UnloadGame (void)
489 {
490  if (!FreeLibrary (game_library))
491  Com_Error (ERR_FATAL, "FreeLibrary failed for game library");
492  game_library = NULL;
493 }
494 
495 /*
496 =================
497 Sys_GetGameAPI
498 
499 Loads the game dll
500 =================
501 */
502 void *Sys_GetGameAPI (void *parms)
503 {
504  void *(*GetGameAPI) (void *);
505  char name[MAX_OSPATH];
506  char *path;
507  char cwd[MAX_OSPATH];
508 #if defined _M_IX86
509  const char *gamename = "gamex86.dll";
510 
511 #ifdef NDEBUG
512  const char *debugdir = "release";
513 #else
514  const char *debugdir = "debug";
515 #endif
516 
517 #elif defined _M_X64
518  const char *gamename = "gamex64.dll";
519 
520 #ifdef NDEBUG
521  const char *debugdir = "releasex64";
522 #else
523  const char *debugdir = "debugx64";
524 #endif
525 
526 #elif defined _M_ALPHA
527  const char *gamename = "gameaxp.dll";
528 
529 #ifdef NDEBUG
530  const char *debugdir = "releaseaxp";
531 #else
532  const char *debugdir = "debugaxp";
533 #endif
534 
535 #endif
536 
537  if (game_library)
538  Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
539 
540  // check the current debug directory first for development purposes
541  _getcwd (cwd, sizeof(cwd));
542  Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename);
543  game_library = LoadLibrary ( name );
544  if (game_library)
545  {
546  Com_DPrintf ("LoadLibrary (%s)\n", name);
547  }
548  else
549  {
550 #ifdef DEBUG
551  // check the current directory for other development purposes
552  Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename);
553  game_library = LoadLibrary ( name );
554  if (game_library)
555  {
556  Com_DPrintf ("LoadLibrary (%s)\n", name);
557  }
558  else
559 #endif
560  {
561  // now run through the search paths
562  path = NULL;
563  while (1)
564  {
565  path = FS_NextPath (path);
566  if (!path)
567  return NULL; // couldn't find one anywhere
568  Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
569  game_library = LoadLibrary (name);
570  if (game_library)
571  {
572  Com_DPrintf ("LoadLibrary (%s)\n",name);
573  break;
574  }
575  }
576  }
577  }
578 
579  GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI");
580  if (!GetGameAPI)
581  {
582  Sys_UnloadGame ();
583  return NULL;
584  }
585 
586  return GetGameAPI (parms);
587 }
588 
589 //=======================================================================
590 
591 
592 /*
593 ==================
594 ParseCommandLine
595 
596 ==================
597 */
598 void ParseCommandLine (LPSTR lpCmdLine)
599 {
600  argc = 1;
601  argv[0] = "exe";
602 
603  while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
604  {
605  while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
606  lpCmdLine++;
607 
608  if (*lpCmdLine)
609  {
610  argv[argc] = lpCmdLine;
611  argc++;
612 
613  while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
614  lpCmdLine++;
615 
616  if (*lpCmdLine)
617  {
618  *lpCmdLine = 0;
619  lpCmdLine++;
620  }
621 
622  }
623  }
624 
625 }
626 
627 /*
628 ==================
629 WinMain
630 
631 ==================
632 */
634 
635 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
636 {
637  MSG msg;
638  int time, oldtime, newtime;
639  char *cddir;
640 
641  /* previous instances do not exist in Win32 */
642  if (hPrevInstance)
643  return 0;
644 
645  global_hInstance = hInstance;
646 
647  ParseCommandLine (lpCmdLine);
648 
649  // if we find the CD, add a +set cddir xxx command line
650  cddir = Sys_ScanForCD ();
651  if (cddir && argc < MAX_NUM_ARGVS - 3)
652  {
653  int i;
654 
655  // don't override a cddir on the command line
656  for (i=0 ; i<argc ; i++)
657  if (!strcmp(argv[i], "cddir"))
658  break;
659  if (i == argc)
660  {
661  argv[argc++] = "+set";
662  argv[argc++] = "cddir";
663  argv[argc++] = cddir;
664  }
665  }
666 
668  oldtime = Sys_Milliseconds ();
669 
670  /* main window message loop */
671  while (1)
672  {
673  // if at a full screen console, don't update unless needed
674  if (Minimized || (dedicated && dedicated->value) )
675  {
676  Sleep (1);
677  }
678 
679  while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
680  {
681  if (!GetMessage (&msg, NULL, 0, 0))
682  Com_Quit ();
683  sys_msg_time = msg.time;
684  TranslateMessage (&msg);
685  DispatchMessage (&msg);
686  }
687 
688  do
689  {
690  newtime = Sys_Milliseconds ();
691  time = newtime - oldtime;
692  } while (time < 1);
693 
694 // MSDN: "On the x64 architecture, changing the floating point precision is not supported.
695 // If the precision control mask is used on that platform, an assertion and the invalid parameter handler is invoked,
696 // as described in Parameter Validation."
697 #ifdef _M_IX86
698  _controlfp( _PC_24, _MCW_PC );
699 #endif
700  if (ActiveApp)
701  Qcommon_Frame(time);
702 
703  oldtime = newtime;
704  }
705 
706  // never gets here
707  return TRUE;
708 }
dedicated
cvar_t * dedicated
Definition: common.c:47
value
GLfloat value
Definition: qgl_win.c:63
MAX_QPATH
#define MAX_QPATH
Definition: q_shared.h:80
TRUE
#define TRUE
Definition: stb_vorbis.c:617
dpi_monitor_aware
@ dpi_monitor_aware
Definition: sys_win.c:208
WinError
void WinError(void)
Definition: sys_win.c:112
Sys_CopyProtect
void Sys_CopyProtect(void)
Definition: sys_win.c:191
s_win95
qboolean s_win95
Definition: sys_win.c:40
ParseCommandLine
void ParseCommandLine(LPSTR lpCmdLine)
Definition: sys_win.c:598
GetGameAPI
game_export_t * GetGameAPI(game_import_t *import)
Definition: g_main.c:111
console_text
static char console_text[256]
Definition: sys_win.c:281
qboolean
qboolean
Definition: q_shared.h:63
i
int i
Definition: q_shared.c:305
winquake.h
FS_NextPath
char * FS_NextPath(char *prevpath)
Definition: files.c:821
argv
char * argv[MAX_NUM_ARGVS]
Definition: sys_win.c:56
argc
int argc
Definition: sys_win.c:55
SetProcessDPIAwarenessFunc
HRESULT(WINAPI * SetProcessDPIAwarenessFunc)(dpi_awareness value)
Definition: sys_win.c:210
Sys_Quit
void Sys_Quit(void)
Definition: sys_win.c:91
Sys_ConsoleOutput
void Sys_ConsoleOutput(char *string)
Definition: sys_win.c:369
Sys_Init
void Sys_Init(void)
Definition: sys_win.c:238
msg
cvar_t * msg
Definition: cl_main.c:83
game_library
static HINSTANCE game_library
Definition: sys_win.c:481
global_hInstance
HINSTANCE global_hInstance
Definition: sys_win.c:633
Qcommon_Frame
void Qcommon_Frame(int msec)
Definition: common.c:1500
Sys_Error
void Sys_Error(char *error,...)
Definition: sys_win.c:68
dpi_unaware
@ dpi_unaware
Definition: sys_win.c:208
hinput
static HANDLE hinput
Definition: sys_win.c:46
sys_frame_time
unsigned sys_frame_time
Definition: sys_win.c:49
Minimized
qboolean Minimized
Definition: sys_win.c:44
Qcommon_Shutdown
void Qcommon_Shutdown(void)
Definition: common.c:1600
Sys_ConsoleInput
char * Sys_ConsoleInput(void)
Definition: sys_win.c:289
starttime
int starttime
Definition: sys_win.c:42
BOOL
CONST COLORREF COLORREF BOOL
Definition: qgl_win.c:60
Sys_SetDPIAwareness
void Sys_SetDPIAwareness(void)
Definition: sys_win.c:212
CL_Shutdown
void CL_Shutdown(void)
Definition: cl_main.c:1831
Sys_SendKeyEvents
void Sys_SendKeyEvents(void)
Definition: sys_win.c:406
sys_msg_time
unsigned sys_msg_time
Definition: sys_win.c:48
resource.h
dpi_awareness
dpi_awareness
Definition: sys_win.c:208
dpi_system_aware
@ dpi_system_aware
Definition: sys_win.c:208
cl_hwnd
HWND cl_hwnd
Definition: vid_dll.c:58
cvar_s::value
float value
Definition: q_shared.h:331
MAX_OSPATH
#define MAX_OSPATH
Definition: q_shared.h:81
error
static int error(vorb *f, enum STBVorbisError e)
Definition: stb_vorbis.c:865
Sys_AppActivate
void Sys_AppActivate(void)
Definition: sys_win.c:467
console_textlen
static int console_textlen
Definition: sys_win.c:282
NULL
#define NULL
Definition: q_shared.h:67
Sys_GetGameAPI
void * Sys_GetGameAPI(void *parms)
Definition: sys_win.c:502
Com_Error
void Com_Error(int code, char *fmt,...)
Definition: common.c:181
WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
Definition: sys_win.c:635
name
cvar_t * name
Definition: cl_main.c:79
ERR_FATAL
#define ERR_FATAL
Definition: qcommon.h:743
Sys_GetClipboardData
char * Sys_GetClipboardData(void)
Definition: sys_win.c:431
ActiveApp
qboolean ActiveApp
Definition: sys_win.c:43
InitConProc
void InitConProc(int argc, char **argv)
Definition: conproc.c:84
houtput
static HANDLE houtput
Definition: sys_win.c:46
qwclsemaphore
static HANDLE qwclsemaphore
Definition: sys_win.c:52
Sys_ScanForCD
char * Sys_ScanForCD(void)
Definition: sys_win.c:142
Com_Quit
void Com_Quit(void)
Definition: common.c:235
SetProcessDPIAwareFunc
BOOL(WINAPI * SetProcessDPIAwareFunc)()
Definition: sys_win.c:209
Com_DPrintf
void Com_DPrintf(char *fmt,...)
Definition: common.c:157
Qcommon_Init
void Qcommon_Init(int argc, char **argv)
Definition: common.c:1407
DWORD
DWORD
Definition: qgl_win.c:49
Sys_UnloadGame
void Sys_UnloadGame(void)
Definition: sys_win.c:488
Sys_Milliseconds
int Sys_Milliseconds(void)
Definition: q_shwin.c:120
MAX_NUM_ARGVS
#define MAX_NUM_ARGVS
Definition: sys_win.c:54
HRESULT
HRESULT(WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID
Com_sprintf
void Com_sprintf(char *dest, int size, char *fmt,...)
Definition: q_shared.c:1223
DeinitConProc
void DeinitConProc(void)
Definition: conproc.c:153