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