From 1814d9175a48228fa91eb5747f7b1db6f0a926be Mon Sep 17 00:00:00 2001 From: janwas Date: Thu, 24 May 2007 02:32:53 +0000 Subject: [PATCH] dll_ver: don't call Wow64 stuff on 32-bit vista +minor improvements: . move libjpeg-specific stuff to its own header This was SVN commit r5088. --- source/lib/external_libraries/libjpeg.h | 29 +++ source/lib/external_libraries/png.h | 5 + source/lib/external_libraries/zlib.h | 5 + source/lib/module_init.cpp | 1 + source/lib/module_init.h | 4 +- source/lib/res/graphics/tex_jpg.cpp | 22 +-- source/lib/sysdep/win/dll_ver.cpp | 99 +++++++--- source/lib/sysdep/win/mahaf.cpp | 16 +- source/lib/sysdep/win/wutil.cpp | 239 +++++++++++++++--------- source/lib/sysdep/win/wutil.h | 36 +++- 10 files changed, 297 insertions(+), 159 deletions(-) create mode 100644 source/lib/external_libraries/libjpeg.h diff --git a/source/lib/external_libraries/libjpeg.h b/source/lib/external_libraries/libjpeg.h new file mode 100644 index 0000000000..4c0ec99d41 --- /dev/null +++ b/source/lib/external_libraries/libjpeg.h @@ -0,0 +1,29 @@ +/** + * ========================================================================= + * File : libjpeg.h + * Project : 0 A.D. + * Description : bring in libjpeg header+library, with compatibility fixes + * ========================================================================= + */ + +// license: GPL; see lib/license.txt + +#ifndef INCLUDED_LIBJPEG +#define INCLUDED_LIBJPEG + +extern "C" { +// we are not a core library module, so don't define JPEG_INTERNALS +#include +#include +} + +// automatically link against the required library +#if MSC_VERSION +# ifdef NDEBUG +# pragma comment(lib, "jpeg-6b.lib") +# else +# pragma comment(lib, "jpeg-6bd.lib") +# endif // #ifdef NDEBUG +#endif // #ifdef MSC_VERSION + +#endif // #ifndef INCLUDED_LIBJPEG diff --git a/source/lib/external_libraries/png.h b/source/lib/external_libraries/png.h index 11b5e1b2f4..3cb389bc2f 100644 --- a/source/lib/external_libraries/png.h +++ b/source/lib/external_libraries/png.h @@ -8,6 +8,9 @@ // license: GPL; see lib/license.txt +#ifndef INCLUDED_PNG +#define INCLUDED_PNG + // includes , which requires some fixes by our header. #include "lib/external_libraries/zlib.h" @@ -21,3 +24,5 @@ # pragma comment(lib, "libpng13d.lib") # endif // NDEBUG #endif // MSC_VERSION + +#endif // #ifndef INCLUDED_PNG diff --git a/source/lib/external_libraries/zlib.h b/source/lib/external_libraries/zlib.h index 3235bbd98f..f019831fb4 100644 --- a/source/lib/external_libraries/zlib.h +++ b/source/lib/external_libraries/zlib.h @@ -8,6 +8,9 @@ // license: GPL; see lib/license.txt +#ifndef INCLUDED_ZLIB +#define INCLUDED_ZLIB + // zlib.h -> zconf.h includes , which causes conflicts. // define the include guard to prevent it from actually being included and // then manually define the few things that are actually needed. @@ -28,3 +31,5 @@ # pragma comment(lib, "zlib1d.lib") # endif #endif + +#endif // #ifndef INCLUDED_ZLIB diff --git a/source/lib/module_init.cpp b/source/lib/module_init.cpp index 95177ddcc8..bfead376e4 100644 --- a/source/lib/module_init.cpp +++ b/source/lib/module_init.cpp @@ -61,6 +61,7 @@ retry: return false; if(!cpu_CAS(pInitState, latchedInitState, latchedInitState-1)) goto retry; + // refcount reached zero => allow shutdown. if(latchedInitState-1 == MODULE_UNINITIALIZED) return true; diff --git a/source/lib/module_init.h b/source/lib/module_init.h index ab2d146d2b..f62aad01e0 100644 --- a/source/lib/module_init.h +++ b/source/lib/module_init.h @@ -24,7 +24,7 @@ typedef uintptr_t ModuleInitState; // uintptr_t required by cpu_CAS /** * @return whether initialization should go forward, i.e. initState is - * currently MODULE_BEFORE_INIT. increments initState afterwards. + * currently MODULE_UNINITIALIZED. increments initState afterwards. * * (the reason for this function - and tricky part - is thread-safety) **/ @@ -33,7 +33,7 @@ extern bool ModuleShouldInitialize(volatile ModuleInitState* initState); /** * if module reference count is valid, decrement it. * @return whether shutdown should go forward, i.e. this is the last - * shutdown call. if so, sets initState to MODULE_SHUTDOWN. + * shutdown call. **/ extern bool ModuleShouldShutdown(volatile ModuleInitState* initState); diff --git a/source/lib/res/graphics/tex_jpg.cpp b/source/lib/res/graphics/tex_jpg.cpp index da9c6e371c..1d352614f4 100644 --- a/source/lib/res/graphics/tex_jpg.cpp +++ b/source/lib/res/graphics/tex_jpg.cpp @@ -10,35 +10,21 @@ #include "precompiled.h" -extern "C" { -// this is not a core library module, so it doesn't define JPEG_INTERNALS -#include -#include -} +#include "lib/external_libraries/libjpeg.h" #include "lib/res/res.h" #include "tex_codec.h" #include -#if MSC_VERSION - // squelch "dtor / setjmp interaction" warnings. // all attempts to resolve the underlying problem failed; apparently // the warning is generated if setjmp is used at all in C++ mode. -// (png_*_impl have no code that would trigger ctors/dtors, nor are any +// (jpg_*code have no code that would trigger ctors/dtors, nor are any // called in their prolog/epilog code). +#if MSC_VERSION # pragma warning(disable: 4611) - -// pull in the appropriate debug/release library -# ifdef NDEBUG -# pragma comment(lib, "jpeg-6b.lib") -# else -# pragma comment(lib, "jpeg-6bd.lib") -# endif // #ifdef NDEBUG - -#endif // #ifdef MSC_VERSION - +#endif /* IMPORTANT: we assume that JOCTET is 8 bits. */ diff --git a/source/lib/sysdep/win/dll_ver.cpp b/source/lib/sysdep/win/dll_ver.cpp index 55e143c7dc..4f50dba1cb 100644 --- a/source/lib/sysdep/win/dll_ver.cpp +++ b/source/lib/sysdep/win/dll_ver.cpp @@ -17,11 +17,62 @@ #include "lib/path_util.h" #include "win.h" #include "wutil.h" +#include "winit.h" #if MSC_VERSION #pragma comment(lib, "version.lib") // DLL version #endif + +#pragma SECTION_PRE_LIBC(B) +WIN_REGISTER_FUNC(dll_ver_PreLibcInit); +#pragma FORCE_INCLUDE(dll_ver_PreLibcInit) +#pragma SECTION_RESTORE + + +//----------------------------------------------------------------------------- +// temporarily disable and re-enable Wow64 file redirection. +//----------------------------------------------------------------------------- + +// Wow64 'helpfully' redirects all 32-bit apps' accesses of +// %windir\\system32\\drivers to %windir\\system32\\drivers\\SysWOW64. +// that's bad, because the actual drivers are not in the subdirectory. to +// work around this, we disable redirection over the duration of get_ver. + +static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(PVOID*) = 0; +static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(PVOID) = 0; + +static void ImportWow64Functions() +{ + HMODULE hKernel32Dll = LoadLibrary("kernel32.dll"); + *(void**)&pWow64DisableWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64DisableWow64FsRedirection"); + *(void**)&pWow64RevertWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64RevertWow64FsRedirection"); + FreeLibrary(hKernel32Dll); +} + +static void DisableRedirection(PVOID& wasRedirectionEnabled) +{ + // note: don't just check if the function pointers are valid. 32-bit + // Vista includes them but isn't running Wow64, so calling the functions + // would fail. since we have to check if actually on Wow64, there's no + // more need to verify the pointers (their existence is implied). + if(!wutil_IsWow64()) + return; + BOOL ok = pWow64DisableWow64FsRedirection(&wasRedirectionEnabled); + WARN_IF_FALSE(ok); +} + +static void RevertRedirection(PVOID wasRedirectionEnabled) +{ + if(!wutil_IsWow64()) + return; + BOOL ok = pWow64RevertWow64FsRedirection(wasRedirectionEnabled); + WARN_IF_FALSE(ok); +} + + +//----------------------------------------------------------------------------- + // helper function that does all the work; caller wraps it and takes care of // undoing various operations if we fail midway. static LibError get_ver_impl(const char* module_path, char* out_ver, size_t out_ver_len, void*& mem) @@ -58,37 +109,19 @@ static LibError get_ver_impl(const char* module_path, char* out_ver, size_t out_ // get version information for the specified DLL. static LibError get_ver(const char* module_path, char* out_ver, size_t out_ver_len) { + LibError ret; + WIN_SAVE_LAST_ERROR; // GetFileVersion*, Ver* - - // WinXP x64 'helpfully' redirects all 32-bit apps' accesses of - // %windir\\system32\\drivers to %windir\\system32\\drivers\\SysWOW64. - // that's bad, because the actual drivers are not in the subdirectory. - // to work around this, we disable the redirection over the duration of - // this call. if not on a 64-bit OS (i.e. these entry points aren't - // found), no action need be taken. - HMODULE hKernel32Dll = LoadLibrary("kernel32.dll"); - BOOL (WINAPI *pWow64DisableWow64FsRedirection)(PVOID*) = 0; - BOOL (WINAPI *pWow64RevertWow64FsRedirection)(PVOID) = 0; - *(void**)&pWow64DisableWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64DisableWow64FsRedirection"); - *(void**)&pWow64RevertWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64RevertWow64FsRedirection"); - PVOID old_value = 0; - if(pWow64DisableWow64FsRedirection) { - BOOL ok = pWow64DisableWow64FsRedirection(&old_value); - WARN_IF_FALSE(ok); + PVOID wasRedirectionEnabled; + DisableRedirection(wasRedirectionEnabled); + { + void* mem = NULL; + ret = get_ver_impl(module_path, out_ver, out_ver_len, mem); + free(mem); + } + RevertRedirection(wasRedirectionEnabled); } - - void* mem = NULL; - LibError ret = get_ver_impl(module_path, out_ver, out_ver_len, mem); - free(mem); - - if(pWow64DisableWow64FsRedirection) - { - BOOL ok = pWow64RevertWow64FsRedirection(old_value); - WARN_IF_FALSE(ok); - } - FreeLibrary(hKernel32Dll); - WIN_RESTORE_LAST_ERROR; if(ret != INFO::OK) @@ -164,3 +197,13 @@ LibError dll_list_add(const char* name) dll_list_pos = 0; // poison pill, prevent further calls WARN_RETURN(ERR::BUF_SIZE); } + + +//----------------------------------------------------------------------------- + +static LibError dll_ver_PreLibcInit() +{ + ImportWow64Functions(); + + return INFO::OK; +} diff --git a/source/lib/sysdep/win/mahaf.cpp b/source/lib/sysdep/win/mahaf.cpp index c41bfd5539..b6145c2e27 100644 --- a/source/lib/sysdep/win/mahaf.cpp +++ b/source/lib/sysdep/win/mahaf.cpp @@ -140,21 +140,7 @@ static bool Is64BitOs() #if OS_WIN64 return true; #else - // import kernel32!IsWow64Process - const HMODULE hKernel32Dll = LoadLibrary("kernel32.dll"); - BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); - *(void**)&pIsWow64Process = GetProcAddress(hKernel32Dll, "IsWow64Process"); - FreeLibrary(hKernel32Dll); - - // function not found => running on 32-bit Windows - if(!pIsWow64Process) - return false; - - BOOL isWow64Process = FALSE; - const BOOL ok = IsWow64Process(GetCurrentProcess(), &isWow64Process); - WARN_IF_FALSE(ok); - - return (isWow64Process == TRUE); + return wutil_IsWow64(); #endif } diff --git a/source/lib/sysdep/win/wutil.cpp b/source/lib/sysdep/win/wutil.cpp index 22d158f59c..44141db3e1 100644 --- a/source/lib/sysdep/win/wutil.cpp +++ b/source/lib/sysdep/win/wutil.cpp @@ -29,54 +29,8 @@ WIN_REGISTER_FUNC(wutil_Shutdown); #pragma SECTION_RESTORE -char win_sys_dir[MAX_PATH+1]; -char win_exe_dir[MAX_PATH+1]; - - -// only call after a Win32 function indicates failure. -LibError LibError_from_GLE(bool warn_if_failed) -{ - LibError err; - switch(GetLastError()) - { - case ERROR_OUTOFMEMORY: - err = ERR::NO_MEM; break; - - case ERROR_INVALID_PARAMETER: - err = ERR::INVALID_PARAM; break; - case ERROR_INSUFFICIENT_BUFFER: - err = ERR::BUF_SIZE; break; - -/* - case ERROR_ACCESS_DENIED: - err = ERR::FILE_ACCESS; break; - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - err = ERR::TNODE_NOT_FOUND; break; -*/ - default: - err = ERR::FAIL; break; - } - - if(warn_if_failed) - DEBUG_WARN_ERR(err); - return err; -} - - -// return the LibError equivalent of GetLastError(), or ERR::FAIL if -// there's no equal. -// you should SetLastError(0) before calling whatever will set ret -// to make sure we do not return any stale errors. -LibError LibError_from_win32(DWORD ret, bool warn_if_failed) -{ - if(ret != FALSE) - return INFO::OK; - return LibError_from_GLE(warn_if_failed); -} - - //----------------------------------------------------------------------------- +// safe allocator // // safe allocator that may be used independently of libc malloc @@ -98,8 +52,7 @@ void win_free(void* p) //----------------------------------------------------------------------------- -// locking for win-specific code -//----------------------------------------------------------------------------- +// locks // several init functions are before called before _cinit. // POSIX static mutex init may not have been done by then, @@ -153,59 +106,173 @@ static void ShutdownLocks() //----------------------------------------------------------------------------- +// error codes -// explained where used. +// only call after a Win32 function indicates failure. +LibError LibError_from_GLE(bool warn_if_failed) +{ + LibError err; + switch(GetLastError()) + { + case ERROR_OUTOFMEMORY: + err = ERR::NO_MEM; break; + + case ERROR_INVALID_PARAMETER: + err = ERR::INVALID_PARAM; break; + case ERROR_INSUFFICIENT_BUFFER: + err = ERR::BUF_SIZE; break; + +/* + case ERROR_ACCESS_DENIED: + err = ERR::FILE_ACCESS; break; + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + err = ERR::TNODE_NOT_FOUND; break; +*/ + default: + err = ERR::FAIL; break; + } + + if(warn_if_failed) + DEBUG_WARN_ERR(err); + return err; +} + + +// return the LibError equivalent of GetLastError(), or ERR::FAIL if +// there's no equal. +// you should SetLastError(0) before calling whatever will set ret +// to make sure we do not return any stale errors. +LibError LibError_from_win32(DWORD ret, bool warn_if_failed) +{ + if(ret != FALSE) + return INFO::OK; + return LibError_from_GLE(warn_if_failed); +} + + +//----------------------------------------------------------------------------- +// directories + +char win_sys_dir[MAX_PATH+1]; +char win_exe_dir[MAX_PATH+1]; + +static void GetDirectories() +{ + GetSystemDirectory(win_sys_dir, sizeof(win_sys_dir)); + + if(GetModuleFileName(GetModuleHandle(0), win_exe_dir, MAX_PATH) != 0) + path_strip_fn(win_exe_dir); +} + + +//----------------------------------------------------------------------------- +// user32 fix + +// HACK: make sure a reference to user32 is held, even if someone +// decides to delay-load it. this fixes bug #66, which was the +// Win32 mouse cursor (set via user32!SetCursor) appearing as a +// black 32x32(?) rectangle. underlying cause was as follows: +// powrprof.dll was the first client of user32, causing it to be +// loaded. after we were finished with powrprof, we freed it, in turn +// causing user32 to unload. later code would then reload user32, +// which apparently terminally confused the cursor implementation. +// +// since we hold a reference here, user32 will never unload. +// of course, the benefits of delay-loading are lost for this DLL, +// but that is unavoidable. it is safer to force loading it, rather +// than documenting the problem and asking it not be delay-loaded. static HMODULE hUser32Dll; - -static LibError wutil_PreLibcInit() +static void ForciblyLoadUser32Dll() +{ + hUser32Dll = LoadLibrary("user32.dll"); +} + +// avoids Boundschecker warning +static void FreeUser32Dll() +{ + FreeLibrary(hUser32Dll); +} + + +//----------------------------------------------------------------------------- +// memory + +// note: has no effect if config.h's HAVE_VC_DEBUG_ALLOC is 0. +static void EnableMemoryTracking() { - // enable memory tracking and leak detection; - // no effect if !HAVE_VC_DEBUG_ALLOC. #if CONFIG_PARANOIA debug_heap_enable(DEBUG_HEAP_ALL); #elif !defined(NDEBUG) debug_heap_enable(DEBUG_HEAP_NORMAL); #endif +} - // enable low-fragmentation heap +static void EnableLowFragmentationHeap() +{ #if WINVER >= 0x0501 HMODULE hKernel32Dll = LoadLibrary("kernel32.dll"); - if(hKernel32Dll) - { - BOOL (WINAPI* pHeapSetInformation)(HANDLE, HEAP_INFORMATION_CLASS, void*, size_t); - *(void**)&pHeapSetInformation = GetProcAddress(hKernel32Dll, "HeapSetInformation"); - if(pHeapSetInformation) - { - ULONG flags = 2; // enable LFH - pHeapSetInformation(GetProcessHeap(), HeapCompatibilityInformation, &flags, sizeof(flags)); - } + BOOL (WINAPI* pHeapSetInformation)(HANDLE, HEAP_INFORMATION_CLASS, void*, size_t); + *(void**)&pHeapSetInformation = GetProcAddress(hKernel32Dll, "HeapSetInformation"); + if(!pHeapSetInformation) + return; - FreeLibrary(hKernel32Dll); - } + ULONG flags = 2; // enable LFH + pHeapSetInformation(GetProcessHeap(), HeapCompatibilityInformation, &flags, sizeof(flags)); + + FreeLibrary(hKernel32Dll); #endif // #if WINVER >= 0x0501 +} + +//----------------------------------------------------------------------------- +// Wow64 detection + +static bool isWow64; + +static void DetectWow64() +{ + // import kernel32!IsWow64Process + const HMODULE hKernel32Dll = LoadLibrary("kernel32.dll"); + BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); + *(void**)&pIsWow64Process = GetProcAddress(hKernel32Dll, "IsWow64Process"); + FreeLibrary(hKernel32Dll); + + // function not found => running on 32-bit Windows + if(!pIsWow64Process) + { + isWow64 = false; + return; + } + + BOOL isWow64Process = FALSE; + const BOOL ok = IsWow64Process(GetCurrentProcess(), &isWow64Process); + WARN_IF_FALSE(ok); + isWow64 = (isWow64Process == TRUE); +} + +bool wutil_IsWow64() +{ + return isWow64; +} + + +//----------------------------------------------------------------------------- + +static LibError wutil_PreLibcInit() +{ InitLocks(); - GetSystemDirectory(win_sys_dir, sizeof(win_sys_dir)); + ForciblyLoadUser32Dll(); - if(GetModuleFileName(GetModuleHandle(0), win_exe_dir, MAX_PATH) != 0) - path_strip_fn(win_exe_dir); + EnableMemoryTracking(); - // HACK: make sure a reference to user32 is held, even if someone - // decides to delay-load it. this fixes bug #66, which was the - // Win32 mouse cursor (set via user32!SetCursor) appearing as a - // black 32x32(?) rectangle. underlying cause was as follows: - // powrprof.dll was the first client of user32, causing it to be - // loaded. after we were finished with powrprof, we freed it, in turn - // causing user32 to unload. later code would then reload user32, - // which apparently terminally confused the cursor implementation. - // - // since we hold a reference here, user32 will never unload. - // of course, the benefits of delay-loading are lost for this DLL, - // but that is unavoidable. it is safer to force loading it, rather - // than documenting the problem and asking it not be delay-loaded. - hUser32Dll = LoadLibrary("user32.dll"); + EnableLowFragmentationHeap(); + + GetDirectories(); + + DetectWow64(); return INFO::OK; } @@ -213,11 +280,9 @@ static LibError wutil_PreLibcInit() static LibError wutil_Shutdown() { - ShutdownLocks(); + FreeUser32Dll(); - // free the reference taken in win_PreInit; - // this avoids Boundschecker warnings at exit. - FreeLibrary(hUser32Dll); + ShutdownLocks(); return INFO::OK; } diff --git a/source/lib/sysdep/win/wutil.h b/source/lib/sysdep/win/wutil.h index 12f3c0fa45..ca3583768d 100644 --- a/source/lib/sysdep/win/wutil.h +++ b/source/lib/sysdep/win/wutil.h @@ -18,8 +18,17 @@ #include "win.h" -//----------------------------------------------------------------------------- -// locking +// +// safe allocator +// + +extern void* win_alloc(size_t size); +extern void win_free(void* p); + + +// +// locks +// // critical sections used by win-specific code enum @@ -39,13 +48,6 @@ extern void win_unlock(uint idx); // used in a desperate attempt to avoid deadlock in wdbg_exception_handler. extern int win_is_locked(uint idx); - -//----------------------------------------------------------------------------- - -extern void* win_alloc(size_t size); -extern void win_free(void* p); - - // thread safe, usable in constructors #define WIN_ONCE(code)\ {\ @@ -59,6 +61,11 @@ extern void win_free(void* p); win_unlock(ONCE_CS);\ } + +// +// error codes +// + #define WIN_SAVE_LAST_ERROR DWORD last_err__ = GetLastError(); #define WIN_RESTORE_LAST_ERROR STMT(if(last_err__ != 0 && GetLastError() == 0) SetLastError(last_err__);); @@ -79,7 +86,18 @@ LibError LibError_from_GLE(bool warn_if_failed = true); extern LibError LibError_from_win32(DWORD ret, bool warn_if_failed = true); +// +// directories +// + extern char win_sys_dir[MAX_PATH+1]; extern char win_exe_dir[MAX_PATH+1]; + +// +// Wow64 detection +// + +extern bool wutil_IsWow64(); + #endif // #ifndef INCLUDED_WUTIL