+// Wrappers for the dynamically loaded {Set,Get}Layout() functions. They work
+// in exactly the same way as the standard functions and return GDI_ERROR if
+// they're not actually available.
+DWORD GetLayout(HDC hdc);
+DWORD SetLayout(HDC hdc, DWORD dwLayout);
+
+// Create a compatible HDC and copy the layout of the source DC to it. This is
+// necessary in order to draw bitmaps (which are usually blitted from a
+// temporary compatible memory DC to the real target DC) using the same layout.
+HDC CreateCompatibleDCWithLayout(HDC hdc);
+
+} // namespace wxMSW
+
+// ----------------------------------------------------------------------------
+// private classes
+// ----------------------------------------------------------------------------
+
+// instead of duplicating the same code which sets and then restores text
+// colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
+// encapsulate this in a small helper class
+
+// wxBrushAttrsSetter: changes the text colours in the ctor if required and
+// restores them in the dtor
+class wxBrushAttrsSetter : private wxBkModeChanger,
+ private wxTextColoursChanger
+{
+public:
+ wxBrushAttrsSetter(wxMSWDCImpl& dc);
+
+private:
+ wxDECLARE_NO_COPY_CLASS(wxBrushAttrsSetter);
+};
+
+#ifdef __WXWINCE__
+
+#define SET_STRETCH_BLT_MODE(hdc)
+
+#else // !__WXWINCE__
+
+// this class sets the stretch blit mode to COLORONCOLOR during its lifetime
+//
+// don't use it directly, use SET_STRETCH_BLT_MODE() macro instead as it
+// expands to nothing under WinCE which doesn't have SetStretchBltMode()
+class StretchBltModeChanger
+{
+public:
+ StretchBltModeChanger(HDC hdc)
+ : m_hdc(hdc)
+ {
+ m_modeOld = ::SetStretchBltMode(m_hdc, COLORONCOLOR);
+ if ( !m_modeOld )
+ {
+ wxLogLastError(wxT("SetStretchBltMode"));
+ }
+ }
+
+ ~StretchBltModeChanger()
+ {
+ if ( !::SetStretchBltMode(m_hdc, m_modeOld) )
+ {
+ wxLogLastError(wxT("SetStretchBltMode"));
+ }
+ }
+
+private:
+ const HDC m_hdc;
+
+ int m_modeOld;
+
+ wxDECLARE_NO_COPY_CLASS(StretchBltModeChanger);
+};
+
+#define SET_STRETCH_BLT_MODE(hdc) \
+ StretchBltModeChanger wxMAKE_UNIQUE_NAME(stretchModeChanger)(hdc)
+
+#endif // __WXWINCE__/!__WXWINCE__
+
+#if wxUSE_DYNLIB_CLASS
+
+// helper class to cache dynamically loaded libraries and not attempt reloading
+// them if it fails
+class wxOnceOnlyDLLLoader
+{
+public:
+ // ctor argument must be a literal string as we don't make a copy of it!
+ wxOnceOnlyDLLLoader(const wxChar *dllName)
+ : m_dllName(dllName)
+ {
+ }
+
+
+ // return the symbol with the given name or NULL if the DLL not loaded
+ // or symbol not present
+ void *GetSymbol(const wxChar *name)
+ {
+ // we're prepared to handle errors here
+ wxLogNull noLog;
+
+ if ( m_dllName )
+ {
+ m_dll.Load(m_dllName);
+
+ // reset the name whether we succeeded or failed so that we don't
+ // try again the next time
+ m_dllName = NULL;
+ }
+
+ return m_dll.IsLoaded() ? m_dll.GetSymbol(name) : NULL;
+ }
+
+ void Unload()
+ {
+ if ( m_dll.IsLoaded() )
+ {
+ m_dll.Unload();
+ }
+ }
+
+private:
+ wxDynamicLibrary m_dll;
+ const wxChar *m_dllName;
+};
+
+static wxOnceOnlyDLLLoader wxMSIMG32DLL(wxT("msimg32"));
+
+// 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
+// used as a DLL (attempting to unload another DLL from inside DllMain() hangs
+// under Windows because it tries to reacquire the same lock)
+class wxGDIDLLsCleanupModule : public wxModule
+{
+public:
+ virtual bool OnInit() { return true; }
+ virtual void OnExit() { wxMSIMG32DLL.Unload(); }
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxGDIDLLsCleanupModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxGDIDLLsCleanupModule, wxModule)
+
+namespace
+{
+
+#if wxUSE_DC_TRANSFORM_MATRIX
+
+// Class used to dynamically load world transform related API functions.
+class GdiWorldTransformFuncs
+{
+public:
+ static bool IsOk()
+ {
+ if ( !ms_worldTransformSymbolsLoaded )
+ LoadWorldTransformSymbols();
+
+ return ms_pfnSetGraphicsMode &&
+ ms_pfnSetWorldTransform &&
+ ms_pfnGetWorldTransform &&
+ ms_pfnModifyWorldTransform;
+ }
+
+ typedef int (WINAPI *SetGraphicsMode_t)(HDC, int);
+ static SetGraphicsMode_t SetGraphicsMode()
+ {
+ if ( !ms_worldTransformSymbolsLoaded )
+ LoadWorldTransformSymbols();
+
+ return ms_pfnSetGraphicsMode;
+ }
+
+ typedef BOOL (WINAPI *SetWorldTransform_t)(HDC, const XFORM *);
+ static SetWorldTransform_t SetWorldTransform()
+ {
+ if ( !ms_worldTransformSymbolsLoaded )
+ LoadWorldTransformSymbols();
+
+ return ms_pfnSetWorldTransform;
+ }
+
+ typedef BOOL (WINAPI *GetWorldTransform_t)(HDC, LPXFORM);
+ static GetWorldTransform_t GetWorldTransform()
+ {
+ if ( !ms_worldTransformSymbolsLoaded )
+ LoadWorldTransformSymbols();
+
+ return ms_pfnGetWorldTransform;
+ }
+
+ typedef BOOL (WINAPI *ModifyWorldTransform_t)(HDC, const XFORM *, DWORD);
+ static ModifyWorldTransform_t ModifyWorldTransform()
+ {
+ if ( !ms_worldTransformSymbolsLoaded )
+ LoadWorldTransformSymbols();
+
+ return ms_pfnModifyWorldTransform;
+ }
+
+private:
+ static void LoadWorldTransformSymbols()
+ {
+ wxDynamicLibrary dll(wxT("gdi32.dll"));
+
+ wxDL_INIT_FUNC(ms_pfn, SetGraphicsMode, dll);
+ wxDL_INIT_FUNC(ms_pfn, SetWorldTransform, dll);
+ wxDL_INIT_FUNC(ms_pfn, GetWorldTransform, dll);
+ wxDL_INIT_FUNC(ms_pfn, ModifyWorldTransform, dll);
+
+ ms_worldTransformSymbolsLoaded = true;
+ }
+
+ static SetGraphicsMode_t ms_pfnSetGraphicsMode;
+ static SetWorldTransform_t ms_pfnSetWorldTransform;
+ static GetWorldTransform_t ms_pfnGetWorldTransform;
+ static ModifyWorldTransform_t ms_pfnModifyWorldTransform;
+
+ static bool ms_worldTransformSymbolsLoaded;
+};
+
+GdiWorldTransformFuncs::SetGraphicsMode_t
+ GdiWorldTransformFuncs::ms_pfnSetGraphicsMode = NULL;
+GdiWorldTransformFuncs::SetWorldTransform_t
+ GdiWorldTransformFuncs::ms_pfnSetWorldTransform = NULL;
+GdiWorldTransformFuncs::GetWorldTransform_t
+ GdiWorldTransformFuncs::ms_pfnGetWorldTransform = NULL;
+GdiWorldTransformFuncs::ModifyWorldTransform_t
+ GdiWorldTransformFuncs::ms_pfnModifyWorldTransform = NULL;
+
+bool GdiWorldTransformFuncs::ms_worldTransformSymbolsLoaded = false;
+
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+
+} // anonymous namespace
+
+#endif // wxUSE_DYNLIB_CLASS
+
+// ===========================================================================
+// implementation
+// ===========================================================================
+
+// ----------------------------------------------------------------------------
+// wxBrushAttrsSetter
+// ----------------------------------------------------------------------------
+
+wxBrushAttrsSetter::wxBrushAttrsSetter(wxMSWDCImpl& dc)
+ : wxBkModeChanger(GetHdcOf(dc)),
+ wxTextColoursChanger(GetHdcOf(dc))
+{
+ const wxBrush& brush = dc.GetBrush();
+ if ( brush.IsOk() && brush.GetStyle() == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE )
+ {
+ // note that Windows convention is opposite to wxWidgets one, this is
+ // why text colour becomes the background one and vice versa
+ wxTextColoursChanger::Change(dc.GetTextBackground(),
+ dc.GetTextForeground());
+
+ wxBkModeChanger::Change(dc.GetBackgroundMode());
+ }
+}
+
+// ----------------------------------------------------------------------------
+// wxDC MSW-specific methods
+// ----------------------------------------------------------------------------
+
+WXHDC wxDC::GetHDC() const
+{
+ wxMSWDCImpl * const impl = wxDynamicCast(GetImpl(), wxMSWDCImpl);
+ return impl ? impl->GetHDC() : 0;
+}
+
+// ---------------------------------------------------------------------------
+// wxMSWDCImpl
+// ---------------------------------------------------------------------------
+
+wxMSWDCImpl::wxMSWDCImpl( wxDC *owner, WXHDC hDC ) :
+ wxDCImpl( owner )
+{
+ Init();
+ m_hDC = hDC;
+}
+
+wxMSWDCImpl::~wxMSWDCImpl()
+{
+ if ( m_hDC != 0 )
+ {
+ SelectOldObjects(m_hDC);
+
+ // if we own the HDC, we delete it, otherwise we just release it
+
+ if ( m_bOwnsDC )
+ {
+ ::DeleteDC(GetHdc());
+ }
+ else // we don't own our HDC
+ {
+ if (m_window)
+ {
+ ::ReleaseDC(GetHwndOf(m_window), GetHdc());
+ }
+ else
+ {
+ // Must have been a wxScreenDC
+ ::ReleaseDC((HWND) NULL, GetHdc());
+ }
+ }
+ }