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, + ¶ms + ) ) + { + wxLogLastError(_T("EnumerateLoadedModules")); + } + } + + return dlls; +} + +#endif // wxUSE_DYNLIB_CLASS + -- 2.47.2