1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        msw/dlmsw.cpp
3 // Purpose:     Win32-specific part of wxDynamicLibrary and related classes
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     2005-01-10 (partly extracted from common/dynlib.cpp)
7 // RCS-ID:      $Id: dlmsw.cpp 58750 2009-02-08 10:01:03Z VZ $
8 // Copyright:   (c) 1998-2005 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 
20 #include  "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23   #pragma hdrstop
24 #endif
25 
26 #if wxUSE_DYNLIB_CLASS
27 
28 #include "wx/msw/private.h"
29 #include "wx/msw/debughlp.h"
30 
31 const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll");
32 
33 // ----------------------------------------------------------------------------
34 // private classes
35 // ----------------------------------------------------------------------------
36 
37 // wrap some functions from version.dll: load them dynamically and provide a
38 // clean interface
39 class wxVersionDLL
40 {
41 public:
42     // load version.dll and bind to its functions
43     wxVersionDLL();
44 
45     // return the file version as string, e.g. "x.y.z.w"
46     wxString GetFileVersion(const wxString& filename) const;
47 
48 private:
49     typedef DWORD (APIENTRY *GetFileVersionInfoSize_t)(PTSTR, PDWORD);
50     typedef BOOL (APIENTRY *GetFileVersionInfo_t)(PTSTR, DWORD, DWORD, PVOID);
51     typedef BOOL (APIENTRY *VerQueryValue_t)(const PVOID, PTSTR, PVOID *, PUINT);
52 
53     #define DO_FOR_ALL_VER_FUNCS(what)                                        \
54         what(GetFileVersionInfoSize);                                         \
55         what(GetFileVersionInfo);                                             \
56         what(VerQueryValue)
57 
58     #define DECLARE_VER_FUNCTION(func) func ## _t m_pfn ## func
59 
60     DO_FOR_ALL_VER_FUNCS(DECLARE_VER_FUNCTION);
61 
62     #undef DECLARE_VER_FUNCTION
63 
64 
65     wxDynamicLibrary m_dll;
66 
67 
68     DECLARE_NO_COPY_CLASS(wxVersionDLL)
69 };
70 
71 // class used to create wxDynamicLibraryDetails objects
72 class WXDLLIMPEXP_BASE wxDynamicLibraryDetailsCreator
73 {
74 public:
75     // type of parameters being passed to EnumModulesProc
76     struct EnumModulesProcParams
77     {
78         wxDynamicLibraryDetailsArray *dlls;
79         wxVersionDLL *verDLL;
80     };
81 
82     // the declared type of the first EnumModulesProc() parameter changed in
83     // recent SDK versions and is no PCSTR instead of old PSTR, we know that
84     // it's const in version 11 and non-const in version 8 included with VC8
85     // (and earlier), suppose that it's only changed in version 11
86     #if defined(API_VERSION_NUMBER) && API_VERSION_NUMBER >= 11
87         typedef PCSTR NameStr_t;
88     #else
89         typedef PSTR NameStr_t;
90     #endif
91 
92     // TODO: fix EnumerateLoadedModules() to use EnumerateLoadedModules64()
93     #ifdef __WIN64__
94         typedef DWORD64 DWORD_32_64;
95     #else
96         typedef DWORD DWORD_32_64;
97     #endif
98 
99     static BOOL CALLBACK
100     EnumModulesProc(NameStr_t name, DWORD_32_64 base, ULONG size, void *data);
101 };
102 
103 // ----------------------------------------------------------------------------
104 // private functions
105 // ----------------------------------------------------------------------------
106 
107 // return the module handle for the given base name
108 static
wxGetModuleHandle(const char * name,void * addr)109 HMODULE wxGetModuleHandle(const char *name, void *addr)
110 {
111     // we want to use GetModuleHandleEx() instead of usual GetModuleHandle()
112     // because the former works correctly for comctl32.dll while the latter
113     // returns NULL when comctl32.dll version 6 is used under XP (note that
114     // GetModuleHandleEx() is only available under XP and later, coincidence?)
115 
116     // check if we can use GetModuleHandleEx
117     typedef BOOL (WINAPI *GetModuleHandleEx_t)(DWORD, LPCSTR, HMODULE *);
118 
119     static const GetModuleHandleEx_t INVALID_FUNC_PTR = (GetModuleHandleEx_t)-1;
120 
121     static GetModuleHandleEx_t s_pfnGetModuleHandleEx = INVALID_FUNC_PTR;
122     if ( s_pfnGetModuleHandleEx == INVALID_FUNC_PTR )
123     {
124         wxDynamicLibrary dll(_T("kernel32.dll"), wxDL_VERBATIM);
125         s_pfnGetModuleHandleEx =
126             (GetModuleHandleEx_t)dll.RawGetSymbol(_T("GetModuleHandleExA"));
127 
128         // dll object can be destroyed, kernel32.dll won't be unloaded anyhow
129     }
130 
131     // get module handle from its address
132     if ( s_pfnGetModuleHandleEx )
133     {
134         // flags are GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
135         //           GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
136         HMODULE hmod;
137         if ( s_pfnGetModuleHandleEx(6, (char *)addr, &hmod) && hmod )
138             return hmod;
139     }
140 
141     // Windows CE only has Unicode API, so even we have an ANSI string here, we
142     // still need to use GetModuleHandleW() there and so do it everywhere to
143     // avoid #ifdefs -- this code is not performance-critical anyhow...
144     return ::GetModuleHandle(wxString::FromAscii((char *)name));
145 }
146 
147 // ============================================================================
148 // wxVersionDLL implementation
149 // ============================================================================
150 
151 // ----------------------------------------------------------------------------
152 // loading
153 // ----------------------------------------------------------------------------
154 
wxVersionDLL()155 wxVersionDLL::wxVersionDLL()
156 {
157     // don't give errors if DLL can't be loaded or used, we're prepared to
158     // handle it
159     wxLogNull noLog;
160 
161     if ( m_dll.Load(_T("version.dll"), wxDL_VERBATIM) )
162     {
163         // the functions we load have either 'A' or 'W' suffix depending on
164         // whether we're in ANSI or Unicode build
165         #ifdef UNICODE
166             #define SUFFIX L"W"
167         #else // ANSI
168             #define SUFFIX "A"
169         #endif // UNICODE/ANSI
170 
171         #define LOAD_VER_FUNCTION(name)                                       \
172             m_pfn ## name = (name ## _t)m_dll.GetSymbol(_T(#name SUFFIX));    \
173         if ( !m_pfn ## name )                                                 \
174         {                                                                     \
175             m_dll.Unload();                                                   \
176             return;                                                           \
177         }
178 
179         DO_FOR_ALL_VER_FUNCS(LOAD_VER_FUNCTION);
180 
181         #undef LOAD_VER_FUNCTION
182     }
183 }
184 
185 // ----------------------------------------------------------------------------
186 // wxVersionDLL operations
187 // ----------------------------------------------------------------------------
188 
GetFileVersion(const wxString & filename) const189 wxString wxVersionDLL::GetFileVersion(const wxString& filename) const
190 {
191     wxString ver;
192     if ( m_dll.IsLoaded() )
193     {
194         wxChar *pc = wx_const_cast(wxChar *, filename.c_str());
195 
196         DWORD dummy;
197         DWORD sizeVerInfo = m_pfnGetFileVersionInfoSize(pc, &dummy);
198         if ( sizeVerInfo )
199         {
200             wxCharBuffer buf(sizeVerInfo);
201             if ( m_pfnGetFileVersionInfo(pc, 0, sizeVerInfo, buf.data()) )
202             {
203                 void *pVer;
204                 UINT sizeInfo;
205                 if ( m_pfnVerQueryValue(buf.data(), _T("\\"), &pVer, &sizeInfo) )
206                 {
207                     VS_FIXEDFILEINFO *info = (VS_FIXEDFILEINFO *)pVer;
208                     ver.Printf(_T("%d.%d.%d.%d"),
209                                HIWORD(info->dwFileVersionMS),
210                                LOWORD(info->dwFileVersionMS),
211                                HIWORD(info->dwFileVersionLS),
212                                LOWORD(info->dwFileVersionLS));
213                 }
214             }
215         }
216     }
217     //else: we failed to load DLL, can't retrieve version info
218 
219     return ver;
220 }
221 
222 // ============================================================================
223 // wxDynamicLibraryDetailsCreator implementation
224 // ============================================================================
225 
226 /* static */
227 BOOL CALLBACK
EnumModulesProc(NameStr_t name,DWORD_32_64 base,ULONG size,void * data)228 wxDynamicLibraryDetailsCreator::EnumModulesProc(NameStr_t name,
229                                                 DWORD_32_64 base,
230                                                 ULONG size,
231                                                 void *data)
232 {
233     EnumModulesProcParams *params = (EnumModulesProcParams *)data;
234 
235     wxDynamicLibraryDetails *details = new wxDynamicLibraryDetails;
236 
237     // fill in simple properties
238     details->m_name = wxString::FromAscii(name);
239     details->m_address = wx_reinterpret_cast(void *, base);
240     details->m_length = size;
241 
242     // to get the version, we first need the full path
243     HMODULE hmod = wxGetModuleHandle(name, (void *)base);
244     if ( hmod )
245     {
246         wxString fullname = wxGetFullModuleName(hmod);
247         if ( !fullname.empty() )
248         {
249             details->m_path = fullname;
250             details->m_version = params->verDLL->GetFileVersion(fullname);
251         }
252     }
253 
254     params->dlls->Add(details);
255 
256     // continue enumeration (returning FALSE would have stopped it)
257     return TRUE;
258 }
259 
260 // ============================================================================
261 // wxDynamicLibrary implementation
262 // ============================================================================
263 
264 // ----------------------------------------------------------------------------
265 // misc functions
266 // ----------------------------------------------------------------------------
267 
GetProgramHandle()268 wxDllType wxDynamicLibrary::GetProgramHandle()
269 {
270     return (wxDllType)::GetModuleHandle(NULL);
271 }
272 
273 // ----------------------------------------------------------------------------
274 // loading/unloading DLLs
275 // ----------------------------------------------------------------------------
276 
277 /* static */
278 wxDllType
RawLoad(const wxString & libname,int flags)279 wxDynamicLibrary::RawLoad(const wxString& libname, int flags)
280 {
281     return flags & wxDL_GET_LOADED
282             ? ::GetModuleHandle(libname)
283             : ::LoadLibrary(libname);
284 }
285 
286 /* static */
Unload(wxDllType handle)287 void wxDynamicLibrary::Unload(wxDllType handle)
288 {
289     ::FreeLibrary(handle);
290 }
291 
292 /* static */
RawGetSymbol(wxDllType handle,const wxString & name)293 void *wxDynamicLibrary::RawGetSymbol(wxDllType handle, const wxString& name)
294 {
295     return (void *)::GetProcAddress(handle,
296 #ifdef __WXWINCE__
297                                             name.c_str()
298 #else
299                                             name.ToAscii()
300 #endif // __WXWINCE__
301                                    );
302 }
303 
304 // ----------------------------------------------------------------------------
305 // enumerating loaded DLLs
306 // ----------------------------------------------------------------------------
307 
308 /* static */
ListLoaded()309 wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
310 {
311     wxDynamicLibraryDetailsArray dlls;
312 
313 #if wxUSE_DBGHELP
314     if ( wxDbgHelpDLL::Init() )
315     {
316         // prepare to use functions for version info extraction
317         wxVersionDLL verDLL;
318 
319         wxDynamicLibraryDetailsCreator::EnumModulesProcParams params;
320         params.dlls = &dlls;
321         params.verDLL = &verDLL;
322 
323         if ( !wxDbgHelpDLL::EnumerateLoadedModules
324                             (
325                                 ::GetCurrentProcess(),
326                                 wxDynamicLibraryDetailsCreator::EnumModulesProc,
327                                 &params
328                             ) )
329         {
330             wxLogLastError(_T("EnumerateLoadedModules"));
331         }
332     }
333 #endif // wxUSE_DBGHELP
334 
335     return dlls;
336 }
337 
338 #endif // wxUSE_DYNLIB_CLASS
339 
340