]> git.saurik.com Git - wxWidgets.git/commitdiff
1. extracted MSW-specific part of wxDynamicLibrary in msw/dlmsw.cpp
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 16 Jan 2005 20:50:06 +0000 (20:50 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 16 Jan 2005 20:50:06 +0000 (20:50 +0000)
2. added and documented wxDynamicLibrary::ListLoaded()

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@31403 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
docs/latex/wx/dynlib.tex
include/wx/dynlib.h
src/common/dynlib.cpp
src/msw/dlmsw.cpp [new file with mode: 0644]

index 688bc2b9042e412829d06980dd6fc9cf339ec731..380862a04f676b70680dfe3cc532fe17f204552a 100644 (file)
@@ -33,6 +33,7 @@ All:
 - Added support to the wxODBC classes for Firebird 1.5 database
 - The samples\db sample program now includes an optional example of using a BLOB
   datatype (if BLOB support is enabled and supported by the database)
 - Added support to the wxODBC classes for Firebird 1.5 database
 - The samples\db sample program now includes an optional example of using a BLOB
   datatype (if BLOB support is enabled and supported by the database)
+- added wxDynamicLibrary::ListLoaded()
 
 All (GUI):
 
 
 All (GUI):
 
index 59ef7f8a828215d283e61c2bbb6ea0cdb94bb140..53152726d8a7467c9db25cd5c69ba6a54a31f11a 100644 (file)
@@ -1,6 +1,6 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Name:        dynlib.tex
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Name:        dynlib.tex
-%% Purpose:     wxDynamicLibrary documentation
+%% Purpose:     wxDynamicLibrary and wxDynamicLibraryDetails documentation
 %% Author:      Vadim Zeitlin
 %% Modified by:
 %% Created:     14.01.02 (extracted from dllload.tex)
 %% Author:      Vadim Zeitlin
 %% Modified by:
 %% Created:     14.01.02 (extracted from dllload.tex)
@@ -22,7 +22,17 @@ done in the objects destructor automatically.
 %
 %\helpref{wxDllLoader}{wxdllloader}
 
 %
 %\helpref{wxDllLoader}{wxdllloader}
 
+\wxheading{Derived from}
 
 
+No base class.
+
+\wxheading{Include files}
+
+<wx/dynlib.h>
+
+(only available if \texttt{wxUSE\_DYNLIB\_CLASS} is set to $1$)
+
+\latexignore{\rtfignore{\wxheading{Members}}}
 
 \membersection{wxDynamicLibrary::wxDynamicLibrary}\label{wxdynamiclibrarywxdynamiclibrary}
 
 
 \membersection{wxDynamicLibrary::wxDynamicLibrary}\label{wxdynamiclibrarywxdynamiclibrary}
 
@@ -111,6 +121,19 @@ this function doesn't log an error message if the symbol is not found.
 Returns \true if the library was successfully loaded, \false otherwise.
 
 
 Returns \true if the library was successfully loaded, \false otherwise.
 
 
+\membersection{wxDynamicLibrary::ListLoaded}\label{wxdynamiclibrarylistloaded}
+
+\func{static wxDynamicLibraryDetailsArray}{ListLoaded}{\void}
+
+This static method returns an \helpref{array}{wxarray} containing the details
+of all modules loaded into the address space of the current project, the array
+elements are object of \texttt{wxDynamicLibraryDetails} class. The array will
+be empty if an error occured.
+
+This method is currently only implemented under Win32 and is useful mostly for
+diagnostics purposes.
+
+
 \membersection{wxDynamicLibrary::Load}\label{wxdynamiclibraryload}
 
 \func{bool}{Load}{\param{const wxString\& }{name}, \param{int }{flags = wxDL\_DEFAULT}}
 \membersection{wxDynamicLibrary::Load}\label{wxdynamiclibraryload}
 
 \func{bool}{Load}{\param{const wxString\& }{name}, \param{int }{flags = wxDL\_DEFAULT}}
@@ -143,3 +166,70 @@ during a longer period of time than the scope of the wxDynamicLibrary object.
 In this case you may call \helpref{Detach}{wxdynamiclibrarydetach} and store
 the handle somewhere and call this static method later to unload it.
 
 In this case you may call \helpref{Detach}{wxdynamiclibrarydetach} and store
 the handle somewhere and call this static method later to unload it.
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{\class{wxDynamicLibraryDetails}}\label{wxdynamiclibrarydetails}
+
+This class is used for the objects returned by 
+\helpref{wxDynamicLibrary::ListLoaded}{wxdynamiclibrarylistloaded} method and
+contains the information about a single module loaded into the address space of
+the current process. A module in this context may be either a dynamic library
+or the main program itself.
+
+\wxheading{Derived from}
+
+No base class.
+
+\wxheading{Include files}
+
+<wx/dynlib.h>
+
+(only available if \texttt{wxUSE\_DYNLIB\_CLASS} is set to $1$)
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+\membersection{wxDynamicLibraryDetails::GetName}\label{wxdynamiclibrarygetname}
+
+\constfunc{wxString}{GetName}{\void}
+
+Returns the base name of this module, e.g. \texttt{kernel32.dll} or 
+\texttt{libc-2.3.2.so}.
+
+
+\membersection{wxDynamicLibraryDetails::GetPath}\label{wxdynamiclibrarygetpath}
+
+\constfunc{wxString}{GetPath}{\void}
+
+Returns the full path of this module if available, e.g. 
+\texttt{c:$\backslash$windows$\backslash$system32$\backslash$kernel32.dll} or 
+\texttt{/lib/libc-2.3.2.so}.
+
+
+\membersection{wxDynamicLibraryDetails::GetAddress}\label{wxdynamiclibrarygetaddress}
+
+\constfunc{bool}{GetAddress}{\param{void **}{addr}, \param{size\_t }{*len}}
+
+Retrieves the load address and the size of this module.
+
+\wxheading{Parameters}
+
+\docparam{addr}{the pointer to the location to return load address in, may be
+\texttt{NULL}}
+
+\docparam{len}{pointer to the location to return the size of this module in
+memory in, may be \texttt{NULL}}
+
+\wxheading{Return value}
+
+\true if the load address and module size were retrieved, \false if this
+information is not available.
+
+
+\membersection{wxDynamicLibraryDetails::GetVersion}\label{wxdynamiclibrarygetversion}
+
+\constfunc{wxString}{GetVersion}{\void}
+
+Returns the version of this module, e.g. \texttt{5.2.3790.0} or 
+\texttt{2.3.2}. The returned string is empty if the version information is not
+available.
+
index e163ae209866aebc2e3276135530710103099de7..ceef9b58c5fb54e05fb664f8e0c6e91104f3107c 100644 (file)
@@ -21,6 +21,7 @@
 #if wxUSE_DYNLIB_CLASS
 
 #include "wx/string.h"
 #if wxUSE_DYNLIB_CLASS
 
 #include "wx/string.h"
+#include "wx/dynarray.h"
 
 // FIXME: can this go in private.h or something too??
 #if defined(__WXPM__) || defined(__EMX__)
 
 // FIXME: can this go in private.h or something too??
 #if defined(__WXPM__) || defined(__EMX__)
@@ -32,6 +33,8 @@
 #include "wx/msw/private.h"
 #endif
 
 #include "wx/msw/private.h"
 #endif
 
+class WXDLLIMPEXP_BASE wxDynamicLibraryDetailsCreator;
+
 // ----------------------------------------------------------------------------
 // conditional compilation
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // conditional compilation
 // ----------------------------------------------------------------------------
@@ -106,9 +109,62 @@ enum wxPluginCategory
 #define wxDYNLIB_FUNCTION(type, name, dynlib) \
     type pfn ## name = (type)(dynlib).GetSymbol(_T(#name))
 
 #define wxDYNLIB_FUNCTION(type, name, dynlib) \
     type pfn ## name = (type)(dynlib).GetSymbol(_T(#name))
 
-// ---------------------------------------------------------------------------
-// wxDynamicLibrary
-// ---------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// wxDynamicLibraryDetails: contains details about a loaded wxDynamicLibrary
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_BASE wxDynamicLibraryDetails
+{
+public:
+    // ctor, normally never used as these objects are only created by
+    // wxDynamicLibrary::ListLoaded()
+    wxDynamicLibraryDetails() { m_address = NULL; m_length = 0; }
+
+    // get the (base) name
+    wxString GetName() const { return m_name; }
+
+    // get the full path of this object
+    wxString GetPath() const { return m_path; }
+
+    // get the load address and the extent, return true if this information is
+    // available
+    bool GetAddress(void **addr, size_t *len) const
+    {
+        if ( !m_address )
+            return false;
+
+        if ( addr )
+            *addr = m_address;
+        if ( len )
+            *len = m_length;
+
+        return true;
+    }
+
+    // return the version of the DLL (may be empty if no version info)
+    wxString GetVersion() const
+    {
+        return m_version;
+    }
+
+private:
+    wxString m_name,
+             m_path,
+             m_version;
+
+    void *m_address;
+    size_t m_length;
+
+    friend class wxDynamicLibraryDetailsCreator;
+};
+
+WX_DECLARE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetails,
+                                  wxDynamicLibraryDetailsArray,
+                                  WXDLLIMPEXP_BASE);
+
+// ----------------------------------------------------------------------------
+// wxDynamicLibrary: represents a handle to a DLL/shared object
+// ----------------------------------------------------------------------------
 
 class WXDLLIMPEXP_BASE wxDynamicLibrary
 {
 
 class WXDLLIMPEXP_BASE wxDynamicLibrary
 {
@@ -135,8 +191,13 @@ public:
     bool IsLoaded() const { return m_handle != 0; }
 
     // load the library with the given name (full or not), return true if ok
     bool IsLoaded() const { return m_handle != 0; }
 
     // load the library with the given name (full or not), return true if ok
-    bool Load(wxString libname, int flags = wxDL_DEFAULT);
+    bool Load(const wxString& libname, int flags = wxDL_DEFAULT);
 
 
+    // raw function for loading dynamic libs: always behaves as if
+    // wxDL_VERBATIM were specified and doesn't log error message if the
+    // library couldn't be loaded but simply returns NULL
+    static wxDllType RawLoad(const wxString& libname);
+    
     // detach the library object from its handle, i.e. prevent the object from
     // unloading the library in its dtor -- the caller is now responsible for
     // doing this
     // detach the library object from its handle, i.e. prevent the object from
     // unloading the library in its dtor -- the caller is now responsible for
     // doing this
@@ -172,8 +233,19 @@ public:
     //
     // Returns a pointer to the symbol on success, or NULL if an error occurred
     // or the symbol wasn't found.
     //
     // Returns a pointer to the symbol on success, or NULL if an error occurred
     // or the symbol wasn't found.
-    void *GetSymbol(const wxString& name, bool *success = 0) const;
+    void *GetSymbol(const wxString& name, bool *success = NULL) const;
 
 
+    // low-level version of GetSymbol()
+    static void *RawGetSymbol(wxDllType handle, const wxString& name);
+    void *RawGetSymbol(const wxString& name) const
+    {
+        return RawGetSymbol(m_handle, name);
+    }
+
+    // return all modules/shared libraries in the address space of this process
+    //
+    // returns an empty array if not implemented or an error occured
+    static wxDynamicLibraryDetailsArray ListLoaded();
 
     // return platform-specific name of dynamic library with proper extension
     // and prefix (e.g. "foo.dll" on Windows or "libfoo.so" on Linux)
 
     // return platform-specific name of dynamic library with proper extension
     // and prefix (e.g. "foo.dll" on Windows or "libfoo.so" on Linux)
@@ -196,7 +268,7 @@ public:
 #endif
 
 protected:
 #endif
 
 protected:
-    // the real implementation of GetSymbol()
+    // common part of GetSymbol() and HasSymbol()
     void *DoGetSymbol(const wxString& name, bool *success = 0) const;
 
 
     void *DoGetSymbol(const wxString& name, bool *success = 0) const;
 
 
index c2adec781804ff8fa6c7e284d3c15ab68cf1ccb3..c7c5b82f98cab6498b08f5d78b8decf9c55560f0 100644 (file)
 
 #if wxUSE_DYNLIB_CLASS
 
 
 #if wxUSE_DYNLIB_CLASS
 
-#if defined(__WINDOWS__)
-    #include "wx/msw/wrapwin.h"
-#endif
-
 #include "wx/dynlib.h"
 #include "wx/filefn.h"
 #include "wx/intl.h"
 #include "wx/dynlib.h"
 #include "wx/filefn.h"
 #include "wx/intl.h"
 #include "wx/app.h"
 #include "wx/apptrait.h"
 
 #include "wx/app.h"
 #include "wx/apptrait.h"
 
+#include "wx/arrimpl.cpp"
+
 #if defined(__WXMAC__)
     #include "wx/mac/private.h"
 #endif
 
 #if defined(__WXMAC__)
     #include "wx/mac/private.h"
 #endif
 
+WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray);
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -152,9 +151,9 @@ void *dlsym(void *handle, const char *symbol)
 // ---------------------------------------------------------------------------
 
 //FIXME:  This class isn't really common at all, it should be moved into
 // ---------------------------------------------------------------------------
 
 //FIXME:  This class isn't really common at all, it should be moved into
-//        platform dependent files.
+//        platform dependent files (already done for Windows)
 
 
-#if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
+#if defined(__WXPM__) || defined(__EMX__)
     const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll");
 #elif defined(__WXMAC__) && !defined(__DARWIN__)
     const wxChar *wxDynamicLibrary::ms_dllext = _T("");
     const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll");
 #elif defined(__WXMAC__) && !defined(__DARWIN__)
     const wxChar *wxDynamicLibrary::ms_dllext = _T("");
@@ -180,11 +179,12 @@ wxDllType wxDynamicLibrary::GetProgramHandle()
 #endif
 }
 
 #endif
 }
 
