make sure winit shutdown actually happens during self-test (fixes leaks and possibly failure to unload driver)
revamp module init: no more atexit and "premain" init => no longer need to call any wstartup init function. winit section names now use group numbers instead of letters. delay_load -> wdll_delay_load dll_ver -> wdll_ver add aken build environment cleanup wsock.cpp, have it import its functions properly wsdl: defend against GameSetup calling SDL_Quit twice. This was SVN commit r5108.
This commit is contained in:
parent
7fe6c3d77f
commit
b879e344f1
7
source/lib/sysdep/win/aken/makefile
Normal file
7
source/lib/sysdep/win/aken/makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||||
|
# file to this component. This file merely indirects to the real make file
|
||||||
|
# that is shared by all the driver components of the Windows NT DDK
|
||||||
|
#
|
||||||
|
|
||||||
|
!INCLUDE $(NTMAKEENV)\makefile.def
|
5
source/lib/sysdep/win/aken/sources
Normal file
5
source/lib/sysdep/win/aken/sources
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
TARGETNAME=aken
|
||||||
|
TARGETPATH=.
|
||||||
|
TARGETTYPE=DRIVER
|
||||||
|
|
||||||
|
SOURCES=aken.cpp
|
@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* =========================================================================
|
|
||||||
* File : delay_load.h
|
|
||||||
* Project : 0 A.D.
|
|
||||||
* Description : allow delay-loading DLLs.
|
|
||||||
* =========================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
// license: GPL; see lib/license.txt
|
|
||||||
|
|
||||||
struct DllLoadNotify;
|
|
||||||
|
|
||||||
extern void wdll_add_notify(DllLoadNotify*);
|
|
||||||
|
|
||||||
// note: this mechanism relies on the compiler calling non-local static
|
|
||||||
// object ctors, which doesn't happen if compiling this code into
|
|
||||||
// a static library. recommended workaround is to call wdll_add_notify via
|
|
||||||
// win.cpp module init mechanism.
|
|
||||||
struct DllLoadNotify
|
|
||||||
{
|
|
||||||
const char* dll_name;
|
|
||||||
LibError (*func)(void);
|
|
||||||
DllLoadNotify* next;
|
|
||||||
|
|
||||||
DllLoadNotify(const char* _dll_name, LibError (*_func)(void))
|
|
||||||
{
|
|
||||||
dll_name = _dll_name;
|
|
||||||
func = _func;
|
|
||||||
wdll_add_notify(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WDLL_LOAD_NOTIFY(dll_name, func)\
|
|
||||||
static DllLoadNotify func##_NOTIFY(dll_name, func)
|
|
@ -17,8 +17,8 @@
|
|||||||
#include "wutil.h"
|
#include "wutil.h"
|
||||||
#include "winit.h"
|
#include "winit.h"
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(B) // early; whrt depends on us
|
#pragma SECTION_INIT(2) // early; whrt depends on us
|
||||||
WIN_REGISTER_FUNC(wcpu_Init);
|
WINIT_REGISTER_FUNC(wcpu_Init);
|
||||||
#pragma FORCE_INCLUDE(wcpu_Init)
|
#pragma FORCE_INCLUDE(wcpu_Init)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
#include "wutil.h"
|
#include "wutil.h"
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(D)
|
#pragma SECTION_INIT(5)
|
||||||
WIN_REGISTER_FUNC(wdbg_init);
|
WINIT_REGISTER_FUNC(wdbg_init);
|
||||||
#pragma FORCE_INCLUDE(wdbg_init)
|
#pragma FORCE_INCLUDE(wdbg_init)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -38,11 +38,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(D)
|
#pragma SECTION_INIT(5)
|
||||||
WIN_REGISTER_FUNC(wdbg_sym_init);
|
WINIT_REGISTER_FUNC(wdbg_sym_init);
|
||||||
#pragma FORCE_INCLUDE(wdbg_sym_init)
|
#pragma FORCE_INCLUDE(wdbg_sym_init)
|
||||||
#pragma SECTION_POST_ATEXIT(J)
|
#pragma SECTION_SHUTDOWN(5)
|
||||||
WIN_REGISTER_FUNC(wdbg_sym_shutdown);
|
WINIT_REGISTER_FUNC(wdbg_sym_shutdown);
|
||||||
#pragma FORCE_INCLUDE(wdbg_sym_shutdown)
|
#pragma FORCE_INCLUDE(wdbg_sym_shutdown)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
#include "wutil.h"
|
#include "wutil.h"
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_POST_ATEXIT(J)
|
#pragma SECTION_SHUTDOWN(5)
|
||||||
WIN_REGISTER_FUNC(wdir_watch_shutdown);
|
WINIT_REGISTER_FUNC(wdir_watch_shutdown);
|
||||||
#pragma FORCE_INCLUDE(wdir_watch_shutdown)
|
#pragma FORCE_INCLUDE(wdir_watch_shutdown)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
@ -155,10 +155,10 @@ static LibError wdir_watch_shutdown()
|
|||||||
hIOCP = INVALID_HANDLE_VALUE;
|
hIOCP = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
// free all (dynamically allocated) Watch objects
|
// free all (dynamically allocated) Watch objects
|
||||||
for(WatchIt it = watches.begin(); it != watches.end(); ++it)
|
/*si for(WatchIt it = watches.begin(); it != watches.end(); ++it)
|
||||||
delete it->second;
|
delete it->second;
|
||||||
watches.clear();
|
watches.clear();
|
||||||
|
*/
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
32
source/lib/sysdep/win/wdll_delay_load.h
Normal file
32
source/lib/sysdep/win/wdll_delay_load.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* =========================================================================
|
||||||
|
* File : wdll_delay_load.h
|
||||||
|
* Project : 0 A.D.
|
||||||
|
* Description : DLL delay loading and notification
|
||||||
|
* =========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// license: GPL; see lib/license.txt
|
||||||
|
|
||||||
|
#ifndef INCLUDED_WDLL_DELAY_LOAD
|
||||||
|
#define INCLUDED_WDLL_DELAY_LOAD
|
||||||
|
|
||||||
|
// must be POD because it is used before static ctors run.
|
||||||
|
struct WdllLoadNotify
|
||||||
|
{
|
||||||
|
const char* dll_name;
|
||||||
|
LibError (*func)(void);
|
||||||
|
WdllLoadNotify* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void wdll_add_notify(WdllLoadNotify*);
|
||||||
|
|
||||||
|
// request that func be called if and when dll_name is ever delay-loaded.
|
||||||
|
// must be invoked at function scope.
|
||||||
|
#define WDLL_ADD_NOTIFY(dll_name, func)\
|
||||||
|
STMT(\
|
||||||
|
static WdllLoadNotify UID__ = { dll_name, func };\
|
||||||
|
wdll_add_notify(&UID__);\
|
||||||
|
)
|
||||||
|
|
||||||
|
#endif // #ifndef INCLUDED_WDLL_DELAY_LOAD
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* =========================================================================
|
* =========================================================================
|
||||||
* File : dll_ver.cpp
|
* File : wdll_ver.cpp
|
||||||
* Project : 0 A.D.
|
* Project : 0 A.D.
|
||||||
* Description : return DLL version information.
|
* Description : return DLL version information.
|
||||||
* =========================================================================
|
* =========================================================================
|
||||||
@ -9,7 +9,7 @@
|
|||||||
// license: GPL; see lib/license.txt
|
// license: GPL; see lib/license.txt
|
||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
#include "dll_ver.h"
|
#include "wdll_ver.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -93,15 +93,15 @@ static LibError get_ver(const char* module_path, char* out_ver, size_t out_ver_l
|
|||||||
// build a string containing DLL filename(s) and their version info.
|
// build a string containing DLL filename(s) and their version info.
|
||||||
//
|
//
|
||||||
|
|
||||||
static char* dll_list_buf;
|
static char* ver_list_buf;
|
||||||
static size_t dll_list_chars;
|
static size_t ver_list_chars;
|
||||||
static char* dll_list_pos;
|
static char* ver_list_pos;
|
||||||
|
|
||||||
// set output buffer into which DLL names and their versions will be written.
|
// set output buffer into which DLL names and their versions will be written.
|
||||||
void dll_list_init(char* buf, size_t chars)
|
void wdll_ver_list_init(char* buf, size_t chars)
|
||||||
{
|
{
|
||||||
dll_list_pos = dll_list_buf = buf;
|
ver_list_pos = ver_list_buf = buf;
|
||||||
dll_list_chars = chars;
|
ver_list_chars = chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -110,10 +110,10 @@ void dll_list_init(char* buf, size_t chars)
|
|||||||
// name should preferably be the complete path to DLL, to make sure
|
// name should preferably be the complete path to DLL, to make sure
|
||||||
// we don't inadvertently load another one on the library search path.
|
// we don't inadvertently load another one on the library search path.
|
||||||
// we add the .dll extension if necessary.
|
// we add the .dll extension if necessary.
|
||||||
LibError dll_list_add(const char* name)
|
LibError wdll_ver_list_add(const char* name)
|
||||||
{
|
{
|
||||||
// not be called before dll_list_init or after failure
|
// not be called before wdll_ver_list_init or after failure
|
||||||
if(!dll_list_pos)
|
if(!ver_list_pos)
|
||||||
WARN_RETURN(ERR::LOGIC);
|
WARN_RETURN(ERR::LOGIC);
|
||||||
|
|
||||||
// some driver names are stored in the registry without .dll extension.
|
// some driver names are stored in the registry without .dll extension.
|
||||||
@ -134,26 +134,26 @@ LibError dll_list_add(const char* name)
|
|||||||
(void)get_ver(dll_name, dll_ver, sizeof(dll_ver));
|
(void)get_ver(dll_name, dll_ver, sizeof(dll_ver));
|
||||||
// if this fails, default is already set and we don't want to abort.
|
// if this fails, default is already set and we don't want to abort.
|
||||||
|
|
||||||
const ssize_t max_chars_to_write = (ssize_t)dll_list_chars - (dll_list_pos-dll_list_buf) - 10;
|
const ssize_t max_chars_to_write = (ssize_t)ver_list_chars - (ver_list_pos-ver_list_buf) - 10;
|
||||||
// reserves enough room for subsequent comma and "..." strings.
|
// reserves enough room for subsequent comma and "..." strings.
|
||||||
|
|
||||||
// not first time: prepend comma to string (room was reserved above).
|
// not first time: prepend comma to string (room was reserved above).
|
||||||
if(dll_list_pos != dll_list_buf)
|
if(ver_list_pos != ver_list_buf)
|
||||||
dll_list_pos += sprintf(dll_list_pos, ", ");
|
ver_list_pos += sprintf(ver_list_pos, ", ");
|
||||||
|
|
||||||
// extract filename.
|
// extract filename.
|
||||||
const char* dll_fn = path_name_only(dll_name);
|
const char* dll_fn = path_name_only(dll_name);
|
||||||
|
|
||||||
int len = snprintf(dll_list_pos, max_chars_to_write, "%s (%s)", dll_fn, dll_ver);
|
int len = snprintf(ver_list_pos, max_chars_to_write, "%s (%s)", dll_fn, dll_ver);
|
||||||
// success
|
// success
|
||||||
if(len > 0)
|
if(len > 0)
|
||||||
{
|
{
|
||||||
dll_list_pos += len;
|
ver_list_pos += len;
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// didn't fit; complain
|
// didn't fit; complain
|
||||||
sprintf(dll_list_pos, "..."); // (room was reserved above)
|
sprintf(ver_list_pos, "..."); // (room was reserved above)
|
||||||
dll_list_pos = 0; // poison pill, prevent further calls
|
ver_list_pos = 0; // poison pill, prevent further calls
|
||||||
WARN_RETURN(ERR::BUF_SIZE);
|
WARN_RETURN(ERR::BUF_SIZE);
|
||||||
}
|
}
|
@ -1,26 +1,26 @@
|
|||||||
/**
|
/**
|
||||||
* =========================================================================
|
* =========================================================================
|
||||||
* File : dll_ver.h
|
* File : wdll_ver.h
|
||||||
* Project : 0 A.D.
|
* Project : 0 A.D.
|
||||||
* Description : return DLL version information.
|
* Description : return DLL version information
|
||||||
* =========================================================================
|
* =========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// license: GPL; see lib/license.txt
|
// license: GPL; see lib/license.txt
|
||||||
|
|
||||||
#ifndef INCLUDED_DLL_VER
|
#ifndef INCLUDED_WDLL_VER
|
||||||
#define INCLUDED_DLL_VER
|
#define INCLUDED_WDLL_VER
|
||||||
|
|
||||||
// note: this module is not re-entrant or thread-safe!
|
// WARNING: not re-entrant or thread-safe!
|
||||||
|
|
||||||
// set output buffer into which DLL names and their versions will be written.
|
// set output buffer into which DLL names and their versions will be written.
|
||||||
extern void dll_list_init(char* buf, size_t chars);
|
extern void wdll_ver_list_init(char* buf, size_t chars);
|
||||||
|
|
||||||
// read DLL file version and append that and its name to the list.
|
// read DLL file version and append that and its name to the list.
|
||||||
//
|
//
|
||||||
// name should preferably be the complete path to DLL, to make sure
|
// name should preferably be the complete path to DLL, to make sure
|
||||||
// we don't inadvertently load another one on the library search path.
|
// we don't inadvertently load another one on the library search path.
|
||||||
// we add the .dll extension if necessary.
|
// we add the .dll extension if necessary.
|
||||||
extern LibError dll_list_add(const char* name);
|
extern LibError wdll_ver_list_add(const char* name);
|
||||||
|
|
||||||
#endif // #ifndef INCLUDED_DLL_VER
|
#endif // #ifndef INCLUDED_WDLL_VER
|
@ -11,7 +11,7 @@
|
|||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
#include "lib/sysdep/gfx.h"
|
#include "lib/sysdep/gfx.h"
|
||||||
|
|
||||||
#include "dll_ver.h" // dll_list_*
|
#include "wdll_ver.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
|
||||||
#if MSC_VERSION
|
#if MSC_VERSION
|
||||||
@ -145,7 +145,7 @@ static LibError win_get_gfx_drv_ver()
|
|||||||
DWORD i;
|
DWORD i;
|
||||||
char drv_name[MAX_PATH+1];
|
char drv_name[MAX_PATH+1];
|
||||||
|
|
||||||
dll_list_init(gfx_drv_ver, GFX_DRV_VER_LEN);
|
wdll_ver_list_init(gfx_drv_ver, GFX_DRV_VER_LEN);
|
||||||
|
|
||||||
HKEY hkOglDrivers;
|
HKEY hkOglDrivers;
|
||||||
const char* key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
|
const char* key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
|
||||||
@ -166,7 +166,7 @@ static LibError win_get_gfx_drv_ver()
|
|||||||
{
|
{
|
||||||
DWORD drv_name_len = ARRAY_SIZE(drv_name)-5; // for ".dll"
|
DWORD drv_name_len = ARRAY_SIZE(drv_name)-5; // for ".dll"
|
||||||
if(RegQueryValueEx(hkSet, "Dll", 0, 0, (LPBYTE)drv_name, &drv_name_len) == 0)
|
if(RegQueryValueEx(hkSet, "Dll", 0, 0, (LPBYTE)drv_name, &drv_name_len) == 0)
|
||||||
ret = dll_list_add(drv_name);
|
ret = wdll_ver_list_add(drv_name);
|
||||||
|
|
||||||
RegCloseKey(hkSet);
|
RegCloseKey(hkSet);
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ static LibError win_get_gfx_drv_ver()
|
|||||||
if(err != ERROR_SUCCESS) // error or no more items - bail
|
if(err != ERROR_SUCCESS) // error or no more items - bail
|
||||||
break;
|
break;
|
||||||
if(type == REG_SZ)
|
if(type == REG_SZ)
|
||||||
ret = dll_list_add(drv_name);
|
ret = wdll_ver_list_add(drv_name);
|
||||||
} // for each value
|
} // for each value
|
||||||
|
|
||||||
RegCloseKey(hkOglDrivers);
|
RegCloseKey(hkOglDrivers);
|
||||||
|
@ -28,11 +28,11 @@
|
|||||||
// insert a case in ConstructCounterAt's switch statement.
|
// insert a case in ConstructCounterAt's switch statement.
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(D) // wposix depends on us
|
#pragma SECTION_INIT(4) // wposix depends on us
|
||||||
WIN_REGISTER_FUNC(whrt_Init);
|
WINIT_REGISTER_FUNC(whrt_Init);
|
||||||
#pragma FORCE_INCLUDE(whrt_Init)
|
#pragma FORCE_INCLUDE(whrt_Init)
|
||||||
#pragma SECTION_POST_ATEXIT(V)
|
#pragma SECTION_SHUTDOWN(8)
|
||||||
WIN_REGISTER_FUNC(whrt_Shutdown);
|
WINIT_REGISTER_FUNC(whrt_Shutdown);
|
||||||
#pragma FORCE_INCLUDE(whrt_Shutdown)
|
#pragma FORCE_INCLUDE(whrt_Shutdown)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -15,24 +15,23 @@
|
|||||||
typedef LibError (*PfnLibErrorVoid)(void);
|
typedef LibError (*PfnLibErrorVoid)(void);
|
||||||
|
|
||||||
// pointers to start and end of function tables.
|
// pointers to start and end of function tables.
|
||||||
// note: COFF tosses out empty segments, so we have to put in one value
|
// notes:
|
||||||
// (zero, because CallFunctionPointers has to ignore entries =0 anyway).
|
// - COFF tosses out empty segments, so we have to put in one value
|
||||||
#pragma SECTION_PRE_LIBC(A)
|
// (zero, because CallFunctionPointers has to ignore entries =0 anyway).
|
||||||
PfnLibErrorVoid pre_libc_begin = 0;
|
// - ASCII '$' and 'Z' come before resp. after '0'..'9', so use that to
|
||||||
#pragma SECTION_PRE_LIBC(Z)
|
// bound the section names.
|
||||||
PfnLibErrorVoid pre_libc_end = 0;
|
#pragma SECTION_INIT($)
|
||||||
#pragma SECTION_PRE_MAIN(A)
|
PfnLibErrorVoid initBegin = 0;
|
||||||
PfnLibErrorVoid pre_main_begin = 0;
|
#pragma SECTION_INIT(Z)
|
||||||
#pragma SECTION_PRE_MAIN(Z)
|
PfnLibErrorVoid initEnd = 0;
|
||||||
PfnLibErrorVoid pre_main_end = 0;
|
#pragma SECTION_SHUTDOWN($)
|
||||||
#pragma SECTION_POST_ATEXIT(A)
|
PfnLibErrorVoid shutdownBegin = 0;
|
||||||
PfnLibErrorVoid shutdown_begin = 0;
|
#pragma SECTION_SHUTDOWN(Z)
|
||||||
#pragma SECTION_POST_ATEXIT(Z)
|
PfnLibErrorVoid shutdownEnd = 0;
|
||||||
PfnLibErrorVoid shutdown_end = 0;
|
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
// note: /include is not necessary, since these are referenced below.
|
// note: /include is not necessary, since these are referenced below.
|
||||||
|
|
||||||
#pragma comment(linker, "/merge:.LIB=.data")
|
#pragma comment(linker, "/merge:.WINIT=.data")
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,17 +52,12 @@ static void CallFunctionPointers(PfnLibErrorVoid* begin, PfnLibErrorVoid* end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void winit_CallPreLibcFunctions()
|
void winit_CallInitFunctions()
|
||||||
{
|
{
|
||||||
CallFunctionPointers(&pre_libc_begin, &pre_libc_end);
|
CallFunctionPointers(&initBegin, &initEnd);
|
||||||
}
|
|
||||||
|
|
||||||
void winit_CallPreMainFunctions()
|
|
||||||
{
|
|
||||||
CallFunctionPointers(&pre_main_begin, &pre_main_end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void winit_CallShutdownFunctions()
|
void winit_CallShutdownFunctions()
|
||||||
{
|
{
|
||||||
CallFunctionPointers(&shutdown_begin, &shutdown_end);
|
CallFunctionPointers(&shutdownBegin, &shutdownEnd);
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
#ifndef INCLUDED_WINIT
|
#ifndef INCLUDED_WINIT
|
||||||
#define INCLUDED_WINIT
|
#define INCLUDED_WINIT
|
||||||
|
|
||||||
// register functions to be called before libc init, before main,
|
|
||||||
// or after atexit.
|
|
||||||
//
|
|
||||||
// overview:
|
// overview:
|
||||||
// participating modules store function pointer(s) to their init and/or
|
// participating modules store function pointer(s) to their init and/or
|
||||||
// shutdown function in a specific COFF section. the sections are
|
// shutdown function in a specific COFF section. the sections are
|
||||||
@ -26,21 +23,18 @@
|
|||||||
//
|
//
|
||||||
// details:
|
// details:
|
||||||
// the section names are of the format ".LIB${type}{group}".
|
// the section names are of the format ".LIB${type}{group}".
|
||||||
// {type} is C for pre-libc init, I for pre-main init, or
|
// {type} is I for initialization- or S for shutdown functions.
|
||||||
// T for terminators (last of the atexit handlers).
|
// {group} is [0, 9]; all functions in a group are called before those of
|
||||||
// {group} is [B, Y]; all functions in a group are called before those of
|
// the next higher group, but order within the group is undefined.
|
||||||
// the next (alphabetically) higher group, but order within the group is
|
// (this is because the linker sorts sections alphabetically but doesn't
|
||||||
// undefined. this is because the linker sorts sections alphabetically,
|
// specify the order in which object files are processed.)
|
||||||
// but doesn't specify the order in which object files are processed.
|
|
||||||
// another consequence is that groups A and Z must not be used!
|
|
||||||
// (data placed there might end up outside the start/end markers)
|
|
||||||
//
|
//
|
||||||
// example:
|
// example:
|
||||||
// #pragma SECTION_PRE_LIBC(G))
|
// #pragma SECTION_INIT(7))
|
||||||
// WIN_REGISTER_FUNC(wtime_init);
|
// WINIT_REGISTER_FUNC(wtime_init);
|
||||||
// #pragma FORCE_INCLUDE(wtime_init)
|
// #pragma FORCE_INCLUDE(wtime_init)
|
||||||
// #pragma SECTION_POST_ATEXIT(D))
|
// #pragma SECTION_SHUTDOWN(3))
|
||||||
// WIN_REGISTER_FUNC(wtime_shutdown);
|
// WINIT_REGISTER_FUNC(wtime_shutdown);
|
||||||
// #pragma FORCE_INCLUDE(wtime_shutdown)
|
// #pragma FORCE_INCLUDE(wtime_shutdown)
|
||||||
// #pragma SECTION_RESTORE
|
// #pragma SECTION_RESTORE
|
||||||
//
|
//
|
||||||
@ -50,7 +44,7 @@
|
|||||||
// if init already happened. that would be brittle and hard to verify.
|
// if init already happened. that would be brittle and hard to verify.
|
||||||
// - singleton: variant of the above, but not applicable to a
|
// - singleton: variant of the above, but not applicable to a
|
||||||
// procedural interface (and quite ugly to boot).
|
// procedural interface (and quite ugly to boot).
|
||||||
// - registration: NLSO constructors call a central notification function.
|
// - registration: static constructors call a central notification function.
|
||||||
// module dependencies would be quite difficult to express - this would
|
// module dependencies would be quite difficult to express - this would
|
||||||
// require a graph or separate lists for each priority (clunky).
|
// require a graph or separate lists for each priority (clunky).
|
||||||
// worse, a fatal flaw is that other C++ constructors may depend on the
|
// worse, a fatal flaw is that other C++ constructors may depend on the
|
||||||
@ -68,23 +62,21 @@
|
|||||||
// notes:
|
// notes:
|
||||||
// - #pragma cannot be packaged in macros due to expansion rules.
|
// - #pragma cannot be packaged in macros due to expansion rules.
|
||||||
// - __declspec(allocate) would be tempting, since that could be
|
// - __declspec(allocate) would be tempting, since that could be
|
||||||
// wrapped in WIN_REGISTER_FUNC. unfortunately it inexplicably cannot
|
// wrapped in WINIT_REGISTER_FUNC. unfortunately it inexplicably cannot
|
||||||
// cope with split string literals (e.g. "ab" "c"). that disqualifies
|
// cope with split string literals (e.g. "ab" "c"). that disqualifies
|
||||||
// it, since we want to hide the section name behind a macro, which
|
// it, since we want to hide the section name behind a macro, which
|
||||||
// would require the abovementioned merging.
|
// would require the abovementioned merging.
|
||||||
|
|
||||||
// note: the purpose of pre-libc init (with the resulting requirement that
|
// note: init functions are called before _cinit and MUST NOT use
|
||||||
// no CRT functions be used during init!) is to allow the use of the
|
// any stateful CRT functions (e.g. atexit)!
|
||||||
// initialized module in static ctors.
|
#define SECTION_INIT(group) data_seg(".WINIT$I" #group)
|
||||||
#define SECTION_PRE_LIBC(group) data_seg(".LIB$C" #group)
|
#define SECTION_SHUTDOWN(group) data_seg(".WINIT$S" #group)
|
||||||
#define SECTION_PRE_MAIN(group) data_seg(".LIB$I" #group)
|
|
||||||
#define SECTION_POST_ATEXIT(group) data_seg(".LIB$T" #group)
|
|
||||||
#define SECTION_RESTORE data_seg()
|
#define SECTION_RESTORE data_seg()
|
||||||
// use to make sure the link-stage optimizer doesn't discard the
|
// use to make sure the link-stage optimizer doesn't discard the
|
||||||
// function pointers (happens on VC8)
|
// function pointers (happens on VC8)
|
||||||
#define FORCE_INCLUDE(id) comment(linker, "/include:_p"#id)
|
#define FORCE_INCLUDE(id) comment(linker, "/include:_p"#id)
|
||||||
|
|
||||||
#define WIN_REGISTER_FUNC(func)\
|
#define WINIT_REGISTER_FUNC(func)\
|
||||||
static LibError func(void);\
|
static LibError func(void);\
|
||||||
EXTERN_C LibError (*p##func)(void) = func
|
EXTERN_C LibError (*p##func)(void) = func
|
||||||
|
|
||||||
@ -92,8 +84,7 @@
|
|||||||
* call each registered function.
|
* call each registered function.
|
||||||
* these are invoked by wstartup at the appropriate times.
|
* these are invoked by wstartup at the appropriate times.
|
||||||
**/
|
**/
|
||||||
extern void winit_CallPreLibcFunctions();
|
extern void winit_CallInitFunctions();
|
||||||
extern void winit_CallPreMainFunctions();
|
|
||||||
extern void winit_CallShutdownFunctions();
|
extern void winit_CallShutdownFunctions();
|
||||||
|
|
||||||
#endif // #ifndef INCLUDED_WINIT
|
#endif // #ifndef INCLUDED_WINIT
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
#include "lib/bits.h"
|
#include "lib/bits.h"
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(J)
|
#pragma SECTION_INIT(5)
|
||||||
WIN_REGISTER_FUNC(waio_init);
|
WINIT_REGISTER_FUNC(waio_init);
|
||||||
#pragma FORCE_INCLUDE(waio_init)
|
#pragma FORCE_INCLUDE(waio_init)
|
||||||
#pragma SECTION_POST_ATEXIT(D)
|
#pragma SECTION_SHUTDOWN(5)
|
||||||
WIN_REGISTER_FUNC(waio_shutdown);
|
WINIT_REGISTER_FUNC(waio_shutdown);
|
||||||
#pragma FORCE_INCLUDE(waio_shutdown)
|
#pragma FORCE_INCLUDE(waio_shutdown)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
#include "lib/bits.h"
|
#include "lib/bits.h"
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(J)
|
#pragma SECTION_INIT(5)
|
||||||
WIN_REGISTER_FUNC(wposix_Init);
|
WINIT_REGISTER_FUNC(wposix_Init);
|
||||||
#pragma FORCE_INCLUDE(wposix_Init)
|
#pragma FORCE_INCLUDE(wposix_Init)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -11,103 +11,115 @@
|
|||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
#include "wsock.h"
|
#include "wsock.h"
|
||||||
|
|
||||||
#include "../delay_load.h"
|
#include "lib/sysdep/win/wdll_delay_load.h"
|
||||||
#include "wposix_internal.h"
|
#include "wposix_internal.h"
|
||||||
#include "wsock_internal.h"
|
#include "wsock_internal.h"
|
||||||
|
#include "lib/module_init.h"
|
||||||
|
|
||||||
#if MSC_VERSION
|
#if MSC_VERSION
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_MAIN(K)
|
#pragma SECTION_INIT(5)
|
||||||
WIN_REGISTER_FUNC(wsock_init);
|
WINIT_REGISTER_FUNC(wsock_init);
|
||||||
#pragma FORCE_INCLUDE(wsock_init)
|
#pragma FORCE_INCLUDE(wsock_init)
|
||||||
#pragma SECTION_POST_ATEXIT(D)
|
#pragma SECTION_SHUTDOWN(5)
|
||||||
WIN_REGISTER_FUNC(wsock_shutdown);
|
WINIT_REGISTER_FUNC(wsock_shutdown);
|
||||||
#pragma FORCE_INCLUDE(wsock_shutdown)
|
#pragma FORCE_INCLUDE(wsock_shutdown)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t htons(uint16_t s)
|
||||||
|
{
|
||||||
|
return (s >> 8) | ((s & 0xff) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
// IPv6 globals
|
// IPv6 globals
|
||||||
// These are included in the linux C libraries and in newer platform SDKs,
|
// These are included in the linux C libraries and in newer platform SDKs,
|
||||||
// so should only be needed in VC++6 or earlier.
|
// so should only be needed in VC++6 or earlier.
|
||||||
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; // ::
|
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; // ::
|
||||||
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; // ::_1
|
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; // ::_1
|
||||||
|
|
||||||
static HMODULE hWs2_32Dll;
|
|
||||||
static int dll_refs;
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// manual import of certain functions
|
||||||
|
|
||||||
|
// don't delay-load because we don't want to require these functions to be
|
||||||
|
// present. the user must be able to check if they are available (currently,
|
||||||
|
// on Win2k with IPv6 update or WinXP). can't use compile-time HAVE_* to
|
||||||
|
// make that decision because we don't want to distribute a separate EXE.
|
||||||
|
|
||||||
|
// function pointers, automatically initialized before any use of ws2_32.dll
|
||||||
|
static int (WINAPI *pgetnameinfo)(const struct sockaddr*, socklen_t, char*, socklen_t, char*, socklen_t, unsigned int);
|
||||||
|
static int (WINAPI *pgetaddrinfo)(const char*, const char*, const struct addrinfo*, struct addrinfo**);
|
||||||
|
static void (WINAPI *pfreeaddrinfo)(struct addrinfo*);
|
||||||
|
|
||||||
|
static HMODULE hWs2_32Dll;
|
||||||
|
|
||||||
|
static void ImportOptionalFunctions()
|
||||||
|
{
|
||||||
|
*(void**)&pgetnameinfo = GetProcAddress(hWs2_32Dll, "getnameinfo");
|
||||||
|
*(void**)&pgetaddrinfo = GetProcAddress(hWs2_32Dll, "getaddrinfo");
|
||||||
|
*(void**)&pfreeaddrinfo = GetProcAddress(hWs2_32Dll, "freeaddrinfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, unsigned int flags)
|
||||||
|
{
|
||||||
|
return pgetnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getaddrinfo(const char* nodename, const char* servname, const struct addrinfo* hints, struct addrinfo** res)
|
||||||
|
{
|
||||||
|
return pgetaddrinfo(nodename, servname, hints, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeaddrinfo(struct addrinfo* ai)
|
||||||
|
{
|
||||||
|
pfreeaddrinfo(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static ModuleInitState initState;
|
||||||
|
|
||||||
// called from delay loader the first time a wsock function is called
|
// called from delay loader the first time a wsock function is called
|
||||||
// (shortly before the actual wsock function is called).
|
// (shortly before the actual wsock function is called).
|
||||||
static LibError wsock_actual_init()
|
static LibError wsock_actual_init()
|
||||||
{
|
{
|
||||||
|
if(!ModuleShouldInitialize(&initState))
|
||||||
|
return INFO::OK;
|
||||||
|
|
||||||
hWs2_32Dll = LoadLibrary("ws2_32.dll");
|
hWs2_32Dll = LoadLibrary("ws2_32.dll");
|
||||||
|
|
||||||
// first time: call WSAStartup
|
char d[1024];
|
||||||
if(!dll_refs++)
|
int ret = WSAStartup(0x0002, d); // want 2.0
|
||||||
{
|
debug_assert(ret == 0);
|
||||||
char d[1024];
|
|
||||||
if(WSAStartup(0x0002, d) != 0) // want 2.0
|
ImportOptionalFunctions();
|
||||||
debug_warn("WSAStartup failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// called via module init mechanism. triggers wsock_actual_init when
|
|
||||||
// someone first calls a wsock function.
|
|
||||||
static LibError wsock_init()
|
static LibError wsock_init()
|
||||||
{
|
{
|
||||||
WDLL_LOAD_NOTIFY("ws2_32", wsock_actual_init);
|
// trigger wsock_actual_init when someone first calls a wsock function.
|
||||||
|
static WdllLoadNotify loadNotify = { "ws2_32", wsock_actual_init };
|
||||||
|
wdll_add_notify(&loadNotify);
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static LibError wsock_shutdown()
|
static LibError wsock_shutdown()
|
||||||
{
|
{
|
||||||
// call WSACleanup if DLL was used
|
if(!ModuleShouldShutdown(&initState))
|
||||||
// (this way is easier to understand than ONCE in loop below)
|
return INFO::OK;
|
||||||
if(dll_refs > 0)
|
|
||||||
if(WSACleanup() < 0)
|
|
||||||
debug_warn("WSACleanup failed");
|
|
||||||
|
|
||||||
// remove all references
|
int ret = WSACleanup();
|
||||||
while(dll_refs-- > 0)
|
debug_assert(ret >= 0);
|
||||||
FreeLibrary(hWs2_32Dll);
|
|
||||||
|
FreeLibrary(hWs2_32Dll);
|
||||||
|
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// manual import instead of delay-load because we don't want to require
|
|
||||||
// these functions to be present. the user must be able to check if they
|
|
||||||
// are available (currently, on Win2k with IPv6 update or WinXP).
|
|
||||||
// can't use compile-time HAVE_* to make that decision because
|
|
||||||
// we don't want to distribute a separate binary for this.
|
|
||||||
//
|
|
||||||
// note: can't import at startup because we don't want to load wsock unless necessary
|
|
||||||
// don't use delay load because we don't want to confuse error handling for other users
|
|
||||||
//
|
|
||||||
// don't bother caching - these functions themselves take a while and aren't time-critical
|
|
||||||
|
|
||||||
static void* import(const char* name)
|
|
||||||
{
|
|
||||||
return GetProcAddress(hWs2_32Dll, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_getnameinfo_t import_getnameinfo() { return (fp_getnameinfo_t )import("getnameinfo" ); }
|
|
||||||
fp_getaddrinfo_t import_getaddrinfo() { return (fp_getaddrinfo_t )import("getaddrinfo" ); }
|
|
||||||
fp_freeaddrinfo_t import_freeaddrinfo() { return (fp_freeaddrinfo_t)import("freeaddrinfo"); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t htons(uint16_t s)
|
|
||||||
{
|
|
||||||
return (s >> 8) | ((s & 0xff) << 8);
|
|
||||||
}
|
|
||||||
|
@ -156,8 +156,8 @@ struct addrinfo
|
|||||||
int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
|
int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
|
||||||
size_t ai_addrlen; // Length of ai_addr
|
size_t ai_addrlen; // Length of ai_addr
|
||||||
char *ai_canonname; // Canonical name for nodename
|
char *ai_canonname; // Canonical name for nodename
|
||||||
struct sockaddr *ai_addr; // Binary address
|
struct sockaddr* ai_addr; // Binary address
|
||||||
struct addrinfo *ai_next; // Next structure in linked list
|
struct addrinfo* ai_next; // Next structure in linked list
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hint flags for getaddrinfo
|
// Hint flags for getaddrinfo
|
||||||
@ -169,22 +169,9 @@ struct addrinfo
|
|||||||
#define NI_MAXHOST 1025
|
#define NI_MAXHOST 1025
|
||||||
#define NI_MAXSERV 32
|
#define NI_MAXSERV 32
|
||||||
|
|
||||||
// Note that these are function pointers. They will be initialized by the
|
extern int getnameinfo(const struct sockaddr*, socklen_t, char*, socklen_t, char*, socklen_t, unsigned int);
|
||||||
// wsock_init in wsock.cpp
|
extern int getaddrinfo(const char*, const char*, const struct addrinfo*, struct addrinfo**);
|
||||||
typedef int (__stdcall *fp_getnameinfo_t)(const struct sockaddr *sa, socklen_t salen, char *node,
|
extern void freeaddrinfo(struct addrinfo*);
|
||||||
socklen_t nodelen, char *serv, socklen_t servlen, unsigned int flags);
|
|
||||||
typedef int (__stdcall *fp_getaddrinfo_t)(const char *nodename, const char *servname,
|
|
||||||
const struct addrinfo *hints, struct addrinfo **res);
|
|
||||||
typedef void (__stdcall *fp_freeaddrinfo_t)(struct addrinfo *ai);
|
|
||||||
|
|
||||||
extern fp_getnameinfo_t import_getnameinfo();
|
|
||||||
extern fp_getaddrinfo_t import_getaddrinfo();
|
|
||||||
extern fp_freeaddrinfo_t import_freeaddrinfo();
|
|
||||||
|
|
||||||
#define getnameinfo (import_getnameinfo())
|
|
||||||
#define getaddrinfo (import_getaddrinfo())
|
|
||||||
#define freeaddrinfo (import_freeaddrinfo())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// getaddr/nameinfo error codes
|
// getaddr/nameinfo error codes
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
#include "lib/sysdep/win/whrt/whrt.h"
|
#include "lib/sysdep/win/whrt/whrt.h"
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(M) // late; dependent on whrt
|
#pragma SECTION_INIT(7) // depends on whrt
|
||||||
WIN_REGISTER_FUNC(wtime_Init);
|
WINIT_REGISTER_FUNC(wtime_Init);
|
||||||
#pragma FORCE_INCLUDE(wtime_Init)
|
#pragma FORCE_INCLUDE(wtime_Init)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "lib/posix/posix_pthread.h"
|
#include "lib/posix/posix_pthread.h"
|
||||||
#include "lib/ogl.h" // needed to pull in the delay-loaded opengl32.dll
|
#include "lib/ogl.h" // needed to pull in the delay-loaded opengl32.dll
|
||||||
#include "winit.h"
|
#include "lib/module_init.h"
|
||||||
#include "wutil.h"
|
#include "wutil.h"
|
||||||
|
|
||||||
|
|
||||||
@ -43,16 +43,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_MAIN(K)
|
|
||||||
WIN_REGISTER_FUNC(wsdl_init);
|
|
||||||
#pragma FORCE_INCLUDE(wsdl_init)
|
|
||||||
#pragma SECTION_POST_ATEXIT(D)
|
|
||||||
WIN_REGISTER_FUNC(wsdl_shutdown);
|
|
||||||
#pragma FORCE_INCLUDE(wsdl_shutdown)
|
|
||||||
#pragma SECTION_RESTORE
|
|
||||||
|
|
||||||
|
|
||||||
// in fullscreen mode, i.e. not windowed.
|
// in fullscreen mode, i.e. not windowed.
|
||||||
// video mode will be restored when app is deactivated.
|
// video mode will be restored when app is deactivated.
|
||||||
static bool fullscreen;
|
static bool fullscreen;
|
||||||
@ -1303,16 +1293,26 @@ inline void* SDL_GL_GetProcAddress(const char* name)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// init/shutdown
|
// init/shutdown
|
||||||
|
|
||||||
static LibError wsdl_init()
|
// note: winit no longer supports pre-main init since that requires users
|
||||||
|
// to manually call an init function at the start of main() (unreliable).
|
||||||
|
// we do all init in SDL_Init, which means that any printfs before then
|
||||||
|
// are lost. oh well.
|
||||||
|
|
||||||
|
// defend against calling SDL_Quit twice (GameSetup does this to work
|
||||||
|
// around ATI driver breakage)
|
||||||
|
static ModuleInitState initState;
|
||||||
|
|
||||||
|
int SDL_Init(Uint32 UNUSED(flags))
|
||||||
{
|
{
|
||||||
|
if(!ModuleShouldInitialize(&initState))
|
||||||
|
return 0;
|
||||||
|
|
||||||
hInst = GetModuleHandle(0);
|
hInst = GetModuleHandle(0);
|
||||||
|
|
||||||
// redirect stdout to file (otherwise it's simply ignored on Win32).
|
// redirect stdout to file (otherwise it's simply ignored on Win32).
|
||||||
// notes:
|
// notes:
|
||||||
// - use full path for safety (works even if someone does chdir)
|
// - use full path for safety (works even if someone does chdir)
|
||||||
// - SDL does this in its WinMain hook. we need to do this here
|
// - SDL does this in its WinMain hook; see note above.
|
||||||
// (before main is called) instead of in SDL_Init to completely
|
|
||||||
// emulate SDL; bonus: we don't miss any output before SDL_Init.
|
|
||||||
char path[MAX_PATH];
|
char path[MAX_PATH];
|
||||||
snprintf(path, ARRAY_SIZE(path), "%s\\stdout.txt", win_exe_dir);
|
snprintf(path, ARRAY_SIZE(path), "%s\\stdout.txt", win_exe_dir);
|
||||||
// ignore BoundsChecker warnings here. subsystem is set to "Windows"
|
// ignore BoundsChecker warnings here. subsystem is set to "Windows"
|
||||||
@ -1320,8 +1320,7 @@ static LibError wsdl_init()
|
|||||||
// stdout isn't associated with a lowio handle; _close ends up
|
// stdout isn't associated with a lowio handle; _close ends up
|
||||||
// getting called with fd = -1. oh well, nothing we can do.
|
// getting called with fd = -1. oh well, nothing we can do.
|
||||||
FILE* f = freopen(path, "wt", stdout);
|
FILE* f = freopen(path, "wt", stdout);
|
||||||
if(!f)
|
debug_assert(f);
|
||||||
debug_warn("stdout freopen failed");
|
|
||||||
|
|
||||||
#if CONFIG_PARANOIA
|
#if CONFIG_PARANOIA
|
||||||
// disable buffering, so that no writes are lost even if the program
|
// disable buffering, so that no writes are lost even if the program
|
||||||
@ -1331,12 +1330,14 @@ static LibError wsdl_init()
|
|||||||
|
|
||||||
enable_kbd_hook(true);
|
enable_kbd_hook(true);
|
||||||
|
|
||||||
return INFO::OK;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDL_Quit()
|
||||||
static LibError wsdl_shutdown()
|
|
||||||
{
|
{
|
||||||
|
if(!ModuleShouldShutdown(&initState))
|
||||||
|
return;
|
||||||
|
|
||||||
is_shutdown = true;
|
is_shutdown = true;
|
||||||
|
|
||||||
// redirected to stdout.txt in SDL_Init;
|
// redirected to stdout.txt in SDL_Init;
|
||||||
@ -1348,19 +1349,4 @@ static LibError wsdl_shutdown()
|
|||||||
video_shutdown();
|
video_shutdown();
|
||||||
|
|
||||||
enable_kbd_hook(false);
|
enable_kbd_hook(false);
|
||||||
|
|
||||||
return INFO::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// these are placebos. since some init needs to happen before main(),
|
|
||||||
// we take care of it all in the module init/shutdown hooks.
|
|
||||||
|
|
||||||
int SDL_Init(Uint32 UNUSED(flags))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL_Quit()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "lib/path_util.h"
|
#include "lib/path_util.h"
|
||||||
#include "lib/res/file/file.h"
|
#include "lib/res/file/file.h"
|
||||||
#include "dll_ver.h" // dll_list_*
|
#include "wdll_ver.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "wutil.h"
|
#include "wutil.h"
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ typedef std::set<std::string> StringSet;
|
|||||||
// <dir>: no trailing.
|
// <dir>: no trailing.
|
||||||
static LibError add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
|
static LibError add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
|
||||||
{
|
{
|
||||||
// note: dll_list_add requires the full DLL path but DirEnt only gives us
|
// note: wdll_ver_list_add requires the full DLL path but DirEnt only gives us
|
||||||
// the name. for efficiency, we append this via PathPackage.
|
// the name. for efficiency, we append this via PathPackage.
|
||||||
PathPackage pp;
|
PathPackage pp;
|
||||||
RETURN_ERR(path_package_set_dir(&pp, dir));
|
RETURN_ERR(path_package_set_dir(&pp, dir));
|
||||||
@ -71,13 +71,13 @@ static LibError add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
|
|||||||
if(!IsOpenAlDll(&ent))
|
if(!IsOpenAlDll(&ent))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// already in StringSet (i.e. has already been dll_list_add-ed)
|
// already in StringSet (i.e. has already been wdll_ver_list_add-ed)
|
||||||
std::pair<StringSet::iterator, bool> ret = dlls->insert(ent.name);
|
std::pair<StringSet::iterator, bool> ret = dlls->insert(ent.name);
|
||||||
if(!ret.second) // insert failed - element already there
|
if(!ret.second) // insert failed - element already there
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
(void)path_package_append_file(&pp, ent.name);
|
(void)path_package_append_file(&pp, ent.name);
|
||||||
(void)dll_list_add(pp.path);
|
(void)wdll_ver_list_add(pp.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)dir_close(&d);
|
(void)dir_close(&d);
|
||||||
@ -140,9 +140,9 @@ LibError win_get_snd_info()
|
|||||||
{
|
{
|
||||||
// find all DLLs related to OpenAL, retrieve their versions,
|
// find all DLLs related to OpenAL, retrieve their versions,
|
||||||
// and store in snd_drv_ver string.
|
// and store in snd_drv_ver string.
|
||||||
dll_list_init(snd_drv_ver, SND_DRV_VER_LEN);
|
wdll_ver_list_init(snd_drv_ver, SND_DRV_VER_LEN);
|
||||||
if(!wutil_IsVista())
|
if(!wutil_IsVista())
|
||||||
(void)dll_list_add(GetDirectSoundDriverPath());
|
(void)wdll_ver_list_add(GetDirectSoundDriverPath());
|
||||||
StringSet dlls; // ensures uniqueness
|
StringSet dlls; // ensures uniqueness
|
||||||
(void)add_oal_dlls_in_dir(win_exe_dir, &dlls);
|
(void)add_oal_dlls_in_dir(win_exe_dir, &dlls);
|
||||||
(void)add_oal_dlls_in_dir(win_sys_dir, &dlls);
|
(void)add_oal_dlls_in_dir(win_sys_dir, &dlls);
|
||||||
|
@ -8,39 +8,90 @@
|
|||||||
|
|
||||||
// license: GPL; see lib/license.txt
|
// license: GPL; see lib/license.txt
|
||||||
|
|
||||||
|
// this module can wrap the program in a SEH __try block and takes care of
|
||||||
|
// calling winit's functions at the appropriate times.
|
||||||
|
// to use it, set Linker Options -> Advanced -> Entry Point to
|
||||||
|
// "entry" (without quotes).
|
||||||
|
//
|
||||||
|
// besides commandeering the entry point, it hooks ExitProcess.
|
||||||
|
// control flow overview: entry [-> RunWithinTryBlock] -> InitAndCallMain ->
|
||||||
|
// (init) -> mainCRTStartup -> main -> exit -> HookedExitProcess ->
|
||||||
|
// (shutdown) -> ExitProcess.
|
||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
#include "wstartup.h"
|
#include "wstartup.h"
|
||||||
|
|
||||||
#include "winit.h"
|
#include "win.h"
|
||||||
#include "wdbg.h" // wdbg_exception_filter
|
#include <process.h> // __security_init_cookie
|
||||||
#include "win.h" // GetExceptionInformation
|
#include <detours.h>
|
||||||
|
|
||||||
#if MSC_VERSION >= 1400
|
#include "winit.h"
|
||||||
#include <process.h> // __security_init_cookie
|
#include "wdbg.h" // wdbg_exception_filter
|
||||||
#define NEED_COOKIE_INIT
|
|
||||||
|
|
||||||
|
#if MSC_VERSION
|
||||||
|
#pragma comment(lib, "detours.lib")
|
||||||
|
#pragma comment(lib, "detoured.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// this module is responsible for startup and triggering winit's calls to
|
|
||||||
// registered functions at the appropriate times. control flow overview:
|
|
||||||
// entry [-> RunWithinTryBlock] -> InitAndCallMain -> MainCRTStartup ->
|
|
||||||
// main -> wstartup_PreMainInit.
|
|
||||||
// our atexit handler is called as the last of them, provided constructors
|
|
||||||
// do not use atexit! (this requirement is documented)
|
|
||||||
//
|
|
||||||
// rationale: see declaration of wstartup_PreMainInit.
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// do shutdown at exit
|
||||||
|
|
||||||
void wstartup_PreMainInit()
|
// note: the alternative of using atexit has two disadvantages.
|
||||||
|
// - the call to atexit must come after _cinit, which means we'd need to be
|
||||||
|
// called manually from main (see discussion on init below)
|
||||||
|
// - other calls to atexit from ctors or hidden compiler-generated init code
|
||||||
|
// for static objects would cause those handlers to be called after ours,
|
||||||
|
// which may cause shutdown order bugs.
|
||||||
|
|
||||||
|
static VOID (WINAPI *RealExitProcess)(UINT uExitCode);
|
||||||
|
|
||||||
|
static VOID WINAPI HookedExitProcess(UINT uExitCode)
|
||||||
{
|
{
|
||||||
winit_CallPreMainFunctions();
|
winit_CallShutdownFunctions();
|
||||||
|
|
||||||
atexit(winit_CallShutdownFunctions);
|
RealExitProcess(uExitCode);
|
||||||
|
|
||||||
// no point redirecting stdout yet - the current directory
|
|
||||||
// may be incorrect (file_set_root not yet called).
|
|
||||||
// (w)sdl will take care of it anyway.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void InstallExitHook()
|
||||||
|
{
|
||||||
|
// (can't do this in a static initializer because they haven't run yet!)
|
||||||
|
RealExitProcess = ExitProcess;
|
||||||
|
|
||||||
|
DetourTransactionBegin();
|
||||||
|
DetourUpdateThread(GetCurrentThread());
|
||||||
|
DetourAttach(&(PVOID&)RealExitProcess, HookedExitProcess);
|
||||||
|
DetourTransactionCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// init
|
||||||
|
|
||||||
|
// the init functions need to be called before any use of Windows-specific
|
||||||
|
// code.
|
||||||
|
//
|
||||||
|
// one possibility is using WinMain as the entry point, and then calling the
|
||||||
|
// application's main(), but this is expressly forbidden by the C standard.
|
||||||
|
// VC apparently makes use of this and changes its calling convention.
|
||||||
|
// if we call it, everything appears to work but stack traces in
|
||||||
|
// release mode are incorrect (symbol address is off by 4).
|
||||||
|
//
|
||||||
|
// another alternative is re#defining the app's main function to app_main,
|
||||||
|
// having the OS call our main, and then dispatching to app_main.
|
||||||
|
// however, this leads to trouble when another library (e.g. SDL) wants to
|
||||||
|
// do the same.
|
||||||
|
// moreover, this file is compiled into a static library and used both for
|
||||||
|
// the 0ad executable as well as the separate self-test. this means
|
||||||
|
// we can't enable the main() hook for one and disable it in the other.
|
||||||
|
//
|
||||||
|
// requiring users to call us at the beginning of main is brittle in general
|
||||||
|
// and not possible with the self-test's auto-generated main file.
|
||||||
|
//
|
||||||
|
// the only alternative is to commandeer the entry point and do all init
|
||||||
|
// before calling mainCRTStartup. this means init will be finished before
|
||||||
|
// C++ static ctors run (allowing our APIs to be called from those ctors),
|
||||||
|
// but also denies init the use of any non-stateless CRT functions!
|
||||||
|
|
||||||
// these aren't defined in VC include files, so we have to do it manually.
|
// these aren't defined in VC include files, so we have to do it manually.
|
||||||
#ifdef USE_WINMAIN
|
#ifdef USE_WINMAIN
|
||||||
@ -53,10 +104,9 @@ EXTERN_C int mainCRTStartup(void);
|
|||||||
// entry and entry_noSEH)
|
// entry and entry_noSEH)
|
||||||
static int InitAndCallMain()
|
static int InitAndCallMain()
|
||||||
{
|
{
|
||||||
// perform all initialization that needs to run before _cinit
|
winit_CallInitFunctions();
|
||||||
// (i.e. when C++ ctors are called).
|
|
||||||
// be very careful to avoid non-stateless libc functions!
|
InstallExitHook();
|
||||||
winit_CallPreLibcFunctions();
|
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
#ifdef USE_WINMAIN
|
#ifdef USE_WINMAIN
|
||||||
@ -68,6 +118,9 @@ static int InitAndCallMain()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// entry point and SEH wrapper
|
||||||
|
|
||||||
typedef int(*PfnIntVoid)(void);
|
typedef int(*PfnIntVoid)(void);
|
||||||
|
|
||||||
static int RunWithinTryBlock(PfnIntVoid func)
|
static int RunWithinTryBlock(PfnIntVoid func)
|
||||||
@ -87,7 +140,7 @@ static int RunWithinTryBlock(PfnIntVoid func)
|
|||||||
|
|
||||||
int entry()
|
int entry()
|
||||||
{
|
{
|
||||||
#ifdef NEED_COOKIE_INIT
|
#if MSC_VERSION >= 1400
|
||||||
// 2006-02-16 workaround for R6035 on VC8:
|
// 2006-02-16 workaround for R6035 on VC8:
|
||||||
//
|
//
|
||||||
// SEH code compiled with /GS pushes a "security cookie" onto the
|
// SEH code compiled with /GS pushes a "security cookie" onto the
|
||||||
@ -111,7 +164,7 @@ int entry()
|
|||||||
// (e.g. unit tests, where it's better to let the debugger handle any errors)
|
// (e.g. unit tests, where it's better to let the debugger handle any errors)
|
||||||
int entry_noSEH()
|
int entry_noSEH()
|
||||||
{
|
{
|
||||||
#ifdef NEED_COOKIE_INIT
|
#if MSC_VERSION >= 1400
|
||||||
// see above. this is also necessary here in case pre-libc init
|
// see above. this is also necessary here in case pre-libc init
|
||||||
// functions use SEH.
|
// functions use SEH.
|
||||||
__security_init_cookie();
|
__security_init_cookie();
|
||||||
|
@ -11,34 +11,6 @@
|
|||||||
#ifndef INCLUDED_WSTARTUP
|
#ifndef INCLUDED_WSTARTUP
|
||||||
#define INCLUDED_WSTARTUP
|
#define INCLUDED_WSTARTUP
|
||||||
|
|
||||||
/**
|
|
||||||
* call at the beginning of main(). exact requirements: after _cinit AND
|
|
||||||
* before any use of sysdep/win/* or call to atexit.
|
|
||||||
*
|
|
||||||
* rationale:
|
|
||||||
* our Windows-specific init code needs to run before the rest of the
|
|
||||||
* main() code. ideally this would happen automagically.
|
|
||||||
* one possibility is using WinMain as the entry point, and then calling the
|
|
||||||
* application's main(), but this is expressly forbidden by the C standard.
|
|
||||||
* VC apparently makes use of this and changes its calling convention.
|
|
||||||
* if we call it, everything appears to work but stack traces in
|
|
||||||
* release mode are incorrect (symbol address is off by 4).
|
|
||||||
*
|
|
||||||
* another alternative is re#defining the app's main function to app_main,
|
|
||||||
* having the OS call our main, and then dispatching to app_main.
|
|
||||||
* however, this leads to trouble when another library (e.g. SDL) wants to
|
|
||||||
* do the same.
|
|
||||||
*
|
|
||||||
* moreover, this file is compiled into a static library and used both for
|
|
||||||
* the 0ad executable as well as the separate self-test. this means
|
|
||||||
* we can't enable the main() hook for one and disable it in the other.
|
|
||||||
*
|
|
||||||
* the consequence is that automatic init isn't viable. this is
|
|
||||||
* unfortunate because integration into new projects requires
|
|
||||||
* remembering to call the init function, but it can't be helped.
|
|
||||||
**/
|
|
||||||
extern void wstartup_PreMainInit();
|
|
||||||
|
|
||||||
// entry points (normal and without SEH wrapper; see definition)
|
// entry points (normal and without SEH wrapper; see definition)
|
||||||
EXTERN_C int entry();
|
EXTERN_C int entry();
|
||||||
EXTERN_C int entry_noSEH();
|
EXTERN_C int entry_noSEH();
|
||||||
|
@ -20,11 +20,11 @@
|
|||||||
#include "winit.h"
|
#include "winit.h"
|
||||||
|
|
||||||
|
|
||||||
#pragma SECTION_PRE_LIBC(B)
|
#pragma SECTION_INIT(1) // early, several modules depend on us
|
||||||
WIN_REGISTER_FUNC(wutil_PreLibcInit);
|
WINIT_REGISTER_FUNC(wutil_PreLibcInit);
|
||||||
#pragma FORCE_INCLUDE(wutil_PreLibcInit)
|
#pragma FORCE_INCLUDE(wutil_PreLibcInit)
|
||||||
#pragma SECTION_POST_ATEXIT(Y)
|
#pragma SECTION_SHUTDOWN(8)
|
||||||
WIN_REGISTER_FUNC(wutil_Shutdown);
|
WINIT_REGISTER_FUNC(wutil_Shutdown);
|
||||||
#pragma FORCE_INCLUDE(wutil_Shutdown)
|
#pragma FORCE_INCLUDE(wutil_Shutdown)
|
||||||
#pragma SECTION_RESTORE
|
#pragma SECTION_RESTORE
|
||||||
|
|
||||||
|
@ -13,9 +13,6 @@
|
|||||||
#include "lib/res/sound/snd_mgr.h"
|
#include "lib/res/sound/snd_mgr.h"
|
||||||
#include "lib/res/graphics/tex.h"
|
#include "lib/res/graphics/tex.h"
|
||||||
#include "lib/res/graphics/cursor.h"
|
#include "lib/res/graphics/cursor.h"
|
||||||
#if OS_WIN
|
|
||||||
# include "lib/sysdep/win/wstartup.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ps/CConsole.h"
|
#include "ps/CConsole.h"
|
||||||
#include "ps/CLogger.h"
|
#include "ps/CLogger.h"
|
||||||
@ -878,11 +875,6 @@ void Shutdown(uint flags)
|
|||||||
|
|
||||||
void EarlyInit()
|
void EarlyInit()
|
||||||
{
|
{
|
||||||
#if OS_WIN
|
|
||||||
// see discussion at declaration of wstartup_PreMainInit.
|
|
||||||
wstartup_PreMainInit(); // must come before any use of lib/sysdep/win
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MICROLOG(L"EarlyInit");
|
MICROLOG(L"EarlyInit");
|
||||||
|
|
||||||
// If you ever want to catch a particular allocation:
|
// If you ever want to catch a particular allocation:
|
||||||
|
Loading…
Reference in New Issue
Block a user