diff --git a/build/wxExtend.props b/build/wxExtend.props index cd4b458..77b3d9f 100644 --- a/build/wxExtend.props +++ b/build/wxExtend.props @@ -26,6 +26,7 @@ Create + @@ -40,7 +41,8 @@ - + + diff --git a/build/wxExtendDll-10.0.vcxproj.filters b/build/wxExtendDll-10.0.vcxproj.filters index 3b17acd..1ac4ea9 100644 --- a/build/wxExtendDll-10.0.vcxproj.filters +++ b/build/wxExtendDll-10.0.vcxproj.filters @@ -23,6 +23,9 @@ {be99b1e7-e013-4c69-8966-6b34932a1711} + + {e7ddefe0-5d58-4fda-943c-717689ad974c} + @@ -55,6 +58,9 @@ Source Files + + Source Files + @@ -81,21 +87,30 @@ Header Files\persist - - Header Files\persist - Header Files Header Files + + Header Files + Header Files Header Files\aui + + Header Files + + + Header Files\private + + + Header Files\persist + diff --git a/build/wxExtendDll-15.0.vcxproj.filters b/build/wxExtendDll-15.0.vcxproj.filters index 1f92ab5..23c82e6 100644 --- a/build/wxExtendDll-15.0.vcxproj.filters +++ b/build/wxExtendDll-15.0.vcxproj.filters @@ -23,6 +23,9 @@ {be99b1e7-e013-4c69-8966-6b34932a1711} + + {e7ddefe0-5d58-4fda-943c-717689ad974c} + @@ -55,6 +58,9 @@ Source Files + + Source Files + @@ -81,15 +87,15 @@ Header Files\persist - - Header Files\persist - Header Files Header Files + + Header Files + Header Files @@ -99,6 +105,12 @@ Header Files + + Header Files\private + + + Header Files\persist + diff --git a/build/wxExtendLib-10.0.vcxproj.filters b/build/wxExtendLib-10.0.vcxproj.filters index 0971bbd..c345585 100644 --- a/build/wxExtendLib-10.0.vcxproj.filters +++ b/build/wxExtendLib-10.0.vcxproj.filters @@ -20,6 +20,12 @@ {33d4709f-47d3-42c1-9562-bc4743799b49} + + {be99b1e7-e013-4c69-8966-6b34932a1711} + + + {e7ddefe0-5d58-4fda-943c-717689ad974c} + @@ -52,6 +58,9 @@ Source Files + + Source Files + @@ -78,9 +87,6 @@ Header Files\persist - - Header Files\persist - Header Files @@ -93,6 +99,18 @@ Header Files + + Header Files\aui + + + Header Files + + + Header Files\private + + + Header Files\persist + @@ -188,9 +206,4 @@ Resource Files\Localization - - - Resource Files - - \ No newline at end of file diff --git a/build/wxExtendLib-15.0.vcxproj.filters b/build/wxExtendLib-15.0.vcxproj.filters index ff50048..8a6dd33 100644 --- a/build/wxExtendLib-15.0.vcxproj.filters +++ b/build/wxExtendLib-15.0.vcxproj.filters @@ -20,6 +20,12 @@ {33d4709f-47d3-42c1-9562-bc4743799b49} + + {be99b1e7-e013-4c69-8966-6b34932a1711} + + + {e7ddefe0-5d58-4fda-943c-717689ad974c} + @@ -52,6 +58,9 @@ Source Files + + Source Files + @@ -78,9 +87,6 @@ Header Files\persist - - Header Files\persist - Header Files @@ -94,8 +100,17 @@ Header Files + Header Files\aui + + Header Files + + Header Files\private + + + Header Files\persist + diff --git a/include/wxex/persist/dialog.h b/include/wxex/persist/toplevel.h similarity index 61% rename from include/wxex/persist/dialog.h rename to include/wxex/persist/toplevel.h index aabb4d9..da7da08 100644 --- a/include/wxex/persist/dialog.h +++ b/include/wxex/persist/toplevel.h @@ -1,106 +1,98 @@ -/* - Copyright 2015-2018 Amebis - Copyright 2016 GÉANT - - This file is part of wxExtend. - - wxExtend is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - wxExtend is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with wxExtend. If not, see . -*/ - -#pragma once - -#include "../common.h" - -#include -#include -#include -#include - -/// \addtogroup wxExtend -/// @{ - -/// -/// `wxPersistentDialog` kind for persistent storage -/// -#define wxPERSIST_DIALOG_KIND "Dialog" - -/// -/// Supports saving/restoring wxDialog state -/// -class wxPersistentDialog : - public wxPersistentWindow, - private wxTopLevelWindow::GeometrySerializer -{ -public: - /// - /// Constructs a persistent dialog object - /// - wxPersistentDialog(wxDialog *mgr) : wxPersistentWindow(mgr) - { - } - - /// - /// \returns `wxT(wxPERSIST_DIALOG_KIND)` - /// - virtual wxString GetKind() const wxOVERRIDE - { - return wxT(wxPERSIST_DIALOG_KIND); - } - - /// - /// Saves dialog state - /// - virtual void Save() const wxOVERRIDE - { - const wxDialog * const wnd = Get(); - - // Code copied from wxPersistentTLW::Save() - wnd->SaveGeometry(*this); - } - - /// - /// Restores dialog state - /// - virtual bool Restore() wxOVERRIDE - { - wxDialog * const wnd = Get(); - - return wnd->RestoreToGeometry(*this); - } - -private: - wxDECLARE_NO_COPY_CLASS(wxPersistentDialog); - -private: - virtual bool SaveField(const wxString& name, int value) const wxOVERRIDE - { - return SaveValue(name, value); - } - - virtual bool RestoreField(const wxString& name, int* value) wxOVERRIDE - { - return RestoreValue(name, value); - } -}; - - -/// -/// wxDialog's instantiation of wxCreatePersistentObject template -/// -inline wxPersistentObject *wxCreatePersistentObject(wxDialog *mgr) -{ - return new wxPersistentDialog(mgr); -} - -/// @} +/* + Copyright 2015-2018 Amebis + Copyright 2016 GÉANT + + This file is part of wxExtend. + + wxExtend is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + wxExtend is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with wxExtend. If not, see . +*/ + +#pragma once + +#include "../common.h" +#include "../private/tlwgeom.h" + +#include +#include +#include +#include + +/// \addtogroup wxExtend +/// @{ + +/// +/// Supports saving/restoring wxTopLevelWindow state +/// +class wxPersistentTLWEx : + public wxPersistentWindow, + private wxTopLevelWindow::GeometrySerializer +{ +public: + /// + /// Constructs a persistent dialog object + /// + wxPersistentTLWEx(wxTopLevelWindow *mgr) : wxPersistentWindow(mgr) + { + } + + /// + /// \returns `wxT(wxPERSIST_TLW_KIND)` + /// + virtual wxString GetKind() const wxOVERRIDE + { + return wxT(wxPERSIST_TLW_KIND); + } + + /// + /// Saves dialog state + /// + virtual void Save() const wxOVERRIDE + { + const wxTopLevelWindow * const wnd = Get(); + + wxTLWGeometryEx geom; + if (geom.GetFrom(wnd)) + geom.Save(*this); + } + + /// + /// Restores dialog state + /// + virtual bool Restore() wxOVERRIDE + { + wxTopLevelWindow * const wnd = Get(); + + wxTLWGeometryEx geom; + if (!geom.Restore(*this)) + return false; + + return geom.ApplyTo(wnd); + } + +private: + wxDECLARE_NO_COPY_CLASS(wxPersistentTLWEx); + +private: + virtual bool SaveField(const wxString& name, int value) const wxOVERRIDE + { + return SaveValue(name, value); + } + + virtual bool RestoreField(const wxString& name, int* value) wxOVERRIDE + { + return RestoreValue(name, value); + } +}; + +/// @} diff --git a/include/wxex/private/tlwgeom.h b/include/wxex/private/tlwgeom.h new file mode 100644 index 0000000..9b325f6 --- /dev/null +++ b/include/wxex/private/tlwgeom.h @@ -0,0 +1,346 @@ +/* + Copyright 2015-2018 Amebis + Copyright 2016 GÉANT + + This file is part of wxExtend. + + wxExtend is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + wxExtend is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with wxExtend. If not, see . +*/ + +#pragma once + +#include +#include + +#ifndef USER_DEFAULT_SCREEN_DPI +#define USER_DEFAULT_SCREEN_DPI 96 +#endif + +/// \addtogroup wxExtend +/// @{ + +/// +/// `wxPersistentDialog` kind for persistent storage +/// +#define wxPERSIST_TLW_MONITOR_X "xmon" +#define wxPERSIST_TLW_MONITOR_Y "ymon" +#define wxPERSIST_TLW_MONITOR_W "wmon" +#define wxPERSIST_TLW_MONITOR_H "hmon" +#define wxPERSIST_TLW_DPI_HORZ "xdpi" +#define wxPERSIST_TLW_DPI_VERT "ydpi" + + +class wxTLWGeometryEx : public wxTLWGeometryBase +{ +public: + wxTLWGeometryEx() + { + wxZeroMemory(m_placement); + m_placement.length = sizeof(m_placement); + + wxZeroMemory(m_mntinfo); + m_mntinfo.cbSize = sizeof(m_mntinfo); + + m_dpiHorz = USER_DEFAULT_SCREEN_DPI; + m_dpiVert = USER_DEFAULT_SCREEN_DPI; + } + + virtual bool Save(const Serializer& ser) const wxOVERRIDE + { + // For compatibility with the existing saved positions/sizes, use the + // same keys as the generic version (which was previously used under + // MSW too). + + // Normal position and size. + const RECT& rc = m_placement.rcNormalPosition; + if (!ser.SaveField(wxPERSIST_TLW_X, rc.left) || + !ser.SaveField(wxPERSIST_TLW_Y, rc.top) || + !ser.SaveField(wxPERSIST_TLW_W, rc.right - rc.left) || + !ser.SaveField(wxPERSIST_TLW_H, rc.bottom - rc.top)) + return false; + + // Maximized/minimized state. + UINT show = m_placement.showCmd; + if (!ser.SaveField(wxPERSIST_TLW_MAXIMIZED, show == SW_SHOWMAXIMIZED)) + return false; + + if (!ser.SaveField(wxPERSIST_TLW_ICONIZED, show == SW_SHOWMINIMIZED)) + return false; + + // Maximized window position. + const POINT pt = m_placement.ptMaxPosition; + if (!ser.SaveField(wxPERSIST_TLW_MAX_X, pt.x) || + !ser.SaveField(wxPERSIST_TLW_MAX_Y, pt.y)) + return false; + + // We don't currently save the minimized window position, it doesn't + // seem useful for anything and is probably just a left over from + // Windows 3.1 days, when icons were positioned on the desktop instead + // of being located in the taskbar. + + // Monitor position and size. + const RECT& rcMon = m_mntinfo.rcWork; + if (!ser.SaveField(wxPERSIST_TLW_MONITOR_X, rcMon.left) || + !ser.SaveField(wxPERSIST_TLW_MONITOR_Y, rcMon.top) || + !ser.SaveField(wxPERSIST_TLW_MONITOR_W, rcMon.right - rcMon.left) || + !ser.SaveField(wxPERSIST_TLW_MONITOR_H, rcMon.bottom - rcMon.top)) + return false; + + // DPI. + if (!ser.SaveField(wxPERSIST_TLW_DPI_HORZ, m_dpiHorz) || + !ser.SaveField(wxPERSIST_TLW_DPI_VERT, m_dpiVert)) + return false; + + return true; + } + + virtual bool Restore(Serializer& ser) wxOVERRIDE + { + // Normal position and size. + wxRect r; + if (!ser.RestoreField(wxPERSIST_TLW_X, &r.x) || + !ser.RestoreField(wxPERSIST_TLW_Y, &r.y) || + !ser.RestoreField(wxPERSIST_TLW_W, &r.width) || + !ser.RestoreField(wxPERSIST_TLW_H, &r.height)) + return false; + wxCopyRectToRECT(r, m_placement.rcNormalPosition); + + // Maximized/minimized state. + // + // Note the special case of SW_MINIMIZE: while GetWindowPlacement() + // returns SW_SHOWMINIMIZED when the window is iconized, we restore it + // as SW_MINIMIZE as this is what the code in wxTLW checks to determine + // whether the window is supposed to be iconized or not. + // + // Just to confuse matters further, note that SW_MAXIMIZE is exactly + // the same thing as SW_SHOWMAXIMIZED. + int tmp; + UINT& show = m_placement.showCmd; + if (ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp) + show = SW_MAXIMIZE; + else if (ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) && tmp) + show = SW_MINIMIZE; + else + show = SW_SHOWNORMAL; + + // Maximized window position. + if (ser.RestoreField(wxPERSIST_TLW_MAX_X, &r.x) && + ser.RestoreField(wxPERSIST_TLW_MAX_Y, &r.y)) + { + m_placement.ptMaxPosition.x = r.x; + m_placement.ptMaxPosition.y = r.y; + } else { + m_placement.ptMaxPosition.x = -1; + m_placement.ptMaxPosition.y = -1; + } + + m_placement.ptMinPosition.x = -1; + m_placement.ptMinPosition.y = -1; + + // Monitor position and size. + wxRect rmon; + if (!ser.RestoreField(wxPERSIST_TLW_MONITOR_X, &rmon.x) || + !ser.RestoreField(wxPERSIST_TLW_MONITOR_Y, &rmon.y) || + !ser.RestoreField(wxPERSIST_TLW_MONITOR_W, &rmon.width) || + !ser.RestoreField(wxPERSIST_TLW_MONITOR_H, &rmon.height)) + return false; + wxCopyRectToRECT(rmon, m_mntinfo.rcWork); + + // DPI. + if (!ser.RestoreField(wxPERSIST_TLW_DPI_HORZ, &r.x) || + !ser.RestoreField(wxPERSIST_TLW_DPI_VERT, &r.y)) + return false; + m_dpiHorz = r.x; + m_dpiVert = r.y; + + return true; + } + + virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE + { + WXHWND hWnd = GetHwndOf(tlw); + if (!::GetWindowPlacement(hWnd, &m_placement)) + { + wxLogLastError(wxS("GetWindowPlacement")); + return false; + } + + HMONITOR hMonitor = ::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + wxASSERT_MSG(hMonitor, wxT("error locating monitor")); + if (!::GetMonitorInfo(hMonitor, &m_mntinfo)) + { + wxLogLastError(wxS("GetMonitorInfo")); + return false; + } + + GetDPI(hWnd, &m_dpiHorz, &m_dpiVert) || GetDPI(hMonitor, &m_dpiHorz, &m_dpiVert); + + return true; + } + + virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE + { + // There is a subtlety here: if the window is currently hidden, + // restoring its geometry shouldn't show it, so we must use SW_HIDE as + // show command, but showing it later should restore it to the correct + // state, so we need to remember it in wxTLW itself. And even if it's + // currently shown, we still need to update its show command, so that + // it matches the real window state after SetWindowPlacement() call. + tlw->MSWSetShowCommand(m_placement.showCmd); + if (!tlw->IsShown()) + { + m_placement.showCmd = SW_HIDE; + } + + // Get monitor to restore window to. + HMONITOR hMonitor = ::MonitorFromRect(&m_mntinfo.rcWork, MONITOR_DEFAULTTONEAREST); + wxASSERT_MSG(hMonitor, wxT("error locating monitor")); + MONITORINFO mntinfo; + mntinfo.cbSize = sizeof(mntinfo); + if (!::GetMonitorInfo(hMonitor, &mntinfo)) + { + wxLogLastError(wxS("GetMonitorInfo")); + return false; + } + + UINT dpiHorz, dpiVert; + GetDPI(hMonitor, &dpiHorz, &dpiVert); + + SIZE + sizeWorkPrev = { + m_mntinfo.rcWork.right - m_mntinfo.rcWork.left, + m_mntinfo.rcWork.bottom - m_mntinfo.rcWork.top + }, + sizeWork = { + mntinfo.rcWork.right - mntinfo.rcWork.left, + mntinfo.rcWork.bottom - mntinfo.rcWork.top + }; + + // + // Project the coordinates: + // - Position relative to monitor working area center. + // - Scale according to DPI. + // + + if (m_placement.ptMaxPosition.x != -1 && m_placement.ptMaxPosition.y != -1) { + m_placement.ptMaxPosition.x = wxMulDivInt32(m_placement.ptMaxPosition.x - m_mntinfo.rcWork.left, sizeWork.cx, sizeWorkPrev.cx) + mntinfo.rcWork.left; + m_placement.ptMaxPosition.y = wxMulDivInt32(m_placement.ptMaxPosition.y - m_mntinfo.rcWork.top, sizeWork.cy, sizeWorkPrev.cy) + mntinfo.rcWork.top; + } + + SIZE sizeWndPrev, sizeWnd; + HWND hWnd = GetHwndOf(tlw); + + if (tlw->GetWindowStyle() & wxRESIZE_BORDER) { + sizeWndPrev.cx = m_placement.rcNormalPosition.right - m_placement.rcNormalPosition.left; + sizeWndPrev.cy = m_placement.rcNormalPosition.bottom - m_placement.rcNormalPosition.top; + sizeWnd.cx = wxMulDivInt32(sizeWndPrev.cx, dpiHorz, m_dpiHorz); + sizeWnd.cy = wxMulDivInt32(sizeWndPrev.cy, dpiVert, m_dpiVert); + } else { + // The window is not resizable. Do not change its size. + WINDOWPLACEMENT placement = { sizeof(placement) }; + if (!::GetWindowPlacement(hWnd, &placement)) + { + wxLogLastError(wxS("GetWindowPlacement")); + return false; + } + SIZE size = { + placement.rcNormalPosition.right - placement.rcNormalPosition.left, + placement.rcNormalPosition.bottom - placement.rcNormalPosition.top + }; + + UINT dpiWndHorz, dpiWndVert; + GetDPI(hWnd, &dpiWndHorz, &dpiWndVert) || GetDPI(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &dpiWndHorz, &dpiWndVert); + + sizeWndPrev.cx = wxMulDivInt32(size.cx, m_dpiHorz, dpiWndHorz); + sizeWndPrev.cy = wxMulDivInt32(size.cy, m_dpiVert, dpiWndVert); + sizeWnd.cx = wxMulDivInt32(size.cx, dpiHorz, dpiWndHorz); + sizeWnd.cy = wxMulDivInt32(size.cy, dpiVert, dpiWndVert); + } + + m_placement.rcNormalPosition.left = wxMulDivInt32(m_placement.rcNormalPosition.left + sizeWndPrev.cx / 2 - m_mntinfo.rcWork.left, sizeWork.cx, sizeWorkPrev.cx) + mntinfo.rcWork.left - sizeWnd.cx / 2; + m_placement.rcNormalPosition.top = wxMulDivInt32(m_placement.rcNormalPosition.top + sizeWndPrev.cy / 2 - m_mntinfo.rcWork.top, sizeWork.cy, sizeWorkPrev.cy) + mntinfo.rcWork.top - sizeWnd.cy / 2; + m_placement.rcNormalPosition.right = m_placement.rcNormalPosition.left + sizeWnd.cx; + m_placement.rcNormalPosition.bottom = m_placement.rcNormalPosition.top + sizeWnd.cy; + + if (!::SetWindowPlacement(hWnd, &m_placement)) + { + wxLogLastError(wxS("SetWindowPlacement")); + return false; + } + + return true; + } + +private: + static bool GetDPI(HWND hWnd, UINT *dpiHorz, UINT *dpiVert) + { + wxASSERT(dpiHorz); + wxASSERT(dpiVert); + +#if wxUSE_DYNLIB_CLASS + typedef HRESULT(WINAPI *GetDpiForWindow_t)(HWND); + static GetDpiForWindow_t s_pfnGetDpiForWindow = NULL; + if (!s_pfnGetDpiForWindow && s_dllUser32.IsLoaded()) + s_pfnGetDpiForWindow = (GetDpiForWindow_t)s_dllUser32.GetSymbol(wxT("GetDpiForWindow")); + + if (s_pfnGetDpiForWindow) { + *dpiHorz = *dpiVert = s_pfnGetDpiForWindow(hWnd); + return true; + } +#endif + + *dpiHorz = *dpiVert = USER_DEFAULT_SCREEN_DPI; + return false; + } + + static bool GetDPI(HMONITOR hMonitor, UINT *dpiHorz, UINT *dpiVert) + { + wxASSERT(dpiHorz); + wxASSERT(dpiVert); + +#if wxUSE_DYNLIB_CLASS + enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI + }; + typedef HRESULT(WINAPI *GetDpiForMonitor_t)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *); + static GetDpiForMonitor_t s_pfnGetDpiForMonitor = NULL; + if (!s_pfnGetDpiForMonitor) { + if (s_dllShCore.IsLoaded()) + s_pfnGetDpiForMonitor = (GetDpiForMonitor_t)s_dllShCore.GetSymbol(wxT("GetDpiForMonitor")); + } + + if (s_pfnGetDpiForMonitor) { + s_pfnGetDpiForMonitor(hMonitor, MDT_DEFAULT, dpiHorz, dpiVert); + return true; + } +#endif + + *dpiHorz = *dpiVert = USER_DEFAULT_SCREEN_DPI; + return false; + } + +private: + WINDOWPLACEMENT m_placement; + MONITORINFO m_mntinfo; + UINT m_dpiHorz; + UINT m_dpiVert; + +#if wxUSE_DYNLIB_CLASS + static wxDynamicLibrary s_dllUser32; + static wxDynamicLibrary s_dllShCore; +#endif +}; diff --git a/src/stdafx.h b/src/stdafx.h index df826ea..902ab00 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -26,6 +26,9 @@ #include "../include/wxex/aui/framemanager.h" +#include "../include/wxex/persist/auimanager.h" +#include "../include/wxex/persist/toplevel.h" + #include "../include/wxex/appbar.h" #include "../include/wxex/comutils.h" #include "../include/wxex/crypto.h" @@ -37,3 +40,5 @@ #include "../include/wxex/xml.h" #include "../include/wxex/common.h" + +#include "../include/wxex/private/tlwgeom.h" diff --git a/src/tlwgeom.cpp b/src/tlwgeom.cpp new file mode 100644 index 0000000..5567b0c --- /dev/null +++ b/src/tlwgeom.cpp @@ -0,0 +1,28 @@ +/* + Copyright 2015-2018 Amebis + Copyright 2016 GÉANT + Based on code written by Jeffrey Richter. + + This file is part of wxExtend. + + wxExtend is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + wxExtend is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with wxExtend. If not, see . +*/ + +#include "stdafx.h" + + +#if wxUSE_DYNLIB_CLASS +wxDynamicLibrary wxTLWGeometryEx::s_dllUser32(wxT("user32.dll")); +wxDynamicLibrary wxTLWGeometryEx::s_dllShCore(wxT("shcore.dll")); +#endif