-bool wxDynamicLibrary::Load(wxString libname, int flags)
+bool wxDynamicLibrary::Load(const wxString& libnameOrig, int flags)
 {
     wxASSERT_MSG(m_handle == 0, _T("Library already loaded."));
 
     // add the proper extension for the DLL ourselves unless told not to
 {
     wxASSERT_MSG(m_handle == 0, _T("Library already loaded."));
 
     // add the proper extension for the DLL ourselves unless told not to
+    wxString libname = libnameOrig;
     if ( !(flags & wxDL_VERBATIM) )
     {
         // and also check that the libname doesn't already have it
     if ( !(flags & wxDL_VERBATIM) )
     {
         // and also check that the libname doesn't already have it
@@ -279,7 +279,7 @@ bool wxDynamicLibrary::Load(wxString libname, int flags)
     m_handle = shl_load(libname.fn_str(), BIND_DEFERRED, 0);
 
 #elif defined(__WINDOWS__)
     m_handle = shl_load(libname.fn_str(), BIND_DEFERRED, 0);
 
 #elif defined(__WINDOWS__)
-    m_handle = ::LoadLibrary(libname.c_str());
+    m_handle = RawLoad(libname);
 #else
     #error  "runtime shared lib support not implemented on this platform"
 #endif
 #else
     #error  "runtime shared lib support not implemented on this platform"
 #endif
@@ -306,6 +306,8 @@ bool wxDynamicLibrary::Load(wxString libname, int flags)
     return IsLoaded();
 }
 
     return IsLoaded();
 }
 
+#ifndef __WXMSW__
+
 /* static */
 void wxDynamicLibrary::Unload(wxDllType handle)
 {
 /* static */
 void wxDynamicLibrary::Unload(wxDllType handle)
 {
@@ -315,8 +317,6 @@ void wxDynamicLibrary::Unload(wxDllType handle)
     dlclose( handle );
 #elif defined(HAVE_SHL_LOAD)
     shl_unload( handle );
     dlclose( handle );
 #elif defined(HAVE_SHL_LOAD)
     shl_unload( handle );
-#elif defined(__WINDOWS__)
-    ::FreeLibrary( handle );
 #elif defined(__WXMAC__) && !defined(__DARWIN__)
     CloseConnection( (CFragConnectionID*) &handle );
 #else
 #elif defined(__WXMAC__) && !defined(__DARWIN__)
     CloseConnection( (CFragConnectionID*) &handle );
 #else
@@ -324,6 +324,8 @@ void wxDynamicLibrary::Unload(wxDllType handle)
 #endif
 }
 
 #endif
 }
 
+#endif // !__WXMSW__
+
 void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const
 {
     wxCHECK_MSG( IsLoaded(), NULL,
 void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const
 {
     wxCHECK_MSG( IsLoaded(), NULL,
@@ -359,12 +361,7 @@ void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const
         symbol = 0;
 
 #elif defined(__WINDOWS__)
         symbol = 0;
 
 #elif defined(__WINDOWS__)
-#ifdef __WXWINCE__
-    symbol = (void*) ::GetProcAddress( m_handle, name );
-#else
-    symbol = (void*) ::GetProcAddress( m_handle, name.mb_str() );
-#endif
-
+    symbol = RawGetSymbol(m_handle, name);
 #else
 #error  "runtime shared lib support not implemented"
 #endif
 #else
 #error  "runtime shared lib support not implemented"
 #endif
@@ -402,6 +399,10 @@ void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const
     return symbol;
 }
 
     return symbol;
 }
 
+// ----------------------------------------------------------------------------
+// informational methods
+// ----------------------------------------------------------------------------
+
 /*static*/
 wxString
 wxDynamicLibrary::CanonicalizeName(const wxString& name,
 /*static*/
 wxString
 wxDynamicLibrary::CanonicalizeName(const wxString& name,
diff --git a/src/msw/dlmsw.cpp b/src/msw/dlmsw.cpp
new file mode 100644 (file)
index 0000000..f0f1076
--- /dev/null
@@ -0,0 +1,300 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        msw/dlmsw.cpp
+// Purpose:     Win32-specific part of wxDynamicLibrary and related classes
+// Author:      Vadim Zeitlin
+// Modified by:
+// Created:     2005-01-10 (partly extracted from common/dynlib.cpp)
+// RCS-ID:      $Id$
+// Copyright:   (c) 1998-2005 Vadim Zeitlin <vadim@wxwindows.org>
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include  "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+  #pragma hdrstop
+#endif
+
+#if wxUSE_DYNLIB_CLASS
+
+#include "wx/msw/private.h"
+#include "wx/msw/debughlp.h"
+
+const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll");
+
+// ----------------------------------------------------------------------------
+// private classes
+// ----------------------------------------------------------------------------
+
+// wrap some functions from version.dll: load them dynamically and provide a
+// clean interface
+class wxVersionDLL
+{
+public:
+    // load version.dll and bind to its functions
+    wxVersionDLL();
+
+    // return the file version as string, e.g. "x.y.z.w"
+    wxString GetFileVersion(const wxString& filename) const;
+
+private:
+    typedef DWORD (APIENTRY *GetFileVersionInfoSize_t)(PTSTR, PDWORD);
+    typedef BOOL (APIENTRY *GetFileVersionInfo_t)(PTSTR, DWORD, DWORD, PVOID);
+    typedef BOOL (APIENTRY *VerQueryValue_t)(const PVOID, PTSTR, PVOID *, PUINT);
+
+    #define DO_FOR_ALL_VER_FUNCS(what)                                        \
+        what(GetFileVersionInfoSize);                                         \
+        what(GetFileVersionInfo);                                             \
+        what(VerQueryValue)
+
+    #define DECLARE_VER_FUNCTION(func) func ## _t m_pfn ## func
+
+    DO_FOR_ALL_VER_FUNCS(DECLARE_VER_FUNCTION);
+
+    #undef DECLARE_VER_FUNCTION
+
+
+    wxDynamicLibrary m_dll;
+
+
+    DECLARE_NO_COPY_CLASS(wxVersionDLL)
+};
+
+// class used to create wxDynamicLibraryDetails objects
+class WXDLLIMPEXP_BASE wxDynamicLibraryDetailsCreator
+{
+public:
+    // type of parameters being passed to EnumModulesProc
+    struct EnumModulesProcParams
+    {
+        wxDynamicLibraryDetailsArray *dlls;
+        wxVersionDLL *verDLL;
+    };
+
+    static BOOL CALLBACK
+        EnumModulesProc(PSTR name, DWORD base, ULONG size, void *data);
+};
+
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+
+// return the module handle for the given base name
+static
+HMODULE wxGetModuleHandle(const char *name, void *addr)
+{
+    // we want to use GetModuleHandleEx() instead of usual GetModuleHandle()
+    // because the former works correctly for comctl32.dll while the latter
+    // returns NULL when comctl32.dll version 6 is used under XP (note that
+    // GetModuleHandleEx() is only available under XP and later, coincidence?)
+
+    // check if we can use GetModuleHandleEx
+    typedef BOOL (WINAPI *GetModuleHandleEx_t)(DWORD, LPCTSTR, HMODULE *);
+
+    static const GetModuleHandleEx_t INVALID_FUNC_PTR = (GetModuleHandleEx_t)-1;
+
+    static GetModuleHandleEx_t s_pfnGetModuleHandleEx = INVALID_FUNC_PTR;
+    if ( s_pfnGetModuleHandleEx == INVALID_FUNC_PTR )
+    {
+        wxDynamicLibrary dll(_T("kernel32.dll"), wxDL_VERBATIM);
+        s_pfnGetModuleHandleEx =
+            (GetModuleHandleEx_t)dll.RawGetSymbol(_T("GetModuleHandleExA"));
+
+        // dll object can be destroyed, kernel32.dll won't be unloaded anyhow
+    }
+
+    // get module handle from its address
+    if ( s_pfnGetModuleHandleEx )
+    {
+        // flags are GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+        //           GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+        HMODULE hmod;
+        if ( s_pfnGetModuleHandleEx(6, (char *)addr, &hmod) && hmod )
+            return hmod;
+    }
+
+    // if failed, try by name
+    return ::GetModuleHandleA(name);
+}
+
+// ============================================================================
+// wxVersionDLL implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// loading
+// ----------------------------------------------------------------------------
+
+wxVersionDLL::wxVersionDLL()
+{
+    // don't give errors if DLL can't be loaded or used, we're prepared to
+    // handle it
+    wxLogNull noLog;
+
+    if ( m_dll.Load(_T("version.dll"), wxDL_VERBATIM) )
+    {
+        // the functions we load have either 'A' or 'W' suffix depending on
+        // whether we're in ANSI or Unicode build
+        #ifdef UNICODE
+            #define SUFFIX L"W"
+        #else // ANSI
+            #define SUFFIX "A"
+        #endif // UNICODE/ANSI
+
+        #define LOAD_VER_FUNCTION(name)                                       \
+            m_pfn ## name = (name ## _t)m_dll.GetSymbol(_T(#name SUFFIX));    \
+        if ( !m_pfn ## name )                                                 \
+        {                                                                     \
+            m_dll.Unload();                                                   \
+            return;                                                           \
+        }
+
+        DO_FOR_ALL_VER_FUNCS(LOAD_VER_FUNCTION);
+
+        #undef LOAD_VER_FUNCTION
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxVersionDLL operations
+// ----------------------------------------------------------------------------
+
+wxString wxVersionDLL::GetFileVersion(const wxString& filename) const
+{
+    wxString ver;
+    if ( m_dll.IsLoaded() )
+    {
+        wxChar *pc = wx_const_cast(wxChar *, filename.c_str());
+
+        DWORD dummy;
+        DWORD sizeVerInfo = m_pfnGetFileVersionInfoSize(pc, &dummy);
+        if ( sizeVerInfo )
+        {
+            wxCharBuffer buf(sizeVerInfo);
+            if ( m_pfnGetFileVersionInfo(pc, 0, sizeVerInfo, buf.data()) )
+            {
+                void *pVer;
+                UINT sizeInfo;
+                if ( m_pfnVerQueryValue(buf.data(), _T("\\"), &pVer, &sizeInfo) )
+                {
+                    VS_FIXEDFILEINFO *info = (VS_FIXEDFILEINFO *)pVer;
+                    ver.Printf(_T("%d.%d.%d.%d"),
+                               HIWORD(info->dwFileVersionMS),
+                               LOWORD(info->dwFileVersionMS),
+                               HIWORD(info->dwFileVersionLS),
+                               LOWORD(info->dwFileVersionLS));
+                }
+            }
+        }
+    }
+    //else: we failed to load DLL, can't retrieve version info
+
+    return ver;
+}
+
+// ============================================================================
+// wxDynamicLibraryDetailsCreator implementation
+// ============================================================================
+
+/* static */
+BOOL CALLBACK
+wxDynamicLibraryDetailsCreator::EnumModulesProc(PSTR name,
+                                                DWORD base,
+                                                ULONG size,
+                                                void *data)
+{
+    EnumModulesProcParams *params = (EnumModulesProcParams *)data;
+
+    wxDynamicLibraryDetails *details = new wxDynamicLibraryDetails;
+
+    // fill in simple properties
+    details->m_name = wxString::FromAscii(name);
+    details->m_address = wx_reinterpret_cast(void *, base);
+    details->m_length = size;
+
+    // to get the version, we first need the full path
+    HMODULE hmod = wxGetModuleHandle(name, (void *)base);
+    if ( hmod )
+    {
+        wxString fullname = wxGetFullModuleName(hmod);
+        if ( !fullname.empty() )
+        {
+            details->m_path = fullname;
+            details->m_version = params->verDLL->GetFileVersion(fullname);
+        }
+    }
+
+    params->dlls->Add(details);
+
+    // continue enumeration (returning FALSE would have stopped it)
+    return TRUE;
+}
+
+// ============================================================================
+// wxDynamicLibrary implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// loading/unloading DLLs
+// ----------------------------------------------------------------------------
+
+/* static */
+wxDllType wxDynamicLibrary::RawLoad(const wxString& libname)
+{
+    return ::LoadLibrary(libname);
+}
+
+/* static */
+void wxDynamicLibrary::Unload(wxDllType handle)
+{
+    ::FreeLibrary(handle);
+}
+
+/* static */
+void *wxDynamicLibrary::RawGetSymbol(wxDllType handle, const wxString& name)
+{
+    return ::GetProcAddress(handle, name);
+}
+
+// ----------------------------------------------------------------------------
+// enumerating loaded DLLs
+// ----------------------------------------------------------------------------
+
+/* static */
+wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
+{
+    wxDynamicLibraryDetailsArray dlls;
+
+    if ( wxDbgHelpDLL::Init() )
+    {
+        // prepare to use functions for version info extraction
+        wxVersionDLL verDLL;
+
+        wxDynamicLibraryDetailsCreator::EnumModulesProcParams params;
+        params.dlls = &dlls;
+        params.verDLL = &verDLL;
+
+        if ( !wxDbgHelpDLL::EnumerateLoadedModules
+                            (
+                                ::GetCurrentProcess(),
+                                wxDynamicLibraryDetailsCreator::EnumModulesProc,
+                                &params
+                            ) )
+        {
+            wxLogLastError(_T("EnumerateLoadedModules"));
+        }
+    }
+
+    return dlls;
+}
+
+#endif // wxUSE_DYNLIB_CLASS
+