From 03915200af8bdd99789a8b478969deff68b5d0ef Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 18 Jun 2015 23:22:13 +0200 Subject: [PATCH 01/12] Use the hosts file in debugrpt sample under all systems. Attach the hosts file under all platforms to the debug report: this makes more sense the hosts file could be potentially useful, unlike autoexec.bat and /etc/motd that were used before, is also consistent between the platforms and, finally, avoids the error due to autoexec.bat not existing any more in the modern Windows versions. Closes #16655. --- samples/debugrpt/debugrpt.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/samples/debugrpt/debugrpt.cpp b/samples/debugrpt/debugrpt.cpp index 235eafc227..cb136be70c 100644 --- a/samples/debugrpt/debugrpt.cpp +++ b/samples/debugrpt/debugrpt.cpp @@ -369,10 +369,20 @@ void MyApp::GenerateReport(wxDebugReport::Context ctx) // can also add an existing file directly, it will be copied // automatically #ifdef __WXMSW__ - report->AddFile(wxT("c:\\autoexec.bat"), wxT("DOS startup file")); -#else - report->AddFile(wxT("/etc/motd"), wxT("Message of the day")); -#endif + wxString windir; + if ( !wxGetEnv("WINDIR", &windir) ) + windir = "C:\\Windows"; + fn.AssignDir(windir); + fn.AppendDir("system32"); + fn.AppendDir("drivers"); + fn.AppendDir("etc"); +#else // !__WXMSW__ + fn.AssignDir("/etc"); +#endif // __WXMSW__/!__WXMSW__ + fn.SetFullName("hosts"); + + if ( fn.FileExists() ) + report->AddFile(fn.GetFullPath(), "Local hosts file"); // calling Show() is not mandatory, but is more polite if ( wxDebugReportPreviewStd().Show(*report) ) From 6ae8145e9dba7f362234bd638873da6d3edb4503 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 18 Jun 2015 23:29:16 +0200 Subject: [PATCH 02/12] Fix incorrect flags in a sizer in wxDebugReportDialog. Don't use wxEXPAND (implicitly added by SizerFlags()) and wxCENTRE together. --- src/generic/dbgrptg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/dbgrptg.cpp b/src/generic/dbgrptg.cpp index 30f72a3a07..7651c00700 100644 --- a/src/generic/dbgrptg.cpp +++ b/src/generic/dbgrptg.cpp @@ -332,7 +332,7 @@ wxDebugReportDialog::wxDebugReportDialog(wxDebugReport& dbgrpt) wxSizer *sizerPreview = new wxStaticBoxSizer(wxVERTICAL, this, _("&Debug report preview:")); - sizerPreview->Add(CreateTextSizer(msg), SizerFlags(0).Centre()); + sizerPreview->Add(CreateTextSizer(msg), wxSizerFlags().Centre().Border()); // ... and the list of files in this debug report with buttons to view them wxSizer *sizerFileBtns = new wxBoxSizer(wxVERTICAL); From 39ad820bee987fee118cef2282bd88ff96633b41 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 18 Jun 2015 23:57:59 +0200 Subject: [PATCH 03/12] Check for Win32 exceptions inside our WindowProc(). Don't let unhandled Win32 (i.e. structured) exceptions escape from wxWndProc() as they can just disappear into thin air when running under WOW64 as 32 bit exceptions can't propagate through 64 bit kernel. So catch them immediately and pass them to the global handler while we have the chance to do it, as we're never going to get it in the outer __try/__catch block in wxEntry() in src/msw/main.cpp. In particular, this allows to catch crashes in wxEVT_PAINT handlers, such as the one in debughlp sample, again. Closes #16656. --- docs/changes.txt | 1 + include/wx/msw/seh.h | 4 ++-- src/msw/window.cpp | 20 ++++++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 4079463a44..2696c5b934 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -133,6 +133,7 @@ wxMSW: - Make default wxSizer border DPI-aware. - Improve wxMimeTypesManager open command detection (Eric Jensen). - Make wxFILTER_INCLUDE_LIST in wxTextValidator actually usable. +- Fix handling crashes in wxEVT_PAINT event handlers. - Fix appearance of toggled wxToggleButtons with bitmap (tm). - Fix setting menu item bitmaps after appending them (Artur Wieczorek). - Fix setting label of submenu items (Artur Wieczorek). diff --git a/include/wx/msw/seh.h b/include/wx/msw/seh.h index d00efd4962..7c3abba4e4 100644 --- a/include/wx/msw/seh.h +++ b/include/wx/msw/seh.h @@ -14,8 +14,8 @@ // the exception handler which should be called from the exception filter // - // it calsl wxApp::OnFatalException() if possible - extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs); + // it calls wxApp::OnFatalException() if wxTheApp object exists + WXDLLIMPEXP_BASE unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs); // helper macro for wxSEH_HANDLE #if defined(__BORLANDC__) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 85340d781f..a29b0b75bd 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -82,6 +82,7 @@ #include "wx/msw/private.h" #include "wx/msw/private/keyboard.h" #include "wx/msw/dcclient.h" +#include "wx/msw/seh.h" #include "wx/private/textmeasure.h" #if wxUSE_TOOLTIPS @@ -2757,10 +2758,21 @@ wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) LRESULT rc; - if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) ) - rc = wnd->MSWWindowProc(message, wParam, lParam); - else - rc = ::DefWindowProc(hWnd, message, wParam, lParam); + // We have to catch unhandled Win32 exceptions here because otherwise they + // would be simply lost if we're called from a kernel callback (as it + // happens when we process WM_PAINT, for example under WOW64: the 32 bit + // exceptions can't pass through the 64 bit kernel in this case and so are + // mostly just suppressed, although the exact behaviour differs across + // Windows versions, see the "Remarks" section of WindowProc documentation + // at https://msdn.microsoft.com/en-us/library/ms633573.aspx + wxSEH_TRY + { + if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) ) + rc = wnd->MSWWindowProc(message, wParam, lParam); + else + rc = ::DefWindowProc(hWnd, message, wParam, lParam); + } + wxSEH_HANDLE(0) return rc; } From 2720a03cb749899d52563f80314daa2453dae430 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 19 Jun 2015 00:05:42 +0200 Subject: [PATCH 04/12] Test crashing in wxEVT_TIMER handler too in debugrpt sample. This test was useful to verify that we don't need a __try/__catch block around the code processing WM_TIMER as it's not called from the kernel and so doesn't suffer from the same problem as WM_PAINT, i.e. exceptions happening inside wxEVT_TIMER handlers are caught without problems. See #16656. --- samples/debugrpt/debugrpt.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/samples/debugrpt/debugrpt.cpp b/samples/debugrpt/debugrpt.cpp index cb136be70c..6184c98b40 100644 --- a/samples/debugrpt/debugrpt.cpp +++ b/samples/debugrpt/debugrpt.cpp @@ -20,6 +20,7 @@ #include "wx/msgdlg.h" #include "wx/button.h" #include "wx/dcclient.h" +#include "wx/timer.h" #include "wx/datetime.h" #include "wx/ffile.h" @@ -145,6 +146,7 @@ enum DebugRpt_Crash = 100, DebugRpt_Current, DebugRpt_Paint, + DebugRpt_Timer, DebugRpt_Upload, DebugRpt_About = wxID_ABOUT }; @@ -159,11 +161,23 @@ private: void OnReportForCrash(wxCommandEvent& event); void OnReportForCurrent(wxCommandEvent& event); void OnReportPaint(wxCommandEvent& event); + void OnReportTimer(wxCommandEvent& event); void OnReportUpload(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); void OnPaint(wxPaintEvent& event); + // a timer whose only purpose in life is to crash as soon as it's started + class BadTimer : public wxTimer + { + public: + BadTimer() { } + + virtual void Notify() wxOVERRIDE + { + foo(8); + } + } m_badTimer; // number of lines drawn in OnPaint() int m_numLines; @@ -221,6 +235,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(DebugRpt_Crash, MyFrame::OnReportForCrash) EVT_MENU(DebugRpt_Current, MyFrame::OnReportForCurrent) EVT_MENU(DebugRpt_Paint, MyFrame::OnReportPaint) + EVT_MENU(DebugRpt_Timer, MyFrame::OnReportTimer) EVT_MENU(DebugRpt_Upload, MyFrame::OnReportUpload) EVT_MENU(DebugRpt_About, MyFrame::OnAbout) @@ -245,6 +260,8 @@ MyFrame::MyFrame() wxT("Create report for the current program context")); menuReport->Append(DebugRpt_Paint, wxT("Report for &paint handler\tCtrl-P"), wxT("Provoke a repeatable crash in wxEVT_PAINT handler")); + menuReport->Append(DebugRpt_Timer, wxT("Report for &timer handler\tCtrl-T"), + wxT("Provoke a crash in wxEVT_TIMER handler")); menuReport->AppendSeparator(); menuReport->AppendCheckItem(DebugRpt_Upload, wxT("Up&load debug report"), wxT("You need to configure a web server accepting debug report uploads to use this function")); @@ -291,6 +308,12 @@ void MyFrame::OnReportPaint(wxCommandEvent& WXUNUSED(event)) Refresh(); } +void MyFrame::OnReportTimer(wxCommandEvent& WXUNUSED(event)) +{ + // this will result in a crash in BadTimer::OnNotify() soon + m_badTimer.StartOnce(100); +} + void MyFrame::OnReportUpload(wxCommandEvent& event) { wxGetApp().UploadReport(event.IsChecked()); From 20ac03bfd827d2c8d6f109065527726f46700f4a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 19 Jun 2015 01:25:52 +0200 Subject: [PATCH 05/12] Test wxDynamicLibrary::ListLoaded() in debugrpt sample. The list of loaded dynamic libraries gets included in the debug report, so it seems logical to test this function independently in this sample to allow checking whether it works correctly without having to generate a debug report first. --- samples/debugrpt/debugrpt.cpp | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/samples/debugrpt/debugrpt.cpp b/samples/debugrpt/debugrpt.cpp index 6184c98b40..48b69a6d70 100644 --- a/samples/debugrpt/debugrpt.cpp +++ b/samples/debugrpt/debugrpt.cpp @@ -17,6 +17,7 @@ #include "wx/frame.h" #include "wx/icon.h" #include "wx/menu.h" +#include "wx/choicdlg.h" #include "wx/msgdlg.h" #include "wx/button.h" #include "wx/dcclient.h" @@ -26,6 +27,7 @@ #include "wx/ffile.h" #include "wx/filename.h" #include "wx/debugrpt.h" +#include "wx/dynlib.h" #if !wxUSE_DEBUGREPORT #error "This sample can't be built without wxUSE_DEBUGREPORT" @@ -142,6 +144,7 @@ void foo(int n) enum { + DebugRpt_ListLoadedDLLs = 50, DebugRpt_Quit = wxID_EXIT, DebugRpt_Crash = 100, DebugRpt_Current, @@ -157,6 +160,7 @@ public: MyFrame(); private: + void OnListLoadedDLLs(wxCommandEvent& event); void OnQuit(wxCommandEvent& event); void OnReportForCrash(wxCommandEvent& event); void OnReportForCurrent(wxCommandEvent& event); @@ -231,6 +235,7 @@ wxIMPLEMENT_APP(MyApp); // ---------------------------------------------------------------------------- wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(DebugRpt_ListLoadedDLLs, MyFrame::OnListLoadedDLLs) EVT_MENU(DebugRpt_Quit, MyFrame::OnQuit) EVT_MENU(DebugRpt_Crash, MyFrame::OnReportForCrash) EVT_MENU(DebugRpt_Current, MyFrame::OnReportForCurrent) @@ -251,6 +256,8 @@ MyFrame::MyFrame() SetIcon(wxICON(sample)); wxMenu *menuFile = new wxMenu; + menuFile->Append(DebugRpt_ListLoadedDLLs, wxT("&List loaded DLLs...\tCtrl-L")); + menuFile->AppendSeparator(); menuFile->Append(DebugRpt_Quit, wxT("E&xit\tAlt-X")); wxMenu *menuReport = new wxMenu; @@ -280,6 +287,47 @@ MyFrame::MyFrame() Show(); } +void MyFrame::OnListLoadedDLLs(wxCommandEvent& WXUNUSED(event)) +{ + const wxDynamicLibraryDetailsArray loaded = wxDynamicLibrary::ListLoaded(); + const size_t count = loaded.size(); + if ( !count ) + { + wxLogError("Failed to get the list of loaded dynamic libraries."); + return; + } + + wxArrayString names; + names.reserve(count); + for ( size_t n = 0; n < count; n++ ) + { + names.push_back(loaded[n].GetName()); + } + + for ( ;; ) + { + const int sel = wxGetSingleChoiceIndex + ( + "Choose a library to show more information about it", + "List of loaded dynamic libraries", + names, + this + ); + if ( sel == wxNOT_FOUND ) + return; + + const wxDynamicLibraryDetails& det = loaded[sel]; + void *addr = 0; + size_t len = 0; + det.GetAddress(&addr, &len); + wxLogMessage("Full path is \"%s\", memory range %p:%p, version \"%s\"", + det.GetPath(), + addr, + static_cast(static_cast(addr) + len), + det.GetVersion()); + } +} + void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { Close(true); From 28587c97d88fbf9b84af6c7151347b2c409268a6 Mon Sep 17 00:00:00 2001 From: Suzumizaki-Kimitaka Date: Fri, 19 Jun 2015 13:43:06 +0900 Subject: [PATCH 06/12] Add support for Unicode to wxStackWalker. Use wide-char versions of debug help functions if available, falling back to the narrow char ones otherwise. Also improve 64 bit support by using 64 bit versions of the functions if available as well. Closes #15138. --- docs/changes.txt | 1 + include/wx/msw/debughlp.h | 238 ++++++++++++++++++--- include/wx/msw/stackwalk.h | 9 +- src/msw/debughlp.cpp | 413 +++++++++++++++++++++++++++++++++++-- src/msw/dlmsw.cpp | 21 +- src/msw/stackwalk.cpp | 58 ++---- 6 files changed, 634 insertions(+), 106 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 2696c5b934..8707982594 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -134,6 +134,7 @@ wxMSW: - Improve wxMimeTypesManager open command detection (Eric Jensen). - Make wxFILTER_INCLUDE_LIST in wxTextValidator actually usable. - Fix handling crashes in wxEVT_PAINT event handlers. +- Fix wxStackWalker to work with Unicode identifiers (Suzumizaki-kimitaka). - Fix appearance of toggled wxToggleButtons with bitmap (tm). - Fix setting menu item bitmaps after appending them (Artur Wieczorek). - Fix setting label of submenu items (Artur Wieczorek). diff --git a/include/wx/msw/debughlp.h b/include/wx/msw/debughlp.h index 3d94ee2168..d63a213cb9 100644 --- a/include/wx/msw/debughlp.h +++ b/include/wx/msw/debughlp.h @@ -1,8 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // Name: wx/msw/debughlp.h // Purpose: wraps dbghelp.h standard file -// Author: Vadim Zeitlin -// Modified by: +// Author: Vadim Zeitlin, Suzumizaki-kimitaka // Created: 2005-01-08 (extracted from msw/crashrpt.cpp) // Copyright: (c) 2003-2005 Vadim Zeitlin // Licence: wxWindows licence @@ -19,12 +18,19 @@ #endif // __WXWINCE__ #include "wx/msw/private.h" -// wxUSE_DBGHELP can be predefined as 0 to avoid the use of dbghelp.dll if this -// is undesirable for some reason. +// wxUSE_DBGHELP can be predefined on the compiler command line to force using +// dbghelp.dll even if it's not detected or, on the contrary, avoid using even +// if it's available. #ifndef wxUSE_DBGHELP // The only compiler which is known to have the necessary headers is MSVC. #ifdef __VISUALC__ - #define wxUSE_DBGHELP 1 + // MSVC7.1 shipped with API v9 and we don't support anything earlier + // anyhow. + #if API_VERSION_NUMBER >= 9 + #define wxUSE_DBGHELP 1 + #else + #define wxUSE_DBGHELP 0 + #endif #else #define wxUSE_DBGHELP 0 #endif @@ -32,6 +38,117 @@ #if wxUSE_DBGHELP +/* + +The table below shows which functions are exported by dbghelp.dll. + +On 64 bit Windows, there seems to be no difference between 32bit dll and 64bit +one. Vista-64 and Win8-64 look the same, but "Ex" and "ExW" versions exist only +in Windows 8. + +Note that SymGetLineFromAddrW and EnumerateLoadedModulesW DON'T exist at all. + +function | Windows | XP-32 Vista-64 Win8-64 +SymEnumSymbolsW n/a v v +SymFromAddrW n/a v v +SymInitializeW n/a v v + +SymEnumSymbols v v v +SymFromAddr v v v +SymInitialize v v v + +SymGetLineFromAddrW64 n/a v v +SymGetLineFromAddr64 v v v +SymGetLineFromAddrW n/a n/a n/a +SymGetLineFromAddr v v v + +EnumerateLoadedModulesW64 n/a v v +EnumerateLoadedModules64 v v v +EnumerateLoadedModulesW n/a n/a n/a +EnumerateLoadedModules v v v + +*/ + +// It's not really clear whether API v10 is used by anything as VC8 still used +// v9, just as MSVC7.1, while VC9 already used v11, but provide support for it +// just in case. +#if API_VERSION_NUMBER < 10/*{{{*/ + +typedef BOOL +(CALLBACK *PENUMLOADED_MODULES_CALLBACKW64)(PWSTR ModuleName, + DWORD64 ModuleBase, + ULONG ModuleSize, + PVOID UserContext); + +typedef struct _IMAGEHLP_LINEW64 +{ + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PWSTR FileName; + DWORD64 Address; +} IMAGEHLP_LINEW64, *PIMAGEHLP_LINEW64; + +typedef struct _SYMBOL_INFOW +{ + ULONG SizeOfStruct; + ULONG TypeIndex; + ULONG64 Reserved[2]; + ULONG Index; + ULONG Size; + ULONG64 ModBase; + ULONG Flags; + ULONG64 Value; + ULONG64 Address; + ULONG Register; + ULONG Scope; + ULONG Tag; + ULONG NameLen; + ULONG MaxNameLen; + WCHAR Name[1]; +} SYMBOL_INFOW, *PSYMBOL_INFOW; + +typedef BOOL +(CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACKW)(PSYMBOL_INFOW pSymInfo, + ULONG SymbolSize, + PVOID UserContext); + +typedef BOOL +(CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACK)(PSYMBOL_INFO pSymInfo, + ULONG SymbolSize, + PVOID UserContext); + +#endif // API_VERSION_NUMBER < 10/*}}}*/ + +// wx-prefixed types map to either the ANSI or Unicode ("W") version depending +// on the build of wx itself. +#ifdef UNICODE + #define wxPSYM_ENUMERATESYMBOLS_CALLBACK PSYM_ENUMERATESYMBOLS_CALLBACKW +#else // !UNICODE + #define wxPSYM_ENUMERATESYMBOLS_CALLBACK PSYM_ENUMERATESYMBOLS_CALLBACK +#endif // UNICODE/!UNICODE + +// This one could be already defined by wx/msw/stackwalk.h +#ifndef wxSYMBOL_INFO + #ifdef UNICODE + #define wxSYMBOL_INFO SYMBOL_INFOW + #else // !UNICODE + #define wxSYMBOL_INFO SYMBOL_INFO + #endif // UNICODE/!UNICODE +#endif // !defined(wxSYMBOL_INFO) + +typedef wxSYMBOL_INFO* wxPSYMBOL_INFO; + +// This differs from PENUMLOADED_MODULES_CALLBACK[W]64 in that it always uses +// "const" for its first argument when the SDK used to pass a non-const string +// here until API_VERSION_NUMBER==11, so we can't just define it as an existing +// typedef. +typedef BOOL +(CALLBACK *wxPENUMLOADED_MODULES_CALLBACK)(const wxChar* moduleName, + DWORD64 moduleBase, + ULONG moduleSize, + void *userContext); + // ---------------------------------------------------------------------------- // wxDbgHelpDLL: dynamically load dbghelp.dll functions // ---------------------------------------------------------------------------- @@ -131,31 +248,61 @@ public: // function types typedef DWORD (WINAPI *SymGetOptions_t)(); typedef DWORD (WINAPI *SymSetOptions_t)(DWORD); - typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL); + typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPCSTR, BOOL); + typedef BOOL (WINAPI *SymInitializeW_t)(HANDLE, LPCWSTR, BOOL); typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE); typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); + typedef BOOL (WINAPI *SymFromAddrW_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFOW); typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD_PTR); typedef DWORD_PTR (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD_PTR); - typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD_PTR, + typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE); + typedef BOOL (WINAPI *SymGetLineFromAddr64_t)(HANDLE, DWORD64, + PDWORD, PIMAGEHLP_LINE64); + typedef BOOL (WINAPI *SymGetLineFromAddrW64_t)(HANDLE, DWORD64, + PDWORD, PIMAGEHLP_LINEW64); typedef BOOL (WINAPI *SymSetContext_t)(HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT); typedef BOOL (WINAPI *SymEnumSymbols_t)(HANDLE, ULONG64, PCSTR, - PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID); + PSYM_ENUMERATESYMBOLS_CALLBACK, + const PVOID); + typedef BOOL (WINAPI *SymEnumSymbolsW_t)(HANDLE, ULONG64, PCWSTR, + PSYM_ENUMERATESYMBOLS_CALLBACKW, + const PVOID); typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID); typedef BOOL (WINAPI *SymCleanup_t)(HANDLE); typedef BOOL (WINAPI *EnumerateLoadedModules_t)(HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID); + typedef BOOL (WINAPI *EnumerateLoadedModules64_t)(HANDLE, PENUMLOADED_MODULES_CALLBACK64, PVOID); + typedef BOOL (WINAPI *EnumerateLoadedModulesW64_t)(HANDLE, PENUMLOADED_MODULES_CALLBACKW64, PVOID); typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, CONST PMINIDUMP_EXCEPTION_INFORMATION, CONST PMINIDUMP_USER_STREAM_INFORMATION, CONST PMINIDUMP_CALLBACK_INFORMATION); + // Higher level functions selecting the right debug help library function + // to call: for CallFoo(), it can be Foo(), Foo64(), FooW() or FooW64() + // depending on the build options and function availability. + // + // They also provide more convenient to use wx-specific API, e.g. work with + // wxString instead of char/wchar_t pointers and omit the arguments we + // don't need. + static BOOL CallSymInitialize(HANDLE, BOOL); + static BOOL CallEnumerateLoadedModules(HANDLE, wxPENUMLOADED_MODULES_CALLBACK, PVOID); + static BOOL CallSymFromAddr(HANDLE, DWORD64, + size_t* offset, wxString* name); + static BOOL CallSymGetLineFromAddr(HANDLE, DWORD64, + wxString* fileName, size_t* line); + static BOOL CallSymEnumSymbols(HANDLE hProcess, + ULONG64 baseOfDll, + wxPSYM_ENUMERATESYMBOLS_CALLBACK callback, + const PVOID callbackParam); + // The macro called by wxDO_FOR_ALL_SYM_FUNCS() below takes 2 arguments: // the name of the function in the program code, which never has "64" // suffix, and the name of the function in the DLL which can have "64" @@ -176,26 +323,56 @@ public: #define wxSYM_CALL_64(what, name) what(name, name) #endif - #define wxDO_FOR_ALL_SYM_FUNCS(what) \ - wxSYM_CALL_64(what, StackWalk); \ - wxSYM_CALL_64(what, SymFunctionTableAccess); \ - wxSYM_CALL_64(what, SymGetModuleBase); \ - wxSYM_CALL_64(what, SymGetLineFromAddr); \ - wxSYM_CALL_64(what, EnumerateLoadedModules); \ - \ - wxSYM_CALL(what, SymGetOptions); \ - wxSYM_CALL(what, SymSetOptions); \ - wxSYM_CALL(what, SymInitialize); \ - wxSYM_CALL(what, SymFromAddr); \ - wxSYM_CALL(what, SymSetContext); \ - wxSYM_CALL(what, SymEnumSymbols); \ - wxSYM_CALL(what, SymGetTypeInfo); \ - wxSYM_CALL(what, SymCleanup); \ + #define wxSYM_CALL_ALWAYS_W(what, name) what(name ## W, name ## W) + + #define wxSYM_CALL_ALTERNATIVES(what, name) \ + what(name, name); \ + what(name ## 64, name ## 64); \ + what(name ## W64, name ## W64) + + #define wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PUBLIC(what) \ + wxSYM_CALL_64(what, StackWalk); \ + wxSYM_CALL_64(what, SymFunctionTableAccess); \ + wxSYM_CALL_64(what, SymGetModuleBase); \ + \ + wxSYM_CALL(what, SymGetOptions); \ + wxSYM_CALL(what, SymSetOptions); \ + wxSYM_CALL(what, SymSetContext); \ + wxSYM_CALL(what, SymGetTypeInfo); \ + wxSYM_CALL(what, SymCleanup); \ wxSYM_CALL(what, MiniDumpWriteDump) + #define wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PRIVATE(what) \ + wxSYM_CALL(what, SymInitialize); \ + wxSYM_CALL(what, SymFromAddr); \ + wxSYM_CALL(what, SymEnumSymbols) + + #define wxDO_FOR_ALL_SYM_FUNCS_REQUIRED(what) \ + wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PRIVATE(what); \ + wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PUBLIC(what) + + // Alternation will work when the following functions are not found, + // therefore they are not included in REQUIRED version. + #define wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(what) \ + wxSYM_CALL_ALTERNATIVES(what, SymGetLineFromAddr); \ + wxSYM_CALL_ALTERNATIVES(what, EnumerateLoadedModules); \ + wxSYM_CALL_ALWAYS_W(what, SymInitialize); \ + wxSYM_CALL_ALWAYS_W(what, SymFromAddr); \ + wxSYM_CALL_ALWAYS_W(what, SymEnumSymbols) + + #define wxDO_FOR_ALL_SYM_FUNCS(what) \ + wxDO_FOR_ALL_SYM_FUNCS_REQUIRED(what); \ + wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(what) + #define wxDECLARE_SYM_FUNCTION(func, name) static func ## _t func - wxDO_FOR_ALL_SYM_FUNCS(wxDECLARE_SYM_FUNCTION); + wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PUBLIC(wxDECLARE_SYM_FUNCTION); + +private: + wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PRIVATE(wxDECLARE_SYM_FUNCTION); + wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(wxDECLARE_SYM_FUNCTION); + +public: #undef wxDECLARE_SYM_FUNCTION @@ -209,10 +386,10 @@ public: static void LogError(const wxChar *func); // return textual representation of the value of given symbol - static wxString DumpSymbol(PSYMBOL_INFO pSymInfo, void *pVariable); + static wxString DumpSymbol(wxPSYMBOL_INFO pSymInfo, void *pVariable); // return the name of the symbol with given type index - static wxString GetSymbolName(PSYMBOL_INFO pSymInfo); + static wxString GetSymbolName(wxPSYMBOL_INFO pSymInfo); private: // dereference the given symbol, i.e. return symbol which is not a @@ -222,17 +399,20 @@ private: // dereferenced the symbol // // return the tag of the dereferenced symbol - static SymbolTag DereferenceSymbol(PSYMBOL_INFO pSymInfo, void **ppData); + static SymbolTag DereferenceSymbol(wxPSYMBOL_INFO pSymInfo, void **ppData); - static wxString DumpField(PSYMBOL_INFO pSymInfo, + static wxString DumpField(wxPSYMBOL_INFO pSymInfo, void *pVariable, unsigned level); static wxString DumpBaseType(BasicType bt, DWORD64 length, void *pVariable); - static wxString DumpUDT(PSYMBOL_INFO pSymInfo, + static wxString DumpUDT(wxPSYMBOL_INFO pSymInfo, void *pVariable, unsigned level = 0); + + static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp); + static bool DoInit(); }; #endif // wxUSE_DBGHELP diff --git a/include/wx/msw/stackwalk.h b/include/wx/msw/stackwalk.h index 6ff467205e..e068ea2d95 100644 --- a/include/wx/msw/stackwalk.h +++ b/include/wx/msw/stackwalk.h @@ -19,6 +19,13 @@ struct _EXCEPTION_POINTERS; // and these in dbghelp.h struct _SYMBOL_INFO; +struct _SYMBOL_INFOW; + +#if wxUSE_UNICODE + #define wxSYMBOL_INFO _SYMBOL_INFOW +#else // !wxUSE_UNICODE + #define wxSYMBOL_INFO _SYMBOL_INFO +#endif // wxUSE_UNICODE/!wxUSE_UNICODE // ---------------------------------------------------------------------------- // wxStackFrame @@ -52,7 +59,7 @@ public: GetParam(size_t n, wxString *type, wxString *name, wxString *value) const; // callback used by OnGetParam(), don't call directly - void OnParam(_SYMBOL_INFO *pSymInfo); + void OnParam(wxSYMBOL_INFO *pSymInfo); protected: virtual void OnGetName(); diff --git a/src/msw/debughlp.cpp b/src/msw/debughlp.cpp index 161a532933..592595d4a5 100644 --- a/src/msw/debughlp.cpp +++ b/src/msw/debughlp.cpp @@ -1,8 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // Name: src/msw/debughlp.cpp // Purpose: various Win32 debug helpers -// Author: Vadim Zeitlin -// Modified by: +// Author: Vadim Zeitlin, Suzumizaki-kimitaka // Created: 2005-01-08 (extracted from crashrpt.cpp) // Copyright: (c) 2003-2005 Vadim Zeitlin // Licence: wxWindows licence @@ -26,6 +25,8 @@ #if wxUSE_DBGHELP && wxUSE_DYNLIB_CLASS +#include "wx/scopedarray.h" + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -34,6 +35,59 @@ // ourselves to that many levels of embedded fields inside structs static const unsigned MAX_DUMP_DEPTH = 20; +// ---------------------------------------------------------------------------- +// local helpers +// ---------------------------------------------------------------------------- + +namespace +{ + +// Automatically initialize SizeOfStruct field of debug help structs to the +// correct value. +template +struct SizedStruct : public T +{ + SizedStruct() + { + ::ZeroMemory(this, sizeof(T)); + this->SizeOfStruct = sizeof(T); + } +}; + +// This is used for working with variable-sized SYMBOL_INFO[W] structs that +// have a variable length array as their last field. +template +class VarSizedStruct +{ +public: + VarSizedStruct() + { + ::ZeroMemory(m_buffer, sizeof(T) + MAX_NAME_LEN); + + (*this)->SizeOfStruct = sizeof(T); + (*this)->MaxNameLen = MAX_NAME_LEN; + } + + operator T*() + { + return static_cast(static_cast(m_buffer)); + } + + T* operator->() + { + return *this; + } + +private: + // Currently this is just a constant, we could make it a template parameter + // if we wanted. + enum { MAX_NAME_LEN = 1024 }; + + BYTE m_buffer[sizeof(T) + MAX_NAME_LEN]; +}; + +} // anonymous namespace + // ---------------------------------------------------------------------------- // globals // ---------------------------------------------------------------------------- @@ -62,7 +116,8 @@ wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION); // load all function we need from the DLL -static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp) +/* static */ +bool wxDbgHelpDLL::BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp) { #define LOAD_SYM_FUNCTION(func, name) \ wxDbgHelpDLL::func = (wxDbgHelpDLL::func ## _t) \ @@ -73,15 +128,27 @@ static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp) return false; \ } - wxDO_FOR_ALL_SYM_FUNCS(LOAD_SYM_FUNCTION); + wxDO_FOR_ALL_SYM_FUNCS_REQUIRED(LOAD_SYM_FUNCTION); #undef LOAD_SYM_FUNCTION + #define LOAD_SYM_FUNCTION_OPTIONAL(func, name) \ + if ( dllDbgHelp.HasSymbol(wxT(#name)) ) \ + { \ + wxDbgHelpDLL::func = (wxDbgHelpDLL::func ## _t) \ + dllDbgHelp.GetSymbol(wxT(#name)); \ + } + + wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(LOAD_SYM_FUNCTION_OPTIONAL); + + #undef LOAD_SYM_FUNCTION_CAN_FAIL + return true; } // called by Init() if we hadn't done this before -static bool DoInit() +/* static */ +bool wxDbgHelpDLL::DoInit() { wxDynamicLibrary dllDbgHelp(wxT("dbghelp.dll"), wxDL_VERBATIM); if ( dllDbgHelp.IsLoaded() ) @@ -170,13 +237,13 @@ DoGetTypeInfo(DWORD64 base, ULONG ti, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc) static inline bool -DoGetTypeInfo(PSYMBOL_INFO pSym, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc) +DoGetTypeInfo(wxPSYMBOL_INFO pSym, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc) { return DoGetTypeInfo(pSym->ModBase, pSym->TypeIndex, type, rc); } static inline -wxDbgHelpDLL::BasicType GetBasicType(PSYMBOL_INFO pSym) +wxDbgHelpDLL::BasicType GetBasicType(wxPSYMBOL_INFO pSym) { wxDbgHelpDLL::BasicType bt; return DoGetTypeInfo(pSym, TI_GET_BASETYPE, &bt) @@ -185,7 +252,7 @@ wxDbgHelpDLL::BasicType GetBasicType(PSYMBOL_INFO pSym) } /* static */ -wxString wxDbgHelpDLL::GetSymbolName(PSYMBOL_INFO pSym) +wxString wxDbgHelpDLL::GetSymbolName(wxPSYMBOL_INFO pSym) { wxString s; @@ -289,7 +356,7 @@ wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress) } wxString -wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) +wxDbgHelpDLL::DumpField(wxPSYMBOL_INFO pSym, void *pVariable, unsigned level) { wxString s; @@ -336,7 +403,7 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) // now pass to the type representing the type of this member - SYMBOL_INFO sym = *pSym; + wxSYMBOL_INFO sym = *pSym; if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &sym.TypeIndex) ) break; @@ -387,7 +454,7 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) } /* static */ wxString -wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level) +wxDbgHelpDLL::DumpUDT(wxPSYMBOL_INFO pSym, void *pVariable, unsigned level) { wxString s; @@ -454,7 +521,7 @@ wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level) s << wxT(" {\n"); // Iterate through all children - SYMBOL_INFO sym; + wxSYMBOL_INFO sym; wxZeroMemory(sym); sym.ModBase = pSym->ModBase; for ( unsigned i = 0; i < dwChildrenCount; i++ ) @@ -486,7 +553,7 @@ wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level) /* static */ wxDbgHelpDLL::SymbolTag -wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym, void **ppData) +wxDbgHelpDLL::DereferenceSymbol(wxPSYMBOL_INFO pSym, void **ppData) { SymbolTag tag = SYMBOL_TAG_NULL; for ( ;; ) @@ -523,10 +590,10 @@ wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym, void **ppData) } /* static */ wxString -wxDbgHelpDLL::DumpSymbol(PSYMBOL_INFO pSym, void *pVariable) +wxDbgHelpDLL::DumpSymbol(wxPSYMBOL_INFO pSym, void *pVariable) { wxString s; - SYMBOL_INFO symDeref = *pSym; + wxSYMBOL_INFO symDeref = *pSym; switch ( DereferenceSymbol(&symDeref, &pVariable) ) { default: @@ -552,6 +619,322 @@ wxDbgHelpDLL::DumpSymbol(PSYMBOL_INFO pSym, void *pVariable) return s; } +// ---------------------------------------------------------------------------- +// Helpers for selecting the best available function on the current platform. +// ---------------------------------------------------------------------------- + +// Store the original callback and the data for it: objects of this type are +// used as bridges for the enumeration functions taking callbacks of different +// types. +struct wxEnumLoadedCallbackBridge +{ +public: + wxEnumLoadedCallbackBridge(wxPENUMLOADED_MODULES_CALLBACK ptr, PVOID content) + : m_callback(ptr), m_data(content) + { + } + + wxPENUMLOADED_MODULES_CALLBACK m_callback; + PVOID m_data; +}; + +// As mentioned near wxPENUMLOADED_MODULES_CALLBACK definition, until v11 of +// the API the parameters were non-const. +#if API_VERSION_NUMBER < 11 + #define wxHAS_NON_CONST_MODULE_NAME + + #define wxMODULE_NAMEA PSTR +#else + #define wxMODULE_NAMEA PCSTR +#endif + +#if defined(UNICODE) && defined(wxHAS_NON_CONST_MODULE_NAME) + +static BOOL CALLBACK +wxEnumLoadedW64Callback(PWSTR ModuleName, + DWORD64 ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +{ + wxEnumLoadedCallbackBridge& + bridge = *static_cast(UserContext); + + return (*bridge.m_callback)(ModuleName, ModuleBase, ModuleSize, bridge.m_data); +} + +#endif // UNICODE && wxHAS_NON_CONST_MODULE_NAME + +static BOOL CALLBACK +wxEnumLoaded64Callback(wxMODULE_NAMEA ModuleName, + DWORD64 ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +{ + wxEnumLoadedCallbackBridge& + bridge = *static_cast(UserContext); + + return (*bridge.m_callback) + ( +#ifdef UNICODE + wxConvLocal.cMB2WC(ModuleName), +#else // !UNICODE + ModuleName, +#endif // UNICODE + ModuleBase, ModuleSize, bridge.m_data + ); +} + +static BOOL CALLBACK +wxEnumLoadedCallback(wxMODULE_NAMEA ModuleName, + DWORD_PTR ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +{ + wxEnumLoadedCallbackBridge& + bridge = *static_cast(UserContext); + + return (*bridge.m_callback) + ( +#ifdef UNICODE + wxConvLocal.cMB2WC(ModuleName), +#else // !UNICODE + ModuleName, +#endif // UNICODE + ModuleBase, ModuleSize, bridge.m_data + ); +} + +/* static */ +BOOL +wxDbgHelpDLL::CallEnumerateLoadedModules(HANDLE handle, + wxPENUMLOADED_MODULES_CALLBACK callback, + PVOID callbackParam) +{ +#ifdef UNICODE + if ( EnumerateLoadedModulesW64 ) + { +#ifdef wxHAS_NON_CONST_MODULE_NAME + // We need to pass by a bridge just to convert non-const module name to + // the const one taken by our callback. + wxEnumLoadedCallbackBridge br(callback, callbackParam); + if ( EnumerateLoadedModulesW64(handle, &wxEnumLoadedW64Callback, &br) ) + return TRUE; +#else // new SDK + // We can use our callback directly. + if ( EnumerateLoadedModulesW64(handle, callback, callbackParam) ) + return TRUE; +#endif // old/new SDK + } +#endif // UNICODE + + if ( EnumerateLoadedModules64 ) + { + // We need a bridge if we need to convert to Unicode or if we're using + // an older SDK with a non-const first argument, so just use it always + // to avoid having too many complicated preprocessor checks. + wxEnumLoadedCallbackBridge br(callback, callbackParam); + if ( EnumerateLoadedModules64(handle, &wxEnumLoaded64Callback, &br) ) + return TRUE; + } + + if ( EnumerateLoadedModules ) + { + // With this function we need a bridge in any case because the type of + // module base argument used by EnumerateLoadedModules() differs from + // that used by EnumerateLoadedModules[W]64(). + wxEnumLoadedCallbackBridge br(callback, callbackParam); + if ( EnumerateLoadedModules(handle, &wxEnumLoadedCallback, &br) ) + return TRUE; + } + + return FALSE; +} + +/* static */ +BOOL +wxDbgHelpDLL::CallSymInitialize(HANDLE hProcess, BOOL fInvadeProcess) +{ +#ifdef UNICODE + if ( SymInitializeW ) + { + if ( SymInitializeW(hProcess, NULL, fInvadeProcess) ) + return TRUE; + } +#endif // UNICODE + + if ( SymInitialize ) + { + if ( SymInitialize(hProcess, NULL, fInvadeProcess) ) + return TRUE; + } + + return FALSE; +} + +/* static */ +BOOL +wxDbgHelpDLL::CallSymFromAddr(HANDLE hProcess, + DWORD64 Address, + size_t* offset, + wxString* name) +{ + DWORD64 dwDisplacement; + +#ifdef UNICODE + if ( SymFromAddrW ) + { + VarSizedStruct infoW; + if ( SymFromAddrW(hProcess, Address, &dwDisplacement, infoW) ) + { + *offset = dwDisplacement; + *name = infoW->Name; + return TRUE; + } + } +#endif // UNICODE + + if ( SymFromAddr ) + { + VarSizedStruct info; + if ( SymFromAddr(hProcess, Address, &dwDisplacement, info) ) + { + *offset = dwDisplacement; + *name = info->Name; + return TRUE; + } + } + + return FALSE; +} + +/* static */ +BOOL +wxDbgHelpDLL::CallSymGetLineFromAddr(HANDLE hProcess, + DWORD64 dwAddr, + wxString* fileName, + size_t* line) +{ + DWORD dwDisplacement; + +#ifdef UNICODE + if ( SymGetLineFromAddrW64 ) + { + SizedStruct lineW64; + if ( SymGetLineFromAddrW64(hProcess, dwAddr, &dwDisplacement, &lineW64) ) + { + *fileName = lineW64.FileName; + *line = lineW64.LineNumber; + return TRUE; + } + } +#endif // UNICODE + + if ( SymGetLineFromAddr64 ) + { + SizedStruct line64; + if ( SymGetLineFromAddr64(hProcess, dwAddr, &dwDisplacement, &line64) ) + { + *fileName = line64.FileName; + *line = line64.LineNumber; + return TRUE; + } + } + + if ( SymGetLineFromAddr ) + { + SizedStruct line32; + if ( SymGetLineFromAddr(hProcess, dwAddr, &dwDisplacement, &line32) ) + { + *fileName = line32.FileName; + *line = line32.LineNumber; + return TRUE; + } + } + + return FALSE; +} + +#ifdef UNICODE + +// Allow to adapt callback supposed to be used with SymEnumSymbolsW() with +// SymEnumSymbols(). +struct wxEnumSymbolsCallbackBridge +{ +public: + wxEnumSymbolsCallbackBridge(PSYM_ENUMERATESYMBOLS_CALLBACKW ptr, PVOID content) + : m_callback(ptr), m_data(content) + { + } + + PSYM_ENUMERATESYMBOLS_CALLBACKW m_callback; + PVOID m_data; +}; + +static BOOL CALLBACK +wxEnumSymbolsCallback(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext) +{ + wxEnumSymbolsCallbackBridge& + bridge = *static_cast(UserContext); + + const wxWCharBuffer buf = wxConvLocal.cMB2WC(pSymInfo->Name); + const size_t len = buf.length(); + + // Allocate enough space for the wide char version of the struct. + // + // Note that there is no +1 here because sizeof(SYMBOL_INFOW) already + // includes 1 byte of the name. + wxScopedArray symbolBuffer(sizeof(SYMBOL_INFOW) + len*sizeof(WCHAR)); + + SYMBOL_INFOW* const infoW = (SYMBOL_INFOW*)symbolBuffer.get(); + + // Copy the original struct contents except for the last byte, which is the + // first byte of its (narrow) name that we don't need. + CopyMemory(infoW, pSymInfo, sizeof(SYMBOL_INFO) - sizeof(CHAR)); + + // Size is different for narrow and wide variants of the struct, so fix it + // up now. + infoW->SizeOfStruct = sizeof(SYMBOL_INFOW); + + // Finally copy the converted name, which is the reason for doing all this. + wxStrncpy(infoW->Name, buf.data(), len); + + return (*bridge.m_callback)(infoW, SymbolSize, bridge.m_data); +} + +#endif // UNICODE + +/* static */ +BOOL +wxDbgHelpDLL::CallSymEnumSymbols(HANDLE hProcess, + ULONG64 baseOfDll, + wxPSYM_ENUMERATESYMBOLS_CALLBACK callback, + const PVOID callbackParam) +{ +#ifdef UNICODE + if ( SymEnumSymbolsW ) + { + if ( SymEnumSymbolsW(hProcess, baseOfDll, NULL, callback, callbackParam) ) + return TRUE; + } + + if ( SymEnumSymbols ) + { + wxEnumSymbolsCallbackBridge br(callback, callbackParam); + + if ( SymEnumSymbols(hProcess, baseOfDll, NULL, wxEnumSymbolsCallback, &br) ) + return TRUE; + } +#else // !UNICODE + if ( SymEnumSymbols ) + { + if ( SymEnumSymbols(hProcess, baseOfDll, NULL, callback, callbackParam) ) + return TRUE; + } +#endif // UNICODE/!UNICODE + + return FALSE; +} + // ---------------------------------------------------------------------------- // debugging helpers // ---------------------------------------------------------------------------- diff --git a/src/msw/dlmsw.cpp b/src/msw/dlmsw.cpp index 9bdbae9c13..0118a3ff22 100644 --- a/src/msw/dlmsw.cpp +++ b/src/msw/dlmsw.cpp @@ -77,15 +77,8 @@ public: wxVersionDLL *verDLL; }; - // TODO: fix EnumerateLoadedModules() to use EnumerateLoadedModules64() - #ifdef __WIN64__ - typedef DWORD64 DWORD_32_64; - #else - typedef DWORD DWORD_32_64; - #endif - static BOOL CALLBACK - EnumModulesProc(PCSTR name, DWORD_32_64 base, ULONG size, void *data); + EnumModulesProc(const wxChar* name, DWORD64 base, ULONG size, PVOID data); }; // ============================================================================ @@ -172,8 +165,8 @@ wxString wxVersionDLL::GetFileVersion(const wxString& filename) const /* static */ BOOL CALLBACK -wxDynamicLibraryDetailsCreator::EnumModulesProc(PCSTR name, - DWORD_32_64 base, +wxDynamicLibraryDetailsCreator::EnumModulesProc(const wxChar* name, + DWORD64 base, ULONG size, void *data) { @@ -276,15 +269,9 @@ wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded() params.dlls = &dlls; params.verDLL = &verDLL; - // Note that the cast of EnumModulesProc is needed because the type of - // PENUMLOADED_MODULES_CALLBACK changed: in old SDK versions its first - // argument was non-const PSTR while now it's PCSTR. By explicitly - // casting to whatever the currently used headers require we ensure - // that the code compilers in any case. - if ( !wxDbgHelpDLL::EnumerateLoadedModules + if ( !wxDbgHelpDLL::CallEnumerateLoadedModules ( ::GetCurrentProcess(), - (PENUMLOADED_MODULES_CALLBACK) wxDynamicLibraryDetailsCreator::EnumModulesProc, ¶ms ) ) diff --git a/src/msw/stackwalk.cpp b/src/msw/stackwalk.cpp index f9c8ca986e..4b59c4a381 100644 --- a/src/msw/stackwalk.cpp +++ b/src/msw/stackwalk.cpp @@ -50,29 +50,16 @@ void wxStackFrame::OnGetName() m_hasName = true; // get the name of the function for this stack frame entry - static const size_t MAX_NAME_LEN = 1024; - BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_NAME_LEN]; - wxZeroMemory(symbolBuffer); - - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_NAME_LEN; - - DWORD64 symDisplacement = 0; - if ( !wxDbgHelpDLL::SymFromAddr + if ( !wxDbgHelpDLL::CallSymFromAddr ( ::GetCurrentProcess(), GetSymAddr(), - &symDisplacement, - pSymbol + &m_offset, + &m_name ) ) { wxDbgHelpDLL::LogError(wxT("SymFromAddr")); - return; } - - m_name = wxString::FromAscii(pSymbol->Name); - m_offset = symDisplacement; } void wxStackFrame::OnGetLocation() @@ -82,25 +69,11 @@ void wxStackFrame::OnGetLocation() m_hasLocation = true; - // get the source line for this stack frame entry - IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) }; - DWORD dwLineDisplacement; - if ( !wxDbgHelpDLL::SymGetLineFromAddr - ( - ::GetCurrentProcess(), - GetSymAddr(), - &dwLineDisplacement, - &lineInfo - ) ) - { - // it is normal that we don't have source info for some symbols, - // notably all the ones from the system DLLs... - //wxDbgHelpDLL::LogError(wxT("SymGetLineFromAddr")); - return; - } - - m_filename = wxString::FromAscii(lineInfo.FileName); - m_line = lineInfo.LineNumber; + // get the source line for this stack frame entry ignoring possible errors + // (it's normal that we don't have source info for some symbols, e.g. all + // those from the system DLLs) + wxDbgHelpDLL::CallSymGetLineFromAddr(::GetCurrentProcess(), GetSymAddr(), + &m_filename, &m_line); } bool @@ -125,11 +98,10 @@ wxStackFrame::GetParam(size_t n, return true; } -void wxStackFrame::OnParam(PSYMBOL_INFO pSymInfo) +void wxStackFrame::OnParam(wxSYMBOL_INFO *pSymInfo) { m_paramTypes.Add(wxEmptyString); - - m_paramNames.Add(wxString::FromAscii(pSymInfo->Name)); + m_paramNames.Add(pSymInfo->Name); // if symbol information is corrupted and we crash, the exception is going // to be ignored when we're called from WalkFromException() because of the @@ -158,7 +130,7 @@ void wxStackFrame::OnParam(PSYMBOL_INFO pSymInfo) } BOOL CALLBACK -EnumSymbolsProc(PSYMBOL_INFO pSymInfo, ULONG WXUNUSED(SymSize), PVOID data) +EnumSymbolsProc(wxPSYMBOL_INFO pSymInfo, ULONG WXUNUSED(SymSize), PVOID data) { wxStackFrame *frame = static_cast(data); @@ -195,11 +167,10 @@ void wxStackFrame::OnGetParam() return; } - if ( !wxDbgHelpDLL::SymEnumSymbols + if ( !wxDbgHelpDLL::CallSymEnumSymbols ( ::GetCurrentProcess(), NULL, // DLL base: use current context - NULL, // no mask, get all symbols EnumSymbolsProc, // callback this // data to pass to it ) ) @@ -232,10 +203,9 @@ void wxStackWalker::WalkFrom(const CONTEXT *pCtx, size_t skip, size_t maxDepth) // below which should be a real handle... so this is what we use const HANDLE hProcess = ::GetCurrentProcess(); - if ( !wxDbgHelpDLL::SymInitialize + if ( !wxDbgHelpDLL::CallSymInitialize ( hProcess, - NULL, // use default symbol search path TRUE // load symbols for all loaded modules ) ) { @@ -382,7 +352,7 @@ wxStackFrame::GetParam(size_t WXUNUSED(n), return false; } -void wxStackFrame::OnParam(_SYMBOL_INFO * WXUNUSED(pSymInfo)) +void wxStackFrame::OnParam(wxSYMBOL_INFO * WXUNUSED(pSymInfo)) { } From 01af56440a717f90022856611124a0d6c7b15290 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 27 Jul 2015 02:58:07 +0200 Subject: [PATCH 07/12] Use wxRound() instead of implicit float-to-int conversion in wxSTC. At the very least, this avoids tons of gcc warnings about implicit conversions from float to int and it could also be more correct if the coordinates can really be fractional. --- src/stc/PlatWX.cpp | 23 ++++++++++++----------- src/stc/ScintillaWX.cpp | 15 ++++++++------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/stc/PlatWX.cpp b/src/stc/PlatWX.cpp index dbd2397134..3e44e8db78 100644 --- a/src/stc/PlatWX.cpp +++ b/src/stc/PlatWX.cpp @@ -14,6 +14,7 @@ #if wxUSE_STC #ifndef WX_PRECOMP + #include "wx/math.h" #include "wx/menu.h" #include "wx/dcmemory.h" #include "wx/settings.h" @@ -50,8 +51,8 @@ Point Point::FromLong(long lpoint) { } wxRect wxRectFromPRectangle(PRectangle prc) { - wxRect r(prc.left, prc.top, - prc.Width(), prc.Height()); + wxRect r(wxRound(prc.left), wxRound(prc.top), + wxRound(prc.Width()), wxRound(prc.Height())); return r; } @@ -140,7 +141,7 @@ void Font::Create(const FontParameters &fp) { else weight = wxFONTWEIGHT_NORMAL; - wxFont font(fp.size, + wxFont font(wxRound(fp.size), wxFONTFAMILY_DEFAULT, fp.italic ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL, weight, @@ -320,8 +321,8 @@ void SurfaceImpl::Polygon(Point *pts, int npts, ColourDesired fore, ColourDesire wxPoint *p = new wxPoint[npts]; for (int i=0; iDrawPolygon(npts, p); delete [] p; @@ -501,7 +502,7 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { wxRect r = wxRectFromPRectangle(rc); hdc->Blit(r.x, r.y, r.width, r.height, ((SurfaceImpl&)surfaceSource).hdc, - from.x, from.y, wxCOPY); + wxRound(from.x), wxRound(from.y), wxCOPY); } void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font, XYPOSITION ybase, @@ -514,7 +515,7 @@ void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font, XYPOSITION ybase, // ybase is where the baseline should be, but wxWin uses the upper left // corner, so I need to calculate the real position for the text... - hdc->DrawText(stc2wx(s, len), rc.left, ybase - GetAscent(font)); + hdc->DrawText(stc2wx(s, len), wxRound(rc.left), wxRound(ybase - GetAscent(font))); } void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font, XYPOSITION ybase, @@ -527,7 +528,7 @@ void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font, XYPOSITION ybase, hdc->SetClippingRegion(wxRectFromPRectangle(rc)); // see comments above - hdc->DrawText(stc2wx(s, len), rc.left, ybase - GetAscent(font)); + hdc->DrawText(stc2wx(s, len), wxRound(rc.left), wxRound(ybase - GetAscent(font))); hdc->DestroyClippingRegion(); } @@ -542,7 +543,7 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font, XYPOSITION ybas // ybase is where the baseline should be, but wxWin uses the upper left // corner, so I need to calculate the real position for the text... - hdc->DrawText(stc2wx(s, len), rc.left, ybase - GetAscent(font)); + hdc->DrawText(stc2wx(s, len), wxRound(rc.left), wxRound(ybase - GetAscent(font))); hdc->SetBackgroundMode(wxBRUSHSTYLE_SOLID); } @@ -784,7 +785,7 @@ PRectangle Window::GetMonitorRect(Point pt) { if (! wid) return PRectangle(); #if wxUSE_DISPLAY // Get the display the point is found on - int n = wxDisplay::GetFromPoint(wxPoint(pt.x, pt.y)); + int n = wxDisplay::GetFromPoint(wxPoint(wxRound(pt.x), wxRound(pt.y))); wxDisplay dpy(n == wxNOT_FOUND ? 0 : n); rect = dpy.GetGeometry(); #else @@ -1428,7 +1429,7 @@ void Menu::Destroy() { } void Menu::Show(Point pt, Window &w) { - GETWIN(w.GetID())->PopupMenu((wxMenu*)mid, pt.x - 4, pt.y); + GETWIN(w.GetID())->PopupMenu((wxMenu*)mid, wxRound(pt.x - 4), wxRound(pt.y)); Destroy(); } diff --git a/src/stc/ScintillaWX.cpp b/src/stc/ScintillaWX.cpp index a6c7d01aef..b639c0320d 100644 --- a/src/stc/ScintillaWX.cpp +++ b/src/stc/ScintillaWX.cpp @@ -24,6 +24,7 @@ #ifndef WX_PRECOMP #include "wx/scrolbar.h" + #include "wx/math.h" #include "wx/menu.h" #include "wx/timer.h" #endif // WX_PRECOMP @@ -433,7 +434,7 @@ bool ScintillaWX::ModifyScrollBars(int nMax, int nPage) { horizEnd = 0; if (!horizontalScrollBarVisible || Wrapping()) horizEnd = 0; - int pageWidth = rcText.Width(); + int pageWidth = wxRound(rcText.Width()); if (stc->m_hScrollBar == NULL) { // Use built-in scrollbar int sbMax = stc->GetScrollRange(wxHORIZONTAL); @@ -664,7 +665,7 @@ void ScintillaWX::UpdateSystemCaret() { CreateSystemCaret(); } Point pos = PointMainCaret(); - ::SetCaretPos(pos.x, pos.y); + ::SetCaretPos(wxRound(pos.x), wxRound(pos.y)); } #endif } @@ -842,7 +843,7 @@ void ScintillaWX::FullPaintDC(wxDC* dc) { void ScintillaWX::DoHScroll(int type, int pos) { int xPos = xOffset; PRectangle rcText = GetTextRectangle(); - int pageWidth = rcText.Width() * 2 / 3; + int pageWidth = wxRound(rcText.Width() * 2 / 3); if (type == wxEVT_SCROLLWIN_LINEUP || type == wxEVT_SCROLL_LINEUP) xPos -= H_SCROLL_STEP; else if (type == wxEVT_SCROLLWIN_LINEDOWN || type == wxEVT_SCROLL_LINEDOWN) @@ -852,7 +853,7 @@ void ScintillaWX::DoHScroll(int type, int pos) { else if (type == wxEVT_SCROLLWIN_PAGEDOWN || type == wxEVT_SCROLL_PAGEDOWN) { xPos += pageWidth; if (xPos > scrollWidth - rcText.Width()) { - xPos = scrollWidth - rcText.Width(); + xPos = wxRound(scrollWidth - rcText.Width()); } } else if (type == wxEVT_SCROLLWIN_TOP || type == wxEVT_SCROLL_TOP) @@ -894,14 +895,14 @@ void ScintillaWX::DoMouseWheel(wxMouseWheelAxis axis, int rotation, int delta, int pixels; if (axis == wxMOUSE_WHEEL_HORIZONTAL) { - wheelHRotation += rotation * (columnsPerAction * vs.spaceWidth); + wheelHRotation += wxRound(rotation * (columnsPerAction * vs.spaceWidth)); pixels = wheelHRotation / delta; wheelHRotation -= pixels * delta; if (pixels != 0) { xPos += pixels; PRectangle rcText = GetTextRectangle(); if (xPos > scrollWidth - rcText.Width()) { - xPos = scrollWidth - rcText.Width(); + xPos = wxRound(scrollWidth - rcText.Width()); } HorizontalScrollTo(xPos); } @@ -1190,7 +1191,7 @@ void ScintillaWX::DoScrollToLine(int line) { void ScintillaWX::DoScrollToColumn(int column) { - HorizontalScrollTo(column * vs.spaceWidth); + HorizontalScrollTo(wxRound(column * vs.spaceWidth)); } // wxGTK doesn't appear to need this explicit clipping code any longer, but I From 6caa5e92c195253fe7a6ad35e1b36bee10597e1e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 27 Jul 2015 03:28:07 +0200 Subject: [PATCH 08/12] Fix warnings about pointer/int casts in Win32 part of libtiff too. Do the same thing for tif_win32.c as f995dfcc20b7e930029544dc70a7780509b8c028 did for tif_unix.c, i.e. use a union for casting between HANDLEs and ints to avoid compiler warnings which were given for the explicit casts before. --- src/tiff/libtiff/tif_unix.c | 6 ------ src/tiff/libtiff/tif_win32.c | 24 +++++++++++++----------- src/tiff/libtiff/tiffiop.h | 11 +++++++++++ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/tiff/libtiff/tif_unix.c b/src/tiff/libtiff/tif_unix.c index 5ae1934103..1db40cdfd0 100644 --- a/src/tiff/libtiff/tif_unix.c +++ b/src/tiff/libtiff/tif_unix.c @@ -54,12 +54,6 @@ #include "tiffiop.h" -typedef union fd_as_handle_union -{ - int fd; - thandle_t h; -} fd_as_handle_union_t; - static tmsize_t _tiffReadProc(thandle_t fd, void* buf, tmsize_t size) { diff --git a/src/tiff/libtiff/tif_win32.c b/src/tiff/libtiff/tif_win32.c index b64dd8d5cf..479860c8d0 100644 --- a/src/tiff/libtiff/tif_win32.c +++ b/src/tiff/libtiff/tif_win32.c @@ -210,6 +210,8 @@ TIFFFdOpen(int ifd, const char* name, const char* mode) int fSuppressMap; int m; fSuppressMap=0; + fd_as_handle_union_t fdh; + fdh.fd = ifd; for (m=0; mode[m]!=0; m++) { if (mode[m]=='u') @@ -218,7 +220,7 @@ TIFFFdOpen(int ifd, const char* name, const char* mode) break; } } - tif = TIFFClientOpen(name, mode, (thandle_t)ifd, + tif = TIFFClientOpen(name, mode, fdh.h, _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, fSuppressMap ? _tiffDummyMapProc : _tiffMapProc, @@ -237,7 +239,7 @@ TIFF* TIFFOpen(const char* name, const char* mode) { static const char module[] = "TIFFOpen"; - thandle_t fd; + fd_as_handle_union_t fdh; int m; DWORD dwMode; TIFF* tif; @@ -253,19 +255,19 @@ TIFFOpen(const char* name, const char* mode) default: return ((TIFF*)0); } - fd = (thandle_t)CreateFileA(name, + fdh.h = CreateFileA(name, (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode, (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL, NULL); - if (fd == INVALID_HANDLE_VALUE) { + if (fdh.h == INVALID_HANDLE_VALUE) { TIFFErrorExt(0, module, "%s: Cannot open", name); return ((TIFF *)0); } - tif = TIFFFdOpen((int)fd, name, mode); + tif = TIFFFdOpen(fdh.fd, name, mode); if(!tif) - CloseHandle(fd); + CloseHandle(fdh.h); return tif; } @@ -276,7 +278,7 @@ TIFF* TIFFOpenW(const wchar_t* name, const char* mode) { static const char module[] = "TIFFOpenW"; - thandle_t fd; + fd_as_handle_union_t fdh; int m; DWORD dwMode; int mbsize; @@ -294,12 +296,12 @@ TIFFOpenW(const wchar_t* name, const char* mode) default: return ((TIFF*)0); } - fd = (thandle_t)CreateFileW(name, + fdh.h = CreateFileW(name, (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ|GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode, (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL, NULL); - if (fd == INVALID_HANDLE_VALUE) { + if (fdh.h == INVALID_HANDLE_VALUE) { TIFFErrorExt(0, module, "%S: Cannot open", name); return ((TIFF *)0); } @@ -318,10 +320,10 @@ TIFFOpenW(const wchar_t* name, const char* mode) NULL, NULL); } - tif = TIFFFdOpen((int)fd, + tif = TIFFFdOpen(fdh.fd, (mbname != NULL) ? mbname : "", mode); if(!tif) - CloseHandle(fd); + CloseHandle(fdh.h); _TIFFfree(mbname); diff --git a/src/tiff/libtiff/tiffiop.h b/src/tiff/libtiff/tiffiop.h index 3d9551a80b..748ed4598a 100644 --- a/src/tiff/libtiff/tiffiop.h +++ b/src/tiff/libtiff/tiffiop.h @@ -77,6 +77,17 @@ typedef struct client_info { char *name; } TIFFClientInfoLink; +/* + * Union allowing to cast between the OS-specific handles and integer file + * descriptors without triggering compiler warnings, even if their types are + * not the same. + */ +typedef union fd_as_handle_union +{ + int fd; + thandle_t h; +} fd_as_handle_union_t; + /* * Typedefs for ``method pointers'' used internally. * these are depriciated and provided only for backwards compatibility From 2c61e1b0daa1d19e6fa827f878eb8f9812577e80 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 27 Jul 2015 03:40:16 +0200 Subject: [PATCH 09/12] No changes, just use helper wxColourToPalRGB() in wxMSW code. This is shorter than writing out all wxColour components. --- src/msw/listctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 1e53d52128..a266a60892 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -1225,7 +1225,7 @@ wxColour wxListCtrl::GetTextColour() const // Sets the text colour of the listview void wxListCtrl::SetTextColour(const wxColour& col) { - ListView_SetTextColor(GetHwnd(), PALETTERGB(col.Red(), col.Green(), col.Blue())); + ListView_SetTextColor(GetHwnd(), wxColourToPalRGB(col)); } // Gets the index of the topmost visible item when in From 73a5c206134c19d8615a189bdb0803b02237d1d4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 27 Jul 2015 03:41:30 +0200 Subject: [PATCH 10/12] No real changes, just a tiny refactoring in wxMSW wxListCtrl. Reuse wxListCtrl::SetTextColour() instead of calling ListView_SetTextColor() from wxListCtrl::SetForegroundColour(). This ensures that the two functions behave consistently, e.g. they now both use palette-relative colour instead of a raw RGB value in the case of the latter method as before. This probably doesn't change anything in practice nowadays. --- src/msw/listctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index a266a60892..b5f6abd6f6 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -505,7 +505,7 @@ bool wxListCtrl::SetForegroundColour(const wxColour& col) if ( !wxWindow::SetForegroundColour(col) ) return false; - ListView_SetTextColor(GetHwnd(), wxColourToRGB(col)); + SetTextColour(col); return true; } From b17b0ab15159b84e19a0b49974feb8fed390c86e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 27 Jul 2015 03:55:01 +0200 Subject: [PATCH 11/12] Work around or suppress gcc -Wunused-value warnings in wxMSW code. TDM-GCC 4.9.2 gave many of these warnings for the calls to Windows common controls macros, avoid them by adding error reporting where it makes sense or just suppressing the warning by explicitly casting to void elsewhere (e.g. for the macros which have no meaningful return value at all or return something that we're not interested in instead of just success/failure indicator). --- src/msw/headerctrl.cpp | 8 +++--- src/msw/listctrl.cpp | 17 +++++++----- src/msw/notebook.cpp | 24 ++++++++++------- src/msw/treectrl.cpp | 59 +++++++++++++++++++++++------------------- 4 files changed, 63 insertions(+), 45 deletions(-) diff --git a/src/msw/headerctrl.cpp b/src/msw/headerctrl.cpp index 1fdebf74d8..359324b439 100644 --- a/src/msw/headerctrl.cpp +++ b/src/msw/headerctrl.cpp @@ -90,7 +90,7 @@ bool wxHeaderCtrl::Create(wxWindow *parent, // use 0 here but this starts to look ugly) if ( wxApp::GetComCtl32Version() >= 600 ) { - Header_SetBitmapMargin(GetHwnd(), ::GetSystemMetrics(SM_CXEDGE)); + (void)Header_SetBitmapMargin(GetHwnd(), ::GetSystemMetrics(SM_CXEDGE)); } return true; @@ -237,7 +237,8 @@ void wxHeaderCtrl::DoUpdate(unsigned int idx) if ( !m_isHidden[idx] ) { // but it wasn't hidden before, so remove it - Header_DeleteItem(GetHwnd(), MSWToNativeIdx(idx)); + if ( !Header_DeleteItem(GetHwnd(), MSWToNativeIdx(idx)) ) + wxLogLastError(wxS("Header_DeleteItem()")); m_isHidden[idx] = true; } @@ -252,7 +253,8 @@ void wxHeaderCtrl::DoUpdate(unsigned int idx) else // and it was shown before as well { // we need to remove the old column - Header_DeleteItem(GetHwnd(), MSWToNativeIdx(idx)); + if ( !Header_DeleteItem(GetHwnd(), MSWToNativeIdx(idx)) ) + wxLogLastError(wxS("Header_DeleteItem()")); } DoInsertItem(col, idx); diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index b5f6abd6f6..29f9986bf0 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -519,8 +519,10 @@ bool wxListCtrl::SetBackgroundColour(const wxColour& col) // we set the same colour for both the "empty" background and the items // background COLORREF color = wxColourToRGB(col); - ListView_SetBkColor(GetHwnd(), color); - ListView_SetTextBkColor(GetHwnd(), color); + if ( !ListView_SetBkColor(GetHwnd(), color) ) + wxLogLastError(wxS("ListView_SetBkColor()")); + if ( !ListView_SetTextBkColor(GetHwnd(), color) ) + wxLogLastError(wxS("ListView_SetTextBkColor()")); return true; } @@ -936,7 +938,7 @@ bool wxListCtrl::SetItemState(long item, long state, long stateMask) // to, so do it explicitly if ( changingFocus && !HasFlag(wxLC_SINGLE_SEL) ) { - ListView_SetSelectionMark(GetHwnd(), item); + (void)ListView_SetSelectionMark(GetHwnd(), item); } return true; @@ -1225,7 +1227,8 @@ wxColour wxListCtrl::GetTextColour() const // Sets the text colour of the listview void wxListCtrl::SetTextColour(const wxColour& col) { - ListView_SetTextColor(GetHwnd(), wxColourToPalRGB(col)); + if ( !ListView_SetTextColor(GetHwnd(), wxColourToPalRGB(col)) ) + wxLogLastError(wxS("ListView_SetTextColor()")); } // Gets the index of the topmost visible item when in @@ -2656,7 +2659,8 @@ bool HandleSubItemPrepaint(LPNMLVCUSTOMDRAW pLVCD, HFONT hfont, int colCount) it.iSubItem = col; it.pszText = text; it.cchTextMax = WXSIZEOF(text); - ListView_GetItem(hwndList, &it); + if ( !ListView_GetItem(hwndList, &it) ) + return false; HIMAGELIST himl = ListView_GetImageList(hwndList, LVSIL_SMALL); if ( himl && ImageList_GetImageCount(himl) ) @@ -3086,7 +3090,8 @@ void wxListCtrl::RefreshItem(long item) void wxListCtrl::RefreshItems(long itemFrom, long itemTo) { - ListView_RedrawItems(GetHwnd(), itemFrom, itemTo); + if ( !ListView_RedrawItems(GetHwnd(), itemFrom, itemTo) ) + wxLogLastError(wxS("ListView_RedrawItems")); } // ---------------------------------------------------------------------------- diff --git a/src/msw/notebook.cpp b/src/msw/notebook.cpp index b3f42c5118..68a6ef46c9 100644 --- a/src/msw/notebook.cpp +++ b/src/msw/notebook.cpp @@ -360,7 +360,7 @@ int wxNotebook::SetSelection(size_t nPage) UpdateSelection(nPage); - TabCtrl_SetCurSel(GetHwnd(), nPage); + (void)TabCtrl_SetCurSel(GetHwnd(), nPage); SendPageChangedEvent(selectionOld, nPage); } @@ -406,7 +406,7 @@ int wxNotebook::ChangeSelection(size_t nPage) if ( m_selection == wxNOT_FOUND || nPage != (size_t)m_selection ) { - TabCtrl_SetCurSel(GetHwnd(), nPage); + (void)TabCtrl_SetCurSel(GetHwnd(), nPage); UpdateSelection(nPage); } @@ -508,7 +508,7 @@ wxRect wxNotebook::GetPageSize() const // The value of 20 is chosen arbitrarily but seems to work if ( rc.right > 20 && rc.bottom > 20 ) { - TabCtrl_AdjustRect(GetHwnd(), false, &rc); + (void)TabCtrl_AdjustRect(GetHwnd(), false, &rc); wxCopyRECTToRect(rc, r); } @@ -525,7 +525,7 @@ void wxNotebook::SetPageSize(const wxSize& size) rc.right = size.x; rc.bottom = size.y; - TabCtrl_AdjustRect(GetHwnd(), true, &rc); + (void)TabCtrl_AdjustRect(GetHwnd(), true, &rc); // and now set it SetSize(rc.right - rc.left, rc.bottom - rc.top); @@ -552,9 +552,11 @@ wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const if ( GetPageCount() > 0 ) { RECT rect; - TabCtrl_GetItemRect(GetHwnd(), 0, &rect); - tabSize.x = rect.right - rect.left; - tabSize.y = rect.bottom - rect.top; + if ( TabCtrl_GetItemRect(GetHwnd(), 0, &rect) ) + { + tabSize.x = rect.right - rect.left; + tabSize.y = rect.bottom - rect.top; + } } const int rows = GetRowCount(); @@ -601,7 +603,8 @@ wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage) // selected page is visible and others are hidden: pageRemoved->Show(false); - TabCtrl_DeleteItem(GetHwnd(), nPage); + if ( !TabCtrl_DeleteItem(GetHwnd(), nPage) ) + wxLogLastError(wxS("TabCtrl_DeleteItem()")); if ( m_pages.IsEmpty() ) { @@ -654,7 +657,8 @@ bool wxNotebook::DeleteAllPages() m_pages.Clear(); - TabCtrl_DeleteAllItems(GetHwnd()); + if ( !TabCtrl_DeleteAllItems(GetHwnd()) ) + wxLogLastError(wxS("TabCtrl_DeleteAllItems()")); m_selection = wxNOT_FOUND; @@ -986,7 +990,7 @@ void wxNotebook::OnSize(wxSizeEvent& event) UpdateBgBrush(); #endif // wxUSE_UXTHEME - TabCtrl_AdjustRect(GetHwnd(), false, &rc); + (void)TabCtrl_AdjustRect(GetHwnd(), false, &rc); int width = rc.right - rc.left, height = rc.bottom - rc.top; diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 8bc7a6ac09..cf59c7bc03 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -340,11 +340,11 @@ static bool SetFocus(HWND hwndTV, HTREEITEM htItem) // prevent the tree from unselecting the old focus which it // would do by default (TreeView_SelectItem unselects the // focused item) - TreeView_SelectItem(hwndTV, 0); + (void)TreeView_SelectItem(hwndTV, 0); SelectItem(hwndTV, htFocus); } - TreeView_SelectItem(hwndTV, htItem); + (void)TreeView_SelectItem(hwndTV, htItem); if ( !wasSelected ) { @@ -359,7 +359,7 @@ static bool SetFocus(HWND hwndTV, HTREEITEM htItem) bool wasFocusSelected = IsItemSelected(hwndTV, htFocus); // just clear the focus - TreeView_SelectItem(hwndTV, 0); + (void)TreeView_SelectItem(hwndTV, 0); if ( wasFocusSelected ) { @@ -873,7 +873,7 @@ unsigned int wxTreeCtrl::GetIndent() const void wxTreeCtrl::SetIndent(unsigned int indent) { - TreeView_SetIndent(GetHwnd(), indent); + (void)TreeView_SetIndent(GetHwnd(), indent); } void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which) @@ -1969,7 +1969,7 @@ void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item) wxCHECK_RET( !IsHiddenRoot(item), wxT("can't show hidden root item") ); // no error return - TreeView_EnsureVisible(GetHwnd(), HITEM(item)); + (void)TreeView_EnsureVisible(GetHwnd(), HITEM(item)); } void wxTreeCtrl::ScrollTo(const wxTreeItemId& item) @@ -2031,7 +2031,8 @@ wxTextCtrl *wxTreeCtrl::EditLabel(const wxTreeItemId& item, // End label editing, optionally cancelling the edit void wxTreeCtrl::DoEndEditLabel(bool discardChanges) { - TreeView_EndEditLabelNow(GetHwnd(), discardChanges); + if ( !TreeView_EndEditLabelNow(GetHwnd(), discardChanges) ) + wxLogLastError(wxS("TreeView_EndEditLabelNow()")); DeleteTextCtrl(); } @@ -2170,7 +2171,8 @@ void wxTreeCtrl::SortChildren(const wxTreeItemId& item) // OnCompareItems if ( GetClassInfo() == wxCLASSINFO(wxTreeCtrl) ) { - TreeView_SortChildren(GetHwnd(), HITEM(item), 0); + if ( !TreeView_SortChildren(GetHwnd(), HITEM(item), 0) ) + wxLogLastError(wxS("TreeView_SortChildren()")); } else { @@ -2178,7 +2180,8 @@ void wxTreeCtrl::SortChildren(const wxTreeItemId& item) tvSort.hParent = HITEM(item); tvSort.lpfnCompare = wxTreeSortHelper::Compare; tvSort.lParam = (LPARAM)this; - TreeView_SortChildrenCB(GetHwnd(), &tvSort, 0 /* reserved */); + if ( !TreeView_SortChildrenCB(GetHwnd(), &tvSort, 0 /* reserved */) ) + wxLogLastError(wxS("TreeView_SortChildrenCB()")); } } @@ -2996,25 +2999,26 @@ wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) tviAux.hItem = HITEM(m_htClickedItem); tviAux.mask = TVIF_STATE | TVIF_PARAM; tviAux.stateMask = 0xffffffff; - TreeView_GetItem(GetHwnd(), &tviAux); + if ( TreeView_GetItem(GetHwnd(), &tviAux) ) + { + tv.itemNew.state = tviAux.state; + tv.itemNew.lParam = tviAux.lParam; - tv.itemNew.state = tviAux.state; - tv.itemNew.lParam = tviAux.lParam; + tv.ptDrag.x = x; + tv.ptDrag.y = y; - tv.ptDrag.x = x; - tv.ptDrag.y = y; + // do it before SendMessage() call below to avoid + // reentrancies here if there is another WM_MOUSEMOVE + // in the queue already + m_htClickedItem.Unset(); - // do it before SendMessage() call below to avoid - // reentrancies here if there is another WM_MOUSEMOVE - // in the queue already - m_htClickedItem.Unset(); + ::SendMessage(GetHwndOf(GetParent()), WM_NOTIFY, + tv.hdr.idFrom, (LPARAM)&tv ); - ::SendMessage(GetHwndOf(GetParent()), WM_NOTIFY, - tv.hdr.idFrom, (LPARAM)&tv ); - - // don't pass it to the default window proc, it would - // start dragging again - processed = true; + // don't pass it to the default window proc, it would + // start dragging again + processed = true; + } } } #endif // __WXWINCE__ @@ -3028,7 +3032,8 @@ wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // highlight the item as target (hiding drag image is // necessary - otherwise the display will be corrupted) m_dragImage->Hide(); - TreeView_SelectDropTarget(GetHwnd(), htItem); + if ( !TreeView_SelectDropTarget(GetHwnd(), htItem) ) + wxLogLastError(wxS("TreeView_SelectDropTarget()")); m_dragImage->Show(); } } @@ -3101,7 +3106,8 @@ wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // if we don't do it, the tree seems to think that 2 items // are selected simultaneously which is quite weird - TreeView_SelectDropTarget(GetHwnd(), 0); + if ( !TreeView_SelectDropTarget(GetHwnd(), 0) ) + wxLogLastError(wxS("TreeView_SelectDropTarget(0)")); } #endif // wxUSE_DRAGIMAGE @@ -3235,7 +3241,8 @@ wxTreeCtrl::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // if we don't do it, the tree seems to think that 2 items // are selected simultaneously which is quite weird - TreeView_SelectDropTarget(GetHwnd(), 0); + if ( !TreeView_SelectDropTarget(GetHwnd(), 0) ) + wxLogLastError(wxS("TreeView_SelectDropTarget(0)")); } } } From 0eab78625662ec7d232bb9ef4253a8e8c5df5238 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 27 Jul 2015 03:59:42 +0200 Subject: [PATCH 12/12] Suppress a harmless warning with MinGW 3.4.5 in wxMSW wxTreeCtrl. Cast NM_DBLCLK to UINT explicitly as it's defined as int in the ancient version of the headers used with this compiler. --- src/msw/treectrl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index cf59c7bc03..3112e1eb93 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -3652,7 +3652,10 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) if ( MSWIsOnItem(tvhti.flags) ) { event.m_item = tvhti.hItem; - eventType = hdr->code == NM_DBLCLK + // Cast is needed for the very old (gcc 3.4.5) MinGW + // headers which didn't define NM_DBLCLK as unsigned, + // resulting in signed/unsigned comparison warning. + eventType = hdr->code == (UINT)NM_DBLCLK ? wxEVT_TREE_ITEM_ACTIVATED : wxEVT_TREE_ITEM_RIGHT_CLICK;