icculus quake2 doxygen  1.0 dev
sys_win.c
Go to the documentation of this file.
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 #include "../qcommon/qcommon.h"
23 #include "winquake.h"
24 #include "resource.h"
25 #include <errno.h>
26 #include <float.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <direct.h>
30 #include <io.h>
31 #include <conio.h>
32 #include "../win32/conproc.h"
33 
34 #define MINIMUM_WIN_MEMORY 0x0a00000
35 #define MAXIMUM_WIN_MEMORY 0x1000000
36 
37 //#define DEMO
38 
40 
44 
45 static HANDLE hinput, houtput;
46 
47 unsigned sys_msg_time;
48 unsigned sys_frame_time;
49 
50 
51 static HANDLE qwclsemaphore;
52 
53 #define MAX_NUM_ARGVS 128
54 int argc;
56 
57 
58 /*
59 ===============================================================================
60 
61 SYSTEM IO
62 
63 ===============================================================================
64 */
65 
66 
67 void Sys_Error (char *error, ...)
68 {
69  va_list argptr;
70  char text[1024];
71 
72  CL_Shutdown ();
74 
75  va_start (argptr, error);
76  vsprintf (text, error, argptr);
77  va_end (argptr);
78 
79  MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
80 
81  if (qwclsemaphore)
82  CloseHandle (qwclsemaphore);
83 
84 // shut down QHOST hooks if necessary
85  DeinitConProc ();
86 
87  exit (1);
88 }
89 
90 void Sys_Quit (void)
91 {
92  timeEndPeriod( 1 );
93 
94  CL_Shutdown();
96  CloseHandle (qwclsemaphore);
97  if (dedicated && dedicated->value)
98  FreeConsole ();
99 
100 // shut down QHOST hooks if necessary
101  DeinitConProc ();
102 
103  exit (0);
104 }
105 
106 
107 void WinError (void)
108 {
109  LPVOID lpMsgBuf;
110 
111  FormatMessage(
112  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
113  NULL,
114  GetLastError(),
115  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
116  (LPTSTR) &lpMsgBuf,
117  0,
118  NULL
119  );
120 
121  // Display the string.
122  MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
123 
124  // Free the buffer.
125  LocalFree( lpMsgBuf );
126 }
127 
128 //================================================================
129 
130 
131 /*
132 ================
133 Sys_ScanForCD
134 
135 ================
136 */
137 char *Sys_ScanForCD (void)
138 {
139  static char cddir[MAX_OSPATH];
140  static qboolean done;
141 #ifndef DEMO
142  char drive[4];
143  FILE *f;
144  char test[MAX_QPATH];
145 
146  if (done) // don't re-check
147  return cddir;
148 
149  // no abort/retry/fail errors
150  SetErrorMode (SEM_FAILCRITICALERRORS);
151 
152  drive[0] = 'c';
153  drive[1] = ':';
154  drive[2] = '\\';
155  drive[3] = 0;
156 
157  done = true;
158 
159  // scan the drives
160  for (drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++)
161  {
162  // where activision put the stuff...
163  sprintf (cddir, "%sinstall\\data", drive);
164  sprintf (test, "%sinstall\\data\\quake2.exe", drive);
165  f = fopen(test, "r");
166  if (f)
167  {
168  fclose (f);
169  if (GetDriveType (drive) == DRIVE_CDROM)
170  return cddir;
171  }
172  }
173 #endif
174 
175  cddir[0] = 0;
176 
177  return NULL;
178 }
179 
180 /*
181 ================
182 Sys_CopyProtect
183 
184 ================
185 */
186 void Sys_CopyProtect (void)
187 {
188 #ifndef DEMO
189  char *cddir;
190 
191  cddir = Sys_ScanForCD();
192  if (!cddir[0])
193  Com_Error (ERR_FATAL, "You must have the Quake2 CD in the drive to play.");
194 #endif
195 }
196 
197 
198 //================================================================
199 
200 
201 /*
202 ================
203 Sys_Init
204 ================
205 */
206 void Sys_Init (void)
207 {
208  OSVERSIONINFO vinfo;
209 
210 #if 0
211  // allocate a named semaphore on the client so the
212  // front end can tell if it is alive
213 
214  // mutex will fail if semephore already exists
215  qwclsemaphore = CreateMutex(
216  NULL, /* Security attributes */
217  0, /* owner */
218  "qwcl"); /* Semaphore name */
219  if (!qwclsemaphore)
220  Sys_Error ("QWCL is already running on this system");
221  CloseHandle (qwclsemaphore);
222 
223  qwclsemaphore = CreateSemaphore(
224  NULL, /* Security attributes */
225  0, /* Initial count */
226  1, /* Maximum count */
227  "qwcl"); /* Semaphore name */
228 #endif
229 
230  timeBeginPeriod( 1 );
231 
232  vinfo.dwOSVersionInfoSize = sizeof(vinfo);
233 
234  if (!GetVersionEx (&vinfo))
235  Sys_Error ("Couldn't get OS info");
236 
237  if (vinfo.dwMajorVersion < 4)
238  Sys_Error ("Quake2 requires windows version 4 or greater");
239  if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)
240  Sys_Error ("Quake2 doesn't run on Win32s");
241  else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
242  s_win95 = true;
243 
244  if (dedicated->value)
245  {
246  if (!AllocConsole ())
247  Sys_Error ("Couldn't create dedicated server console");
248  hinput = GetStdHandle (STD_INPUT_HANDLE);
249  houtput = GetStdHandle (STD_OUTPUT_HANDLE);
250 
251  // let QHOST hook in
252  InitConProc (argc, argv);
253  }
254 }
255 
256 
257 static char console_text[256];
258 static int console_textlen;
259 
260 /*
261 ================
262 Sys_ConsoleInput
263 ================
264 */
265 char *Sys_ConsoleInput (void)
266 {
267  INPUT_RECORD recs[1024];
268  int dummy;
269  int ch, numread, numevents;
270 
271  if (!dedicated || !dedicated->value)
272  return NULL;
273 
274 
275  for ( ;; )
276  {
277  if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
278  Sys_Error ("Error getting # of console events");
279 
280  if (numevents <= 0)
281  break;
282 
283  if (!ReadConsoleInput(hinput, recs, 1, &numread))
284  Sys_Error ("Error reading console input");
285 
286  if (numread != 1)
287  Sys_Error ("Couldn't read console input");
288 
289  if (recs[0].EventType == KEY_EVENT)
290  {
291  if (!recs[0].Event.KeyEvent.bKeyDown)
292  {
293  ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
294 
295  switch (ch)
296  {
297  case '\r':
298  WriteFile(houtput, "\r\n", 2, &dummy, NULL);
299 
300  if (console_textlen)
301  {
303  console_textlen = 0;
304  return console_text;
305  }
306  break;
307 
308  case '\b':
309  if (console_textlen)
310  {
311  console_textlen--;
312  WriteFile(houtput, "\b \b", 3, &dummy, NULL);
313  }
314  break;
315 
316  default:
317  if (ch >= ' ')
318  {
319  if (console_textlen < sizeof(console_text)-2)
320  {
321  WriteFile(houtput, &ch, 1, &dummy, NULL);
323  console_textlen++;
324  }
325  }
326 
327  break;
328 
329  }
330  }
331  }
332  }
333 
334  return NULL;
335 }
336 
337 
338 /*
339 ================
340 Sys_ConsoleOutput
341 
342 Print text to the dedicated console
343 ================
344 */
345 void Sys_ConsoleOutput (char *string)
346 {
347  int dummy;
348  char text[256];
349 
350  if (!dedicated || !dedicated->value)
351  return;
352 
353  if (console_textlen)
354  {
355  text[0] = '\r';
356  memset(&text[1], ' ', console_textlen);
357  text[console_textlen+1] = '\r';
358  text[console_textlen+2] = 0;
359  WriteFile(houtput, text, console_textlen+2, &dummy, NULL);
360  }
361 
362  WriteFile(houtput, string, strlen(string), &dummy, NULL);
363 
364  if (console_textlen)
365  WriteFile(houtput, console_text, console_textlen, &dummy, NULL);
366 }
367 
368 
369 /*
370 ================
371 Sys_SendKeyEvents
372 
373 Send Key_Event calls
374 ================
375 */
376 void Sys_SendKeyEvents (void)
377 {
378  MSG msg;
379 
380  while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
381  {
382  if (!GetMessage (&msg, NULL, 0, 0))
383  Sys_Quit ();
384  sys_msg_time = msg.time;
385  TranslateMessage (&msg);
386  DispatchMessage (&msg);
387  }
388 
389  // grab frame time
390  sys_frame_time = timeGetTime(); // FIXME: should this be at start?
391 }
392 
393 
394 
395 /*
396 ================
397 Sys_GetClipboardData
398 
399 ================
400 */
401 char *Sys_GetClipboardData( void )
402 {
403  char *data = NULL;
404  char *cliptext;
405 
406  if ( OpenClipboard( NULL ) != 0 )
407  {
408  HANDLE hClipboardData;
409 
410  if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 )
411  {
412  if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 )
413  {
414  data = malloc( GlobalSize( hClipboardData ) + 1 );
415  strcpy( data, cliptext );
416  GlobalUnlock( hClipboardData );
417  }
418  }
419  CloseClipboard();
420  }
421  return data;
422 }
423 
424 /*
425 ==============================================================================
426 
427  WINDOWS CRAP
428 
429 ==============================================================================
430 */
431 
432 /*
433 =================
434 Sys_AppActivate
435 =================
436 */
437 void Sys_AppActivate (void)
438 {
439  ShowWindow ( cl_hwnd, SW_RESTORE);
440  SetForegroundWindow ( cl_hwnd );
441 }
442 
443 /*
444 ========================================================================
445 
446 GAME DLL
447 
448 ========================================================================
449 */
450 
451 static HINSTANCE game_library;
452 
453 /*
454 =================
455 Sys_UnloadGame
456 =================
457 */
458 void Sys_UnloadGame (void)
459 {
460  if (!FreeLibrary (game_library))
461  Com_Error (ERR_FATAL, "FreeLibrary failed for game library");
462  game_library = NULL;
463 }
464 
465 /*
466 =================
467 Sys_GetGameAPI
468 
469 Loads the game dll
470 =================
471 */
472 void *Sys_GetGameAPI (void *parms)
473 {
474  void *(*GetGameAPI) (void *);
475  char name[MAX_OSPATH];
476  char *path;
477  char cwd[MAX_OSPATH];
478 #if defined _M_IX86
479  const char *gamename = "gamex86.dll";
480 
481 #ifdef NDEBUG
482  const char *debugdir = "release";
483 #else
484  const char *debugdir = "debug";
485 #endif
486 
487 #elif defined _M_ALPHA
488  const char *gamename = "gameaxp.dll";
489 
490 #ifdef NDEBUG
491  const char *debugdir = "releaseaxp";
492 #else
493  const char *debugdir = "debugaxp";
494 #endif
495 
496 #endif
497 
498  if (game_library)
499  Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
500 
501  // check the current debug directory first for development purposes
502  _getcwd (cwd, sizeof(cwd));
503  Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename);
504  game_library = LoadLibrary ( name );
505  if (game_library)
506  {
507  Com_DPrintf ("LoadLibrary (%s)\n", name);
508  }
509  else
510  {
511 #ifdef DEBUG
512  // check the current directory for other development purposes
513  Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename);
514  game_library = LoadLibrary ( name );
515  if (game_library)
516  {
517  Com_DPrintf ("LoadLibrary (%s)\n", name);
518  }
519  else
520 #endif
521  {
522  // now run through the search paths
523  path = NULL;
524  while (1)
525  {
526  path = FS_NextPath (path);
527  if (!path)
528  return NULL; // couldn't find one anywhere
529  Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
530  game_library = LoadLibrary (name);
531  if (game_library)
532  {
533  Com_DPrintf ("LoadLibrary (%s)\n",name);
534  break;
535  }
536  }
537  }
538  }
539 
540  GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI");
541  if (!GetGameAPI)
542  {
543  Sys_UnloadGame ();
544  return NULL;
545  }
546 
547  return GetGameAPI (parms);
548 }
549 
550 //=======================================================================
551 
552 
553 /*
554 ==================
555 ParseCommandLine
556 
557 ==================
558 */
559 void ParseCommandLine (LPSTR lpCmdLine)
560 {
561  argc = 1;
562  argv[0] = "exe";
563 
564  while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
565  {
566  while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
567  lpCmdLine++;
568 
569  if (*lpCmdLine)
570  {
571  argv[argc] = lpCmdLine;
572  argc++;
573 
574  while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
575  lpCmdLine++;
576 
577  if (*lpCmdLine)
578  {
579  *lpCmdLine = 0;
580  lpCmdLine++;
581  }
582 
583  }
584  }
585 
586 }
587 
588 /*
589 ==================
590 WinMain
591 
592 ==================
593 */
595 
596 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
597 {
598  MSG msg;
599  int time, oldtime, newtime;
600  char *cddir;
601 
602  /* previous instances do not exist in Win32 */
603  if (hPrevInstance)
604  return 0;
605 
606  global_hInstance = hInstance;
607 
608  ParseCommandLine (lpCmdLine);
609 
610  // if we find the CD, add a +set cddir xxx command line
611  cddir = Sys_ScanForCD ();
612  if (cddir && argc < MAX_NUM_ARGVS - 3)
613  {
614  int i;
615 
616  // don't override a cddir on the command line
617  for (i=0 ; i<argc ; i++)
618  if (!strcmp(argv[i], "cddir"))
619  break;
620  if (i == argc)
621  {
622  argv[argc++] = "+set";
623  argv[argc++] = "cddir";
624  argv[argc++] = cddir;
625  }
626  }
627 
629  oldtime = Sys_Milliseconds ();
630 
631  /* main window message loop */
632  while (1)
633  {
634  // if at a full screen console, don't update unless needed
635  if (Minimized || (dedicated && dedicated->value) )
636  {
637  Sleep (1);
638  }
639 
640  while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
641  {
642  if (!GetMessage (&msg, NULL, 0, 0))
643  Com_Quit ();
644  sys_msg_time = msg.time;
645  TranslateMessage (&msg);
646  DispatchMessage (&msg);
647  }
648 
649  do
650  {
651  newtime = Sys_Milliseconds ();
652  time = newtime - oldtime;
653  } while (time < 1);
654 // Con_Printf ("time:%5.2f - %5.2f = %5.2f\n", newtime, oldtime, time);
655 
656  // _controlfp( ~( _EM_ZERODIVIDE /*| _EM_INVALID*/ ), _MCW_EM );
657  _controlfp( _PC_24, _MCW_PC );
658  Qcommon_Frame (time);
659 
660  oldtime = newtime;
661  }
662 
663  // never gets here
664  return TRUE;
665 }
dedicated
cvar_t * dedicated
Definition: common.c:47
MAX_QPATH
#define MAX_QPATH
Definition: q_shared.h:73
ActiveApp
int ActiveApp
Definition: sys_win.c:42
WinError
void WinError(void)
Definition: sys_win.c:107
Sys_CopyProtect
void Sys_CopyProtect(void)
Definition: sys_win.c:186
s_win95
qboolean s_win95
Definition: sys_win.c:39
ParseCommandLine
void ParseCommandLine(LPSTR lpCmdLine)
Definition: sys_win.c:559
GetGameAPI
game_export_t * GetGameAPI(game_import_t *import)
Definition: g_main.c:113
console_text
static char console_text[256]
Definition: sys_win.c:257
qboolean
qboolean
Definition: q_shared.h:56
i
int i
Definition: q_shared.c:305
winquake.h
FS_NextPath
char * FS_NextPath(char *prevpath)
Definition: files.c:865
argv
char * argv[MAX_NUM_ARGVS]
Definition: sys_win.c:55
argc
int argc
Definition: sys_win.c:54
Sys_Quit
void Sys_Quit(void)
Definition: sys_win.c:90
Sys_ConsoleOutput
void Sys_ConsoleOutput(char *string)
Definition: sys_win.c:345
Sys_Init
void Sys_Init(void)
Definition: sys_win.c:206
msg
cvar_t * msg
Definition: cl_main.c:98
game_library
static HINSTANCE game_library
Definition: sys_win.c:451
global_hInstance
HINSTANCE global_hInstance
Definition: sys_win.c:594
Qcommon_Frame
void Qcommon_Frame(int msec)
Definition: common.c:1524
Sys_Error
void Sys_Error(char *error,...)
Definition: sys_win.c:67
hinput
static HANDLE hinput
Definition: sys_win.c:45
sys_frame_time
unsigned sys_frame_time
Definition: sys_win.c:48
Minimized
qboolean Minimized
Definition: sys_win.c:43
Qcommon_Shutdown
void Qcommon_Shutdown(void)
Definition: common.c:1619
Sys_ConsoleInput
char * Sys_ConsoleInput(void)
Definition: sys_win.c:265
starttime
int starttime
Definition: sys_win.c:41
CL_Shutdown
void CL_Shutdown(void)
Definition: cl_main.c:1868
Sys_SendKeyEvents
void Sys_SendKeyEvents(void)
Definition: sys_win.c:376
sys_msg_time
unsigned sys_msg_time
Definition: sys_win.c:47
resource.h
cl_hwnd
HWND cl_hwnd
Definition: vid_dll.c:53
cvar_s::value
float value
Definition: q_shared.h:324
MAX_OSPATH
#define MAX_OSPATH
Definition: q_shared.h:74
Sys_AppActivate
void Sys_AppActivate(void)
Definition: sys_win.c:437
console_textlen
static int console_textlen
Definition: sys_win.c:258
NULL
#define NULL
Definition: q_shared.h:60
Sys_GetGameAPI
void * Sys_GetGameAPI(void *parms)
Definition: sys_win.c:472
Com_Error
void Com_Error(int code, char *fmt,...)
Definition: common.c:203
WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
Definition: sys_win.c:596
name
cvar_t * name
Definition: cl_main.c:94
ERR_FATAL
#define ERR_FATAL
Definition: qcommon.h:735
Sys_GetClipboardData
char * Sys_GetClipboardData(void)
Definition: sys_win.c:401
InitConProc
void InitConProc(int argc, char **argv)
Definition: conproc.c:84
houtput
static HANDLE houtput
Definition: sys_win.c:45
qwclsemaphore
static HANDLE qwclsemaphore
Definition: sys_win.c:51
Sys_ScanForCD
char * Sys_ScanForCD(void)
Definition: sys_win.c:137
Com_Quit
void Com_Quit(void)
Definition: common.c:255
Com_DPrintf
void Com_DPrintf(char *fmt,...)
Definition: common.c:155
Qcommon_Init
void Qcommon_Init(int argc, char **argv)
Definition: common.c:1430
Sys_UnloadGame
void Sys_UnloadGame(void)
Definition: sys_win.c:458
Sys_Milliseconds
int Sys_Milliseconds(void)
Definition: q_shwin.c:120
MAX_NUM_ARGVS
#define MAX_NUM_ARGVS
Definition: sys_win.c:53
Com_sprintf
void Com_sprintf(char *dest, int size, char *fmt,...)
Definition: q_shared.c:1236
DeinitConProc
void DeinitConProc(void)
Definition: conproc.c:153