1
0
forked from 0ad/0ad

Removes WInit module completely. Refs #2611

Comments By: phosit
Differential Revision: https://code.wildfiregames.com/D5085
This was SVN commit r27810.
This commit is contained in:
Vladislav Belov 2023-08-22 17:59:01 +00:00
parent 11e8f80b58
commit 82bf9bb902
10 changed files with 29 additions and 463 deletions

View File

@ -1076,9 +1076,6 @@ function setup_main_exe ()
linkoptions {
-- wraps main thread in a __try block(see wseh.cpp). replace with mainCRTStartup if that's undesired.
"/ENTRY:wseh_EntryPoint",
-- see wstartup.h
"/INCLUDE:_wstartup_InitAndRegisterShutdown",
}
links { "delayimp" }
@ -1479,8 +1476,6 @@ function setup_tests()
-- from "lowlevel" static lib; must be added here to be linked in
files { source_root.."lib/sysdep/os/win/error_dialog.rc" }
-- see wstartup.h
linkoptions { "/INCLUDE:_wstartup_InitAndRegisterShutdown" }
-- Enables console for the TEST project on Windows
linkoptions { "/SUBSYSTEM:CONSOLE" }

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2023 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -30,15 +30,10 @@
#include "lib/allocators/shared_ptr.h"
#include "lib/path.h" // path_is_subpath
#include "lib/sysdep/os/win/win.h"
#include "lib/sysdep/os/win/winit.h"
#include "lib/sysdep/os/win/wutil.h"
#include "lib/sysdep/os/win/wiocp.h"
WINIT_REGISTER_MAIN_INIT(wdir_watch_Init);
WINIT_REGISTER_MAIN_SHUTDOWN(wdir_watch_Shutdown);
//-----------------------------------------------------------------------------
// DirHandle
@ -370,13 +365,13 @@ Status dir_watch_Poll(DirWatchNotifications& notifications)
//-----------------------------------------------------------------------------
static Status wdir_watch_Init()
Status wdir_watch_Init()
{
s_dirWatchManager = new DirWatchManager;
return INFO::OK;
}
static Status wdir_watch_Shutdown()
Status wdir_watch_Shutdown()
{
SAFE_DELETE(s_dirWatchManager);
return INFO::OK;

View File

@ -1,95 +0,0 @@
/* Copyright (C) 2010 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* windows-specific module init and shutdown mechanism
*/
#include "precompiled.h"
#include "lib/sysdep/os/win/winit.h"
#include "lib/sysdep/os/win/win.h" // GetTickCount for quick'n dirty timing
// see http://blogs.msdn.com/larryosterman/archive/2004/09/27/234840.aspx
// for discussion of a similar mechanism.
//
// note: this module is kept distinct from the CRT's init/shutdown mechanism
// to insulate against changes there. another advantage is that callbacks
// can return Status instead of int.
// currently (2008-02-17) the init groups are populated as follows:
// critical : wposix
// early : wutil
// early2 : whrt, wdbg_heap
// main : waio, wsock, wtime, wdir_watch
// late : wsdl
typedef Status (*PfnLibError)();
// pointers to start and end of function tables.
// notes:
// - COFF tosses out empty segments, so we have to put in one value
// (zero, because CallFunctionPointers has to ignore entries =0 anyway).
// - ASCII '$' and 'Z' come before resp. after '0'..'9', so use that to
// bound the section names.
__declspec(allocate(".WINIT$I$")) PfnLibError initBegin = 0;
__declspec(allocate(".WINIT$IZ")) PfnLibError initEnd = 0;
__declspec(allocate(".WINIT$S$")) PfnLibError shutdownBegin = 0;
__declspec(allocate(".WINIT$SZ")) PfnLibError shutdownEnd = 0;
// note: #pragma comment(linker, "/include") is not necessary since
// these are referenced below.
/**
* call into a range of function pointers.
* @param [begin, end): STL-style range
*
* note: pointers = 0 are ignored. this is because the above placeholders
* are initialized to 0 and because the range may be larger than
* expected due to COFF section padding (with zeroes).
**/
static void CallFunctionPointers(PfnLibError* begin, PfnLibError* end)
{
const DWORD t0 = GetTickCount();
for(PfnLibError* ppfunc = begin; ppfunc < end; ppfunc++)
{
if(*ppfunc)
{
(*ppfunc)();
}
}
const DWORD t1 = GetTickCount();
debug_printf("WINIT| total elapsed time in callbacks %d ms (+-10)\n", t1-t0);
}
void winit_CallInitFunctions()
{
CallFunctionPointers(&initBegin, &initEnd);
}
void winit_CallShutdownFunctions()
{
CallFunctionPointers(&shutdownBegin, &shutdownEnd);
}

View File

@ -1,172 +0,0 @@
/* Copyright (C) 2010 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* windows-specific module init and shutdown mechanism
*/
#ifndef INCLUDED_WINIT
#define INCLUDED_WINIT
/*
Overview
--------
This facility allows registering init and shutdown functions with only
one line of code and zero runtime overhead. It provides for dependencies
between modules, allowing groups of functions to run before others.
Details
-------
Participating modules store function pointer(s) to their init and/or
shutdown function in a specific COFF section. The sections are
grouped according to the desired notification and the order in which
functions are to be called (useful if one module depends on another).
They are then gathered by the linker and arranged in alphabetical order.
Placeholder variables in the sections indicate where the series of
functions begins and ends for a given notification time.
At runtime, all of the function pointers between the markers are invoked.
Example
-------
(at file scope:)
WINIT_REGISTER_MAIN_INIT(InitCallback);
Rationale
---------
Several methods of module init are possible: (see Large Scale C++ Design)
- on-demand initialization: each exported function would have to check
if init already happened. that would be brittle and hard to verify.
- singleton: variant of the above, but not applicable to a
procedural interface (and quite ugly to boot).
- registration: static constructors call a central notification function.
module dependencies would be quite difficult to express - this would
require a graph or separate lists for each priority (clunky).
worse, a fatal flaw is that other C++ constructors may depend on the
modules we are initializing and already have run. there is no way
to influence ctor call order between separate source files, so
this is out of the question.
- linker-based registration: same as above, but the linker takes care
of assembling various functions into one sorted table. the list of
init functions is available before C++ ctors have run. incidentally,
zero runtime overhead is incurred. unfortunately, this approach is
MSVC-specific. however, the MS CRT uses a similar method for its
init, so this is expected to remain supported.
*/
//-----------------------------------------------------------------------------
// section declarations
// section names are of the format ".WINIT${type}{group}".
// {type} is I for initialization- or S for shutdown functions.
// {group} is [0, 9] - see below.
// note: __declspec(allocate) requires declaring segments in advance via
// #pragma section.
#pragma section(".WINIT$I$", read)
#pragma section(".WINIT$I0", read)
#pragma section(".WINIT$I1", read)
#pragma section(".WINIT$I2", read)
#pragma section(".WINIT$I6", read)
#pragma section(".WINIT$I7", read)
#pragma section(".WINIT$IZ", read)
#pragma section(".WINIT$S$", read)
#pragma section(".WINIT$S0", read)
#pragma section(".WINIT$S1", read)
#pragma section(".WINIT$S6", read)
#pragma section(".WINIT$S7", read)
#pragma section(".WINIT$S8", read)
#pragma section(".WINIT$SZ", read)
#pragma comment(linker, "/merge:.WINIT=.rdata")
//-----------------------------------------------------------------------------
// Function groups
// to allow correct ordering of module init in the face of dependencies,
// we introduce 'groups'. all functions in one are called before those in
// the next higher group, but order within the group is undefined.
// (this is because the linker sorts sections alphabetically but doesn't
// specify the order in which object files are processed.)
// these macros register a function to be called at the given time.
// usage: invoke at file scope, passing a function identifier/symbol.
// rationale:
// - __declspec(allocate) requires section declarations, but allows users to
// write only one line (instead of needing an additional #pragma data_seg)
// - fixed groups instead of passing a group number are more clear and
// encourage thinking about init order. (__declspec(allocate) requires
// a single string literal anyway and doesn't support string merging)
// - why EXTERN_C and __pragma? VC8's link-stage optimizer believes
// the static function pointers defined by WINIT_REGISTER_* to be unused;
// unless action is taken, they would be removed. to prevent this, we
// forcibly include the function pointer symbols. this means the variable
// must be extern, not static. the linker needs to know the decorated
// symbol name, so we disable mangling via EXTERN_C.
// very early init; must not fail, since error handling code *crashes*
// if called before these have completed.
#define WINIT_REGISTER_CRITICAL_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I0")) Status (*p##func)(void) = func
// meant for modules with dependents but whose init is complicated and may
// raise error/warning messages (=> can't go in WINIT_REGISTER_CRITICAL_INIT)
#define WINIT_REGISTER_EARLY_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I1")) Status (*p##func)(void) = func
// available for dependents of WINIT_REGISTER_EARLY_INIT-modules that
// must still come before WINIT_REGISTER_MAIN_INIT.
#define WINIT_REGISTER_EARLY_INIT2(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I2")) Status (*p##func)(void) = func
// most modules will go here unless they are often used or
// have many dependents.
#define WINIT_REGISTER_MAIN_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I6")) Status (*p##func)(void) = func
// available for any modules that may need to come after
// WINIT_REGISTER_MAIN_INIT (unlikely)
#define WINIT_REGISTER_LATE_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I7")) Status (*p##func)(void) = func
#define WINIT_REGISTER_EARLY_SHUTDOWN(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S0")) Status (*p##func)(void) = func
#define WINIT_REGISTER_EARLY_SHUTDOWN2(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S1")) Status (*p##func)(void) = func
#define WINIT_REGISTER_MAIN_SHUTDOWN(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S6")) Status (*p##func)(void) = func
#define WINIT_REGISTER_LATE_SHUTDOWN(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S7")) Status (*p##func)(void) = func
#define WINIT_REGISTER_LATE_SHUTDOWN2(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S8")) Status (*p##func)(void) = func
//-----------------------------------------------------------------------------
/**
* call each registered function.
*
* if this is called before CRT initialization, callbacks must not use any
* non-stateless CRT functions such as atexit. see wstartup.h for the
* current status on this issue.
**/
extern void winit_CallInitFunctions();
extern void winit_CallShutdownFunctions();
#endif // #ifndef INCLUDED_WINIT

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2023 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -39,13 +39,10 @@
#include "lib/sysdep/filesystem.h" // O_DIRECT
#include "lib/sysdep/os/win/wutil.h" // wutil_SetPrivilege
#include "lib/sysdep/os/win/wiocp.h"
#include "lib/sysdep/os/win/winit.h"
#include "lib/sysdep/os/win/wposix/crt_posix.h" // _get_osfhandle
#include <ctime>
WINIT_REGISTER_MAIN_SHUTDOWN(waio_Shutdown);
// (dynamic linking preserves compatibility with previous Windows versions)
static WUTIL_FUNC(pSetFileCompletionNotificationModes, BOOL, (HANDLE, UCHAR));
static WUTIL_FUNC(pSetFileIoOverlappedRange, BOOL, (HANDLE, PUCHAR, ULONG));
@ -392,7 +389,7 @@ static Status waio_Init()
}
static Status waio_Shutdown()
Status waio_Shutdown()
{
if(waio_initState == 0) // we were never initialized
return INFO::OK;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2023 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -24,7 +24,6 @@
#define INCLUDED_WPOSIX_INTERNAL
#include "lib/sysdep/os/win/win.h"
#include "lib/sysdep/os/win/winit.h"
#include "lib/sysdep/os/win/wutil.h"
// cast intptr_t to HANDLE; centralized for easier changing, e.g. avoiding

View File

@ -1,123 +0,0 @@
/* Copyright (C) 2010 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* windows-specific startup code
*/
#include "precompiled.h"
#include "lib/sysdep/os/win/wstartup.h"
#include "lib/sysdep/os/win/winit.h"
/*
Shutdown
--------
our shutdown function must be called after static C++ dtors, since they
may use wpthread and wtime functions. how to accomplish this?
hooking ExitProcess is one way of ensuring we're the very last bit of
code to be called. this has several big problems, though:
- if other exit paths (such as CorExitProcess) are added by MS and
triggered via external code injected into our process, we miss our cue
to shut down. one annoying consequence would be that the Aken driver
remains loaded. however, users also can terminate our process at any
time, so we need to safely handle lack of shutdown anyway.
- IAT hooking breaks if kernel32 is delay-loaded (who knows what
people are going to do..)
- Detours-style trampolines are nonportable (the Detours library currently
only ships with code to handle IA-32) and quite risky, since antivirus
programs may flag this activity.
having all exit paths call our shutdown and then _cexit would work,
provided we actually find and control all of them (unhandled exceptions
and falling off the end of the last thread are non-obvious examples).
that aside, it'd require changes to calling code, and we're trying to
keep this mess hidden and transparent to users.
the remaining alternative is to use atexit. this approach has the
advantage of being covered by the CRT runtime checks and leak detector,
because those are shut down after the atexit handlers are called.
however, it does require that our shutdown callback to be the very last,
i.e. registered first. fortunately, the init stage can guarantee this.
Init
----
For the same reasons as above, our init really should happen before static
C++ ctors are called.
using WinMain as the entry point and then calling the application's main()
doesn't satisy the above requirement, and is expressly forbidden by ANSI C.
(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, since symbol addresses are off by 4 bytes.)
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,
comes after static ctors, and is difficult to achieve in external code
such as the (automatically generated) self-test.
commandeering the entry point, doing init there and then calling
mainCRTStartup would work, but doesn't allow the use of atexit for shutdown
(nor any other non-stateless CRT functions to be called during init).
the way out is to have an init-and-call-atexit function triggered by means
of the CRT init mechanism. we arrange init order such that this happens
before static C++ ctors, thus meeting all of the above requirements.
(note: this is possible because crtexe.c and its .CRT$XI and .CRT$XC
sections holding static initializers and ctors are linked into the
application, not the CRT DLL.)
*/
// reference: see http://www.codeguru.com/cpp/misc/misc/threadsprocesses/article.php/c6945__1
EXTERN_C int wstartup_InitAndRegisterShutdown()
{
winit_CallInitFunctions();
atexit(winit_CallShutdownFunctions);
return 0;
}
// insert our initialization function after _cinit and XIU ("User") block
#if ARCH_AMD64
# define SECTION_ATTRIBUTES read
#else
# define SECTION_ATTRIBUTES read,write
#endif
#pragma section(".CRT$XIV", long,SECTION_ATTRIBUTES)
#undef SECTION_ATTRIBUTES
EXTERN_C __declspec(allocate(".CRT$XIV")) int(*wstartup_pInitAndRegisterShutdown)() = wstartup_InitAndRegisterShutdown;
#pragma comment(linker, "/include:" STRINGIZE(DECORATED_NAME(wstartup_pInitAndRegisterShutdown)))

View File

@ -1,45 +0,0 @@
/* Copyright (C) 2010 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* windows-specific startup code
*/
// linking with this component should automatically arrange for winit's
// functions to be called at the appropriate times.
//
// the current implementation manages to trigger initialization in-between
// calls to CRT init and the static C++ ctors. that means wpthread etc.
// APIs are safe to use from ctors, and winit initializers are allowed
// to use non-stateless CRT functions such as atexit.
//
// IMPORTANT NOTE: if compiling this into a static lib and not using VC8's
// "use library dependency inputs" linking mode, the object file will be
// discarded because it does not contain any symbols that resolve another
// module's undefined external(s). for a discussion of this topic, see:
// http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=144087
// workaround: in the main EXE project, reference a symbol from this module,
// thus forcing it to be linked in. example:
// #pragma comment(linker, "/include:_wstartup_InitAndRegisterShutdown")
// (doing that in this module isn't sufficient, because it would only
// affect the librarian and its generation of the static lib that holds
// this file. instead, the process of linking the main EXE must be fixed.)

View File

@ -31,7 +31,6 @@
#include "lib/sysdep/sysdep.h"
#include "lib/sysdep/os/win/win.h"
#include "lib/sysdep/os/win/wdbg.h" // wdbg_assert
#include "lib/sysdep/os/win/winit.h"
#include <shlobj.h> // SHGetFolderPath
@ -39,10 +38,6 @@
#include <SDL_syswm.h>
WINIT_REGISTER_EARLY_INIT(wutil_Init);
WINIT_REGISTER_LATE_SHUTDOWN(wutil_Shutdown);
//-----------------------------------------------------------------------------
// safe allocator
@ -306,7 +301,7 @@ void wutil_EnableHiDPIOnWindows()
//-----------------------------------------------------------------------------
static Status wutil_Init()
Status wutil_Init()
{
InitLocks();
@ -314,7 +309,7 @@ static Status wutil_Init()
}
static Status wutil_Shutdown()
Status wutil_Shutdown()
{
ShutdownLocks();

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2023 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -100,6 +100,13 @@ that of Atlas depending on commandline parameters.
#endif
#if OS_WIN
// Forward declarations to avoid including Windows dependent headers.
Status waio_Shutdown();
Status wdir_watch_Init();
Status wdir_watch_Shutdown();
Status wutil_Init();
Status wutil_Shutdown();
// We don't want to include Windows.h as it might mess up the rest
// of the file so we just define DWORD as done in Windef.h.
#ifndef DWORD
@ -734,6 +741,11 @@ extern "C" int main(int argc, char* argv[])
}
#endif // OS_UNIX
#if OS_WIN
wutil_Init();
wdir_watch_Init();
#endif
EarlyInit(); // must come at beginning of main
// static_cast is ok, argc is never negative.
@ -742,5 +754,13 @@ extern "C" int main(int argc, char* argv[])
// Shut down profiler initialised by EarlyInit
g_Profiler2.Shutdown();
#if OS_WIN
// All calls to Windows specific functions have to happen before the following
// shutdowns.
wdir_watch_Shutdown();
waio_Shutdown();
wutil_Shutdown();
#endif
return EXIT_SUCCESS;
}