/* Copyright (C) 1996-1997 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 "quakedef.h" #include "winquake.h" #include "resource.h" #include "errno.h" #include "fcntl.h" #include #include #include #include #ifdef NODIRECTX #define DDActive 0 #endif #ifdef MULTITHREAD #include #endif static HINSTANCE game_library; /* ================= Sys_UnloadGame ================= */ void Sys_UnloadGame (void) { if (!FreeLibrary (game_library)) Sys_Error ("FreeLibrary failed for game library"); game_library = NULL; } /* ================= Sys_GetGameAPI Loads the game dll ================= */ void *Sys_GetGameAPI (void *parms) { void *(VARGS *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 __amd64__ const char *gamename = "gameamd.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) Sys_Error ("Sys_GetGameAPI without Sys_UnloadingGame"); // check the current debug directory first for development purposes #ifdef _WIN32 GetCurrentDirectory(sizeof(cwd), cwd); #else _getcwd (cwd, sizeof(cwd)); #endif snprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename); game_library = LoadLibrary ( name ); if (game_library) { Con_DPrintf ("LoadLibrary (%s)\n", name); } else { #ifdef DEBUG // check the current directory for other development purposes _snprintf (name, sizeof(name), "%s/%s", cwd, gamename); game_library = LoadLibrary ( name ); if (game_library) { Con_DPrintf ("LoadLibrary (%s)\n", name); } else #endif { // now run through the search paths path = NULL; while (1) { path = COM_NextPath (path); if (!path) return NULL; // couldn't find one anywhere snprintf (name, sizeof(name), "%s/%s", path, gamename); game_library = LoadLibrary (name); if (game_library) { Con_DPrintf ("LoadLibrary (%s)\n",name); break; } } } } GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI"); if (!GetGameAPI) { Sys_UnloadGame (); return NULL; } return GetGameAPI (parms); } #define MINIMUM_WIN_MEMORY 0x0800000 #define MAXIMUM_WIN_MEMORY 0x4000000 #define PAUSE_SLEEP 50 // sleep time on pause or minimization #define NOT_FOCUS_SLEEP 20 // sleep time when not focus int starttime; qboolean ActiveApp, Minimized; qboolean WinNT; HWND hwnd_dialog; // startup dialog box static HANDLE hinput, houtput; HANDLE qwclsemaphore; static HANDLE tevent; void Sys_InitFloatTime (void); void VARGS MaskExceptions (void); void Sys_PopFPCW (void); void Sys_PushFPCW_SetHigh (void); int VARGS Sys_DebugLog(char *file, char *fmt, ...) { FILE *fd; va_list argptr; static char data[1024]; va_start(argptr, fmt); vsnprintf(data, sizeof(data)-1, fmt, argptr); va_end(argptr); #if defined(CRAZYDEBUGGING) && CRAZYDEBUGGING > 1 { static int sock; if (!sock) { struct sockaddr_in sa; netadr_t na; int _true = true; int listip; listip = COM_CheckParm("-debugip"); NET_StringToAdr(listip?com_argv[listip+1]:"127.0.0.1", &na); NetadrToSockadr(&na, (struct sockaddr_qstorage*)&sa); sa.sin_port = htons(10000); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (-1==connect(sock, (struct sockaddr*)&sa, sizeof(sa))) Sys_Error("Couldn't send debug log lines\n"); setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&_true, sizeof(_true)); } send(sock, data, strlen(data), 0); } #endif fd = fopen(file, "ab"); if (fd) { fprintf(fd, "%s", data); fclose(fd); return 0; } return 1; }; int *debug; #if (_WIN32_WINNT < 0x0400) #define LLKHF_ALTDOWN 0x00000020 #define LLKHF_UP 0x00000080 #define WH_KEYBOARD_LL 13 typedef struct { DWORD vkCode; DWORD scanCode; DWORD flags; DWORD time; DWORD dwExtraInfo; } KBDLLHOOKSTRUCT; #elif defined(MINGW) #define LLKHF_UP 0x00000080 #endif HHOOK llkeyboardhook; cvar_t sys_disableWinKeys = SCVAR("sys_disableWinKeys", "0"); cvar_t sys_disableTaskSwitch = SCVARF("sys_disableTaskSwitch", "0", CVAR_NOTFROMSERVER); // please don't encourage people to use this... LRESULT CALLBACK LowLevelKeyboardProc (INT nCode, WPARAM wParam, LPARAM lParam) { KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam; if (ActiveApp) switch (nCode) { case HC_ACTION: { //Trap the Left Windowskey if (pkbhs->vkCode == VK_LWIN) { Key_Event (K_LWIN, !(pkbhs->flags & LLKHF_UP)); return 1; } //Trap the Right Windowskey if (pkbhs->vkCode == VK_RWIN) { Key_Event (K_RWIN, !(pkbhs->flags & LLKHF_UP)); return 1; } //Trap the Application Key (what a pointless key) if (pkbhs->vkCode == VK_APPS) { Key_Event (K_APP, !(pkbhs->flags & LLKHF_UP)); return 1; } // Disable CTRL+ESC //this works, but we've got to give some way to tab out... if (sys_disableTaskSwitch.value) { if (pkbhs->vkCode == VK_ESCAPE && GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1)) return 1; // Disable ATL+TAB if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN) return 1; // Disable ALT+ESC if (pkbhs->vkCode == VK_ESCAPE && pkbhs->flags & LLKHF_ALTDOWN) return 1; } break; } default: break; } return CallNextHookEx (llkeyboardhook, nCode, wParam, lParam); } void SetHookState(qboolean state) { if (!state == !llkeyboardhook) //not so types are comparable return; if (llkeyboardhook) { UnhookWindowsHookEx(llkeyboardhook); llkeyboardhook = NULL; } if (state) llkeyboardhook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0); } /* =============================================================================== FILE IO =============================================================================== */ /* ================ Sys_filelength ================ */ int Sys_filelength (FILE *f) { int pos; int end; pos = ftell (f); fseek (f, 0, SEEK_END); end = ftell (f); fseek (f, pos, SEEK_SET); return end; } int Sys_FileTime (char *path) { FILE *f; int t=0, retval; if (qrenderer) t = VID_ForceUnlockedAndReturnState (); f = fopen(path, "rb"); if (f) { fclose(f); retval = 1; } else { retval = -1; } if (qrenderer) VID_ForceLockState (t); return retval; } void Sys_mkdir (char *path) { _mkdir (path); } qboolean Sys_remove (char *path) { remove (path); return true; } int Sys_EnumerateFiles (char *gpath, char *match, int (*func)(char *, int, void *), void *parm) { HANDLE r; WIN32_FIND_DATA fd; char apath[MAX_OSPATH]; char apath2[MAX_OSPATH]; char file[MAX_OSPATH]; char *s; int go; if (!gpath) return 0; // strcpy(apath, match); Q_snprintfz(apath, sizeof(apath), "%s/%s", gpath, match); for (s = apath+strlen(apath)-1; s> apath; s--) { if (*s == '/') break; } *s = '\0'; //this is what we ask windows for. Q_snprintfz(file, sizeof(file), "%s/*.*", apath); //we need to make apath contain the path in match but not gpath Q_strncpyz(apath2, match, sizeof(apath)); match = s+1; for (s = apath2+strlen(apath2)-1; s> apath2; s--) { if (*s == '/') break; } *s = '\0'; if (s != apath2) strcat(apath2, "/"); r = FindFirstFile(file, &fd); if (r==(HANDLE)-1) return 1; go = true; do { if (*fd.cFileName == '.'); //don't ever find files with a name starting with '.' else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //is a directory { if (wildcmp(match, fd.cFileName)) { Q_snprintfz(file, sizeof(file), "%s%s/", apath2, fd.cFileName); go = func(file, fd.nFileSizeLow, parm); } } else { if (wildcmp(match, fd.cFileName)) { Q_snprintfz(file, sizeof(file), "%s%s", apath2, fd.cFileName); go = func(file, fd.nFileSizeLow, parm); } } } while(FindNextFile(r, &fd) && go); FindClose(r); return go; } /* =============================================================================== SYSTEM IO =============================================================================== */ /* ================ Sys_MakeCodeWriteable ================ */ void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) { DWORD flOldProtect; //@@@ copy on write or just read-write? if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect)) { char str[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), str, sizeof(str), NULL); Sys_Error("Protection change failed!\nError %d: %s\n", GetLastError(), str); } } /* ================ Sys_Init ================ */ void Sys_Init (void) { // LARGE_INTEGER PerformanceFreq; // unsigned int lowpart, highpart; OSVERSIONINFO vinfo; Cvar_Register(&sys_disableWinKeys, "System vars"); Cvar_Register(&sys_disableTaskSwitch, "System vars"); #ifndef SERVERONLY #ifndef CLIENTONLY if (!isDedicated && !COM_CheckParm("-nomutex")) #else if (!COM_CheckParm("-nomutex")) //we need to create a mutex to allow gamespy to realise that we're running, but it might not be desired as it prevents other clients from running too. #endif { // 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 MaskExceptions (); Sys_SetFPCW (); #if 0 if (!QueryPerformanceFrequency (&PerformanceFreq)) Sys_Error ("No hardware timer available"); // get 32 out of the 64 time bits such that we have around // 1 microsecond resolution lowpart = (unsigned int)PerformanceFreq.LowPart; highpart = (unsigned int)PerformanceFreq.HighPart; lowshift = 0; while (highpart || (lowpart > 2000000.0)) { lowshift++; lowpart >>= 1; lowpart |= (highpart & 1) << 31; highpart >>= 1; } pfreq = 1.0 / (double)lowpart; Sys_InitFloatTime (); #endif // make sure the timer is high precision, otherwise // NT gets 18ms resolution timeBeginPeriod( 1 ); vinfo.dwOSVersionInfoSize = sizeof(vinfo); if (!GetVersionEx (&vinfo)) Sys_Error ("Couldn't get OS info"); if ((vinfo.dwMajorVersion < 4) || (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)) { Sys_Error ("QuakeWorld requires at least Win95 or NT 4.0"); } if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) WinNT = true; else WinNT = false; } void VARGS Sys_Error (const char *error, ...) { va_list argptr; char text[1024]; //, text2[1024]; // DWORD dummy; va_start (argptr, error); vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); SetHookState(false); Host_Shutdown (); MessageBox(NULL, text, "Error", 0); #ifndef SERVERONLY CloseHandle (qwclsemaphore); #endif SetHookState(false); exit (1); } void VARGS Sys_Printf (char *fmt, ...) { va_list argptr; char text[1024]; DWORD dummy; if (!houtput) return; va_start (argptr,fmt); vsnprintf (text, sizeof(text), fmt, argptr); va_end (argptr); WriteFile (houtput, text, strlen(text), &dummy, NULL); } void Sys_Quit (void) { if (VID_ForceUnlockedAndReturnState) VID_ForceUnlockedAndReturnState (); SetHookState(false); Host_Shutdown(); #ifndef SERVERONLY if (tevent) CloseHandle (tevent); if (qwclsemaphore) CloseHandle (qwclsemaphore); #endif SetHookState(false); exit (0); } #if 0 /* ================ Sys_DoubleTime ================ */ double Sys_DoubleTime (void) { static int sametimecount; static unsigned int oldtime; static int first = 1; LARGE_INTEGER PerformanceCount; unsigned int temp, t2; double time; Sys_PushFPCW_SetHigh (); QueryPerformanceCounter (&PerformanceCount); temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) | ((unsigned int)PerformanceCount.HighPart << (32 - lowshift)); if (first) { oldtime = temp; first = 0; } else { // check for turnover or backward time if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000)) { oldtime = temp; // so we can't get stuck } else { t2 = temp - oldtime; time = (double)t2 * pfreq; oldtime = temp; curtime += time; if (curtime == lastcurtime) { sametimecount++; if (sametimecount > 100000) { curtime += 1.0; sametimecount = 0; } } else { sametimecount = 0; } lastcurtime = curtime; } } Sys_PopFPCW (); return curtime; } /* ================ Sys_InitFloatTime ================ */ void Sys_InitFloatTime (void) { int j; Sys_DoubleTime (); j = COM_CheckParm("-starttime"); if (j) { curtime = (double) (Q_atof(com_argv[j+1])); } else { curtime = 0.0; } lastcurtime = curtime; } #endif unsigned int Sys_Milliseconds (void) { static DWORD starttime; static qboolean first = true; DWORD now; // double t; now = timeGetTime(); if (first) { first = false; starttime = now; return 0.0; } /* if (now < starttime) // wrapped? { double r; r = (now) + (LONG_MAX - starttime); starttime = now; return r; } if (now - starttime == 0) return 0.0; */ return (now - starttime); } double Sys_DoubleTime (void) { return Sys_Milliseconds()/1000.f; } ///////////////////////////////////////////////////////////// //clipboard HANDLE clipboardhandle; char *Sys_GetClipboard(void) { char *clipText; if (OpenClipboard(NULL)) { clipboardhandle = GetClipboardData(CF_TEXT); if (clipboardhandle) { clipText = GlobalLock(clipboardhandle); if (clipText) return clipText; //failed at the last hurdle GlobalUnlock(clipboardhandle); } CloseClipboard(); } clipboardhandle = NULL; return NULL; } void Sys_CloseClipboard(char *bf) { if (clipboardhandle) { GlobalUnlock(clipboardhandle); CloseClipboard(); clipboardhandle = NULL; } } void Sys_SaveClipboard(char *text) { HANDLE glob; char *temp; if (!OpenClipboard(NULL)) return; EmptyClipboard(); glob = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1); if (glob == NULL) { CloseClipboard(); return; } temp = GlobalLock(glob); if (temp != NULL) { strcpy(temp, text); GlobalUnlock(glob); SetClipboardData(CF_TEXT, glob); } else GlobalFree(glob); CloseClipboard(); } //end of clipboard ///////////////////////////////////////////////////////////// ///////////////////////////////////////// //the system console stuff char *Sys_ConsoleInput (void) { static char text[256]; static int len; INPUT_RECORD recs[1024]; // int count; int i; int ch; DWORD numevents, numread, dummy=0; HANDLE th; char *clipText, *textCopied; if (!hinput) 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 (len) { text[len] = 0; len = 0; return text; } break; case '\b': if (len) { len--; WriteFile(houtput, "\b \b", 3, &dummy, NULL); } break; default: if (((ch=='V' || ch=='v') && (recs[0].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) || ((recs[0].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) && (recs[0].Event.KeyEvent.wVirtualKeyCode ==VK_INSERT))) { if (OpenClipboard(NULL)) { th = GetClipboardData(CF_TEXT); if (th) { clipText = GlobalLock(th); if (clipText) { textCopied = BZ_Malloc(GlobalSize(th)+1); strcpy(textCopied, clipText); /* Substitutes a NULL for every token */strtok(textCopied, "\n\r\b"); i = strlen(textCopied); if (i+len>=256) i=256-len; if (i>0) { textCopied[i]=0; text[len]=0; strcat(text, textCopied); len+=dummy; WriteFile(houtput, textCopied, i, &dummy, NULL); } BZ_Free(textCopied); } GlobalUnlock(th); } CloseClipboard(); } } else if (ch >= ' ') { WriteFile(houtput, &ch, 1, &dummy, NULL); text[len] = ch; len = (len + 1) & 0xff; } break; } } } } return NULL; } BOOL WINAPI HandlerRoutine (DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: Cbuf_AddText ("quit\n", RESTRICT_LOCAL); return true; } return false; } qboolean Sys_InitTerminal (void) { if (!AllocConsole()) return false; SetConsoleCtrlHandler (HandlerRoutine, TRUE); SetConsoleTitle (FULLENGINENAME " dedicated server"); hinput = GetStdHandle (STD_INPUT_HANDLE); houtput = GetStdHandle (STD_OUTPUT_HANDLE); return true; } void Sys_CloseTerminal (void) { FreeConsole(); hinput = NULL; houtput = NULL; } // //////////////////////////// void Sys_Sleep (void) { } void Sys_SendKeyEvents (void) { MSG msg; if (isDedicated) { #ifndef CLIENTONLY SV_GetConsoleCommands (); #endif return; } while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { // we always update if there are any event, even if we're paused scr_skipupdate = 0; if (!GetMessage (&msg, NULL, 0, 0)) break; // Sys_Quit (); TranslateMessage (&msg); DispatchMessage (&msg); } } void Sys_ServerActivity(void) { FlashWindow(mainwindow, true); } /* ============================================================================== WINDOWS CRAP ============================================================================== */ /* ================== WinMain ================== */ void SleepUntilInput (int time) { MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT); } /* ================== WinMain ================== */ HINSTANCE global_hInstance; int global_nCmdShow; char *argv[MAX_NUM_ARGVS]; static char exename[256]; HWND hwnd_dialog; #ifndef CLIENTONLY qboolean isDedicated = false; #endif /* #ifdef _MSC_VER #include void VARGS Signal_Error_Handler(int i) { int *basepointer; __asm {mov basepointer,ebp}; Sys_Error("Received signal, offset was 0x%8x", basepointer[73]); } #endif */ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // MSG msg; quakeparms_t parms; double time, oldtime, newtime; MEMORYSTATUS lpBuffer; char cwd[1024]; int t; RECT rect; char *qtvfile = NULL; /* previous instances do not exist in Win32 */ if (hPrevInstance) return 0; /* #ifndef _DEBUG #ifdef _MSC_VER signal (SIGFPE, Signal_Error_Handler); signal (SIGILL, Signal_Error_Handler); signal (SIGSEGV, Signal_Error_Handler); #endif #endif */ global_hInstance = hInstance; global_nCmdShow = nCmdShow; lpBuffer.dwLength = sizeof(MEMORYSTATUS); GlobalMemoryStatus (&lpBuffer); parms.argc = 1; argv[0] = exename; while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS)) { while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) lpCmdLine++; if (*lpCmdLine) { if (*lpCmdLine == '\"') { lpCmdLine++; argv[parms.argc] = lpCmdLine; parms.argc++; while (*lpCmdLine && *lpCmdLine != '\"') lpCmdLine++; } else { argv[parms.argc] = lpCmdLine; parms.argc++; while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) lpCmdLine++; } if (*lpCmdLine) { *lpCmdLine = 0; lpCmdLine++; } } } GetModuleFileName(NULL, cwd, sizeof(cwd)-1); strcpy(exename, COM_SkipPath(cwd)); parms.argv = argv; COM_InitArgv (parms.argc, parms.argv); if (COM_CheckParm("--version") || COM_CheckParm("-v")) { printf("version " DISTRIBUTION " " __TIME__ __DATE__ "\n"); return true; } if (!GetCurrentDirectory (sizeof(cwd), cwd)) Sys_Error ("Couldn't determine current directory"); if (parms.argc >= 2) { if (*parms.argv[1] != '-' && *parms.argv[1] != '+') { char *e; qtvfile = parms.argv[1]; GetModuleFileName(NULL, cwd, sizeof(cwd)-1); for (e = cwd+strlen(cwd)-1; e >= cwd; e--) { if (*e == '/' || *e == '\\') { *e = 0; break; } } } } TL_InitLanguages(); //tprints are now allowed parms.basedir = cwd; parms.argc = com_argc; parms.argv = com_argv; #ifndef CLIENTONLY if (COM_CheckParm ("-dedicated")) { isDedicated = true; hwnd_dialog=NULL; if (!Sys_InitTerminal()) Sys_Error ("Couldn't allocate dedicated server console"); } else #endif hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL); if (hwnd_dialog) { if (GetWindowRect (hwnd_dialog, &rect)) { if (rect.left > (rect.top * 2)) { SetWindowPos (hwnd_dialog, 0, (rect.left / 2) - ((rect.right - rect.left) / 2), rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } } ShowWindow (hwnd_dialog, SW_SHOWDEFAULT); UpdateWindow (hwnd_dialog); SetForegroundWindow (hwnd_dialog); } // take the greater of all the available memory or half the total memory, // but at least 8 Mb and no more than 16 Mb, unless they explicitly // request otherwise parms.memsize = lpBuffer.dwAvailPhys; if (parms.memsize < MINIMUM_WIN_MEMORY) parms.memsize = MINIMUM_WIN_MEMORY; if (parms.memsize < (lpBuffer.dwTotalPhys >> 1)) parms.memsize = lpBuffer.dwTotalPhys >> 1; if (parms.memsize > MAXIMUM_WIN_MEMORY) parms.memsize = MAXIMUM_WIN_MEMORY; if (COM_CheckParm ("-heapsize")) { t = COM_CheckParm("-heapsize") + 1; if (t < com_argc) parms.memsize = Q_atoi (com_argv[t]) * 1024; } else if (COM_CheckParm ("-mem")) { t = COM_CheckParm("-mem") + 1; if (t < com_argc) parms.memsize = Q_atoi (com_argv[t]) * 1024*1024; } parms.membase = VirtualAlloc (NULL, parms.memsize, MEM_RESERVE, PAGE_NOACCESS); // parms.membase = malloc (parms.memsize); if (!parms.membase) Sys_Error ("Not enough memory free; check disk space\n"); #ifndef CLIENTONLY if (isDedicated) //compleate denial to switch to anything else - many of the client structures are not initialized. { SV_Init (&parms); SV_Frame (); while (1) { if (!isDedicated) Sys_Error("Dedicated was cleared"); NET_Sleep(100, false); SV_Frame (); } return TRUE; } #endif tevent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!tevent) Sys_Error ("Couldn't create event"); Sys_Printf ("Host_Init\n"); Host_Init (&parms); oldtime = Sys_DoubleTime (); if (qtvfile) Cbuf_AddText(va("qtvplay \"#%s\"\n", qtvfile), RESTRICT_LOCAL); //client console should now be initialized. /* main window message loop */ while (1) { #ifndef CLIENTONLY if (isDedicated) { NET_Sleep(50, false); // find time passed since last cycle newtime = Sys_DoubleTime (); time = newtime - oldtime; oldtime = newtime; SV_Frame (); } else #endif { // yield the CPU for a little while when paused, minimized, or not the focus if (((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing) && !Media_PlayingFullScreen()) { SleepUntilInput (PAUSE_SLEEP); scr_skipupdate = 1; // no point in bothering to draw } else if (!ActiveApp && !DDActive && !Media_PlayingFullScreen()) { SleepUntilInput (NOT_FOCUS_SLEEP); } newtime = Sys_DoubleTime (); time = newtime - oldtime; Host_Frame (time); oldtime = newtime; SetHookState(sys_disableWinKeys.value); // Sleep(0); } } /* return success of application */ return TRUE; } qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate) { HDC hdc; int rate; hdc = GetDC(NULL); *width = GetDeviceCaps(hdc, HORZRES); *height = GetDeviceCaps(hdc, VERTRES); *bpp = GetDeviceCaps(hdc, BITSPIXEL); rate = GetDeviceCaps(hdc, VREFRESH); if (rate == 1) rate = 0; *refreshrate = rate; ReleaseDC(NULL, hdc); return true; } #ifdef NOASM //these couldn't be found... (it is a masm thing, right?) void Sys_HighFPPrecision (void) { } void Sys_LowFPPrecision (void) { } void Sys_SetFPCW (void) { } void MaskExceptions (void) { } #endif #ifdef MULTITHREAD /* Thread creation calls */ typedef struct threadwrap_s { void (*func)(void *); void *args; } threadwrap_t; // the thread call is wrapped so we don't need WINAPI everywhere DWORD WINAPI threadwrapper(void *args) { threadwrap_t tw; tw.func = ((threadwrap_t *)args)->func; tw.args = ((threadwrap_t *)args)->args; free(args); tw.func(tw.args); #ifndef WIN32CRTDLL _endthreadex(0); #endif return 0; } void *Sys_CreateThread(int (*func)(void *), void *args, int stacksize) { threadwrap_t *tw = (threadwrap_t *)malloc(sizeof(threadwrap_t)); HANDLE handle; if (!tw) return NULL; stacksize += 128; // wrapper overhead, also prevent default stack size tw->func = func; tw->args = args; #ifdef WIN32CRTDLL handle = (HANDLE)CreateThread(NULL, stacksize, &threadwrapper, (void *)tw, 0, NULL); #else handle = (HANDLE)_beginthreadex(NULL, stacksize, &threadwrapper, (void *)tw, 0, NULL); #endif if (!handle) { free(tw); return NULL; } return (void *)handle; } void Sys_WaitOnThread(void *thread) { WaitForSingleObject((HANDLE)thread, INFINITE); CloseHandle((HANDLE)thread); } /* Mutex calls */ void *Sys_CreateMutex() { return (void *)CreateMutex(NULL, 0, NULL); } qboolean Sys_TryLockMutex(void *mutex) { return WaitForSingleObject(mutex, 0) == WAIT_OBJECT_0; } qboolean Sys_LockMutex(void *mutex) { return WaitForSingleObject(mutex, INFINITE) == WAIT_OBJECT_0; } qboolean Sys_UnlockMutex(void *mutex) { return !!ReleaseMutex(mutex); } void Sys_DestroyMutex(void *mutex) { CloseHandle(mutex); } #endif