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>
2012-05-09 15:30:53 +00:00
//#define RESTARTTEST
2007-12-30 20:05:49 +00:00
# ifdef MULTITHREAD
# include <process.h>
# endif
2004-12-13 00:44:05 +00:00
2012-07-05 19:42:36 +00:00
# ifdef GLQUAKE
# define PRINTGLARRAYS
# endif
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 ;
2011-10-27 15:46:36 +00:00
unsigned int sys_parentleft ; //valid if sys_parentwindow is set
unsigned int sys_parenttop ;
2009-04-06 00:34:32 +00:00
unsigned int sys_parentwidth ; //valid if sys_parentwindow is set
unsigned int sys_parentheight ;
2004-12-13 00:44:05 +00:00
2012-07-05 19:42:36 +00:00
extern int fs_switchgame ;
2012-05-09 15:30:53 +00:00
# ifdef RESTARTTEST
jmp_buf restart_jmpbuf ;
# endif
2011-07-30 14:14:56 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_RandomBytes
= = = = = = = = = = = = = = = =
*/
# include <wincrypt.h>
qboolean Sys_RandomBytes ( qbyte * string , int len )
{
HCRYPTPROV prov ;
if ( ! CryptAcquireContext ( & prov , NULL , NULL , PROV_RSA_FULL , CRYPT_VERIFYCONTEXT ) )
{
return false ;
}
if ( ! CryptGenRandom ( prov , len , ( BYTE * ) string ) )
{
CryptReleaseContext ( prov , 0 ) ;
return false ;
}
CryptReleaseContext ( prov , 0 ) ;
return true ;
}
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 ;
static HANDLE hinput , houtput ;
HANDLE qwclsemaphore ;
static HANDLE tevent ;
void Sys_InitFloatTime ( 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
) ;
2012-07-05 19:42:36 +00:00
# ifdef PRINTGLARRAYS
2012-04-24 07:59:11 +00:00
# include "glquake.h"
# define GL_ARRAY_BUFFER 0x8892
# define GL_ELEMENT_ARRAY_BUFFER 0x8893
# define GL_ARRAY_BUFFER_BINDING 0x8894
# define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
# define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
# define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
# define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
# define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
# define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
# define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
# define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
# define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
# define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
# endif
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 ) ;
2012-07-05 19:42:36 +00:00
# ifdef PRINTGLARRAYS
2012-04-24 07:59:11 +00:00
int rval ;
void * ptr ;
int i ;
void ( APIENTRY * qglGetVertexAttribiv ) ( GLuint index , GLenum pname , GLint * params ) ;
void ( APIENTRY * qglGetVertexAttribPointerv ) ( GLuint index , GLenum pname , GLvoid * * pointer ) ;
qglGetVertexAttribiv = ( void * ) wglGetProcAddress ( " glGetVertexAttribiv " ) ;
qglGetVertexAttribPointerv = ( void * ) wglGetProcAddress ( " glGetVertexAttribPointerv " ) ;
# pragma comment(lib,"opengl32.lib")
2012-07-07 05:17:43 +00:00
if ( qglGetVertexAttribiv )
2012-05-11 01:57:00 +00:00
{
2012-07-07 05:17:43 +00:00
glGetIntegerv ( GL_ARRAY_BUFFER_BINDING , & rval ) ;
Sys_Printf ( " GL_ARRAY_BUFFER_BINDING: %i \n " , rval ) ;
glGetPointerv ( GL_COLOR_ARRAY_POINTER , & ptr ) ;
Sys_Printf ( " GL_COLOR_ARRAY: %s (%lx) \n " , glIsEnabled ( GL_COLOR_ARRAY ) ? " en " : " dis " , ( int ) ptr ) ;
// glGetPointerv(GL_FOG_COORD_ARRAY_POINTER, &ptr);
// Sys_Printf("GL_FOG_COORDINATE_ARRAY_EXT: %i (%lx)\n", (int) glIsEnabled(GL_FOG_COORDINATE_ARRAY_EXT), (int) ptr);
glGetIntegerv ( GL_ELEMENT_ARRAY_BUFFER_BINDING , & rval ) ;
glGetPointerv ( GL_INDEX_ARRAY_POINTER , & ptr ) ;
Sys_Printf ( " GL_INDEX_ARRAY: %s %i:%p \n " , glIsEnabled ( GL_INDEX_ARRAY ) ? " en " : " dis " , rval , ptr ) ;
glGetPointerv ( GL_NORMAL_ARRAY_POINTER , & ptr ) ;
Sys_Printf ( " GL_NORMAL_ARRAY: %s (%lx) \n " , glIsEnabled ( GL_NORMAL_ARRAY ) ? " en " : " dis " , ( int ) ptr ) ;
// glGetPointerv(GL_SECONDARY_COLOR_ARRAY_POINTER, &ptr);
// Sys_Printf("GL_SECONDARY_COLOR_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_SECONDARY_COLOR_ARRAY), (int) ptr);
for ( i = 0 ; i < 4 ; i + + )
{
qglClientActiveTextureARB ( mtexid0 + i ) ;
glGetIntegerv ( GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING , & rval ) ;
glGetPointerv ( GL_TEXTURE_COORD_ARRAY_POINTER , & ptr ) ;
Sys_Printf ( " GL_TEXTURE_COORD_ARRAY %i: %s %i:%p \n " , i , glIsEnabled ( GL_TEXTURE_COORD_ARRAY ) ? " en " : " dis " , rval , ptr ) ;
}
glGetIntegerv ( GL_VERTEX_ARRAY_BUFFER_BINDING , & rval ) ;
glGetPointerv ( GL_VERTEX_ARRAY_POINTER , & ptr ) ;
Sys_Printf ( " GL_VERTEX_ARRAY: %s %i:%p \n " , glIsEnabled ( GL_VERTEX_ARRAY ) ? " en " : " dis " , rval , ptr ) ;
2012-04-24 07:59:11 +00:00
2012-07-07 05:17:43 +00:00
for ( i = 0 ; i < 16 ; i + + )
{
int en , bo , as , st , ty , no ;
2012-04-24 07:59:11 +00:00
2012-07-07 05:17:43 +00:00
qglGetVertexAttribiv ( i , GL_VERTEX_ATTRIB_ARRAY_ENABLED , & en ) ;
qglGetVertexAttribiv ( i , GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING , & bo ) ;
qglGetVertexAttribiv ( i , GL_VERTEX_ATTRIB_ARRAY_SIZE , & as ) ;
qglGetVertexAttribiv ( i , GL_VERTEX_ATTRIB_ARRAY_STRIDE , & st ) ;
qglGetVertexAttribiv ( i , GL_VERTEX_ATTRIB_ARRAY_TYPE , & ty ) ;
qglGetVertexAttribiv ( i , GL_VERTEX_ATTRIB_ARRAY_NORMALIZED , & no ) ;
qglGetVertexAttribPointerv ( i , GL_VERTEX_ATTRIB_ARRAY_POINTER , & ptr ) ;
2012-04-24 07:59:11 +00:00
2012-07-07 05:17:43 +00:00
Sys_Printf ( " attrib%i: %s as:%i st:%i ty:%0x %s%i:%p \n " , i , en ? " en " : " dis " , as , st , ty , no ? " norm " : " " , bo , ptr ) ;
}
2012-04-24 07:59:11 +00:00
}
# endif
2009-11-04 21:16:50 +00:00
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*/
2011-12-05 15:23:40 +00:00
extern qboolean vid_initializing ;
qboolean oldval = vid_initializing ;
vid_initializing = true ;
2012-02-27 12:23:15 +00:00
// ShowWindow(mainwindow, SW_MINIMIZE);
2011-12-05 15:23:40 +00:00
vid_initializing = oldval ;
2009-11-04 21:16:50 +00:00
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)
2011-05-19 13:34:07 +00:00
# ifndef LLKHF_UP
# define LLKHF_UP 0x00000080
# endif
2004-09-04 17:45:10 +00:00
# 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 ;
}
2012-04-24 07:59:11 +00:00
qboolean Sys_Rename ( char * oldfname , char * newfname )
{
return ! rename ( oldfname , newfname ) ;
}
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 ) ;
2011-05-19 13:34:07 +00:00
Sys_Error ( " Protection change failed! \n Error %d: %s \n " , ( int ) GetLastError ( ) , str ) ;
2007-08-30 02:58:45 +00:00
}
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
#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 ;
}
2011-04-30 17:21:10 +00:00
void Sys_Shutdown ( void )
{
if ( host_parms . membase )
{
VirtualFree ( host_parms . membase , 0 , MEM_RELEASE ) ;
host_parms . membase = 0 ;
}
2012-07-05 19:42:36 +00:00
if ( tevent )
CloseHandle ( tevent ) ;
tevent = NULL ;
if ( qwclsemaphore )
CloseHandle ( qwclsemaphore ) ;
qwclsemaphore = NULL ;
2011-04-30 17:21:10 +00:00
}
2004-08-23 00:15:46 +00:00
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
2011-09-16 05:56:54 +00:00
# ifdef NPFTE
2011-04-30 17:21:10 +00:00
{
extern jmp_buf host_abort ;
/*jump to start of main loop (which exits the main loop)*/
longjmp ( host_abort , 1 ) ;
}
# else
2004-08-23 00:15:46 +00:00
exit ( 1 ) ;
2011-04-30 17:21:10 +00:00
# endif
2004-08-23 00:15:46 +00:00
}
2012-07-05 19:42:36 +00:00
static wchar_t dequake ( conchar_t chr )
{
chr & = CON_CHARMASK ;
/*only this range are quake chars*/
if ( chr > = 0xe000 & & chr < 0xe100 )
{
chr & = 0xff ;
if ( chr > = 146 & & chr < 156 )
chr = chr - 146 + ' 0 ' ;
if ( chr > = 0x12 & & chr < = 0x1b )
chr = chr - 0x12 + ' 0 ' ;
if ( chr = = 143 )
chr = ' . ' ;
if ( chr = = 128 | | chr = = 129 | | chr = = 130 | | chr = = 157 | | chr = = 158 | | chr = = 159 )
chr = ' - ' ;
if ( chr > = 128 )
chr - = 128 ;
if ( chr = = 16 )
chr = ' [ ' ;
if ( chr = = 17 )
chr = ' ] ' ;
if ( chr = = 0x1c )
chr = 249 ;
}
/*this range contains pictograms*/
if ( chr > = 0xe100 & & chr < 0xe200 )
{
chr = ' ? ' ;
}
return chr ;
}
2004-08-23 00:15:46 +00:00
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 )
2012-07-05 19:42:36 +00:00
{
//msvc debug output
conchar_t msg [ 1024 ] , * end ;
wchar_t wide [ 1024 ] ;
int i ;
end = COM_ParseFunString ( CON_WHITEMASK , text , msg , sizeof ( msg ) , false ) ;
for ( i = 0 ; msg + i < end ; i + + )
{
wide [ i ] = dequake ( msg [ i ] & CON_CHARMASK ) ;
}
wide [ i ] = 0 ;
OutputDebugStringW ( wide ) ;
}
2011-01-23 03:33:33 +00:00
# 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
2004-09-04 17:45:10 +00:00
SetHookState ( false ) ;
2009-03-07 05:05:54 +00:00
# else
SV_Shutdown ( ) ;
# endif
2012-07-05 19:42:36 +00:00
TL_Shutdown ( ) ;
2012-05-09 15:30:53 +00:00
# ifdef RESTARTTEST
longjmp ( restart_jmpbuf , 1 ) ;
# endif
2011-09-16 05:56:54 +00:00
# ifdef NPFTE
2009-04-01 22:03:56 +00:00
{
extern jmp_buf host_abort ;
2011-04-30 17:21:10 +00:00
/*jump to start of main loop (which exits the main loop)*/
2009-04-01 22:03:56 +00:00
longjmp ( host_abort , 1 ) ;
}
# else
2012-07-05 19:42:36 +00:00
# ifdef USE_MSVCRT_DEBUG
if ( _CrtDumpMemoryLeaks ( ) )
OutputDebugStringA ( " Leaks detected \n " ) ;
# endif
2011-12-23 03:12:29 +00:00
exit ( 1 ) ;
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
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_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 ;
}
2011-09-16 05:56:54 +00:00
# ifdef NPFTE
2009-04-01 22:03:56 +00:00
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
2011-07-06 01:01:13 +00:00
double sleeptime ;
2009-04-01 22:03:56 +00:00
newtime = Sys_DoubleTime ( ) ;
duratrion = newtime - lastlooptime ;
2011-07-06 01:01:13 +00:00
sleeptime = Host_Frame ( duratrion ) ;
2009-04-01 22:03:56 +00:00
lastlooptime = newtime ;
2009-11-04 21:16:50 +00:00
SetHookState ( sys_disableWinKeys . ival ) ;
2009-04-01 22:03:56 +00:00
2011-07-06 01:01:13 +00:00
Sys_Sleep ( sleeptime ) ;
2009-04-01 22:03:56 +00:00
// Sleep(0);
# else
Sys_Error ( " wut? " ) ;
# endif
}
}
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
2012-07-05 19:42:36 +00:00
# if defined(__MINGW64_VERSION_MAJOR) && (__MINGW64_VERSION_MAJOR >= 3)
# define SHARD_APPIDINFOLINK SHARD_APPIDINFOLINK
# 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 ;
2012-02-12 05:18:31 +00:00
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 } } ;
2012-02-12 05:18:31 +00:00
# ifndef MINGW
# if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600
# define IObjectArray IUnknown
# endif
# endif
static const IID IID_IObjectArray = { 0x92ca9dcd , 0x5622 , 0x4bba , { 0xa8 , 0x05 , 0x5e , 0x9f , 0x54 , 0x1b , 0xd8 , 0xc9 } } ;
# ifndef MINGW
# if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600
typedef struct IObjectCollection
{
struct IObjectCollectionVtbl
{
HRESULT ( __stdcall * QueryInterface ) (
/* [in] IShellLink*/ void * This ,
/* [in] */ const GUID * const riid ,
/* [out] */ void * * ppvObject ) ;
ULONG ( __stdcall * AddRef ) (
/* [in] IShellLink*/ void * This ) ;
ULONG ( __stdcall * Release ) (
/* [in] IShellLink*/ void * This ) ;
HRESULT ( __stdcall * GetCount ) (
/* [in] IShellLink*/ void * This ,
/* [out] */ UINT * pcObjects ) ;
HRESULT ( __stdcall * GetAt ) (
/* [in] IShellLink*/ void * This ,
/* [in] */ UINT uiIndex ,
/* [in] */ const GUID * const riid ,
/* [iid_is][out] */ void * * ppv ) ;
HRESULT ( __stdcall * AddObject ) (
/* [in] IShellLink*/ void * This ,
/* [in] */ void * punk ) ;
HRESULT ( __stdcall * AddFromArray ) (
/* [in] IShellLink*/ void * This ,
/* [in] */ IObjectArray * poaSource ) ;
HRESULT ( __stdcall * RemoveObjectAt ) (
/* [in] IShellLink*/ void * This ,
/* [in] */ UINT uiIndex ) ;
HRESULT ( __stdcall * Clear ) (
/* [in] IShellLink*/ void * This ) ;
} * lpVtbl ;
} IObjectCollection ;
# endif
# endif
static const IID IID_IObjectCollection = { 0x5632b1a4 , 0xe38a , 0x400a , { 0x92 , 0x8a , 0xd4 , 0xcd , 0x63 , 0x23 , 0x02 , 0x95 } } ;
static const CLSID CLSID_EnumerableObjectCollection = { 0x2d3468c1 , 0x36a7 , 0x43b6 , { 0xac , 0x24 , 0xd3 , 0xf0 , 0x2f , 0xd9 , 0x60 , 0x7a } } ;
# ifndef MINGW
# if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600
typedef struct ICustomDestinationList
{
struct ICustomDestinationListVtbl
{
HRESULT ( __stdcall * QueryInterface ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [in] */ const GUID * const riid ,
/* [out] */ void * * ppvObject ) ;
ULONG ( __stdcall * AddRef ) (
/* [in] ICustomDestinationList*/ void * This ) ;
ULONG ( __stdcall * Release ) (
/* [in] ICustomDestinationList*/ void * This ) ;
HRESULT ( __stdcall * SetAppID ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [string][in] */ LPCWSTR pszAppID ) ;
HRESULT ( __stdcall * BeginList ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [out] */ UINT * pcMinSlots ,
/* [in] */ const GUID * const riid ,
/* [out] */ void * * ppv ) ;
HRESULT ( __stdcall * AppendCategory ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [string][in] */ LPCWSTR pszCategory ,
/* [in] IObjectArray*/ void * poa ) ;
HRESULT ( __stdcall * AppendKnownCategory ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [in] KNOWNDESTCATEGORY*/ int category ) ;
HRESULT ( __stdcall * AddUserTasks ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [in] IObjectArray*/ void * poa ) ;
HRESULT ( __stdcall * CommitList ) (
/* [in] ICustomDestinationList*/ void * This ) ;
HRESULT ( __stdcall * GetRemovedDestinations ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [in] */ const IID * const riid ,
/* [out] */ void * * ppv ) ;
HRESULT ( __stdcall * DeleteList ) (
/* [in] ICustomDestinationList*/ void * This ,
/* [string][unique][in] */ LPCWSTR pszAppID ) ;
HRESULT ( __stdcall * AbortList ) (
/* [in] ICustomDestinationList*/ void * This ) ;
} * lpVtbl ;
} ICustomDestinationList ;
# endif
# endif
static const IID IID_ICustomDestinationList = { 0x6332debf , 0x87b5 , 0x4670 , { 0x90 , 0xc0 , 0x5e , 0x57 , 0xb4 , 0x08 , 0xa4 , 0x9e } } ;
static const CLSID CLSID_DestinationList = { 0x77f10cf0 , 0x3db5 , 0x4966 , { 0xb5 , 0x20 , 0xb7 , 0xc5 , 0x4f , 0xd3 , 0x5e , 0xd6 } } ;
2010-12-05 02:46:07 +00:00
# endif
2012-02-12 05:18:31 +00:00
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"
2012-02-12 05:18:31 +00:00
static IShellLinkW * CreateShellLink ( char * command , char * target , char * title , char * desc )
2010-12-05 02:46:07 +00:00
{
HRESULT hr ;
IShellLinkW * link ;
IPropertyStore * prop_store ;
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 ) )
2012-02-12 05:18:31 +00:00
return NULL ;
GetModuleFileNameW ( NULL , buf , sizeof ( buf ) / sizeof ( wchar_t ) - 1 ) ;
IShellLinkW_SetIconLocation ( link , buf , 0 ) ; /*grab the first icon from our exe*/
2010-12-05 02:46:07 +00:00
IShellLinkW_SetPath ( link , buf ) ; /*program to run*/
2012-02-12 05:18:31 +00:00
2010-12-05 02:46:07 +00:00
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
2012-02-12 05:18:31 +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
2012-02-12 05:18:31 +00:00
return link ;
}
void Sys_RecentServer ( char * command , char * target , char * title , char * desc )
{
SHARDAPPIDINFOLINK appinfo ;
IShellLinkW * link ;
link = CreateShellLink ( command , target , title , desc ) ;
if ( ! link )
return ;
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 ) ;
}
}
2012-02-12 05:18:31 +00:00
void Win7_TaskListInit ( void )
{
ICustomDestinationList * cdl ;
IObjectCollection * col ;
IObjectArray * arr ;
IShellLinkW * link ;
CoInitialize ( NULL ) ;
if ( SUCCEEDED ( CoCreateInstance ( & CLSID_DestinationList , NULL , CLSCTX_INPROC_SERVER , & IID_ICustomDestinationList , & cdl ) ) )
{
UINT minslots ;
IUnknown * removed ;
cdl - > lpVtbl - > BeginList ( cdl , & minslots , & IID_IObjectArray , & removed ) ;
if ( SUCCEEDED ( CoCreateInstance ( & CLSID_EnumerableObjectCollection , NULL , CLSCTX_INPROC_SERVER , & IID_IObjectCollection , & col ) ) )
{
switch ( M_GameType ( ) )
{
case MGT_QUAKE1 :
link = CreateShellLink ( " +menu_servers " , " " , " Server List " , " Pick a multiplayer server to join " ) ;
if ( link )
{
col - > lpVtbl - > AddObject ( col , link ) ;
link - > lpVtbl - > Release ( link ) ;
}
link = CreateShellLink ( " +map start " , " " , " Start New Game (Quake) " , " Begin a new single-player game " ) ;
if ( link )
{
col - > lpVtbl - > AddObject ( col , link ) ;
link - > lpVtbl - > Release ( link ) ;
}
break ;
case MGT_QUAKE2 :
link = CreateShellLink ( " +menu_servers " , " " , " Quake2 Server List " , " Pick a multiplayer server to join " ) ;
if ( link )
{
col - > lpVtbl - > AddObject ( col , link ) ;
link - > lpVtbl - > Release ( link ) ;
}
link = CreateShellLink ( " +map unit1 " , " " , " Start New Game (Quake2) " , " Begin a new game " ) ;
if ( link )
{
col - > lpVtbl - > AddObject ( col , link ) ;
link - > lpVtbl - > Release ( link ) ;
}
break ;
case MGT_HEXEN2 :
link = CreateShellLink ( " +menu_servers " , " " , " Hexen2 Server List " , " Pick a multiplayer server to join " ) ;
if ( link )
{
col - > lpVtbl - > AddObject ( col , link ) ;
link - > lpVtbl - > Release ( link ) ;
}
link = CreateShellLink ( " +map demo1 " , " " , " Start New Game (Hexen2) " , " Begin a new game " ) ;
if ( link )
{
col - > lpVtbl - > AddObject ( col , link ) ;
link - > lpVtbl - > Release ( link ) ;
}
break ;
}
if ( SUCCEEDED ( col - > lpVtbl - > QueryInterface ( col , & IID_IObjectArray , & arr ) ) )
{
cdl - > lpVtbl - > AddUserTasks ( cdl , arr ) ;
arr - > lpVtbl - > Release ( arr ) ;
}
col - > lpVtbl - > Release ( col ) ;
}
cdl - > lpVtbl - > AppendKnownCategory ( cdl , 1 ) ;
cdl - > lpVtbl - > CommitList ( cdl ) ;
cdl - > lpVtbl - > Release ( cdl ) ;
}
}
2010-12-23 08:53:23 +00:00
# endif
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 ;
2011-06-05 23:53:33 +00:00
int delay = 0 ;
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
}
}
2012-05-09 15:30:53 +00:00
# ifdef RESTARTTEST
setjmp ( restart_jmpbuf ) ;
# endif
2009-11-04 21:16:50 +00:00
GetModuleFileName ( NULL , cwd , sizeof ( cwd ) - 1 ) ;
strcpy ( exename , COM_SkipPath ( cwd ) ) ;
2011-05-19 13:34:07 +00:00
parms . argv = ( const char * * ) 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)
if ( ! Sys_InitTerminal ( ) )
Sys_Error ( " Couldn't allocate dedicated server console " ) ;
# 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
{
2011-06-05 23:53:33 +00:00
int delay ;
2009-11-04 21:16:50 +00:00
SV_Init ( & parms ) ;
2004-08-23 00:15:46 +00:00
2011-06-05 23:53:33 +00:00
delay = SV_Frame ( ) * 1000 ;
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 " ) ;
2011-06-05 23:53:33 +00:00
NET_Sleep ( delay , false ) ;
delay = SV_Frame ( ) * 1000 ;
2009-11-04 21:16:50 +00:00
}
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
2012-02-12 05:18:31 +00:00
Win7_TaskListInit ( ) ;
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
2011-06-05 23:53:33 +00:00
NET_Sleep ( delay , false ) ;
2009-11-04 21:16:50 +00:00
// find time passed since last cycle
newtime = Sys_DoubleTime ( ) ;
time = newtime - oldtime ;
oldtime = newtime ;
2010-12-07 12:23:56 +00:00
2011-06-05 23:53:33 +00:00
delay = 1000 * SV_Frame ( ) ;
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
else
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
# ifndef SERVERONLY
2011-07-06 01:01:13 +00:00
double 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*/
2011-07-06 01:01:13 +00:00
Sys_Sleep ( sleeptime ) ;
2009-11-04 21:16:50 +00:00
# else
Sys_Error ( " wut? " ) ;
# endif
2004-08-23 00:15:46 +00:00
}
2012-07-05 19:42:36 +00:00
# ifndef SERVERONLY
if ( fs_switchgame ! = - 1 )
{
SetHookState ( false ) ;
Host_Shutdown ( ) ;
COM_InitArgv ( parms . argc , parms . argv ) ;
if ( ! Sys_Startup_CheckMem ( & parms ) )
return 0 ;
Host_Init ( & parms ) ;
}
# 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
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 ) ;
2012-02-27 12:23:15 +00:00
# ifdef CATCHCRASH
__try
{
# endif
tw . func ( tw . args ) ;
# ifdef CATCHCRASH
}
__except ( CrashExceptionHandler ( GetExceptionCode ( ) , GetExceptionInformation ( ) ) )
{
return 1 ;
}
# endif
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 ;
}
2011-07-03 16:24:53 +00:00
void * Sys_CreateThread ( int ( * func ) ( void * ) , void * args , int priority , 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 )
{
2012-02-27 12:23:15 +00:00
#if 0 //def _DEBUG
2010-03-14 14:35:56 +00:00
/*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 ( ) ;
2011-10-27 15:46:36 +00:00
return false ;
# else
2007-12-30 00:09:34 +00:00
return WaitForSingleObject ( mutex , INFINITE ) = = WAIT_OBJECT_0 ;
2011-10-27 15:46:36 +00:00
# endif
2007-12-30 00:09:34 +00:00
}
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 ) ;
}
2011-07-06 01:01:13 +00:00
# endif
2011-07-03 16:24:53 +00:00
2011-07-06 01:01:13 +00:00
void Sys_Sleep ( double seconds )
2011-07-03 16:24:53 +00:00
{
2011-07-06 01:01:13 +00:00
Sleep ( seconds * 1000 ) ;
2011-07-03 16:24:53 +00:00
}