/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sys_win.h #include "../qcommon/qcommon.h" #include "winquake.h" #include "resource.h" #include #include #include #include #include #include #include #include "../win32/conproc.h" #define MINIMUM_WIN_MEMORY 0x0a00000 #define MAXIMUM_WIN_MEMORY 0x1000000 //#define DEMO qboolean s_win95; int starttime; int ActiveApp; qboolean Minimized; static HANDLE hinput, houtput; unsigned sys_msg_time; unsigned sys_frame_time; static HANDLE qwclsemaphore; #define MAX_NUM_ARGVS 128 int argc; char *argv[MAX_NUM_ARGVS]; /* =============================================================================== SYSTEM IO =============================================================================== */ void Sys_Error (char *error, ...) { va_list argptr; char text[1024]; CL_Shutdown (); Qcommon_Shutdown (); va_start (argptr, error); vsprintf (text, error, argptr); va_end (argptr); MessageBox(NULL, text, "Error", 0 /* MB_OK */ ); if (qwclsemaphore) CloseHandle (qwclsemaphore); // shut down QHOST hooks if necessary DeinitConProc (); exit (1); } void Sys_Quit (void) { timeEndPeriod( 1 ); CL_Shutdown(); Qcommon_Shutdown (); CloseHandle (qwclsemaphore); if (dedicated && dedicated->value) FreeConsole (); // shut down QHOST hooks if necessary DeinitConProc (); exit (0); } void WinError (void) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); // Display the string. MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION ); // Free the buffer. LocalFree( lpMsgBuf ); } //================================================================ /* ================ Sys_ScanForCD ================ */ char *Sys_ScanForCD (void) { static char cddir[MAX_OSPATH]; static qboolean done; #ifndef DEMO char drive[4]; FILE *f; char test[MAX_QPATH]; if (done) // don't re-check return cddir; // no abort/retry/fail errors SetErrorMode (SEM_FAILCRITICALERRORS); drive[0] = 'c'; drive[1] = ':'; drive[2] = '\\'; drive[3] = 0; done = true; // scan the drives for (drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++) { // where activision put the stuff... sprintf (cddir, "%sinstall\\data", drive); sprintf (test, "%sinstall\\data\\quake2.exe", drive); f = fopen(test, "r"); if (f) { fclose (f); if (GetDriveType (drive) == DRIVE_CDROM) return cddir; } } #endif cddir[0] = 0; return NULL; } /* ================ Sys_CopyProtect ================ */ void Sys_CopyProtect (void) { #ifndef DEMO char *cddir; cddir = Sys_ScanForCD(); if (!cddir[0]) Com_Error (ERR_FATAL, "You must have the Quake2 CD in the drive to play."); #endif } //================================================================ /* ================ Sys_Init ================ */ void Sys_Init (void) { OSVERSIONINFO vinfo; #if 0 // allocate a named semaphore on the client so the // front end can tell if it is alive // mutex will fail if semephore already exists qwclsemaphore = CreateMutex( NULL, /* Security attributes */ 0, /* owner */ "qwcl"); /* Semaphore name */ if (!qwclsemaphore) Sys_Error ("QWCL is already running on this system"); CloseHandle (qwclsemaphore); qwclsemaphore = CreateSemaphore( NULL, /* Security attributes */ 0, /* Initial count */ 1, /* Maximum count */ "qwcl"); /* Semaphore name */ #endif timeBeginPeriod( 1 ); vinfo.dwOSVersionInfoSize = sizeof(vinfo); if (!GetVersionEx (&vinfo)) Sys_Error ("Couldn't get OS info"); if (vinfo.dwMajorVersion < 4) Sys_Error ("Quake2 requires windows version 4 or greater"); if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s) Sys_Error ("Quake2 doesn't run on Win32s"); else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) s_win95 = true; if (dedicated->value) { if (!AllocConsole ()) Sys_Error ("Couldn't create dedicated server console"); hinput = GetStdHandle (STD_INPUT_HANDLE); houtput = GetStdHandle (STD_OUTPUT_HANDLE); // let QHOST hook in InitConProc (argc, argv); } } static char console_text[256]; static int console_textlen; /* ================ Sys_ConsoleInput ================ */ char *Sys_ConsoleInput (void) { INPUT_RECORD recs[1024]; int dummy; int ch, numread, numevents; if (!dedicated || !dedicated->value) return NULL; for ( ;; ) { if (!GetNumberOfConsoleInputEvents (hinput, &numevents)) Sys_Error ("Error getting # of console events"); if (numevents <= 0) break; if (!ReadConsoleInput(hinput, recs, 1, &numread)) Sys_Error ("Error reading console input"); if (numread != 1) Sys_Error ("Couldn't read console input"); if (recs[0].EventType == KEY_EVENT) { if (!recs[0].Event.KeyEvent.bKeyDown) { ch = recs[0].Event.KeyEvent.uChar.AsciiChar; switch (ch) { case '\r': WriteFile(houtput, "\r\n", 2, &dummy, NULL); if (console_textlen) { console_text[console_textlen] = 0; console_textlen = 0; return console_text; } break; case '\b': if (console_textlen) { console_textlen--; WriteFile(houtput, "\b \b", 3, &dummy, NULL); } break; default: if (ch >= ' ') { if (console_textlen < sizeof(console_text)-2) { WriteFile(houtput, &ch, 1, &dummy, NULL); console_text[console_textlen] = ch; console_textlen++; } } break; } } } } return NULL; } /* ================ Sys_ConsoleOutput Print text to the dedicated console ================ */ void Sys_ConsoleOutput (char *string) { int dummy; char text[256]; if (!dedicated || !dedicated->value) return; if (console_textlen) { text[0] = '\r'; memset(&text[1], ' ', console_textlen); text[console_textlen+1] = '\r'; text[console_textlen+2] = 0; WriteFile(houtput, text, console_textlen+2, &dummy, NULL); } WriteFile(houtput, string, strlen(string), &dummy, NULL); if (console_textlen) WriteFile(houtput, console_text, console_textlen, &dummy, NULL); } /* ================ Sys_SendKeyEvents Send Key_Event calls ================ */ void Sys_SendKeyEvents (void) { MSG msg; while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { if (!GetMessage (&msg, NULL, 0, 0)) Sys_Quit (); sys_msg_time = msg.time; TranslateMessage (&msg); DispatchMessage (&msg); } // grab frame time sys_frame_time = timeGetTime(); // FIXME: should this be at start? } /* ================ Sys_GetClipboardData ================ */ char *Sys_GetClipboardData( void ) { char *data = NULL; char *cliptext; if ( OpenClipboard( NULL ) != 0 ) { HANDLE hClipboardData; if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) { if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) { data = malloc( GlobalSize( hClipboardData ) + 1 ); strcpy( data, cliptext ); GlobalUnlock( hClipboardData ); } } CloseClipboard(); } return data; } /* ============================================================================== WINDOWS CRAP ============================================================================== */ /* ================= Sys_AppActivate ================= */ void Sys_AppActivate (void) { ShowWindow ( cl_hwnd, SW_RESTORE); SetForegroundWindow ( cl_hwnd ); } /* ======================================================================== GAME DLL ======================================================================== */ static HINSTANCE game_library; /* ================= Sys_UnloadGame ================= */ void Sys_UnloadGame (void) { if (!FreeLibrary (game_library)) Com_Error (ERR_FATAL, "FreeLibrary failed for game library"); game_library = NULL; } /* ================= Sys_GetGameAPI Loads the game dll ================= */ void *Sys_GetGameAPI (void *parms) { void *(*GetGameAPI) (void *); char name[MAX_OSPATH]; char *path; char cwd[MAX_OSPATH]; #if defined _M_IX86 const char *gamename = "gamex86.dll"; #ifdef NDEBUG const char *debugdir = "release"; #else const char *debugdir = "debug"; #endif #elif defined _M_ALPHA const char *gamename = "gameaxp.dll"; #ifdef NDEBUG const char *debugdir = "releaseaxp"; #else const char *debugdir = "debugaxp"; #endif #endif if (game_library) Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame"); // check the current debug directory first for development purposes _getcwd (cwd, sizeof(cwd)); Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename); game_library = LoadLibrary ( name ); if (game_library) { Com_DPrintf ("LoadLibrary (%s)\n", name); } else { #ifdef DEBUG // check the current directory for other development purposes Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename); game_library = LoadLibrary ( name ); if (game_library) { Com_DPrintf ("LoadLibrary (%s)\n", name); } else #endif { // now run through the search paths path = NULL; while (1) { path = FS_NextPath (path); if (!path) return NULL; // couldn't find one anywhere Com_sprintf (name, sizeof(name), "%s/%s", path, gamename); game_library = LoadLibrary (name); if (game_library) { Com_DPrintf ("LoadLibrary (%s)\n",name); break; } } } } GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI"); if (!GetGameAPI) { Sys_UnloadGame (); return NULL; } return GetGameAPI (parms); } //======================================================================= /* ================== ParseCommandLine ================== */ void ParseCommandLine (LPSTR lpCmdLine) { argc = 1; argv[0] = "exe"; while (*lpCmdLine && (argc < MAX_NUM_ARGVS)) { while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) lpCmdLine++; if (*lpCmdLine) { argv[argc] = lpCmdLine; argc++; while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) lpCmdLine++; if (*lpCmdLine) { *lpCmdLine = 0; lpCmdLine++; } } } } /* ================== WinMain ================== */ HINSTANCE global_hInstance; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; int time, oldtime, newtime; char *cddir; /* previous instances do not exist in Win32 */ if (hPrevInstance) return 0; global_hInstance = hInstance; ParseCommandLine (lpCmdLine); // if we find the CD, add a +set cddir xxx command line cddir = Sys_ScanForCD (); if (cddir && argc < MAX_NUM_ARGVS - 3) { int i; // don't override a cddir on the command line for (i=0 ; ivalue) ) { Sleep (1); } while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { if (!GetMessage (&msg, NULL, 0, 0)) Com_Quit (); sys_msg_time = msg.time; TranslateMessage (&msg); DispatchMessage (&msg); } do { newtime = Sys_Milliseconds (); time = newtime - oldtime; } while (time < 1); // Con_Printf ("time:%5.2f - %5.2f = %5.2f\n", newtime, oldtime, time); // _controlfp( ~( _EM_ZERODIVIDE /*| _EM_INVALID*/ ), _MCW_EM ); _controlfp( _PC_24, _MCW_PC ); Qcommon_Frame (time); oldtime = newtime; } // never gets here return TRUE; }