Fix crashes in wxMSW when reinitializing the library.

Reset pointers to functions loaded from msimg32.dll when the library is
uninitialized as they may change if it's re-initialized again and msimg32.dll
is reloaded at a different address.

Also do the same thing for the function pointers from gdi32.dll for
consistency, even though it doesn't seem to be actually required in this case.

Closes #17167.
This commit is contained in:
Roger Sanders
2015-09-27 08:45:49 +10:00
committed by Vadim Zeitlin
parent 7c6c21c538
commit 4acb4cf476

View File

@@ -175,6 +175,33 @@ private:
}; };
static wxOnceOnlyDLLLoader wxMSIMG32DLL(wxT("msimg32")); static wxOnceOnlyDLLLoader wxMSIMG32DLL(wxT("msimg32"));
static wxOnceOnlyDLLLoader wxGDI32DLL(wxT("gdi32.dll"));
// Note that originally these function pointers were local static members within
// functions, but we can't do that, because wxWidgets may be initialized,
// uninitialized, and reinitialized within the same program, and our dynamically
// loaded dll's may be unloaded and reloaded as part of that, almost certainly
// ending up at different base addresses due to address space layout
// randomization.
#ifdef USE_DYNAMIC_GDI_FUNCS
typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int,
HDC,int,int,int,int,
BLENDFUNCTION);
static AlphaBlend_t gs_pfnAlphaBlend = NULL;
static bool gs_triedToLoadAlphaBlend = false;
typedef BOOL (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
static GradientFill_t gs_pfnGradientFill = NULL;
static bool gs_triedToLoadGradientFill = false;
typedef DWORD (WINAPI *GetLayout_t)(HDC);
static GetLayout_t gs_pfnGetLayout = NULL;
static bool gs_triedToLoadGetLayout = false;
typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD);
static SetLayout_t gs_pfnSetLayout = NULL;
static bool gs_triedToLoadSetLayout = false;
#endif // USE_DYNAMIC_GDI_FUNCS
// we must ensure that DLLs are unloaded before the static objects cleanup time // we must ensure that DLLs are unloaded before the static objects cleanup time
// because we may hit the notorious DllMain() dead lock in this case if wx is // because we may hit the notorious DllMain() dead lock in this case if wx is
@@ -184,7 +211,24 @@ class wxGDIDLLsCleanupModule : public wxModule
{ {
public: public:
virtual bool OnInit() { return true; } virtual bool OnInit() { return true; }
virtual void OnExit() { wxMSIMG32DLL.Unload(); } virtual void OnExit()
{
wxMSIMG32DLL.Unload();
wxGDI32DLL.Unload();
#ifdef USE_DYNAMIC_GDI_FUNCS
gs_pfnGetLayout = NULL;
gs_triedToLoadGetLayout = false;
gs_pfnSetLayout = NULL;
gs_triedToLoadSetLayout = false;
gs_pfnAlphaBlend = NULL;
gs_triedToLoadAlphaBlend = false;
gs_pfnGradientFill = NULL;
gs_triedToLoadGradientFill = false;
#endif // USE_DYNAMIC_GDI_FUNCS
}
private: private:
wxDECLARE_DYNAMIC_CLASS(wxGDIDLLsCleanupModule); wxDECLARE_DYNAMIC_CLASS(wxGDIDLLsCleanupModule);
@@ -212,11 +256,13 @@ namespace wxDynLoadWrappers
// libgdi32.a import library (at least up to w32api 4.0.3). // libgdi32.a import library (at least up to w32api 4.0.3).
DWORD GetLayout(HDC hdc) DWORD GetLayout(HDC hdc)
{ {
typedef DWORD (WINAPI *GetLayout_t)(HDC); if ( !gs_triedToLoadGetLayout )
static GetLayout_t {
wxDL_INIT_FUNC(s_pfn, GetLayout, wxDynamicLibrary(wxT("gdi32.dll"))); gs_pfnGetLayout = (GetLayout_t)wxGDI32DLL.GetSymbol(wxT("GetLayout"));
gs_triedToLoadGetLayout = true;
}
return s_pfnGetLayout ? s_pfnGetLayout(hdc) : GDI_ERROR; return gs_pfnGetLayout ? gs_pfnGetLayout(hdc) : GDI_ERROR;
} }
// SetLayout is present in newer w32api versions but in older one (e.g. the one // SetLayout is present in newer w32api versions but in older one (e.g. the one
@@ -224,11 +270,13 @@ DWORD GetLayout(HDC hdc)
// at it. // at it.
DWORD SetLayout(HDC hdc, DWORD dwLayout) DWORD SetLayout(HDC hdc, DWORD dwLayout)
{ {
typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD); if ( !gs_triedToLoadSetLayout )
static SetLayout_t {
wxDL_INIT_FUNC(s_pfn, SetLayout, wxDynamicLibrary(wxT("gdi32.dll"))); gs_pfnSetLayout = (SetLayout_t)wxGDI32DLL.GetSymbol(wxT("SetLayout"));
gs_triedToLoadSetLayout = true;
}
return s_pfnSetLayout ? s_pfnSetLayout(hdc, dwLayout) : GDI_ERROR; return gs_pfnSetLayout ? gs_pfnSetLayout(hdc, dwLayout) : GDI_ERROR;
} }
// AlphaBlend() requires linking with libmsimg32.a and we want to avoid this as // AlphaBlend() requires linking with libmsimg32.a and we want to avoid this as
@@ -237,33 +285,34 @@ BOOL AlphaBlend(HDC hdcDest, int xDest, int yDest, int wDest, int hDest,
HDC hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc, HDC hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc,
BLENDFUNCTION bf) BLENDFUNCTION bf)
{ {
typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int, if ( !gs_triedToLoadAlphaBlend )
HDC,int,int,int,int, {
BLENDFUNCTION); gs_pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(wxT("AlphaBlend"));
static const AlphaBlend_t pfnAlphaBlend = gs_triedToLoadAlphaBlend = true;
(AlphaBlend_t)wxMSIMG32DLL.GetSymbol(wxT("AlphaBlend")); }
if ( !pfnAlphaBlend ) if ( !gs_pfnAlphaBlend )
return FALSE; return FALSE;
return pfnAlphaBlend(hdcDest, xDest, yDest, wDest, hDest, return gs_pfnAlphaBlend(hdcDest, xDest, yDest, wDest, hDest,
hdcSrc, xSrc, ySrc, wSrc, hSrc, hdcSrc, xSrc, ySrc, wSrc, hSrc,
bf); bf);
} }
// Just as AlphaBlend(), this one lives in msimg32.dll. // Just as AlphaBlend(), this one lives in msimg32.dll.
BOOL GradientFill(HDC hdc, PTRIVERTEX pVert, ULONG numVert, BOOL GradientFill(HDC hdc, PTRIVERTEX pVert, ULONG numVert,
PVOID pMesh, ULONG numMesh, ULONG mode) PVOID pMesh, ULONG numMesh, ULONG mode)
{ {
typedef BOOL if ( !gs_triedToLoadGradientFill )
(WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); {
static const GradientFill_t pfnGradientFill = gs_pfnGradientFill = (GradientFill_t)wxMSIMG32DLL.GetSymbol(wxT("GradientFill"));
(GradientFill_t)wxMSIMG32DLL.GetSymbol(wxT("GradientFill")); gs_triedToLoadGradientFill = true;
}
if ( !pfnGradientFill ) if ( !gs_pfnGradientFill )
return FALSE; return FALSE;
return pfnGradientFill(hdc, pVert, numVert, pMesh, numMesh, mode); return gs_pfnGradientFill(hdc, pVert, numVert, pMesh, numMesh, mode);
} }
#elif defined(USE_STATIC_GDI_FUNCS) #elif defined(USE_STATIC_GDI_FUNCS)