From defbed48e78f4e84b35f62c2c1b7fd58d740501c Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 16 Jan 2005 20:50:06 +0000
Subject: [PATCH] 1. extracted MSW-specific part of wxDynamicLibrary in
 msw/dlmsw.cpp 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         |   1 +
 docs/latex/wx/dynlib.tex |  92 +++++++++++-
 include/wx/dynlib.h      |  84 ++++++++++-
 src/common/dynlib.cpp    |  33 ++---
 src/msw/dlmsw.cpp        | 300 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 487 insertions(+), 23 deletions(-)
 create mode 100644 src/msw/dlmsw.cpp

diff --git a/docs/changes.txt b/docs/changes.txt
index 688bc2b904..380862a04f 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -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 wxDynamicLibrary::ListLoaded()
 
 All (GUI):
 
diff --git a/docs/latex/wx/dynlib.tex b/docs/latex/wx/dynlib.tex
index 59ef7f8a82..53152726d8 100644
--- a/docs/latex/wx/dynlib.tex
+++ b/docs/latex/wx/dynlib.tex
@@ -1,6 +1,6 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Name:        dynlib.tex
-%% Purpose:     wxDynamicLibrary documentation
+%% Purpose:     wxDynamicLibrary and wxDynamicLibraryDetails documentation
 %% 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}
 
+\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}
 
@@ -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.
 
 
+\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}}
@@ -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.
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\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.
+
diff --git a/include/wx/dynlib.h b/include/wx/dynlib.h
index e163ae2098..ceef9b58c5 100644
--- a/include/wx/dynlib.h
+++ b/include/wx/dynlib.h
@@ -21,6 +21,7 @@
 #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__)
@@ -32,6 +33,8 @@
 #include "wx/msw/private.h"
 #endif
 
+class WXDLLIMPEXP_BASE wxDynamicLibraryDetailsCreator;
+
 // ----------------------------------------------------------------------------
 // conditional compilation
 // ----------------------------------------------------------------------------
@@ -106,9 +109,62 @@ enum wxPluginCategory
 #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
 {
@@ -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 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
@@ -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.
-    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)
@@ -196,7 +268,7 @@ public:
 #endif
 
 protected:
-    // the real implementation of GetSymbol()
+    // common part of GetSymbol() and HasSymbol()
     void *DoGetSymbol(const wxString& name, bool *success = 0) const;
 
 
diff --git a/src/common/dynlib.cpp b/src/common/dynlib.cpp
index c2adec7818..c7c5b82f98 100644
--- a/src/common/dynlib.cpp
+++ b/src/common/dynlib.cpp
@@ -29,10 +29,6 @@
 
 #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"
@@ -42,10 +38,13 @@
 #include "wx/app.h"
 #include "wx/apptrait.h"
 
+#include "wx/arrimpl.cpp"
+
 #if defined(__WXMAC__)
     #include "wx/mac/private.h"
 #endif
 
+WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray);
 
 // ============================================================================
 // 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
-//        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("");
@@ -180,11 +179,12 @@ wxDllType wxDynamicLibrary::GetProgramHandle()
 #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
+    wxString libname = libnameOrig;
     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 = ::LoadLibrary(libname.c_str());
+    m_handle = RawLoad(libname);
 #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();
 }
 
+#ifndef __WXMSW__
+
 /* 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 );
-#elif defined(__WINDOWS__)
-    ::FreeLibrary( handle );
 #elif defined(__WXMAC__) && !defined(__DARWIN__)
     CloseConnection( (CFragConnectionID*) &handle );
 #else
@@ -324,6 +324,8 @@ void wxDynamicLibrary::Unload(wxDllType handle)
 #endif
 }
 
+#endif // !__WXMSW__
+
 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__)
-#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
@@ -402,6 +399,10 @@ void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const
     return symbol;
 }
 
+// ----------------------------------------------------------------------------
+// informational methods
+// ----------------------------------------------------------------------------
+
 /*static*/
 wxString
 wxDynamicLibrary::CanonicalizeName(const wxString& name,
diff --git a/src/msw/dlmsw.cpp b/src/msw/dlmsw.cpp
new file mode 100644
index 0000000000..f0f1076135
--- /dev/null
+++ b/src/msw/dlmsw.cpp
@@ -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
+
-- 
2.50.0

