raze/polymer/eduke32/build/src/winbits.c

375 lines
9.1 KiB
C
Raw Normal View History

// Windows layer-independent code
#include "compat.h"
#include "build.h"
#include "baselayer.h"
#include "osd.h"
#include "cache1d.h"
#include "winbits.h"
#ifdef BITNESS64
Win64 support! (Meaning it works, not that we recommend it for everyday use.) This includes a complete Windows header and library refresh, including the addition of 64-bit compiled libs: *libogg 1.3.0 *libvorbis 1.3.3 *zlib 1.2.7 *libpng 1.5.13 *libvpx 9a3de881c0e681ba1a79a166a86308bbc84b4acd *SDL_mixer 1.2.12 (for RENDERTYPE=SDL) *DirectX import libraries: dsound and dxguid (now included) To build in 64-bit, you essentially need MinGW's MSYS (but not MinGW itself) and MinGW-w64 at the top of your PATH. The target is automatically detected using `$(CC) -dumpmachine`. The EDukeWiki will get detailed instrucitons. All compiler and linker warnings when building in 64-bit mode have been fixed. Remaining 64-bit to-do: - The ebacktrace dll does not build under 64-bit. It uses code specific to the format of 32-bit executables and will have to be ported to work with 64-bit executables. A future 64-bit version will be named ebacktrace1-64.dll. - RENDERTYPE=SDL crashes in SDL_mixer's Mix_Linked_Version(). - DirectInput gives an error and does not function. This only affects joysticks, and the error never happens without any plugged in. - Port the classic renderer ASM to 64-bit. (Just kidding, this is way out of my league.) This commit includes a fair bit of Makefile development spanning all platforms, including simplifying the SDLCONFIG code, fixing build on Mac OS X (thanks rhoenie!), globally factoring Apple brew/port inclusion, enforcing that all -L come before all -l, and ensuring that $(shell ) is always :='d. In addition, I have resurrected the old GCC_MAJOR and GCC_MINOR detection using `$(CC) -dumpversion`, but I have made it failsafe in case the command fails or the version is manually specified. I have applied this new fine-grained detection where applicable, including allowing LTO, and restraining -W's to versions that support them. git-svn-id: https://svn.eduke32.com/eduke32@3278 1a8010ca-5511-0410-912e-c29ae57300e0
2012-12-13 02:37:20 +00:00
# define EBACKTRACEDLL "ebacktrace1-64.dll"
#else
# define EBACKTRACEDLL "ebacktrace1.dll"
#endif
int32_t backgroundidle = 1;
int64_t win_timerfreq = 0;
char silentvideomodeswitch = 0;
static char taskswitching = 1;
static HANDLE instanceflag = NULL;
static OSVERSIONINFOEX osv;
static int32_t togglecomp = 1;
FARPROC pwinever;
//
// CheckWinVersion() -- check to see what version of Windows we happen to be running under
//
BOOL CheckWinVersion(void)
{
HMODULE hntdll = GetModuleHandle("ntdll.dll");
if (hntdll)
pwinever = GetProcAddress(hntdll, "wine_get_version");
ZeroMemory(&osv, sizeof(osv));
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
// we don't like anything older than Windows XP
if (!GetVersionEx((LPOSVERSIONINFOA)&osv)) return FALSE;
if (osv.dwMajorVersion >= 6) return TRUE;
if (osv.dwMajorVersion == 5 && osv.dwMinorVersion >= 1) return TRUE;
return FALSE;
}
static void win_printversion(void)
{
const char *ver = "";
switch (osv.dwPlatformId)
{
case VER_PLATFORM_WIN32_NT:
switch (osv.dwMajorVersion)
{
case 5:
switch (osv.dwMinorVersion)
{
case 1: ver = "XP"; break;
case 2: ver = osv.wProductType == VER_NT_WORKSTATION ? "XP x64" : "Server 2003"; break;
}
break;
case 6:
switch (osv.dwMinorVersion)
{
case 0: ver = osv.wProductType == VER_NT_WORKSTATION ? "Vista" : "Server 2008"; break;
case 1: ver = osv.wProductType == VER_NT_WORKSTATION ? "7" : "Server 2008 R2"; break;
case 2: ver = osv.wProductType == VER_NT_WORKSTATION ? "8" : "Server 2012"; break;
case 3: ver = osv.wProductType == VER_NT_WORKSTATION ? "8.1" : "Server 2012 R2"; break;
}
break;
case 10:
switch (osv.dwMinorVersion)
{
case 0: ver = osv.wProductType == VER_NT_WORKSTATION ? "10" : "Server 10"; break;
}
break;
}
break;
}
char *str = (char *)Bcalloc(1, 256);
int l;
if (pwinever)
l = Bsprintf(str, "Wine %s identifying as Windows %s", (char *)pwinever(), ver);
else
l = Bsprintf(str, "Windows %s", ver);
// service packs
if (osv.szCSDVersion[0])
{
str[l] = 32;
Bstrcat(&str[l], osv.szCSDVersion);
}
initprintf("Running on %s (build %lu.%lu.%lu)\n", str, osv.dwMajorVersion, osv.dwMinorVersion, osv.dwBuildNumber);
Bfree(str);
}
//
// win_allowtaskswitching() -- captures/releases alt+tab hotkeys
//
void win_allowtaskswitching(int32_t onf)
{
if (onf == taskswitching) return;
taskswitching = onf;
if (onf)
{
UnregisterHotKey(0,0);
UnregisterHotKey(0,1);
}
else
{
RegisterHotKey(0,0,MOD_ALT,VK_TAB);
RegisterHotKey(0,1,MOD_ALT|MOD_SHIFT,VK_TAB);
}
}
//
// win_checkinstance() -- looks for another instance of a Build app
//
int32_t win_checkinstance(void)
{
if (!instanceflag) return 0;
return (WaitForSingleObject(instanceflag,0) == WAIT_TIMEOUT);
}
//
// high-resolution timers for profiling
//
int32_t win_inittimer(void)
{
int64_t t;
if (win_timerfreq) return 0; // already installed
// OpenWatcom seems to want us to query the value into a local variable
// instead of the global 'win_timerfreq' or else it gets pissed with an
// access violation
if (!QueryPerformanceFrequency((LARGE_INTEGER *)&t))
{
ShowErrorBox("Failed fetching timer frequency");
return -1;
}
win_timerfreq = t;
return 0;
}
uint64_t win_getu64ticks(void)
{
uint64_t i;
if (win_timerfreq == 0) return 0;
QueryPerformanceCounter((LARGE_INTEGER *)&i);
return i;
}
static void ToggleDesktopComposition(BOOL compEnable)
{
static HMODULE hDWMApiDLL = NULL;
static HRESULT(WINAPI *aDwmEnableComposition)(UINT);
if (!hDWMApiDLL && (hDWMApiDLL = LoadLibrary("DWMAPI.DLL")))
aDwmEnableComposition = (HRESULT(WINAPI *)(UINT))GetProcAddress(hDWMApiDLL, "DwmEnableComposition");
if (aDwmEnableComposition)
{
aDwmEnableComposition(compEnable);
if (!silentvideomodeswitch)
initprintf("%sabling desktop composition...\n", (compEnable) ? "En" : "Dis");
}
}
typedef void (*dllSetString)(const char*);
//
// win_open(), win_init(), win_setvideomode(), win_uninit(), win_close() -- shared code
//
void win_open(void)
{
#ifdef DEBUGGINGAIDS
HMODULE ebacktrace = LoadLibraryA(EBACKTRACEDLL);
if (ebacktrace)
{
dllSetString SetTechnicalName = (dllSetString) GetProcAddress(ebacktrace, "SetTechnicalName");
dllSetString SetProperName = (dllSetString) GetProcAddress(ebacktrace, "SetProperName");
if (SetTechnicalName)
SetTechnicalName(AppTechnicalName);
if (SetProperName)
SetProperName(AppProperName);
}
#endif
instanceflag = CreateSemaphore(NULL, 1,1, WindowClass);
}
void win_init(void)
{
uint32_t i;
cvar_t cvars_win[] =
{
{ "r_togglecomposition","enable/disable toggle of desktop composition when initializing screen modes",(void *) &togglecomp, CVAR_BOOL, 0, 1 },
};
for (i=0; i<ARRAY_SIZE(cvars_win); i++)
{
if (OSD_RegisterCvar(&cvars_win[i]))
continue;
OSD_RegisterFunction(cvars_win[i].name, cvars_win[i].desc, osdcmd_cvar_set);
}
win_printversion();
}
void win_setvideomode(int32_t c)
{
if (togglecomp && osv.dwMajorVersion == 6 && osv.dwMinorVersion < 2)
ToggleDesktopComposition(c < 16);
}
void win_uninit(void)
{
win_allowtaskswitching(1);
}
void win_close(void)
{
if (instanceflag) CloseHandle(instanceflag);
}
//
// ShowErrorBox() -- shows an error message box
//
void ShowErrorBox(const char *m)
{
TCHAR msg[1024];
wsprintf(msg, "%s: %s", m, GetWindowsErrorMsg(GetLastError()));
MessageBox(0, msg, apptitle, MB_OK|MB_ICONSTOP);
}
//
// GetWindowsErrorMsg() -- gives a pointer to a static buffer containing the Windows error message
//
LPTSTR GetWindowsErrorMsg(DWORD code)
{
static TCHAR lpMsgBuf[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)lpMsgBuf, 1024, NULL);
return lpMsgBuf;
}
//
// Miscellaneous
//
int32_t addsearchpath_ProgramFiles(const char *p)
{
int32_t returncode = -1, i;
const char *ProgramFiles[2] = { Bgetenv("ProgramFiles"), Bgetenv("ProgramFiles(x86)") };
for (i = 0; i < 2; ++i)
{
if (ProgramFiles[i])
{
char *buffer = (char*)Bmalloc((strlen(ProgramFiles[i])+1+strlen(p)+1)*sizeof(char));
Bsprintf(buffer,"%s/%s",ProgramFiles[i],p);
if (addsearchpath(buffer) == 0) // if any work, return success
returncode = 0;
Bfree(buffer);
}
}
return returncode;
}
int32_t win_buildargs(char **argvbuf)
{
int32_t buildargc = 0;
*argvbuf = Bstrdup(GetCommandLine());
if (*argvbuf)
{
char quoted = 0, instring = 0, swallownext = 0;
char *wp;
for (const char *p = wp = *argvbuf; *p; p++)
{
if (*p == ' ')
{
if (instring)
{
if (!quoted)
{
// end of a string
*(wp++) = 0;
instring = 0;
}
else
*(wp++) = *p;
}
}
else if (*p == '"' && !swallownext)
{
if (instring)
{
if (quoted && p[1] == ' ')
{
// end of a string
*(wp++) = 0;
instring = 0;
}
quoted = !quoted;
}
else
{
instring = 1;
quoted = 1;
buildargc++;
}
}
else if (*p == '\\' && p[1] == '"' && !swallownext)
swallownext = 1;
else
{
if (!instring)
buildargc++;
instring = 1;
*(wp++) = *p;
swallownext = 0;
}
}
*wp = 0;
}
return buildargc;
}
// Workaround for a bug in mingwrt-4.0.0 and up where a function named main() in misc/src/libcrt/gdtoa/qnan.c takes precedence over the proper one in src/libcrt/crt/main.c.
#if (defined __MINGW32__ && EDUKE32_GCC_PREREQ(4,8)) || EDUKE32_CLANG_PREREQ(3,4)
# undef main
# include "mingw_main.c"
#endif