2004-08-23 00:15:46 +00:00
/*
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
2010-12-07 12:23:56 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-23 00:15:46 +00:00
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"
2009-11-04 21:16:50 +00:00
2004-08-23 00:15:46 +00:00
# include "winquake.h"
# include "resource.h"
# include "errno.h"
# include "fcntl.h"
# include <limits.h>
# include <conio.h>
# include <io.h>
# include <direct.h>
2007-12-30 20:05:49 +00:00
# ifdef MULTITHREAD
# include <process.h>
# endif
2004-12-13 00:44:05 +00:00
2009-11-04 21:16:50 +00:00
# ifdef _DEBUG
2010-03-14 14:35:56 +00:00
# if _MSC_VER >= 1300
2009-11-04 21:16:50 +00:00
# define CATCHCRASH
# endif
2010-03-14 14:35:56 +00:00
# endif
2009-11-04 21:16:50 +00:00
2009-04-01 22:03:56 +00:00
# if !defined(CLIENTONLY) && !defined(SERVERONLY)
qboolean isDedicated = false ;
# endif
2011-01-23 03:33:33 +00:00
qboolean debugout ;
2009-04-01 22:03:56 +00:00
2009-04-06 00:34:32 +00:00
HWND sys_parentwindow ;
unsigned int sys_parentwidth ; //valid if sys_parentwindow is set
unsigned int sys_parentheight ;
2004-12-13 00:44:05 +00:00
2008-11-09 22:29:28 +00:00
void Sys_CloseLibrary ( dllhandle_t * lib )
{
FreeLibrary ( ( HMODULE ) lib ) ;
}
2009-11-04 21:16:50 +00:00
dllhandle_t * Sys_LoadLibrary ( const char * name , dllfunction_t * funcs )
2008-11-09 22:29:28 +00:00
{
int i ;
HMODULE lib ;
lib = LoadLibrary ( name ) ;
if ( ! lib )
2010-11-11 04:03:16 +00:00
{
# ifdef _WIN64
lib = LoadLibrary ( va ( " %s_64 " , name ) ) ;
# elif defined(_WIN32)
lib = LoadLibrary ( va ( " %s_32 " , name ) ) ;
# endif
if ( ! lib )
return NULL ;
}
2008-11-09 22:29:28 +00:00
2009-04-01 22:03:56 +00:00
if ( funcs )
2008-11-09 22:29:28 +00:00
{
2009-04-01 22:03:56 +00:00
for ( i = 0 ; funcs [ i ] . name ; i + + )
{
* funcs [ i ] . funcptr = GetProcAddress ( lib , funcs [ i ] . name ) ;
if ( ! * funcs [ i ] . funcptr )
break ;
}
if ( funcs [ i ] . name )
{
Sys_CloseLibrary ( ( dllhandle_t * ) lib ) ;
lib = NULL ;
}
2008-11-09 22:29:28 +00:00
}
return ( dllhandle_t * ) lib ;
}
2009-11-04 21:16:50 +00:00
void * Sys_GetAddressForName ( dllhandle_t * module , const char * exportname )
2009-03-03 01:52:30 +00:00
{
if ( ! module )
return NULL ;
return GetProcAddress ( ( HINSTANCE ) module , exportname ) ;
}
# ifdef HLSERVER
char * Sys_GetNameForAddress ( dllhandle_t * module , void * address )
{
//windows doesn't provide a function to do this, so we have to do it ourselves.
//this isn't the fastest way...
//halflife needs this function.
char * base = ( char * ) module ;
IMAGE_DATA_DIRECTORY * datadir ;
IMAGE_EXPORT_DIRECTORY * block ;
IMAGE_NT_HEADERS * ntheader ;
IMAGE_DOS_HEADER * dosheader = ( void * ) base ;
int i , j ;
DWORD * funclist ;
DWORD * namelist ;
SHORT * ordilist ;
if ( ! dosheader | | dosheader - > e_magic ! = IMAGE_DOS_SIGNATURE )
return NULL ; //yeah, that wasn't an exe
ntheader = ( void * ) ( base + dosheader - > e_lfanew ) ;
if ( ! dosheader - > e_lfanew | | ntheader - > Signature ! = IMAGE_NT_SIGNATURE )
return NULL ; //urm, wait, a 16bit dos exe?
datadir = & ntheader - > OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_EXPORT ] ;
2010-12-07 12:23:56 +00:00
2009-03-03 01:52:30 +00:00
block = ( IMAGE_EXPORT_DIRECTORY * ) ( base + datadir - > VirtualAddress ) ;
funclist = ( DWORD * ) ( base + block - > AddressOfFunctions ) ;
namelist = ( DWORD * ) ( base + block - > AddressOfNames ) ;
ordilist = ( SHORT * ) ( base + block - > AddressOfNameOrdinals ) ;
for ( i = 0 ; i < block - > NumberOfFunctions ; i + + )
{
if ( base + funclist [ i ] = = address )
{
for ( j = 0 ; j < block - > NumberOfNames ; j + + )
{
if ( ordilist [ j ] = = i )
{
return base + namelist [ i ] ;
}
}
//it has no name. huh?
return NULL ;
}
}
return NULL ;
}
# endif
2009-03-07 05:05:54 +00:00
# ifdef Q2SERVER
2004-12-13 00:44:05 +00:00
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 )
{
2005-03-18 06:14:07 +00:00
void * ( VARGS * GetGameAPI ) ( void * ) ;
2004-12-13 00:44:05 +00:00
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
2009-03-07 04:37:24 +00:00
# elif defined(__amd64__) || defined(__AMD64__) || defined(_AMD64_)
2007-09-02 19:55:17 +00:00
const char * gamename = " gameamd.dll " ;
# ifdef NDEBUG
const char * debugdir = " release " ;
# else
const char * debugdir = " debug " ;
# endif
2004-12-13 00:44:05 +00:00
# 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
2006-03-06 01:41:09 +00:00
snprintf ( name , sizeof ( name ) , " %s/%s/%s " , cwd , debugdir , gamename ) ;
2004-12-13 00:44:05 +00:00
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
2006-03-06 01:41:09 +00:00
snprintf ( name , sizeof ( name ) , " %s/%s " , path , gamename ) ;
2004-12-13 00:44:05 +00:00
game_library = LoadLibrary ( name ) ;
if ( game_library )
{
Con_DPrintf ( " LoadLibrary (%s) \n " , name ) ;
break ;
}
}
}
}
GetGameAPI = ( void * ) GetProcAddress ( game_library , " GetGameAPI " ) ;
if ( ! GetGameAPI )
{
2010-12-07 12:23:56 +00:00
Sys_UnloadGame ( ) ;
2004-12-13 00:44:05 +00:00
return NULL ;
}
return GetGameAPI ( parms ) ;
}
2009-03-07 05:05:54 +00:00
# endif
2004-12-13 00:44:05 +00:00
2004-08-23 00:15:46 +00:00
# define MINIMUM_WIN_MEMORY 0x0800000
2010-03-14 14:35:56 +00:00
# define MAXIMUM_WIN_MEMORY 0x8000000
2004-08-23 00:15:46 +00:00
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 ) ;
2005-12-05 16:47:29 +00:00
int VARGS Sys_DebugLog ( char * file , char * fmt , . . . )
2004-08-23 00:15:46 +00:00
{
2004-12-13 00:44:05 +00:00
FILE * fd ;
2010-12-07 12:23:56 +00:00
va_list argptr ;
2004-12-13 00:44:05 +00:00
static char data [ 1024 ] ;
2010-12-07 12:23:56 +00:00
2004-12-13 00:44:05 +00:00
va_start ( argptr , fmt ) ;
2006-03-06 01:41:09 +00:00
vsnprintf ( data , sizeof ( data ) - 1 , fmt , argptr ) ;
2004-12-13 00:44:05 +00:00
va_end ( argptr ) ;
2004-10-19 16:10:14 +00:00
# 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
2005-01-13 16:29:20 +00:00
fd = fopen ( file , " ab " ) ;
2005-05-08 06:02:03 +00:00
if ( fd )
{
fprintf ( fd , " %s " , data ) ;
fclose ( fd ) ;
2005-12-05 16:47:29 +00:00
return 0 ;
2005-05-08 06:02:03 +00:00
}
2005-12-05 16:47:29 +00:00
return 1 ;
2004-08-23 00:15:46 +00:00
} ;
2009-11-04 21:16:50 +00:00
# ifdef CATCHCRASH
# include "dbghelp.h"
typedef BOOL ( WINAPI * MINIDUMPWRITEDUMP ) (
HANDLE hProcess ,
DWORD ProcessId ,
HANDLE hFile ,
MINIDUMP_TYPE DumpType ,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam ,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam ,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
) ;
2010-03-14 14:35:56 +00:00
DWORD CrashExceptionHandler ( DWORD exceptionCode , LPEXCEPTION_POINTERS exceptionInfo )
2009-11-04 21:16:50 +00:00
{
char dumpPath [ 1024 ] ;
HANDLE hProc = GetCurrentProcess ( ) ;
DWORD procid = GetCurrentProcessId ( ) ;
HANDLE dumpfile ;
HMODULE hDbgHelp ;
MINIDUMPWRITEDUMP fnMiniDumpWriteDump ;
HMODULE hKernel ;
BOOL ( WINAPI * pIsDebuggerPresent ) ( void ) ;
hKernel = LoadLibrary ( " kernel32 " ) ;
pIsDebuggerPresent = ( void * ) GetProcAddress ( hKernel , " IsDebuggerPresent " ) ;
# ifdef GLQUAKE
GLVID_Crashed ( ) ;
# endif
if ( pIsDebuggerPresent ( ) )
{
/*if we have a current window, minimize it to bring us out of fullscreen*/
ShowWindow ( mainwindow , SW_MINIMIZE ) ;
return EXCEPTION_CONTINUE_SEARCH ;
}
/*if we have a current window, kill it, so it can't steal input of handle window messages or anything risky like that*/
DestroyWindow ( mainwindow ) ;
hDbgHelp = LoadLibrary ( " DBGHELP " ) ;
if ( hDbgHelp )
fnMiniDumpWriteDump = ( MINIDUMPWRITEDUMP ) GetProcAddress ( hDbgHelp , " MiniDumpWriteDump " ) ;
else
fnMiniDumpWriteDump = NULL ;
if ( fnMiniDumpWriteDump )
{
if ( MessageBox ( NULL , " KABOOM! We crashed! \n Blame the monkey in the corner. \n I hope you saved your work. \n Would you like to take a dump now? " , DISTRIBUTION " Sucks " , MB_ICONSTOP | MB_YESNO ) ! = IDYES )
return EXCEPTION_EXECUTE_HANDLER ;
/*take a dump*/
GetTempPath ( sizeof ( dumpPath ) - 16 , dumpPath ) ;
Q_strncatz ( dumpPath , DISTRIBUTION " CrashDump.dmp " , sizeof ( dumpPath ) ) ;
dumpfile = CreateFile ( dumpPath , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( dumpfile )
{
MINIDUMP_EXCEPTION_INFORMATION crashinfo ;
crashinfo . ClientPointers = TRUE ;
crashinfo . ExceptionPointers = exceptionInfo ;
crashinfo . ThreadId = GetCurrentThreadId ( ) ;
if ( fnMiniDumpWriteDump ( hProc , procid , dumpfile , MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithDataSegs , & crashinfo , NULL , NULL ) )
{
CloseHandle ( dumpfile ) ;
MessageBox ( NULL , va ( " You can find the crashdump at \n %s \n Please send this file to someone. \n \n Warning: sensitive information (like your current user name) might be present in the dump. \n You will probably want to compress it. " , dumpPath ) , DISTRIBUTION " Sucks " , 0 ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
}
}
2010-07-18 08:42:59 +00:00
else
MessageBox ( NULL , " Kaboom! Sorry. No MiniDumpWriteDump function. " , DISTRIBUTION " Sucks " , 0 ) ;
2009-11-04 21:16:50 +00:00
return EXCEPTION_EXECUTE_HANDLER ;
}
# endif
2004-08-23 00:15:46 +00:00
int * debug ;
2004-09-04 17:45:10 +00:00
2009-03-07 05:05:54 +00:00
# ifndef SERVERONLY
2004-09-04 17:45:10 +00:00
# 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 ;
2006-02-11 02:09:43 +00:00
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...
2004-09-04 17:45:10 +00:00
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 )
{
2010-08-14 00:15:07 +00:00
Key_Event ( 0 , K_LWIN , 0 , ! ( pkbhs - > flags & LLKHF_UP ) ) ;
2004-09-04 17:45:10 +00:00
return 1 ;
}
//Trap the Right Windowskey
if ( pkbhs - > vkCode = = VK_RWIN )
{
2010-08-14 00:15:07 +00:00
Key_Event ( 0 , K_RWIN , 0 , ! ( pkbhs - > flags & LLKHF_UP ) ) ;
2004-09-04 17:45:10 +00:00
return 1 ;
}
//Trap the Application Key (what a pointless key)
if ( pkbhs - > vkCode = = VK_APPS )
{
2010-08-14 00:15:07 +00:00
Key_Event ( 0 , K_APP , 0 , ! ( pkbhs - > flags & LLKHF_UP ) ) ;
2004-09-04 17:45:10 +00:00
return 1 ;
}
// Disable CTRL+ESC
2004-10-03 10:19:58 +00:00
//this works, but we've got to give some way to tab out...
2009-11-04 21:16:50 +00:00
if ( sys_disableTaskSwitch . ival )
2004-10-07 13:04:30 +00:00
{
if ( pkbhs - > vkCode = = VK_ESCAPE & & GetAsyncKeyState ( VK_CONTROL ) > > ( ( sizeof ( SHORT ) * 8 ) - 1 ) )
return 1 ;
2004-09-04 17:45:10 +00:00
// Disable ATL+TAB
2004-10-07 13:04:30 +00:00
if ( pkbhs - > vkCode = = VK_TAB & & pkbhs - > flags & LLKHF_ALTDOWN )
return 1 ;
2004-09-04 17:45:10 +00:00
// Disable ALT+ESC
2004-10-07 13:04:30 +00:00
if ( pkbhs - > vkCode = = VK_ESCAPE & & pkbhs - > flags & LLKHF_ALTDOWN )
return 1 ;
}
2004-09-04 17:45:10 +00:00
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 ) ;
}
2009-03-07 05:05:54 +00:00
# endif
2004-09-04 17:45:10 +00:00
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
FILE IO
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void Sys_mkdir ( char * path )
{
_mkdir ( path ) ;
}
qboolean Sys_remove ( char * path )
{
remove ( path ) ;
return true ;
}
2009-04-01 22:03:56 +00:00
int Sys_EnumerateFiles ( const char * gpath , const char * match , int ( * func ) ( const char * , int , void * ) , void * parm )
2004-08-23 00:15:46 +00:00
{
HANDLE r ;
2010-12-07 12:23:56 +00:00
WIN32_FIND_DATA fd ;
2004-08-23 00:15:46 +00:00
char apath [ MAX_OSPATH ] ;
2006-03-06 01:41:09 +00:00
char apath2 [ MAX_OSPATH ] ;
2004-08-23 00:15:46 +00:00
char file [ MAX_OSPATH ] ;
char * s ;
int go ;
2004-12-05 11:40:15 +00:00
if ( ! gpath )
return 0 ;
// strcpy(apath, match);
2006-05-19 19:15:52 +00:00
Q_snprintfz ( apath , sizeof ( apath ) , " %s/%s " , gpath , match ) ;
2004-12-05 11:40:15 +00:00
for ( s = apath + strlen ( apath ) - 1 ; s > apath ; s - - )
2004-08-23 00:15:46 +00:00
{
2010-12-07 12:23:56 +00:00
if ( * s = = ' / ' )
2004-08-23 00:15:46 +00:00
break ;
}
2004-12-05 11:40:15 +00:00
* s = ' \0 ' ;
2006-03-06 01:41:09 +00:00
2004-12-05 11:40:15 +00:00
//this is what we ask windows for.
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s/*.* " , apath ) ;
2004-12-05 11:40:15 +00:00
//we need to make apath contain the path in match but not gpath
2006-03-06 01:41:09 +00:00
Q_strncpyz ( apath2 , match , sizeof ( apath ) ) ;
2004-12-05 11:40:15 +00:00
match = s + 1 ;
2006-03-06 01:41:09 +00:00
for ( s = apath2 + strlen ( apath2 ) - 1 ; s > apath2 ; s - - )
2004-12-05 11:40:15 +00:00
{
2010-12-07 12:23:56 +00:00
if ( * s = = ' / ' )
2004-12-05 11:40:15 +00:00
break ;
}
* s = ' \0 ' ;
2006-03-06 01:41:09 +00:00
if ( s ! = apath2 )
strcat ( apath2 , " / " ) ;
2004-08-23 00:15:46 +00:00
r = FindFirstFile ( file , & fd ) ;
if ( r = = ( HANDLE ) - 1 )
return 1 ;
go = true ;
do
{
2004-12-05 11:40:15 +00:00
if ( * fd . cFileName = = ' . ' ) ; //don't ever find files with a name starting with '.'
2005-05-30 12:30:41 +00:00
else if ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //is a directory
2004-08-23 00:15:46 +00:00
{
2004-12-05 11:40:15 +00:00
if ( wildcmp ( match , fd . cFileName ) )
{
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s%s/ " , apath2 , fd . cFileName ) ;
2004-12-05 11:40:15 +00:00
go = func ( file , fd . nFileSizeLow , parm ) ;
}
2004-08-23 00:15:46 +00:00
}
else
{
2004-12-05 11:40:15 +00:00
if ( wildcmp ( match , fd . cFileName ) )
{
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s%s " , apath2 , fd . cFileName ) ;
2004-12-05 11:40:15 +00:00
go = func ( file , fd . nFileSizeLow , parm ) ;
}
2004-08-23 00:15:46 +00:00
}
}
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?
2008-11-09 22:29:28 +00:00
if ( ! VirtualProtect ( ( LPVOID ) startaddr , length , PAGE_EXECUTE_READWRITE , & flOldProtect ) )
2007-08-30 02:58:45 +00:00
{
char str [ 1024 ] ;
FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM ,
NULL ,
GetLastError ( ) ,
MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) ,
str ,
sizeof ( str ) ,
NULL ) ;
Sys_Error ( " Protection change failed! \n Error %d: %s \n " , GetLastError ( ) , str ) ;
}
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = =
Sys_Init
= = = = = = = = = = = = = = = =
*/
void Sys_Init ( void )
{
// LARGE_INTEGER PerformanceFreq;
// unsigned int lowpart, highpart;
OSVERSIONINFO vinfo ;
2004-12-25 02:06:27 +00:00
2009-03-07 05:05:54 +00:00
# ifndef SERVERONLY
2007-06-20 00:02:54 +00:00
Cvar_Register ( & sys_disableWinKeys , " System vars " ) ;
Cvar_Register ( & sys_disableTaskSwitch , " System vars " ) ;
2004-08-23 00:15:46 +00:00
# ifndef CLIENTONLY
2004-12-25 02:06:27 +00:00
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.
2004-08-23 00:15:46 +00:00
# endif
{
// allocate a named semaphore on the client so the
// front end can tell if it is alive
2005-07-28 15:22:15 +00:00
// mutex will fail if semephore already exists
2004-08-23 00:15:46 +00:00
qwclsemaphore = CreateMutex (
2010-12-07 12:23:56 +00:00
NULL , // Security attributes
0 , // owner
" qwcl " ) ; // Semaphore name
2004-08-23 00:15:46 +00:00
// if (!qwclsemaphore)
// Sys_Error ("QWCL is already running on this system");
CloseHandle ( qwclsemaphore ) ;
qwclsemaphore = CreateSemaphore (
2010-12-07 12:23:56 +00:00
NULL , // Security attributes
0 , // Initial count
1 , // Maximum count
" qwcl " ) ; // Semaphore name
2004-08-23 00:15:46 +00:00
}
# endif
2004-12-25 02:06:27 +00:00
2004-08-23 00:15:46 +00:00
2009-03-07 05:05:54 +00:00
# ifndef SERVERONLY
2004-08-23 00:15:46 +00:00
MaskExceptions ( ) ;
Sys_SetFPCW ( ) ;
2009-03-07 05:05:54 +00:00
# endif
2004-08-23 00:15:46 +00:00
#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 " ) ;
}
2010-12-07 12:23:56 +00:00
2004-08-23 00:15:46 +00:00
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];
2010-12-07 12:23:56 +00:00
// DWORD dummy;
2004-08-23 00:15:46 +00:00
va_start ( argptr , error ) ;
2006-03-06 01:41:09 +00:00
vsnprintf ( text , sizeof ( text ) , error , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
2009-03-07 05:05:54 +00:00
# ifndef SERVERONLY
2004-09-04 17:45:10 +00:00
SetHookState ( false ) ;
2004-08-23 00:15:46 +00:00
Host_Shutdown ( ) ;
2009-03-07 05:05:54 +00:00
# else
SV_Shutdown ( ) ;
# endif
2004-08-23 00:15:46 +00:00
MessageBox ( NULL , text , " Error " , 0 ) ;
# ifndef SERVERONLY
CloseHandle ( qwclsemaphore ) ;
2009-03-07 05:05:54 +00:00
SetHookState ( false ) ;
2004-08-23 00:15:46 +00:00
# endif
exit ( 1 ) ;
}
void VARGS Sys_Printf ( char * fmt , . . . )
{
va_list argptr ;
char text [ 1024 ] ;
DWORD dummy ;
2011-01-23 03:33:33 +00:00
if ( ! houtput & & ! debugout )
2004-08-23 00:15:46 +00:00
return ;
va_start ( argptr , fmt ) ;
2006-03-06 01:41:09 +00:00
vsnprintf ( text , sizeof ( text ) , fmt , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
2011-01-23 03:33:33 +00:00
# ifdef _DEBUG
if ( debugout )
OutputDebugString ( text ) ; //msvc debug output
# endif
if ( houtput )
WriteFile ( houtput , text , strlen ( text ) , & dummy , NULL ) ;
2004-08-23 00:15:46 +00:00
}
void Sys_Quit ( void )
{
2009-03-07 05:05:54 +00:00
# ifndef SERVERONLY
2004-09-04 17:45:10 +00:00
SetHookState ( false ) ;
2009-03-07 05:05:54 +00:00
Host_Shutdown ( ) ;
2004-08-23 00:15:46 +00:00
if ( tevent )
CloseHandle ( tevent ) ;
if ( qwclsemaphore )
CloseHandle ( qwclsemaphore ) ;
2004-09-04 17:45:10 +00:00
SetHookState ( false ) ;
2009-03-07 05:05:54 +00:00
# else
SV_Shutdown ( ) ;
# endif
2009-04-01 22:03:56 +00:00
# ifdef NPQTV
{
extern jmp_buf host_abort ;
longjmp ( host_abort , 1 ) ;
}
# else
2004-08-23 00:15:46 +00:00
exit ( 0 ) ;
2009-04-01 22:03:56 +00:00
# endif
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
# if 1
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_DoubleTime
= = = = = = = = = = = = = = = =
*/
double Sys_DoubleTime ( void )
{
static int first = 1 ;
2009-11-04 21:16:50 +00:00
static LARGE_INTEGER qpcfreq ;
2004-08-23 00:15:46 +00:00
LARGE_INTEGER PerformanceCount ;
2009-11-04 21:16:50 +00:00
static LONGLONG oldcall ;
static LONGLONG firsttime ;
LONGLONG diff ;
2004-08-23 00:15:46 +00:00
QueryPerformanceCounter ( & PerformanceCount ) ;
if ( first )
{
first = 0 ;
2009-11-04 21:16:50 +00:00
QueryPerformanceFrequency ( & qpcfreq ) ;
firsttime = PerformanceCount . QuadPart ;
diff = 0 ;
2004-08-23 00:15:46 +00:00
}
else
2009-11-04 21:16:50 +00:00
diff = PerformanceCount . QuadPart - oldcall ;
if ( diff > = 0 )
oldcall = PerformanceCount . QuadPart ;
return ( oldcall - firsttime ) / ( double ) qpcfreq . QuadPart ;
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
unsigned int Sys_Milliseconds ( void )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
return Sys_DoubleTime ( ) * 1000 ;
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
# else
2005-08-07 18:08:13 +00:00
unsigned int Sys_Milliseconds ( void )
2004-08-23 00:15:46 +00:00
{
static DWORD starttime ;
static qboolean first = true ;
DWORD now ;
// double t;
now = timeGetTime ( ) ;
if ( first ) {
first = false ;
starttime = now ;
return 0.0 ;
}
2005-08-07 18:08:13 +00:00
/*
2004-08-23 00:15:46 +00:00
if ( now < starttime ) // wrapped?
{
double r ;
2005-08-07 18:08:13 +00:00
r = ( now ) + ( LONG_MAX - starttime ) ;
2004-08-23 00:15:46 +00:00
starttime = now ;
return r ;
}
if ( now - starttime = = 0 )
return 0.0 ;
2005-08-07 18:08:13 +00:00
*/
return ( now - starttime ) ;
}
2004-08-23 00:15:46 +00:00
2005-08-07 18:08:13 +00:00
double Sys_DoubleTime ( void )
{
return Sys_Milliseconds ( ) / 1000.f ;
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
# endif
2004-08-23 00:15:46 +00:00
2006-02-01 22:36:12 +00:00
/////////////////////////////////////////////////////////////
//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 ( ) ;
2004-08-23 00:15:46 +00:00
2006-02-01 22:36:12 +00:00
glob = GlobalAlloc ( GMEM_MOVEABLE , strlen ( text ) + 1 ) ;
if ( glob = = NULL )
{
CloseClipboard ( ) ;
return ;
}
2004-08-23 00:15:46 +00:00
2006-02-01 22:36:12 +00:00
temp = GlobalLock ( glob ) ;
if ( temp ! = NULL )
{
strcpy ( temp , text ) ;
GlobalUnlock ( glob ) ;
SetClipboardData ( CF_TEXT , glob ) ;
}
else
GlobalFree ( glob ) ;
2004-08-23 00:15:46 +00:00
2006-02-01 22:36:12 +00:00
CloseClipboard ( ) ;
}
2004-08-23 00:15:46 +00:00
2006-02-01 22:36:12 +00:00
//end of clipboard
/////////////////////////////////////////////////////////////
2004-08-23 00:15:46 +00:00
/////////////////////////////////////////
//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 ;
2005-05-08 06:02:03 +00:00
if ( ! hinput )
2005-05-17 02:36:54 +00:00
return NULL ;
2005-05-08 06:02:03 +00:00
2004-08-23 00:15:46 +00:00
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 ' :
2010-12-07 12:23:56 +00:00
WriteFile ( houtput , " \r \n " , 2 , & dummy , NULL ) ;
2004-08-23 00:15:46 +00:00
if ( len )
{
text [ len ] = 0 ;
len = 0 ;
return text ;
}
break ;
case ' \b ' :
if ( len )
{
len - - ;
WriteFile ( houtput , " \b \b " , 3 , & dummy , NULL ) ;
}
break ;
default :
2010-12-07 12:23:56 +00:00
if ( ( ( ch = = ' V ' | | ch = = ' v ' ) & & ( recs [ 0 ] . Event . KeyEvent . dwControlKeyState &
( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED ) ) ) | | ( ( recs [ 0 ] . Event . KeyEvent . dwControlKeyState
2004-08-23 00:15:46 +00:00
& 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 > = ' ' )
{
2010-12-07 12:23:56 +00:00
WriteFile ( houtput , & ch , 1 , & dummy , NULL ) ;
2004-08-23 00:15:46 +00:00
text [ len ] = ch ;
len = ( len + 1 ) & 0xff ;
}
break ;
}
}
}
}
return NULL ;
}
BOOL WINAPI HandlerRoutine ( DWORD dwCtrlType )
{
switch ( dwCtrlType )
{
2010-12-07 12:23:56 +00:00
case CTRL_C_EVENT :
2004-08-23 00:15:46 +00:00
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 ;
2009-03-07 05:05:54 +00:00
2009-11-15 03:07:52 +00:00
# ifndef SERVERONLY
if ( qwclsemaphore )
{
CloseHandle ( qwclsemaphore ) ;
qwclsemaphore = NULL ;
}
# endif
2009-03-07 05:05:54 +00:00
//if we still have the splash screen, kill it
if ( hwnd_dialog )
DestroyWindow ( hwnd_dialog ) ;
hwnd_dialog = NULL ;
2004-08-23 00:15:46 +00:00
SetConsoleCtrlHandler ( HandlerRoutine , TRUE ) ;
2005-11-30 01:20:53 +00:00
SetConsoleTitle ( FULLENGINENAME " dedicated server " ) ;
2004-08-23 00:15:46 +00:00
hinput = GetStdHandle ( STD_INPUT_HANDLE ) ;
houtput = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
return true ;
}
void Sys_CloseTerminal ( void )
{
FreeConsole ( ) ;
2005-05-08 06:02:03 +00:00
hinput = NULL ;
houtput = NULL ;
2004-08-23 00:15:46 +00:00
}
//
////////////////////////////
void Sys_Sleep ( void )
{
}
void Sys_SendKeyEvents ( void )
{
MSG msg ;
2005-05-08 06:02:03 +00:00
if ( isDedicated )
2004-08-23 00:15:46 +00:00
{
2004-11-29 01:21:00 +00:00
# ifndef CLIENTONLY
2004-08-23 00:15:46 +00:00
SV_GetConsoleCommands ( ) ;
2004-11-29 01:21:00 +00:00
# endif
2004-08-23 00:15:46 +00:00
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 ();
2009-07-05 18:45:53 +00:00
// if (TranslateMessage (&msg))
// continue;
2004-08-23 00:15:46 +00:00
DispatchMessage ( & msg ) ;
}
}
void Sys_ServerActivity ( void )
{
2009-03-07 05:05:54 +00:00
# ifndef SERVERONLY
2009-04-18 23:48:35 +00:00
if ( GetActiveWindow ( ) ! = mainwindow )
FlashWindow ( mainwindow , true ) ;
2009-03-07 05:05:54 +00:00
# endif
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
WINDOWS CRAP
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
WinMain
= = = = = = = = = = = = = = = = = =
*/
void SleepUntilInput ( int time )
{
MsgWaitForMultipleObjects ( 1 , & tevent , FALSE , time , QS_ALLINPUT ) ;
}
2009-04-01 22:03:56 +00:00
qboolean Sys_Startup_CheckMem ( quakeparms_t * parms )
{
int t ;
MEMORYSTATUS lpBuffer ;
lpBuffer . dwLength = sizeof ( MEMORYSTATUS ) ;
GlobalMemoryStatus ( & lpBuffer ) ;
// 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 )
return false ;
return true ;
}
# ifdef NPQTV
static quakeparms_t parms ;
double lastlooptime ;
qboolean NPQTV_Sys_Startup ( int argc , char * argv [ ] )
{
if ( ! host_initialized )
{
TL_InitLanguages ( ) ;
parms . argc = argc ;
parms . argv = argv ;
parms . basedir = argv [ 0 ] ;
COM_InitArgv ( parms . argc , parms . argv ) ;
if ( ! Sys_Startup_CheckMem ( & parms ) )
return false ;
Host_Init ( & parms ) ;
}
lastlooptime = Sys_DoubleTime ( ) ;
return true ;
}
void NPQTV_Sys_MainLoop ( void )
{
double duratrion , newtime ;
if ( isDedicated )
{
# ifndef CLIENTONLY
NET_Sleep ( 50 , false ) ;
// find time passed since last cycle
newtime = Sys_DoubleTime ( ) ;
duratrion = newtime - lastlooptime ;
lastlooptime = newtime ;
2010-12-07 12:23:56 +00:00
2009-04-01 22:03:56 +00:00
SV_Frame ( ) ;
# else
Sys_Error ( " wut? " ) ;
# endif
}
else
{
# ifndef SERVERONLY
newtime = Sys_DoubleTime ( ) ;
duratrion = newtime - lastlooptime ;
Host_Frame ( duratrion ) ;
lastlooptime = newtime ;
2009-11-04 21:16:50 +00:00
SetHookState ( sys_disableWinKeys . ival ) ;
2009-04-01 22:03:56 +00:00
// Sleep(0);
# else
Sys_Error ( " wut? " ) ;
# endif
}
}
void NPQTV_Sys_Shutdown ( void )
{
//disconnect server/client/etc
CL_Disconnect_f ( ) ;
R_ShutdownRenderer ( ) ;
Host_Shutdown ( ) ;
}
2010-12-18 17:02:47 +00:00
void Sys_RecentServer ( char * command , char * target , char * title , char * desc )
{
}
2009-04-01 22:03:56 +00:00
# else
2010-12-05 02:46:07 +00:00
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = =
WinMain
= = = = = = = = = = = = = = = = = =
*/
HINSTANCE global_hInstance ;
int global_nCmdShow ;
char * argv [ MAX_NUM_ARGVS ] ;
static char exename [ 256 ] ;
HWND hwnd_dialog ;
2010-12-05 02:46:07 +00:00
# define COBJMACROS
2010-12-07 12:23:56 +00:00
# ifndef MINGW
2010-12-23 08:53:23 +00:00
# if _MSC_VER > 1200
2010-12-07 12:23:56 +00:00
# include <shobjidl.h>
# endif
2010-12-23 08:53:23 +00:00
# endif
# if _MSC_VER > 1200
# include <shlguid.h>
# endif
2010-12-07 12:23:56 +00:00
# include <shlobj.h>
2010-12-05 02:46:07 +00:00
//#include <Propsys.h>
2010-12-10 05:01:25 +00:00
# ifdef _MSC_VER
# include "ntverp.h"
# endif
2010-12-07 12:23:56 +00:00
# ifndef SHARD_APPIDINFOLINK
2010-12-10 05:01:25 +00:00
// SDK version 7600 = v7.0a & v7.1
# if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600
2010-12-05 02:46:07 +00:00
typedef struct SHARDAPPIDINFOLINK {
IShellLinkW * psl ;
PCWSTR pszAppID ;
} SHARDAPPIDINFOLINK ;
2010-12-10 05:01:25 +00:00
# endif
2010-12-05 02:46:07 +00:00
# define SHARD_APPIDINFOLINK 0x00000007
2010-12-10 05:01:25 +00:00
# if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600
2010-12-05 02:46:07 +00:00
typedef struct {
GUID fmtid ;
DWORD pid ;
} PROPERTYKEY ;
2010-12-10 05:01:25 +00:00
# endif
2010-12-05 02:46:07 +00:00
typedef struct IPropertyStore IPropertyStore ;
;
2010-12-07 12:23:56 +00:00
# ifndef MINGW
2010-12-10 05:01:25 +00:00
# if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600
2010-12-05 02:46:07 +00:00
typedef struct IPropertyStore
{
CONST_VTBL struct
{
/*IUnknown*/
2010-12-07 12:23:56 +00:00
HRESULT ( STDMETHODCALLTYPE * QueryInterface ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ,
REFIID riid ,
void * * ppvObject ) ;
2010-12-07 12:23:56 +00:00
ULONG ( STDMETHODCALLTYPE * AddRef ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ) ;
2010-12-07 12:23:56 +00:00
ULONG ( STDMETHODCALLTYPE * Release ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ) ;
/*property store stuff*/
2010-12-07 12:23:56 +00:00
HRESULT ( STDMETHODCALLTYPE * GetCount ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ,
ULONG * count ) ;
2010-12-07 12:23:56 +00:00
HRESULT ( STDMETHODCALLTYPE * GetAt ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ,
DWORD prop ,
PROPERTYKEY * key ) ;
2010-12-07 12:23:56 +00:00
HRESULT ( STDMETHODCALLTYPE * GetValue ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ,
PROPERTYKEY * key ,
PROPVARIANT * val ) ;
2010-12-07 12:23:56 +00:00
HRESULT ( STDMETHODCALLTYPE * SetValue ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ,
PROPERTYKEY * key ,
PROPVARIANT * val ) ;
2010-12-07 12:23:56 +00:00
HRESULT ( STDMETHODCALLTYPE * Commit ) (
2010-12-05 02:46:07 +00:00
IPropertyStore * This ) ;
} * lpVtbl ;
} IPropertyStore ;
2010-12-07 12:23:56 +00:00
# endif
2010-12-10 05:01:25 +00:00
# endif
2010-12-05 02:46:07 +00:00
static const IID IID_IPropertyStore = { 0x886d8eeb , 0x8cf2 , 0x4446 , { 0x8d , 0x02 , 0xcd , 0xba , 0x1d , 0xbd , 0xcf , 0x99 } } ;
# endif
2010-12-23 08:53:23 +00:00
# if _MSC_VER > 1200
2010-12-05 02:46:07 +00:00
# define WIN7_APPNAME L"FTEQuake"
void Sys_RecentServer ( char * command , char * target , char * title , char * desc )
{
HRESULT hr ;
IShellLinkW * link ;
IPropertyStore * prop_store ;
SHARDAPPIDINFOLINK appinfo ;
WCHAR buf [ 1024 ] ;
char tmp [ 1024 ] , * s ;
// Get a pointer to the IShellLink interface.
hr = CoCreateInstance ( & CLSID_ShellLink , NULL , CLSCTX_INPROC_SERVER , & IID_IShellLinkW , & link ) ;
if ( FAILED ( hr ) )
return ;
swprintf ( buf , sizeof ( buf ) , L " %S " , exename ) ;
IShellLinkW_SetPath ( link , buf ) ; /*program to run*/
Q_strncpyz ( tmp , com_quakedir , sizeof ( tmp ) ) ;
/*normalize the gamedir, so we don't end up with the same thing multiple times*/
for ( s = tmp ; * s ; s + + )
{
if ( * s = = ' \\ ' )
* s = ' / ' ;
else
* s = tolower ( * s ) ;
}
swprintf ( buf , sizeof ( buf ) , L " %S \" %S \" -basedir \" %S \" " , command , target , tmp ) ;
IShellLinkW_SetArguments ( link , buf ) ; /*args*/
swprintf ( buf , sizeof ( buf ) , L " %S " , desc ) ;
IShellLinkW_SetDescription ( link , buf ) ; /*tooltip*/
2010-12-07 12:23:56 +00:00
2010-12-05 02:46:07 +00:00
hr = IShellLinkW_QueryInterface ( link , & IID_IPropertyStore , & prop_store ) ;
2010-12-07 12:23:56 +00:00
# ifndef MINGW
2010-12-05 02:46:07 +00:00
if ( SUCCEEDED ( hr ) )
{
PROPVARIANT pv ;
PROPERTYKEY PKEY_Title ;
pv . vt = VT_LPSTR ;
pv . pszVal = title ; /*item text*/
CLSIDFromString ( L " {F29F85E0-4FF9-1068-AB91-08002B27B3D9} " , & ( PKEY_Title . fmtid ) ) ;
PKEY_Title . pid = 2 ;
hr = prop_store - > lpVtbl - > SetValue ( prop_store , & PKEY_Title , & pv ) ;
hr = prop_store - > lpVtbl - > Commit ( prop_store ) ;
prop_store - > lpVtbl - > Release ( prop_store ) ;
}
2010-12-07 12:23:56 +00:00
# endif
2010-12-05 02:46:07 +00:00
appinfo . pszAppID = WIN7_APPNAME ;
appinfo . psl = link ;
SHAddToRecentDocs ( SHARD_APPIDINFOLINK , & appinfo ) ;
IShellLinkW_Release ( link ) ;
}
void Win7_Init ( void )
{
HANDLE h ;
HRESULT ( WINAPI * pSetCurrentProcessExplicitAppUserModelID ) ( PCWSTR AppID ) ;
h = LoadLibrary ( " shell32.dll " ) ;
if ( h )
{
pSetCurrentProcessExplicitAppUserModelID = ( void * ) GetProcAddress ( h , " SetCurrentProcessExplicitAppUserModelID " ) ;
if ( pSetCurrentProcessExplicitAppUserModelID )
pSetCurrentProcessExplicitAppUserModelID ( WIN7_APPNAME ) ;
}
}
2010-12-23 08:53:23 +00:00
# endif
2010-12-05 02:46:07 +00:00
2005-10-01 03:09:17 +00:00
/*
2005-09-13 07:10:18 +00:00
# ifdef _MSC_VER
2005-09-08 22:52:46 +00:00
# include <signal.h>
2005-09-13 07:10:18 +00:00
void VARGS Signal_Error_Handler ( int i )
2005-09-08 22:52:46 +00:00
{
int * basepointer ;
__asm { mov basepointer , ebp } ;
2005-10-01 03:09:17 +00:00
Sys_Error ( " Received signal, offset was 0x%8x " , basepointer [ 73 ] ) ;
2005-09-08 22:52:46 +00:00
}
2005-09-13 07:10:18 +00:00
# endif
2005-10-01 03:09:17 +00:00
*/
2005-09-08 22:52:46 +00:00
2004-08-23 00:15:46 +00:00
int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nCmdShow )
{
// MSG msg;
quakeparms_t parms ;
double time , oldtime , newtime ;
2007-03-28 13:27:35 +00:00
char cwd [ 1024 ] ;
2009-04-01 22:03:56 +00:00
const char * qtvfile = NULL ;
2010-12-07 12:23:56 +00:00
2004-12-25 02:06:27 +00:00
/* previous instances do not exist in Win32 */
2004-08-23 00:15:46 +00:00
if ( hPrevInstance )
2005-09-08 22:52:46 +00:00
return 0 ;
2009-11-04 21:16:50 +00:00
2010-12-07 12:23:56 +00:00
# ifndef MINGW
2010-12-23 08:53:23 +00:00
# if _MSC_VER > 1200
2010-12-07 12:23:56 +00:00
Win7_Init ( ) ;
# endif
2010-12-23 08:53:23 +00:00
# endif
2010-12-05 02:46:07 +00:00
2009-11-04 21:16:50 +00:00
# ifdef _MSC_VER
# if _M_IX86_FP >= 1
{
int idedx ;
char cpuname [ 13 ] ;
/*I'm not going to check to make sure cpuid works.*/
__asm
{
xor eax , eax
cpuid
mov dword ptr [ cpuname + 0 ] , ebx
mov dword ptr [ cpuname + 4 ] , edx
mov dword ptr [ cpuname + 8 ] , ecx
}
cpuname [ 12 ] = 0 ;
__asm
{
mov eax , 0x1
cpuid
mov idedx , edx
}
# if _M_IX86_FP >= 2
if ( ! ( idedx & ( 1 < < 26 ) ) )
MessageBox ( NULL , " This is an SSE2 optimised build, and your cpu doesn't seem to support it " , DISTRIBUTION , 0 ) ;
else
# endif
if ( ! ( idedx & ( 1 < < 25 ) ) )
MessageBox ( NULL , " This is an SSE optimised build, and your cpu doesn't seem to support it " , DISTRIBUTION , 0 ) ;
}
# endif
# endif
# ifdef CATCHCRASH
__try
# endif
{
2005-10-01 03:09:17 +00:00
/*
2005-09-13 07:10:18 +00:00
# ifndef _DEBUG
# ifdef _MSC_VER
2009-11-04 21:16:50 +00:00
signal ( SIGFPE , Signal_Error_Handler ) ;
signal ( SIGILL , Signal_Error_Handler ) ;
signal ( SIGSEGV , Signal_Error_Handler ) ;
2005-09-13 07:10:18 +00:00
# endif
# endif
2005-10-01 03:09:17 +00:00
*/
2009-11-04 21:16:50 +00:00
global_hInstance = hInstance ;
global_nCmdShow = nCmdShow ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
parms . argc = 1 ;
argv [ 0 ] = exename ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
while ( * lpCmdLine & & ( parms . argc < MAX_NUM_ARGVS ) )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
while ( * lpCmdLine & & ( ( * lpCmdLine < = 32 ) | | ( * lpCmdLine > 126 ) ) )
2004-08-23 00:15:46 +00:00
lpCmdLine + + ;
2009-11-04 21:16:50 +00:00
if ( * lpCmdLine )
2006-09-17 00:59:22 +00:00
{
2009-11-04 21:16:50 +00:00
if ( * lpCmdLine = = ' \" ' )
{
lpCmdLine + + ;
2006-09-17 00:59:22 +00:00
2009-11-04 21:16:50 +00:00
argv [ parms . argc ] = lpCmdLine ;
parms . argc + + ;
2006-09-17 00:59:22 +00:00
2009-11-04 21:16:50 +00:00
while ( * lpCmdLine & & * lpCmdLine ! = ' \" ' )
lpCmdLine + + ;
}
else
{
argv [ parms . argc ] = lpCmdLine ;
parms . argc + + ;
2006-09-17 00:59:22 +00:00
2009-11-04 21:16:50 +00:00
while ( * lpCmdLine & & ( ( * lpCmdLine > 32 ) & & ( * lpCmdLine < = 126 ) ) )
lpCmdLine + + ;
}
if ( * lpCmdLine )
{
* lpCmdLine = 0 ;
lpCmdLine + + ;
}
2004-08-23 00:15:46 +00:00
}
}
2009-11-04 21:16:50 +00:00
GetModuleFileName ( NULL , cwd , sizeof ( cwd ) - 1 ) ;
strcpy ( exename , COM_SkipPath ( cwd ) ) ;
parms . argv = argv ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
COM_InitArgv ( parms . argc , parms . argv ) ;
2006-02-27 00:42:25 +00:00
2009-11-04 21:16:50 +00:00
if ( COM_CheckParm ( " --version " ) | | COM_CheckParm ( " -v " ) )
2006-09-17 00:59:22 +00:00
{
2010-08-01 22:54:14 +00:00
printf ( " version " DISTRIBUTION " " __TIME__ " " __DATE__ " \n " ) ;
2009-11-04 21:16:50 +00:00
return true ;
}
2011-01-23 03:33:33 +00:00
if ( COM_CheckParm ( " -outputdebugstring " ) )
debugout = true ;
2006-09-17 00:59:22 +00:00
2009-11-04 21:16:50 +00:00
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 ;
2006-09-17 00:59:22 +00:00
2009-11-04 21:16:50 +00:00
qtvfile = parms . argv [ 1 ] ;
2006-09-17 00:59:22 +00:00
2009-11-04 21:16:50 +00:00
GetModuleFileName ( NULL , cwd , sizeof ( cwd ) - 1 ) ;
for ( e = cwd + strlen ( cwd ) - 1 ; e > = cwd ; e - - )
2006-09-17 00:59:22 +00:00
{
2009-11-04 21:16:50 +00:00
if ( * e = = ' / ' | | * e = = ' \\ ' )
{
* e = 0 ;
break ;
}
2006-09-17 00:59:22 +00:00
}
2009-11-04 21:16:50 +00:00
}
2006-09-17 00:59:22 +00:00
}
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
TL_InitLanguages ( ) ;
//tprints are now allowed
2006-02-27 00:42:25 +00:00
2009-11-04 21:16:50 +00:00
parms . basedir = cwd ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
parms . argc = com_argc ;
parms . argv = com_argv ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
# if !defined(CLIENTONLY) && !defined(SERVERONLY)
if ( COM_CheckParm ( " -dedicated " ) )
isDedicated = true ;
# endif
2009-03-07 05:05:54 +00:00
2009-11-04 21:16:50 +00:00
if ( isDedicated )
{
# if !defined(CLIENTONLY)
hwnd_dialog = NULL ;
2010-12-07 12:23:56 +00:00
2009-11-04 21:16:50 +00:00
if ( ! Sys_InitTerminal ( ) )
Sys_Error ( " Couldn't allocate dedicated server console " ) ;
# endif
}
# ifdef IDD_DIALOG1
else
hwnd_dialog = CreateDialog ( hInstance , MAKEINTRESOURCE ( IDD_DIALOG1 ) , NULL , NULL ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
if ( hwnd_dialog )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
RECT rect ;
if ( GetWindowRect ( hwnd_dialog , & rect ) )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
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 ) ;
}
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
ShowWindow ( hwnd_dialog , SW_SHOWDEFAULT ) ;
UpdateWindow ( hwnd_dialog ) ;
SetForegroundWindow ( hwnd_dialog ) ;
}
# endif
2009-04-01 22:03:56 +00:00
2009-11-04 21:16:50 +00:00
if ( ! Sys_Startup_CheckMem ( & parms ) )
Sys_Error ( " Not enough memory free; check disk space \n " ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
# ifndef CLIENTONLY
if ( isDedicated ) //compleate denial to switch to anything else - many of the client structures are not initialized.
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
SV_Init ( & parms ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
SV_Frame ( ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
while ( 1 )
{
if ( ! isDedicated )
Sys_Error ( " Dedicated was cleared " ) ;
2010-12-07 12:23:56 +00:00
NET_Sleep ( 100 , false ) ;
2009-11-04 21:16:50 +00:00
SV_Frame ( ) ;
}
return TRUE ;
}
# endif
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
tevent = CreateEvent ( NULL , FALSE , FALSE , NULL ) ;
if ( ! tevent )
Sys_Error ( " Couldn't create event " ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
# ifdef SERVERONLY
Sys_Printf ( " SV_Init \n " ) ;
SV_Init ( & parms ) ;
# else
Sys_Printf ( " Host_Init \n " ) ;
Host_Init ( & parms ) ;
# endif
2006-09-17 00:59:22 +00:00
2009-11-04 21:16:50 +00:00
oldtime = Sys_DoubleTime ( ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
if ( qtvfile )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
char * ext = COM_FileExtension ( qtvfile ) ;
if ( ! strcmp ( ext , " qwd " ) | | ! strcmp ( ext , " dem " ) | | ! strcmp ( ext , " mvd " ) )
Cbuf_AddText ( va ( " playdemo \" #%s \" \n " , qtvfile ) , RESTRICT_LOCAL ) ;
else
Cbuf_AddText ( va ( " qtvplay \" #%s \" \n " , qtvfile ) , RESTRICT_LOCAL ) ;
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
//client console should now be initialized.
2010-12-07 12:23:56 +00:00
# ifndef MINGW
2010-12-23 08:53:23 +00:00
# if _MSC_VER > 1200
2010-12-05 02:46:07 +00:00
switch ( M_GameType ( ) )
{
case MGT_QUAKE1 :
Sys_RecentServer ( " +menu_servers " , " " , " Server List " , " Pick a server to play on " ) ;
Sys_RecentServer ( " +map start " , " " , " Start New Game (Quake) " , " Begin a new game " ) ;
break ;
case MGT_QUAKE2 :
Sys_RecentServer ( " +menu_servers " , " " , " Server List " , " Pick a server to play on " ) ;
Sys_RecentServer ( " +map unit1 " , " " , " Start New Game (Quake2) " , " Begin a new game " ) ;
break ;
case MGT_HEXEN2 :
Sys_RecentServer ( " +menu_servers " , " " , " Server List " , " Pick a server to play on " ) ;
Sys_RecentServer ( " +map demo1 " , " " , " Start New Game (Hexen2) " , " Begin a new game " ) ;
break ;
}
2010-12-07 12:23:56 +00:00
# endif
2010-12-23 08:53:23 +00:00
# endif
2010-12-05 02:46:07 +00:00
2009-11-04 21:16:50 +00:00
/* main window message loop */
while ( 1 )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
if ( isDedicated )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
# ifndef CLIENTONLY
NET_Sleep ( 50 , false ) ;
// find time passed since last cycle
newtime = Sys_DoubleTime ( ) ;
time = newtime - oldtime ;
oldtime = newtime ;
2010-12-07 12:23:56 +00:00
2009-11-04 21:16:50 +00:00
SV_Frame ( ) ;
# else
Sys_Error ( " wut? " ) ;
# endif
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
else
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
# ifndef SERVERONLY
2010-11-22 02:03:28 +00:00
int sleeptime ;
2009-11-04 21:16:50 +00:00
newtime = Sys_DoubleTime ( ) ;
time = newtime - oldtime ;
2010-11-22 02:03:28 +00:00
sleeptime = Host_Frame ( time ) ;
2009-11-04 21:16:50 +00:00
oldtime = newtime ;
SetHookState ( sys_disableWinKeys . ival ) ;
2010-11-22 02:03:28 +00:00
/*sleep if its not yet time for a frame*/
2010-12-05 02:46:07 +00:00
//if (sleeptime > 0)
// Sleep(sleeptime);
2009-11-04 21:16:50 +00:00
# else
Sys_Error ( " wut? " ) ;
# endif
2004-08-23 00:15:46 +00:00
}
}
}
2009-11-04 21:16:50 +00:00
# ifdef CATCHCRASH
__except ( CrashExceptionHandler ( GetExceptionCode ( ) , GetExceptionInformation ( ) ) )
{
return 1 ;
}
# endif
2004-08-23 00:15:46 +00:00
/* return success of application */
return TRUE ;
}
2009-03-07 05:05:54 +00:00
int __cdecl main ( void )
{
2010-08-01 22:54:14 +00:00
char * cmdline ;
2009-03-07 05:05:54 +00:00
FreeConsole ( ) ;
2010-08-01 22:54:14 +00:00
cmdline = GetCommandLine ( ) ;
2010-08-01 23:35:05 +00:00
while ( * cmdline & & * cmdline = = ' ' )
2010-08-01 22:54:14 +00:00
cmdline + + ;
if ( * cmdline = = ' \" ' )
{
cmdline + + ;
2010-08-01 23:35:05 +00:00
while ( * cmdline & & * cmdline ! = ' \" ' )
2010-08-01 22:54:14 +00:00
cmdline + + ;
if ( * cmdline = = ' \" ' )
cmdline + + ;
}
else
{
2010-08-01 23:35:05 +00:00
while ( * cmdline & & * cmdline ! = ' ' )
2010-08-01 22:54:14 +00:00
cmdline + + ;
}
return WinMain ( GetModuleHandle ( NULL ) , NULL , cmdline , SW_NORMAL ) ;
2009-03-07 05:05:54 +00:00
}
2009-04-01 22:03:56 +00:00
# endif
2009-03-07 05:05:54 +00:00
2006-04-15 03:31:23 +00:00
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 ;
2004-08-23 00:15:46 +00:00
2006-04-15 03:31:23 +00:00
* refreshrate = rate ;
2004-08-23 00:15:46 +00:00
2006-04-15 03:31:23 +00:00
ReleaseDC ( NULL , hdc ) ;
return true ;
}
2004-08-23 00:15:46 +00:00
2009-03-07 04:37:24 +00:00
# if !id386 //these couldn't be found... (it is a masm thing, right?)
2004-08-23 00:15:46 +00:00
void Sys_HighFPPrecision ( void )
{
}
void Sys_LowFPPrecision ( void )
{
}
2009-07-16 22:06:59 +00:00
void VARGS Sys_SetFPCW ( void )
2004-08-23 00:15:46 +00:00
{
}
2009-07-16 22:06:59 +00:00
void VARGS MaskExceptions ( void )
2004-08-23 00:15:46 +00:00
{
}
# endif
2007-12-30 00:09:34 +00:00
# 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 ) ;
2010-12-07 12:23:56 +00:00
tw . func ( tw . args ) ;
2007-12-30 00:09:34 +00:00
2007-12-30 20:05:49 +00:00
# ifndef WIN32CRTDLL
_endthreadex ( 0 ) ;
# endif
2007-12-30 00:09:34 +00:00
return 0 ;
}
2007-12-30 20:05:49 +00:00
void * Sys_CreateThread ( int ( * func ) ( void * ) , void * args , int stacksize )
2007-12-30 00:09:34 +00:00
{
threadwrap_t * tw = ( threadwrap_t * ) malloc ( sizeof ( threadwrap_t ) ) ;
2007-12-30 20:05:49 +00:00
HANDLE handle ;
2010-12-07 12:23:56 +00:00
2007-12-30 20:05:49 +00:00
if ( ! tw )
return NULL ;
2007-12-30 00:09:34 +00:00
2010-03-14 14:35:56 +00:00
if ( stacksize )
stacksize + = 128 ; // wrapper overhead, also prevent default stack size
2007-12-30 00:09:34 +00:00
tw - > func = func ;
tw - > args = args ;
2007-12-30 20:05:49 +00:00
# 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 )
2007-12-30 00:09:34 +00:00
{
free ( tw ) ;
2007-12-30 20:05:49 +00:00
return NULL ;
2007-12-30 00:09:34 +00:00
}
2007-12-30 20:05:49 +00:00
return ( void * ) handle ;
}
void Sys_WaitOnThread ( void * thread )
2010-12-07 12:23:56 +00:00
{
2010-03-14 14:35:56 +00:00
while ( WaitForSingleObject ( ( HANDLE ) thread , 10 ) = = WAIT_TIMEOUT )
{
/*keep responding to window messages*/
MSG msg ;
while ( PeekMessage ( & msg , NULL , 0 , 0 , PM_REMOVE ) )
DispatchMessage ( & msg ) ;
}
2007-12-30 20:05:49 +00:00
CloseHandle ( ( HANDLE ) thread ) ;
2007-12-30 00:09:34 +00:00
}
/* Mutex calls */
2008-06-01 05:42:23 +00:00
void * Sys_CreateMutex ( void )
2007-12-30 00:09:34 +00:00
{
return ( void * ) CreateMutex ( NULL , 0 , NULL ) ;
}
qboolean Sys_TryLockMutex ( void * mutex )
{
return WaitForSingleObject ( mutex , 0 ) = = WAIT_OBJECT_0 ;
}
qboolean Sys_LockMutex ( void * mutex )
{
2010-03-14 14:35:56 +00:00
# ifdef _DEBUG
/*in debug builds, trigger a debug break if we sit on a mutex for longer than 20 secs*/
if ( WaitForSingleObject ( mutex , 20000 ) = = WAIT_OBJECT_0 )
return true ;
OutputDebugString ( " Warning: Suspected mutex deadlock \n " ) ;
DebugBreak ( ) ;
# endif
2007-12-30 00:09:34 +00:00
return WaitForSingleObject ( mutex , INFINITE ) = = WAIT_OBJECT_0 ;
}
qboolean Sys_UnlockMutex ( void * mutex )
{
return ! ! ReleaseMutex ( mutex ) ;
}
void Sys_DestroyMutex ( void * mutex )
{
CloseHandle ( mutex ) ;
}
2008-06-01 05:42:23 +00:00
/* Conditional wait calls */
/*
TODO : Windows Vista has condition variables as documented here :
http : //msdn.microsoft.com/en-us/library/ms682052(VS.85).aspx
Note this uses Slim Reader / Writer locks ( Vista + exclusive )
or critical sections .
The condition variable implementation is based on the libSDL implementation .
This code could probably be made more efficient with the use of events or
different mechanisms but for now the main concern is a correct and
complete solution .
*/
typedef struct condvar_s
{
int waiting ;
int signals ;
CRITICAL_SECTION countlock ;
CRITICAL_SECTION mainlock ;
HANDLE wait_sem ;
HANDLE wait_done ;
} condvar_t ;
2010-12-07 12:23:56 +00:00
void * Sys_CreateConditional ( void )
{
2008-06-01 05:42:23 +00:00
condvar_t * cv ;
cv = ( condvar_t * ) malloc ( sizeof ( condvar_t ) ) ;
if ( ! cv )
return NULL ;
cv - > waiting = 0 ;
cv - > signals = 0 ;
InitializeCriticalSection ( & cv - > mainlock ) ;
InitializeCriticalSection ( & cv - > countlock ) ;
cv - > wait_sem = CreateSemaphore ( NULL , 0 , 0x7fffffff , NULL ) ;
cv - > wait_done = CreateSemaphore ( NULL , 0 , 0x7fffffff , NULL ) ;
if ( cv - > wait_sem & & cv - > wait_done )
return ( void * ) cv ;
// something failed so deallocate everything
if ( cv - > wait_done )
CloseHandle ( cv - > wait_done ) ;
if ( cv - > wait_sem )
CloseHandle ( cv - > wait_sem ) ;
DeleteCriticalSection ( & cv - > countlock ) ;
DeleteCriticalSection ( & cv - > mainlock ) ;
free ( cv ) ;
return NULL ;
}
2010-12-07 12:23:56 +00:00
qboolean Sys_LockConditional ( void * condv )
{
2008-06-01 05:42:23 +00:00
EnterCriticalSection ( & ( ( condvar_t * ) condv ) - > mainlock ) ;
2010-12-07 12:23:56 +00:00
return true ;
2008-06-01 05:42:23 +00:00
}
2010-12-07 12:23:56 +00:00
qboolean Sys_UnlockConditional ( void * condv )
{
2008-06-01 05:42:23 +00:00
LeaveCriticalSection ( & ( ( condvar_t * ) condv ) - > mainlock ) ;
2010-12-07 12:23:56 +00:00
return true ;
2008-06-01 05:42:23 +00:00
}
qboolean Sys_ConditionWait ( void * condv )
{
condvar_t * cv = ( condvar_t * ) condv ;
qboolean success ;
// increase count for non-signaled waiting threads
EnterCriticalSection ( & cv - > countlock ) ;
cv - > waiting + + ;
LeaveCriticalSection ( & cv - > countlock ) ;
LeaveCriticalSection ( & cv - > mainlock ) ; // unlock as per condition variable definition
// wait on a signal
success = ( WaitForSingleObject ( cv - > wait_sem , INFINITE ) ! = WAIT_FAILED ) ;
// update waiting count and alert signaling thread that we're done to avoid the deadlock condition
EnterCriticalSection ( & cv - > countlock ) ;
2010-12-07 12:23:56 +00:00
if ( cv - > signals > 0 )
2008-06-01 05:42:23 +00:00
{
ReleaseSemaphore ( cv - > wait_done , cv - > signals , NULL ) ;
cv - > signals = 0 ;
}
cv - > waiting - - ;
LeaveCriticalSection ( & cv - > countlock ) ;
EnterCriticalSection ( & cv - > mainlock ) ; // lock as per condition variable definition
return success ;
}
2010-12-07 12:23:56 +00:00
qboolean Sys_ConditionSignal ( void * condv )
2008-06-01 05:42:23 +00:00
{
condvar_t * cv = ( condvar_t * ) condv ;
// if there are non-signaled waiting threads, we signal one and wait on the response
EnterCriticalSection ( & cv - > countlock ) ;
if ( cv - > waiting > cv - > signals )
{
cv - > signals + + ;
ReleaseSemaphore ( cv - > wait_sem , 1 , NULL ) ;
LeaveCriticalSection ( & cv - > countlock ) ;
WaitForSingleObject ( cv - > wait_done , INFINITE ) ;
}
else
LeaveCriticalSection ( & cv - > countlock ) ;
return true ;
}
2010-12-07 12:23:56 +00:00
qboolean Sys_ConditionBroadcast ( void * condv )
2008-06-01 05:42:23 +00:00
{
condvar_t * cv = ( condvar_t * ) condv ;
// if there are non-signaled waiting threads, we signal all of them and wait on all the responses back
EnterCriticalSection ( & cv - > countlock ) ;
2010-12-07 12:23:56 +00:00
if ( cv - > waiting > cv - > signals )
2008-06-01 05:42:23 +00:00
{
int i , num_waiting ;
num_waiting = ( cv - > waiting - cv - > signals ) ;
cv - > signals = cv - > waiting ;
2010-12-07 12:23:56 +00:00
2008-06-01 05:42:23 +00:00
ReleaseSemaphore ( cv - > wait_sem , num_waiting , NULL ) ;
LeaveCriticalSection ( & cv - > countlock ) ;
// there's no call to wait for the same object multiple times so we need to loop through
// and burn up the semaphore count
2010-12-07 12:23:56 +00:00
for ( i = 0 ; i < num_waiting ; i + + )
2008-06-01 05:42:23 +00:00
WaitForSingleObject ( cv - > wait_done , INFINITE ) ;
}
else
LeaveCriticalSection ( & cv - > countlock ) ;
return true ;
}
void Sys_DestroyConditional ( void * condv )
{
condvar_t * cv = ( condvar_t * ) condv ;
CloseHandle ( cv - > wait_done ) ;
CloseHandle ( cv - > wait_sem ) ;
DeleteCriticalSection ( & cv - > countlock ) ;
DeleteCriticalSection ( & cv - > mainlock ) ;
free ( cv ) ;
}
2009-07-25 11:05:06 +00:00
# endif