diff --git a/source/graphics/Color.cpp b/source/graphics/Color.cpp index b42ad5afff..95e80b080c 100644 --- a/source/graphics/Color.cpp +++ b/source/graphics/Color.cpp @@ -22,7 +22,7 @@ u32 (*ConvertRGBColorTo4ub)(const RGBColor& src) = fallback_ConvertRGBColorTo4ub // Assembler-optimized function for color conversion #if CPU_IA32 -extern "C" u32 sse_ConvertRGBColorTo4ub(const RGBColor& src); +EXTERN_C u32 sse_ConvertRGBColorTo4ub(const RGBColor& src); #endif void ColorActivateFastImpl() diff --git a/source/gui/CDropDown.cpp b/source/gui/CDropDown.cpp index fbc89bb95c..787dea1ac0 100644 --- a/source/gui/CDropDown.cpp +++ b/source/gui/CDropDown.cpp @@ -9,7 +9,7 @@ gee@pyro.nu #include "CDropDown.h" #include "lib/ogl.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" using namespace std; diff --git a/source/gui/CList.cpp b/source/gui/CList.cpp index 8d46cacdf2..716e8ed31a 100644 --- a/source/gui/CList.cpp +++ b/source/gui/CList.cpp @@ -9,7 +9,7 @@ gee@pyro.nu #include "CList.h" #include "ps/CLogger.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" using namespace std; diff --git a/source/gui/MiniMap.cpp b/source/gui/MiniMap.cpp index 8f63022d95..f82d9d302c 100644 --- a/source/gui/MiniMap.cpp +++ b/source/gui/MiniMap.cpp @@ -12,7 +12,7 @@ #include "graphics/Unit.h" #include "graphics/UnitManager.h" #include "lib/ogl.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" #include "lib/timer.h" #include "network/NetMessage.h" #include "ps/Game.h" diff --git a/source/lib/crashlog_sender.cpp b/source/lib/crashlog_sender.cpp new file mode 100644 index 0000000000..7df35f4467 --- /dev/null +++ b/source/lib/crashlog_sender.cpp @@ -0,0 +1,755 @@ +/** + * ========================================================================= + * File : debug_report.cpp + * Project : 0 A.D. + * Description : preview and send crashlogs to server. + * + * @author jan@wildfiregames.com, joe@wildfiregames.com + * ========================================================================= + */ + +/* + * based on dbgrptg.cpp, + * Copyright (c) 2005 Vadim Zeitlin + * License: wxWindows license + */ + +#include "precompiled.h" + +#include "lib/external_libraries/wxwidgets.h" + +static const wxChar* DIALOG_TITLE = _T("WildfireGames Reporting Utility"); +static const wxChar* PROBLEM_TITLE = _T("Problem Report for 0AD"); +static const wxChar* DIALOG_REGRET = _T("Much to our regret, we must report the program has encountered a problem.\n"); +static const wxChar* DIALOG_REPGEN = _T("A problem report has been generated in the directory\n"); +static const wxChar* DIALOG_SPACER = _T("\n"); +static const wxChar* DIALOG_FILES = _T("The report contains the files listed below.\nWe believe they hold information that will help us to improve the program,\nso please take a minute and send them!\n"); +static const wxChar* DIALOG_PRIVACY = _T("If any of these files contain private information,\nplease uncheck them and they will be removed from the report.\n"); +static const wxChar* DIALOG_RESPECT = _T("We respect your privacy so if you do not wish to send us this problem report\nwe understand and you can use the \"Cancel\" button.\n"); +static const wxChar* DIALOG_APOLOGY = _T("Thank you and we're sorry for the inconvenience!\n"); +static const wxChar* DIALOG_ADDL_INFO = _T("If you have any additional information pertaining to this problem report,\n please enter it here and it will be joined to it:"); +// This is displayed to indicate a successful upload of the report file. +static const wxChar* DIALOG_UPLOAD = _T("Report successfully uploaded."); +// Default location for the crash files to include in the report file. +static const wxChar* LOGS_LOCATION = _T("C:\\0AD\\BINARIES\\LOGS\\"); + + +// ---------------------------------------------------------------------------- +// wxDumpPreviewDlg: simple class for showing ASCII preview of dump files +// ---------------------------------------------------------------------------- + +class wxDumpPreviewDlg : public wxDialog +{ +public: + wxDumpPreviewDlg(wxWindow *parent, + const wxString& title, + const wxString& text); + +private: + // the text we show + wxTextCtrl *m_text; + + DECLARE_NO_COPY_CLASS(wxDumpPreviewDlg) +}; + +wxDumpPreviewDlg::wxDumpPreviewDlg(wxWindow *parent, const wxString& title, const wxString& text) +: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + // create controls + // --------------- + + // use wxTE_RICH2 style to avoid 64kB limit under MSW and display big files + // faster than with wxTE_RICH + m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxPoint(0, 0), wxDefaultSize, + wxTE_MULTILINE | + wxTE_READONLY | + wxTE_NOHIDESEL | + wxTE_RICH2); + m_text->SetValue(text); + + // use fixed-width font + m_text->SetFont(wxFont(12, wxFONTFAMILY_TELETYPE, + wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + + wxButton *btnClose = new wxButton(this, wxID_CANCEL, _("Close")); + + + // layout them + // ----------- + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL), + *sizerBtns = new wxBoxSizer(wxHORIZONTAL); + + sizerBtns->Add(btnClose, 0, 0, 1); + + sizerTop->Add(m_text, 1, wxEXPAND); + sizerTop->Add(sizerBtns, 0, wxALIGN_RIGHT | wxTOP | wxBOTTOM | wxRIGHT, 1); + + // set the sizer &c + // ---------------- + + // make the text window bigger to show more contents of the file + sizerTop->SetItemMinSize(m_text, 600, 300); + SetSizer(sizerTop); + + Layout(); + Fit(); + + m_text->SetFocus(); +} + +// ---------------------------------------------------------------------------- +// wxDumpOpenExternalDlg: choose a command for opening the given file +// ---------------------------------------------------------------------------- + +class wxDumpOpenExternalDlg : public wxDialog +{ +public: + wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename); + + // return the command chosed by user to open this file + const wxString& GetCommand() const { return m_command; } + + wxString m_command; + +private: + +#if wxUSE_FILEDLG + void OnBrowse(wxCommandEvent& event); +#endif // wxUSE_FILEDLG + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxDumpOpenExternalDlg) +}; + +BEGIN_EVENT_TABLE(wxDumpOpenExternalDlg, wxDialog) + +#if wxUSE_FILEDLG +EVT_BUTTON(wxID_MORE, wxDumpOpenExternalDlg::OnBrowse) +#endif + +END_EVENT_TABLE() + + +wxDumpOpenExternalDlg::wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename) +: wxDialog(parent, wxID_ANY, +wxString::Format +( + _("Open file \"%s\""), + filename.GetFullPath().c_str() +) +) +{ + // create controls + // --------------- + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(new wxStaticText(this, wxID_ANY, + wxString::Format + ( + _("Enter command to open file \"%s\":"), + filename.GetFullName().c_str() + )), + wxSizerFlags().Border()); + + wxSizer *sizerH = new wxBoxSizer(wxHORIZONTAL); + + wxTextCtrl *command = new wxTextCtrl + ( + this, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(250, wxDefaultCoord), + 0 +#if wxUSE_VALIDATORS + ,wxTextValidator(wxFILTER_NONE, &m_command) +#endif + ); + sizerH->Add(command, + wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL)); + +#if wxUSE_FILEDLG + + wxButton *browse = new wxButton(this, wxID_MORE, wxT(">>"), + wxDefaultPosition, wxDefaultSize, + wxBU_EXACTFIT); + sizerH->Add(browse, + wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL). Border(wxLEFT)); + +#endif // wxUSE_FILEDLG + + sizerTop->Add(sizerH, wxSizerFlags(0).Expand().Border()); + + sizerTop->Add(new wxStaticLine(this), wxSizerFlags().Expand().Border()); + + sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), + wxSizerFlags().Align(wxALIGN_RIGHT).Border()); + + // set the sizer &c + // ---------------- + + SetSizer(sizerTop); + + Layout(); + Fit(); + + command->SetFocus(); +} + +#if wxUSE_FILEDLG + +void wxDumpOpenExternalDlg::OnBrowse(wxCommandEvent& ) +{ + wxFileName fname(m_command); + wxFileDialog dlg(this, + wxFileSelectorPromptStr, + fname.GetPathWithSep(), + fname.GetFullName() +#ifdef __WXMSW__ + , _("Executable files (*.exe)|*.exe|All files (*.*)|*.*||") +#endif // __WXMSW__ + ); + if ( dlg.ShowModal() == wxID_OK ) + { + m_command = dlg.GetPath(); + TransferDataToWindow(); + } +} + +#endif // wxUSE_FILEDLG + +// ---------------------------------------------------------------------------- +// wxDebugReportDialog: class showing debug report to the user +// ---------------------------------------------------------------------------- + +class wxDebugReportDialog : public wxDialog +{ +public: + wxDebugReportDialog(wxDebugReport& dbgrpt); + + virtual bool TransferDataToWindow(); + virtual bool TransferDataFromWindow(); + +private: + void OnView(wxCommandEvent& ); + void OnViewUpdate(wxUpdateUIEvent& ); + void OnOpen(wxCommandEvent& ); + + + // small helper: add wxEXPAND and wxALL flags + static wxSizerFlags SizerFlags(int proportion) + { + return wxSizerFlags(proportion).Expand().Border(); + } + + + wxDebugReport& m_dbgrpt; + + wxCheckListBox *m_checklst; + wxTextCtrl *m_notes; + + wxArrayString m_files; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxDebugReportDialog) +}; + +// ============================================================================ +// wxDebugReportDialog implementation +// ============================================================================ + +BEGIN_EVENT_TABLE(wxDebugReportDialog, wxDialog) +EVT_BUTTON(wxID_VIEW_DETAILS, wxDebugReportDialog::OnView) +EVT_UPDATE_UI(wxID_VIEW_DETAILS, wxDebugReportDialog::OnViewUpdate) +EVT_BUTTON(wxID_OPEN, wxDebugReportDialog::OnOpen) +EVT_UPDATE_UI(wxID_OPEN, wxDebugReportDialog::OnViewUpdate) +END_EVENT_TABLE() + + +// ---------------------------------------------------------------------------- +// construction +// ---------------------------------------------------------------------------- +/** + * wxDebugReportDialog: This contains modifications to implement changes to + * the content of the dialog. + * + * @param wxDebugReport & dbgrpt reference to compressed report file. + **/ +wxDebugReportDialog::wxDebugReportDialog(wxDebugReport& dbgrpt) +: wxDialog(NULL, wxID_ANY, + wxString(DIALOG_TITLE), + wxDefaultPosition, + wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + m_dbgrpt(dbgrpt) +{ + // upper part of the dialog: explanatory message + wxString msg; + msg << DIALOG_REGRET + << DIALOG_REPGEN + << _T("\"") << dbgrpt.GetDirectory() << _T("\"\n") + << DIALOG_SPACER + << DIALOG_FILES + << DIALOG_PRIVACY + << DIALOG_RESPECT + << DIALOG_SPACER + << DIALOG_APOLOGY + ; + + const wxSizerFlags flagsFixed(SizerFlags(0)); + const wxSizerFlags flagsExpand(SizerFlags(1)); + const wxSizerFlags flagsExpand2(SizerFlags(2)); + + wxSizer *sizerPreview = new wxStaticBoxSizer(wxVERTICAL, this, PROBLEM_TITLE); + sizerPreview->Add(CreateTextSizer(msg), SizerFlags(0).Centre()); + + // ... and the list of files in this debug report with buttons to view them + wxSizer *sizerFileBtns = new wxBoxSizer(wxVERTICAL); + sizerFileBtns->AddStretchSpacer(1); + sizerFileBtns->Add(new wxButton(this, wxID_VIEW_DETAILS, _T("&View...")), + wxSizerFlags().Border(wxBOTTOM)); + sizerFileBtns->Add(new wxButton(this, wxID_OPEN, _T("&Open...")), + wxSizerFlags().Border(wxTOP)); + sizerFileBtns->AddStretchSpacer(1); + + m_checklst = new wxCheckListBox(this, wxID_ANY); + + wxSizer *sizerFiles = new wxBoxSizer(wxHORIZONTAL); + sizerFiles->Add(m_checklst, flagsExpand); + sizerFiles->Add(sizerFileBtns, flagsFixed); + + sizerPreview->Add(sizerFiles, flagsExpand2); + + + // lower part of the dialog: notes field + wxSizer *sizerNotes = new wxStaticBoxSizer(wxVERTICAL, this, _("&Notes:")); + + msg = DIALOG_ADDL_INFO; + + m_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE); + + sizerNotes->Add(CreateTextSizer(msg), flagsFixed); + sizerNotes->Add(m_notes, flagsExpand); + + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(sizerPreview, flagsExpand2); + sizerTop->AddSpacer(5); + sizerTop->Add(sizerNotes, flagsExpand); + sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), flagsFixed); + + SetSizerAndFit(sizerTop); + Layout(); + CentreOnScreen(); +} + +// ---------------------------------------------------------------------------- +// data exchange +// ---------------------------------------------------------------------------- + +bool wxDebugReportDialog::TransferDataToWindow() +{ + // all files are included in the report by default + const size_t count = m_dbgrpt.GetFilesCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxString name, + desc; + if ( m_dbgrpt.GetFile(n, &name, &desc) ) + { + m_checklst->Append(name + _T(" (") + desc + _T(')')); + m_checklst->Check(n); + + m_files.Add(name); + } + } + + return true; +} + +bool wxDebugReportDialog::TransferDataFromWindow() +{ + // any unchecked files should be removed from the report + const size_t count = m_checklst->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( !m_checklst->IsChecked(n) ) + { + m_dbgrpt.RemoveFile(m_files[n]); + } + } + + // if the user entered any notes, add them to the report + const wxString notes = m_notes->GetValue(); + if ( !notes.empty() ) + { + // for now filename fixed, could make it configurable in the future... + m_dbgrpt.AddText(_T("notes.txt"), notes, _T("user notes")); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxDebugReportDialog::OnView(wxCommandEvent& ) +{ + const int sel = m_checklst->GetSelection(); + wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnView()") ); + + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + wxString str; + + wxFFile file(fn.GetFullPath()); + if ( file.IsOpened() && file.ReadAll(&str) ) + { + wxDumpPreviewDlg dlg(this, m_files[sel], str); + dlg.ShowModal(); + } +} + +void wxDebugReportDialog::OnOpen(wxCommandEvent& ) +{ + const int sel = m_checklst->GetSelection(); + wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnOpen()") ); + + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + + // try to get the command to open this kind of files ourselves + wxString command; +#if wxUSE_MIMETYPE + wxFileType * + ft = wxTheMimeTypesManager->GetFileTypeFromExtension(fn.GetExt()); + if ( ft ) + { + command = ft->GetOpenCommand(fn.GetFullPath()); + delete ft; + } +#endif // wxUSE_MIMETYPE + + // if we couldn't, ask the user + if ( command.empty() ) + { + wxDumpOpenExternalDlg dlg(this, fn); + if ( dlg.ShowModal() == wxID_OK ) + { + // get the command chosen by the user and append file name to it + + // if we don't have place marker for file name in the command... + wxString cmd = dlg.GetCommand(); + if ( !cmd.empty() ) + { +#if wxUSE_MIMETYPE + if ( cmd.find(_T('%')) != wxString::npos ) + { + command = wxFileType::ExpandCommand(cmd, fn.GetFullPath()); + } + else // no %s nor %1 +#endif // wxUSE_MIMETYPE + { + // append the file name to the end + command << cmd << _T(" \"") << fn.GetFullPath() << _T('"'); + } + } + } + } + + if ( !command.empty() ) + ::wxExecute(command); +} + +void wxDebugReportDialog::OnViewUpdate(wxUpdateUIEvent& event) +{ + int sel = m_checklst->GetSelection(); + if (sel >= 0) + { + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + event.Enable(fn.FileExists()); + } + else + event.Enable(false); +} + + +// ============================================================================ +// wxDebugReportPreviewStd implementation +// ============================================================================ + +bool wxDebugReportPreviewStd::Show(wxDebugReport& dbgrpt) const +{ + if ( !dbgrpt.GetFilesCount() ) + return false; + + wxDebugReportDialog dlg(dbgrpt); + +#ifdef __WXMSW__ + // before entering the event loop (from ShowModal()), block the event + // handling for all other windows as this could result in more crashes + wxEventLoop::SetCriticalWindow(&dlg); +#endif // __WXMSW__ + + return dlg.ShowModal() == wxID_OK && dbgrpt.GetFilesCount() != 0; +} + + + + + + + + + + + + +// ---------------------------------------------------------------------------- +// custom debug reporting class +// ---------------------------------------------------------------------------- + +// this is your custom debug reporter: it will use curl program (which should +// be available) to upload the crash report to the given URL (which should be +// set up by you) +class MyDebugReport : public wxDebugReportUpload +{ +public: + MyDebugReport() + : wxDebugReportUpload(_T("http://your.url.here/"), _T("report:file"), _T("action")) + { + //This would be the place to put the compressed file in a custom directory + //but since the directory member is private, it would require pulling in yet + //another wxWidget module to modify and I decided against it and take the + //time and date based random location generator. (JAC - 4/16/07) + } + +protected: + // this is called with the contents of the server response: you will + // probably want to parse the XML document in OnServerReply() instead of + // just dumping it as I do + virtual bool OnServerReply(const wxArrayString& reply) + { + if ( reply.IsEmpty() ) + { + wxLogError(_T("Didn't receive the expected server reply.")); + return false; + } + + wxString s(_T("Server replied:\n")); + + const size_t count = reply.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + s << _T('\t') << reply[n] << _T('\n'); + } + + wxLogMessage(_T("%s"), s.c_str()); + + return true; + } + /** + * DoProcess: This is called by the wxWidgets Dialog when OK is clicked. + * Since it overrides a virtual method we must make sure + * that DoProcess() of the parent class is called. + * + * @return bool true if upload was successful, false otherwise. + **/ + virtual bool DoProcess() + { + //Call the DoProcess of the parent class and make sure it is successful. + if ( !wxDebugReportCompress::DoProcess() ) + return false; + + //Shell execute the curl command with the appropriate arguments + //for the custom application of this class: + // + //C:\curl-7.16.0\curl -v -F upfile=@"" --trace trace.txt + // + //The -v and the --trace trace.txt arguments are for debugging and are not required. + wxArrayString output, errors; + int rc = wxExecute(wxString::Format + ( + _T("%s -v -F %s=@\"%s\" --trace trace.txt %s"), + _T("C:\\curl-7.16.0\\curl"), + _T("upfile"), + GetCompressedFileName().c_str(), + _T("http://kaxa.findhere.org/0ad/upload.php") + ), + output, + errors); + //Check the result for errors and log them with wxWidgets. + if ( rc == -1 ) + { + wxLogError(_("Failed to execute curl, please install it in PATH.")); + } + else if ( rc != 0 ) + { + const size_t count = errors.GetCount(); + if ( count ) + { + for ( size_t n = 0; n < count; n++ ) + { + wxLogWarning(_T("%s"), errors[n].c_str()); + } + } + + wxLogError(_("Failed to upload the debug report (error code %d)."), rc); + } + else // rc == 0 + { + //this causes a crash and I have no incentive to debug it + //if ( OnServerReply(output) ) + return true; + } + + return false; + } +}; + +// another possibility would be to build email library from contrib and use +// this class, after uncommenting it: +#if 0 + +#include "wx/net/email.h" + +class MyDebugReport : public wxDebugReportCompress +{ +public: + virtual bool DoProcess() + { + if ( !wxDebugReportCompress::DoProcess() ) + return false; + wxMailMessage msg(GetReportName() + _T(" crash report"), + _T("vadim@wxwindows.org"), + wxEmptyString, // mail body + wxEmptyString, // from address + GetCompressedFileName(), + _T("crashreport.zip")); + + return wxEmail::Send(msg); + } +}; + +#endif // 0 + +// ---------------------------------------------------------------------------- +// application class +// ---------------------------------------------------------------------------- + +// this is a usual application class modified to work with debug reporter +// +// basically just 2 things are necessary: call wxHandleFatalExceptions() as +// early as possible and override OnFatalException() to create the report there +class MyApp : public wxApp +{ +public: + // call wxHandleFatalExceptions here + MyApp(); + + // create our main window here + virtual bool OnInit(); + + // called when a crash occurs in this application + //virtual void OnFatalException(); + + // this is where we really generate the debug report + void GenerateReport(bool CrashFilesExist); + + // if this function is called, we'll use MyDebugReport which would try to + // upload the (next) generated debug report to its URL, otherwise we just + // generate the debug report and leave it in a local file + void UploadReport(bool doIt) { m_uploadReport = doIt; } + +private: + bool m_uploadReport; + bool m_generateReport; + + DECLARE_NO_COPY_CLASS(MyApp) +}; + + +// ---------------------------------------------------------------------------- +// MyApp +// ---------------------------------------------------------------------------- + +MyApp::MyApp() +{ + // user needs to explicitely enable this + m_uploadReport = false; + + // call this to tell the library to call our OnFatalException() + //wxHandleFatalExceptions(); +} + +bool MyApp::OnInit() +{ + if ( !wxApp::OnInit() ) + return false; + + m_uploadReport = true; //Upload the compressed report. + m_generateReport = false; //Flag to report back to wxWidgets that indicates + //whether the DoProcess() method should be called. + GenerateReport(false); //Create the compressed report file. + //The argument is not used in this version but + //is meant to indicate whether crash files already + //existed and the calling method did not create new ones. + //false means the crash files were recently generated... + //true means they already existed. + //new MyFrame; + + return m_generateReport; +} + +void MyApp::GenerateReport(bool CrashFilesExist) +{ + wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport + : new wxDebugReportCompress; + wxString fn1, fn2, fn3; + fn1 = _T(LOGS_LOCATION); + fn1 += _T("crashlog.dmp"); + fn2 = _T(LOGS_LOCATION); + fn2 += _T("crashlog.txt"); + + if(!CrashFilesExist) //This flag better be false or nothing will get added. + { + if(wxFileExists(fn1)) + report->AddFile(fn1, _T("memory dump")); + else + wxLogError(_T("crashlog.dmp not found!")); + if(wxFileExists(fn2)) + report->AddFile(fn2, _T("debug information")); + else + wxLogError(_T("crashlog.txt not found!")); + } + + //Then call the built in wxWidgets dialog which is modified to be + //customizable for each individual project and can be found in + // *****dbgrptg.cpp***** + m_generateReport = wxDebugReportPreviewStd().Show(*report); + if ( m_generateReport ) + { //User clicked OK + if ( report->Process() ) + { + if ( m_uploadReport ) + { + wxLogMessage(DIALOG_UPLOAD); + } + else + { + wxLogMessage(_T("Report generated in \"%s\"."), + report->GetCompressedFileName().c_str()); + report->Reset(); + } + } + // remove all crashlog files whether or not upload was successful!! + wxRemove(fn1); + wxRemove(fn2); + } + //delete the compressed report file always!! + delete report; +} + diff --git a/source/lib/external_libraries/png.h b/source/lib/external_libraries/png.h new file mode 100644 index 0000000000..282517d006 --- /dev/null +++ b/source/lib/external_libraries/png.h @@ -0,0 +1,4 @@ +// includes , which requires some fixes by our header. +#include "lib/external_libraries/zlib.h" + +#include diff --git a/source/lib/sdl.h b/source/lib/external_libraries/sdl.h similarity index 100% rename from source/lib/sdl.h rename to source/lib/external_libraries/sdl.h diff --git a/source/lib/sdl_fwd.h b/source/lib/external_libraries/sdl_fwd.h similarity index 100% rename from source/lib/sdl_fwd.h rename to source/lib/external_libraries/sdl_fwd.h diff --git a/source/lib/external_libraries/wxwidgets.h b/source/lib/external_libraries/wxwidgets.h new file mode 100644 index 0000000000..68d7eead49 --- /dev/null +++ b/source/lib/external_libraries/wxwidgets.h @@ -0,0 +1,54 @@ +/** + * ========================================================================= + * File : wxw.h + * Project : 0 A.D. + * Description : pulls in wxWidgets headers, with compatibility fixes + * + * @author Jan.Wassenberg@stud.uni-karlsruhe.de + * ========================================================================= + */ + +/* + * Copyright (c) 2007 Jan Wassenberg + * + * Redistribution and/or modification are also permitted under the + * terms of the GNU General Public License as published by the + * Free Software Foundation (version 2 or later, at your option). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef INCLUDED_WXW +#define INCLUDED_WXW + +// prevent wxWidgets from pulling in windows.h - it's mostly unnecessary +// and interferes with posix_sock's declarations. +#define _WINDOWS_ // include guard + +// manually define what is actually needed from windows.h: +struct HINSTANCE__ +{ + int unused; +}; +typedef struct HINSTANCE__* HINSTANCE; // definition as if STRICT were #defined + + +#include "wx/wx.h" + +#include "wx/file.h" +#include "wx/ffile.h" +#include "wx/filename.h" +#include "wx/mimetype.h" + +#include "wx/statline.h" + +#include "wx/debugrpt.h" + +#ifdef __WXMSW__ +#include "wx/evtloop.h" // for SetCriticalWindow() +#endif // __WXMSW__ + + +#endif // #ifndef INCLUDED_WXW diff --git a/source/lib/external_libraries/zlib.h b/source/lib/external_libraries/zlib.h new file mode 100644 index 0000000000..6cc1bb95d2 --- /dev/null +++ b/source/lib/external_libraries/zlib.h @@ -0,0 +1,20 @@ +// zlib.h -> zconf.h includes , which causes conflicts. +// define the include guard to prevent it from actually being included and +// then manually define the few things that are actually needed. +#define _WINDOWS_ // windows.h include guard +#ifndef WINAPI +# define WINAPI __stdcall +# define WINAPIV __cdecl +#endif + +#define ZLIB_DLL +#include + +// automatically link against the required library +#if MSC_VERSION +# ifdef NDEBUG +# pragma comment(lib, "zlib1.lib") +# else +# pragma comment(lib, "zlib1d.lib") +# endif +#endif diff --git a/source/lib/input.cpp b/source/lib/input.cpp index b2abf162b4..57a9a7d56d 100644 --- a/source/lib/input.cpp +++ b/source/lib/input.cpp @@ -28,7 +28,7 @@ #include #include "lib.h" -#include "sdl.h" +#include "lib/external_libraries/sdl.h" #include "lib/res/file/file.h" const uint MAX_HANDLERS = 8; diff --git a/source/lib/input.h b/source/lib/input.h index 57157faf6e..3e337362bf 100644 --- a/source/lib/input.h +++ b/source/lib/input.h @@ -25,7 +25,7 @@ #define INPUT_H__ -#include "lib/sdl_fwd.h" +#include "lib/external_libraries/sdl_fwd.h" // input handler return values. enum InReaction diff --git a/source/lib/lib.h b/source/lib/lib.h index 35791957db..6c3a28eaef 100644 --- a/source/lib/lib.h +++ b/source/lib/lib.h @@ -61,14 +61,6 @@ scope #include "config.h" - -#if defined(__cplusplus) -# define EXTERN_C extern "C" -#else -# define EXTERN_C extern -#endif - - const size_t KiB = 1ul << 10; const size_t MiB = 1ul << 20; const size_t GiB = 1ul << 30; diff --git a/source/lib/ogl.cpp b/source/lib/ogl.cpp index c83aed21b7..dc6b0fd788 100644 --- a/source/lib/ogl.cpp +++ b/source/lib/ogl.cpp @@ -28,7 +28,7 @@ #include #include "lib.h" -#include "sdl.h" +#include "lib/external_libraries/sdl.h" #include "debug.h" #include "lib/sysdep/gfx.h" #include "lib/res/h_mgr.h" diff --git a/source/lib/posix/posix.h b/source/lib/posix/posix.h index c56abd1321..cd21c4046e 100644 --- a/source/lib/posix/posix.h +++ b/source/lib/posix/posix.h @@ -60,7 +60,6 @@ need only be renamed (e.g. _open, _stat). #if OS_WIN # include "lib/sysdep/win/wposix/wposix.h" -# include "lib/sysdep/win/win.h" #endif #include "posix_types.h" diff --git a/source/lib/posix/posix_aio.h b/source/lib/posix/posix_aio.h index 4621ce3171..f536ee4e79 100644 --- a/source/lib/posix/posix_aio.h +++ b/source/lib/posix/posix_aio.h @@ -1,7 +1,11 @@ +// despite the comment in wposix.h about not using Windows headers for +// POSIX declarations, this one is harmless (no incompatible declarations) +// and can safely be used on Windows as well. +#include + #if OS_WIN # include "lib/sysdep/win/wposix/waio.h" #else -# include # include #endif diff --git a/source/lib/res/file/compression.cpp b/source/lib/res/file/compression.cpp index 98927f120e..7b2cd6c0d9 100644 --- a/source/lib/res/file/compression.cpp +++ b/source/lib/res/file/compression.cpp @@ -42,16 +42,7 @@ AT_STARTUP(\ //#define NO_ZLIB #ifndef NO_ZLIB -# define ZLIB_DLL -# include - -# if MSC_VERSION -# ifdef NDEBUG -# pragma comment(lib, "zlib1.lib") -# else -# pragma comment(lib, "zlib1d.lib") -# endif -# endif +# include "lib/external_libraries/zlib.h" #else // several switch statements are going to have all cases removed. // squelch the corresponding warning. diff --git a/source/lib/res/graphics/tex_png.cpp b/source/lib/res/graphics/tex_png.cpp index 163d686839..9d41ff8feb 100644 --- a/source/lib/res/graphics/tex_png.cpp +++ b/source/lib/res/graphics/tex_png.cpp @@ -22,14 +22,7 @@ #include "precompiled.h" -// include libpng header. we also prevent it from including windows.h, which -// would conflict with other headers. instead, WINAPI is defined here. -#if OS_WIN -# define _WINDOWS_ -# define WINAPI __stdcall -# define WINAPIV __cdecl -#endif // OS_WIN -#include +#include "lib/external_libraries/png.h" #include "lib/byte_order.h" #include "lib/res/res.h" diff --git a/source/lib/sysdep/compiler.h b/source/lib/sysdep/compiler.h index df26b6b0fb..3f5a5d8385 100644 --- a/source/lib/sysdep/compiler.h +++ b/source/lib/sysdep/compiler.h @@ -94,5 +94,11 @@ # define ASSUME_UNREACHABLE #endif +// extern "C", but does the right thing in pure-C mode +#if defined(__cplusplus) +# define EXTERN_C extern "C" +#else +# define EXTERN_C extern +#endif #endif // #ifndef INCLUDED_COMPILER diff --git a/source/lib/sysdep/gfx.cpp b/source/lib/sysdep/gfx.cpp index 2ab355bf0d..4f0f95d116 100644 --- a/source/lib/sysdep/gfx.cpp +++ b/source/lib/sysdep/gfx.cpp @@ -24,7 +24,7 @@ #include "gfx.h" #include "lib/lib.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" char gfx_card[GFX_CARD_LEN] = ""; diff --git a/source/lib/sysdep/ia32/ia32_memcpy.h b/source/lib/sysdep/ia32/ia32_memcpy.h index 9f1fd2ca5b..6666372885 100644 --- a/source/lib/sysdep/ia32/ia32_memcpy.h +++ b/source/lib/sysdep/ia32/ia32_memcpy.h @@ -1,12 +1,16 @@ #ifndef INCLUDED_IA32_MEMCPY #define INCLUDED_IA32_MEMCPY +#ifdef __cplusplus extern "C" { +#endif extern void ia32_memcpy_init(); extern void* ia32_memcpy(void* RESTRICT dst, const void* RESTRICT src, size_t nbytes); +#ifdef __cplusplus } +#endif #endif // #ifndef INCLUDED_IA32_MEMCPY diff --git a/source/lib/sysdep/ia32/ia32_memcpy_init.cpp b/source/lib/sysdep/ia32/ia32_memcpy_init.cpp index c73c64393a..6fea86c76a 100644 --- a/source/lib/sysdep/ia32/ia32_memcpy_init.cpp +++ b/source/lib/sysdep/ia32/ia32_memcpy_init.cpp @@ -5,7 +5,7 @@ // set by ia32_memcpy_init, referenced by ia32_memcpy (asm) // default to "all codepaths supported" -extern "C" u32 ia32_memcpy_size_mask = ~0u; +EXTERN_C u32 ia32_memcpy_size_mask = ~0u; void ia32_memcpy_init() { diff --git a/source/lib/sysdep/sysdep.h b/source/lib/sysdep/sysdep.h index 04e4153351..cd3b7acb88 100644 --- a/source/lib/sysdep/sysdep.h +++ b/source/lib/sysdep/sysdep.h @@ -23,7 +23,6 @@ #ifndef INCLUDED_SYSDEP #define INCLUDED_SYSDEP -#include "lib/config.h" #include "lib/debug.h" // ErrorReaction #include // needed for sys_vsnprintf diff --git a/source/lib/sysdep/win/delay_load.cpp b/source/lib/sysdep/win/delay_load.cpp index 2b817a8758..422becc8f5 100644 --- a/source/lib/sysdep/win/delay_load.cpp +++ b/source/lib/sysdep/win/delay_load.cpp @@ -25,8 +25,16 @@ #include "precompiled.h" #include "delay_load.h" -#include "win_internal.h" #include "lib/sysdep/cpu.h" +#include "win_internal.h" +#include "winit.h" + + +// note: must be last, since DLLs are unloaded here +#pragma SECTION_POST_ATEXIT(Y) +WIN_REGISTER_FUNC(wdll_shutdown); +#pragma FORCE_INCLUDE(wdll_shutdown) +#pragma SECTION_RESTORE #define _DELAY_IMP_VER 2 @@ -155,11 +163,6 @@ PfnDliHook __pfnDliFailureHook2; -// note: must be last, since DLLs are unloaded here -#pragma SECTION_POST_ATEXIT(Y) -WIN_REGISTER_FUNC(wdll_shutdown); -#pragma FORCE_INCLUDE(wdll_shutdown) -#pragma SECTION_RESTORE #pragma intrinsic(strlen,memcmp,memcpy) diff --git a/source/lib/sysdep/win/dll_ver.cpp b/source/lib/sysdep/win/dll_ver.cpp index 84151643c0..e066a60f62 100644 --- a/source/lib/sysdep/win/dll_ver.cpp +++ b/source/lib/sysdep/win/dll_ver.cpp @@ -28,6 +28,7 @@ #include "lib/path_util.h" #include "win_internal.h" +#include "wutil.h" #if MSC_VERSION #pragma comment(lib, "version.lib") // DLL version diff --git a/source/lib/sysdep/win/wcpu.cpp b/source/lib/sysdep/win/wcpu.cpp index 7f3d4d3176..0bebd928fa 100644 --- a/source/lib/sysdep/win/wcpu.cpp +++ b/source/lib/sysdep/win/wcpu.cpp @@ -27,6 +27,7 @@ #include "lib/posix/posix_pthread.h" #include "lib/posix/posix_time.h" #include "win_internal.h" +#include "wutil.h" // limit allows statically allocated per-CPU structures (for simplicity). // WinAPI only supports max. 32 CPUs anyway (due to DWORD bitfields). diff --git a/source/lib/sysdep/win/wdbg.cpp b/source/lib/sysdep/win/wdbg.cpp index 6069b1786c..eb83a72504 100644 --- a/source/lib/sysdep/win/wdbg.cpp +++ b/source/lib/sysdep/win/wdbg.cpp @@ -33,8 +33,9 @@ #include "lib/app_hooks.h" #include "lib/sysdep/cpu.h" #include "win_internal.h" - #include "wdbg_sym.h" +#include "winit.h" +#include "wutil.h" #pragma SECTION_PRE_LIBC(D) diff --git a/source/lib/sysdep/win/wdbg.h b/source/lib/sysdep/win/wdbg.h index 7e06e0b6b7..703b0a3726 100644 --- a/source/lib/sysdep/win/wdbg.h +++ b/source/lib/sysdep/win/wdbg.h @@ -20,8 +20,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef WDBG_H__ -#define WDBG_H__ +#ifndef INCLUDED_WDBG +#define INCLUDED_WDBG #if HAVE_MS_ASM # define debug_break() __asm { int 3 } @@ -32,4 +32,8 @@ // internal use only: extern void wdbg_set_thread_name(const char* name); -#endif // #ifndef WDBG_H__ +// see rationale at definition. +struct _EXCEPTION_POINTERS; +extern long __stdcall wdbg_exception_filter(_EXCEPTION_POINTERS* ep); + +#endif // #ifndef INCLUDED_WDBG diff --git a/source/lib/sysdep/win/wdbg_sym.cpp b/source/lib/sysdep/win/wdbg_sym.cpp index 1127d5a7ec..8bf8711e10 100644 --- a/source/lib/sysdep/win/wdbg_sym.cpp +++ b/source/lib/sysdep/win/wdbg_sym.cpp @@ -37,6 +37,8 @@ # include "lib/sysdep/ia32/ia32.h" #endif #include "win_internal.h" +#include "winit.h" +#include "wutil.h" #define _NO_CVCONST_H // request SymTagEnum be defined #include // must come after win_internal diff --git a/source/lib/sysdep/win/wdir_watch.cpp b/source/lib/sysdep/win/wdir_watch.cpp index 550b5538e9..d4bf648b08 100644 --- a/source/lib/sysdep/win/wdir_watch.cpp +++ b/source/lib/sysdep/win/wdir_watch.cpp @@ -31,6 +31,8 @@ #include "lib/path_util.h" #include "lib/res/file/file.h" // path_is_subpath #include "win_internal.h" +#include "winit.h" +#include "wutil.h" #pragma SECTION_POST_ATEXIT(J) diff --git a/source/lib/sysdep/win/win.h b/source/lib/sysdep/win/win.h deleted file mode 100644 index 1d4c487841..0000000000 --- a/source/lib/sysdep/win/win.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * ========================================================================= - * File : win.h - * Project : 0 A.D. - * Description : various compatibility fixes for Win32. - * - * @author Jan.Wassenberg@stud.uni-karlsruhe.de - * ========================================================================= - */ - -/* - * Copyright (c) 2003-2004 Jan Wassenberg - * - * Redistribution and/or modification are also permitted under the - * terms of the GNU General Public License as published by the - * Free Software Foundation (version 2 or later, at your option). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef INCLUDED_WIN -#define INCLUDED_WIN - -#include "lib/config.h" - -#if !OS_WIN -#error "win.h: do not include if not compiling for Windows" -#endif - -// libpng.h -> zlib.h -> zconf.h includes , which causes conflicts. -// prevent that, and define what they actually need from windows.h. -// incidentally, this requires all dependents of windows.h to include -// sysdep/win/win_internal.h instead. -#define _WINDOWS_ // windows.h include guard -#define WINAPI __stdcall -#define WINAPIV __cdecl - - -// rationale for manual init: -// our Windows-specific init code needs to run before the regular main() code. -// ideally this would happen automagically. -// one possibility is using WinMain as the entry point, and then calling the -// application's main(), but this is expressly forbidden by the C standard. -// VC apparently makes use of this and changes its calling convention. -// if we call it, everything appears to work but stack traces in -// release mode are incorrect (symbol address is off by 4). -// -// another alternative is re#defining the app's main function to app_main, -// having the OS call our main, and then dispatching to app_main. -// however, this leads to trouble when another library (e.g. SDL) wants to -// do the same. -// -// moreover, this file is compiled into a static library and used both for -// the 0ad executable as well as the separate self-test. this means -// we can't enable the main() hook for one and disable in the other. -// -// the consequence is that automatic init isn't viable. users MUST call this -// at the beginning of main (or at least before using any lib function). -// this is unfortunate because integration into new projects requires -// remembering to call the init function, but it can't be helped. -extern void win_pre_main_init(); - -#endif // #ifndef INCLUDED_WIN diff --git a/source/lib/sysdep/win/win_internal.h b/source/lib/sysdep/win/win_internal.h index 370a26aec8..c1c5a47834 100644 --- a/source/lib/sysdep/win/win_internal.h +++ b/source/lib/sysdep/win/win_internal.h @@ -2,14 +2,14 @@ * ========================================================================= * File : win_internal.h * Project : 0 A.D. - * Description : shared (private) header for Windows-specific code. + * Description : include , with compatibility fixes afterwards * * @author Jan.Wassenberg@stud.uni-karlsruhe.de * ========================================================================= */ /* - * Copyright (c) 2002-2005 Jan Wassenberg + * Copyright (c) 2002-2007 Jan Wassenberg * * Redistribution and/or modification are also permitted under the * terms of the GNU General Public License as published by the @@ -20,19 +20,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef WIN_INTERNAL_H -#define WIN_INTERNAL_H +#ifndef INCLUDED_WIN +#define INCLUDED_WIN #if !OS_WIN #error "win_internal.h: do not include if not compiling for Windows" #endif -#include "lib/lib.h" // BIT - -#if MSC_VERSION >= 1400 // hide "pragma region" from VS2003 -#pragma region WindowsHeaderAndFixes -#endif - // Win32 socket declarations aren't portable (e.g. problems with socklen_t) // => skip winsock.h; posix_sock.h should be used instead. #define _WINSOCKAPI_ @@ -92,11 +86,9 @@ #include -/////////////////////////////////////////////////////////////////////////////// -// +//----------------------------------------------------------------------------- // fixes for VC6 platform SDK -// -/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- // VC6 windows.h doesn't define these #ifndef DWORD_PTR @@ -134,11 +126,9 @@ typedef struct _MEMORYSTATUSEX #endif // #if WINVER < 0x500 -/////////////////////////////////////////////////////////////////////////////// -// +//----------------------------------------------------------------------------- // powrprof.h (not there at all in VC6, missing some parts in VC7) -// -/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- // MinGW headers are already correct; only change on VC #if MSC_VERSION @@ -265,11 +255,9 @@ typedef struct _PROCESSOR_POWER_INFORMATION } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION; -/////////////////////////////////////////////////////////////////////////////// -// +//----------------------------------------------------------------------------- // fixes for dbghelp.h 6.4 -// -/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- // the macros defined "for those without specstrings.h" are incorrect - // parameter definition is missing. @@ -340,167 +328,4 @@ enum DataKind DataIsConstant }; -#if MSC_VERSION >= 1400 // hide "pragma region" from VS2003 -#pragma endregion -#endif - -//----------------------------------------------------------------------------- -// locking - -// critical sections used by win-specific code -enum -{ - ONCE_CS, - WTIME_CS, - WAIO_CS, - WIN_CS, - WDBG_CS, - - NUM_CS -}; - -extern void win_lock(uint idx); -extern void win_unlock(uint idx); - -// used in a desperate attempt to avoid deadlock in wdbg_exception_handler. -extern int win_is_locked(uint idx); - - -//----------------------------------------------------------------------------- -// module init and shutdown - -// register functions to be called before libc init, before main, -// or after atexit. -// -// overview: -// participating modules store function pointer(s) to their init and/or -// shutdown function in a specific COFF section. the sections are -// grouped according to the desired notification and the order in which -// functions are to be called (useful if one module depends on another). -// they are then gathered by the linker and arranged in alphabetical order. -// placeholder variables in the sections indicate where the series of -// functions begins and ends for a given notification time. -// at runtime, all of the function pointers between the markers are invoked. -// -// details: -// the section names are of the format ".LIB${type}{group}". -// {type} is C for pre-libc init, I for pre-main init, or -// T for terminators (last of the atexit handlers). -// {group} is [B, Y]; all functions in a group are called before those of -// the next (alphabetically) higher group, but order within the group is -// undefined. this is because the linker sorts sections alphabetically, -// but doesn't specify the order in which object files are processed. -// another consequence is that groups A and Z must not be used! -// (data placed there might end up outside the start/end markers) -// -// example: -// #pragma SECTION_PRE_LIBC(G)) -// WIN_REGISTER_FUNC(wtime_init); -// #pragma FORCE_INCLUDE(wtime_init) -// #pragma SECTION_POST_ATEXIT(D)) -// WIN_REGISTER_FUNC(wtime_shutdown); -// #pragma FORCE_INCLUDE(wtime_shutdown) -// #pragma SECTION_RESTORE -// -// rationale: -// several methods of module init are possible: (see Large Scale C++ Design) -// - on-demand initialization: each exported function would have to check -// if init already happened. that would be brittle and hard to verify. -// - singleton: variant of the above, but not applicable to a -// procedural interface (and quite ugly to boot). -// - registration: NLSO constructors call a central notification function. -// module dependencies would be quite difficult to express - this would -// require a graph or separate lists for each priority (clunky). -// worse, a fatal flaw is that other C++ constructors may depend on the -// modules we are initializing and already have run. there is no way -// to influence ctor call order between separate source files, so -// this is out of the question. -// - linker-based registration: same as above, but the linker takes care -// of assembling various functions into one sorted table. the list of -// init functions is available before C++ ctors have run. incidentally, -// zero runtime overhead is incurred. unfortunately, this approach is -// MSVC-specific. however, the MS CRT uses a similar method for its -// init, so this is expected to remain supported. - -// macros to simplify usage. -// notes: -// - #pragma cannot be packaged in macros due to expansion rules. -// - __declspec(allocate) would be tempting, since that could be -// wrapped in WIN_REGISTER_FUNC. unfortunately it inexplicably cannot -// cope with split string literals (e.g. "ab" "c"). that disqualifies -// it, since we want to hide the section name behind a macro, which -// would require the abovementioned merging. - -// note: the purpose of pre-libc init (with the resulting requirement that -// no CRT functions be used during init!) is to allow the use of the -// initialized module in static ctors. -#define SECTION_PRE_LIBC(group) data_seg(".LIB$C" #group) -#define SECTION_PRE_MAIN(group) data_seg(".LIB$I" #group) -#define SECTION_POST_ATEXIT(group) data_seg(".LIB$T" #group) -#define SECTION_RESTORE data_seg() -// use to make sure the link-stage optimizer doesn't discard the -// function pointers (happens on VC8) -#define FORCE_INCLUDE(id) comment(linker, "/include:_p"#id) - -#define WIN_REGISTER_FUNC(func)\ - static LibError func(void);\ - extern "C" LibError (*p##func)(void) = func - - -//----------------------------------------------------------------------------- -// misc - -extern void* win_alloc(size_t size); -extern void win_free(void* p); - - -// thread safe, usable in constructors -#define WIN_ONCE(code)\ -{\ - win_lock(ONCE_CS);\ - static bool ONCE_init_; /* avoid name conflict */\ - if(!ONCE_init_)\ - {\ - ONCE_init_ = true;\ - code;\ - }\ - win_unlock(ONCE_CS);\ -} - -#define WIN_SAVE_LAST_ERROR DWORD last_err__ = GetLastError(); -#define WIN_RESTORE_LAST_ERROR STMT(if(last_err__ != 0 && GetLastError() == 0) SetLastError(last_err__);); - - -// return the LibError equivalent of GetLastError(), or ERR::FAIL if -// there's no equal. -// you should SetLastError(0) before calling whatever will set ret -// to make sure we do not return any stale errors. -extern LibError LibError_from_win32(DWORD ret, bool warn_if_failed = true); - - -extern char win_sys_dir[MAX_PATH+1]; -extern char win_exe_dir[MAX_PATH+1]; - - -// this isn't nice (ideally we would avoid coupling win.cpp and wdbg.cpp), but -// necessary; see rationale at function definition. -extern LONG WINAPI wdbg_exception_filter(EXCEPTION_POINTERS* ep); - - - - -#ifdef USE_WINMAIN -extern "C" int WinMainCRTStartup(void); -#else -extern "C" int mainCRTStartup(void); -#endif - - -#define FD_READ BIT(0) -#define FD_WRITE BIT(1) -#define FD_ACCEPT BIT(3) -#define FD_CONNECT BIT(4) -#define FD_CLOSE BIT(5) - - -#endif // #ifndef WIN_INTERNAL_H +#endif // #ifndef INCLUDED_WIN diff --git a/source/lib/sysdep/win/winit.cpp b/source/lib/sysdep/win/winit.cpp new file mode 100644 index 0000000000..9a57a6da4a --- /dev/null +++ b/source/lib/sysdep/win/winit.cpp @@ -0,0 +1,81 @@ +/** + * ========================================================================= + * File : winit.cpp + * Project : 0 A.D. + * Description : windows-specific module init and shutdown mechanism + * + * @author Jan.Wassenberg@stud.uni-karlsruhe.de + * ========================================================================= + */ + +/* + * Copyright (c) 2003-2007 Jan Wassenberg + * + * Redistribution and/or modification are also permitted under the + * terms of the GNU General Public License as published by the + * Free Software Foundation (version 2 or later, at your option). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "precompiled.h" +#include "winit.h" + + +typedef LibError (*PfnLibErrorVoid)(void); + +// pointers to start and end of function tables. +// note: COFF tosses out empty segments, so we have to put in one value +// (zero, because CallFunctionPointers has to ignore entries =0 anyway). +#pragma SECTION_PRE_LIBC(A) +PfnLibErrorVoid pre_libc_begin = 0; +#pragma SECTION_PRE_LIBC(Z) +PfnLibErrorVoid pre_libc_end = 0; +#pragma SECTION_PRE_MAIN(A) +PfnLibErrorVoid pre_main_begin = 0; +#pragma SECTION_PRE_MAIN(Z) +PfnLibErrorVoid pre_main_end = 0; +#pragma SECTION_POST_ATEXIT(A) +PfnLibErrorVoid shutdown_begin = 0; +#pragma SECTION_POST_ATEXIT(Z) +PfnLibErrorVoid shutdown_end = 0; +#pragma SECTION_RESTORE +// note: /include is not necessary, since these are referenced below. + +#pragma comment(linker, "/merge:.LIB=.data") + + +/** + * call into a range of function pointers. + * @param [begin, end): STL-style range + * + * note: pointers = 0 are ignored. this is because the above placeholders + * are initialized to 0 and because the range may be larger than + * expected due to COFF section padding (with zeroes). + **/ +static void CallFunctionPointers(PfnLibErrorVoid* begin, PfnLibErrorVoid* end) +{ + for(PfnLibErrorVoid* ppfunc = begin; ppfunc < end; ppfunc++) + { + if(*ppfunc) + (*ppfunc)(); + } +} + + +void winit_CallPreLibcFunctions() +{ + CallFunctionPointers(&pre_libc_begin, &pre_libc_end); +} + +void winit_CallPreMainFunctions() +{ + CallFunctionPointers(&pre_main_begin, &pre_main_end); +} + +void winit_CallShutdownFunctions() +{ + CallFunctionPointers(&shutdown_begin, &shutdown_end); +} diff --git a/source/lib/sysdep/win/winit.h b/source/lib/sysdep/win/winit.h new file mode 100644 index 0000000000..3fac2e6a99 --- /dev/null +++ b/source/lib/sysdep/win/winit.h @@ -0,0 +1,111 @@ +/** + * ========================================================================= + * File : winit.h + * Project : 0 A.D. + * Description : windows-specific module init and shutdown mechanism + * + * @author Jan.Wassenberg@stud.uni-karlsruhe.de + * ========================================================================= + */ + +/* + * Copyright (c) 2003-2007 Jan Wassenberg + * + * Redistribution and/or modification are also permitted under the + * terms of the GNU General Public License as published by the + * Free Software Foundation (version 2 or later, at your option). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef INCLUDED_WINIT +#define INCLUDED_WINIT + +// register functions to be called before libc init, before main, +// or after atexit. +// +// overview: +// participating modules store function pointer(s) to their init and/or +// shutdown function in a specific COFF section. the sections are +// grouped according to the desired notification and the order in which +// functions are to be called (useful if one module depends on another). +// they are then gathered by the linker and arranged in alphabetical order. +// placeholder variables in the sections indicate where the series of +// functions begins and ends for a given notification time. +// at runtime, all of the function pointers between the markers are invoked. +// +// details: +// the section names are of the format ".LIB${type}{group}". +// {type} is C for pre-libc init, I for pre-main init, or +// T for terminators (last of the atexit handlers). +// {group} is [B, Y]; all functions in a group are called before those of +// the next (alphabetically) higher group, but order within the group is +// undefined. this is because the linker sorts sections alphabetically, +// but doesn't specify the order in which object files are processed. +// another consequence is that groups A and Z must not be used! +// (data placed there might end up outside the start/end markers) +// +// example: +// #pragma SECTION_PRE_LIBC(G)) +// WIN_REGISTER_FUNC(wtime_init); +// #pragma FORCE_INCLUDE(wtime_init) +// #pragma SECTION_POST_ATEXIT(D)) +// WIN_REGISTER_FUNC(wtime_shutdown); +// #pragma FORCE_INCLUDE(wtime_shutdown) +// #pragma SECTION_RESTORE +// +// rationale: +// several methods of module init are possible: (see Large Scale C++ Design) +// - on-demand initialization: each exported function would have to check +// if init already happened. that would be brittle and hard to verify. +// - singleton: variant of the above, but not applicable to a +// procedural interface (and quite ugly to boot). +// - registration: NLSO constructors call a central notification function. +// module dependencies would be quite difficult to express - this would +// require a graph or separate lists for each priority (clunky). +// worse, a fatal flaw is that other C++ constructors may depend on the +// modules we are initializing and already have run. there is no way +// to influence ctor call order between separate source files, so +// this is out of the question. +// - linker-based registration: same as above, but the linker takes care +// of assembling various functions into one sorted table. the list of +// init functions is available before C++ ctors have run. incidentally, +// zero runtime overhead is incurred. unfortunately, this approach is +// MSVC-specific. however, the MS CRT uses a similar method for its +// init, so this is expected to remain supported. + +// macros to simplify usage. +// notes: +// - #pragma cannot be packaged in macros due to expansion rules. +// - __declspec(allocate) would be tempting, since that could be +// wrapped in WIN_REGISTER_FUNC. unfortunately it inexplicably cannot +// cope with split string literals (e.g. "ab" "c"). that disqualifies +// it, since we want to hide the section name behind a macro, which +// would require the abovementioned merging. + +// note: the purpose of pre-libc init (with the resulting requirement that +// no CRT functions be used during init!) is to allow the use of the +// initialized module in static ctors. +#define SECTION_PRE_LIBC(group) data_seg(".LIB$C" #group) +#define SECTION_PRE_MAIN(group) data_seg(".LIB$I" #group) +#define SECTION_POST_ATEXIT(group) data_seg(".LIB$T" #group) +#define SECTION_RESTORE data_seg() +// use to make sure the link-stage optimizer doesn't discard the +// function pointers (happens on VC8) +#define FORCE_INCLUDE(id) comment(linker, "/include:_p"#id) + +#define WIN_REGISTER_FUNC(func)\ + static LibError func(void);\ + EXTERN_C LibError (*p##func)(void) = func + +/** + * call each registered function. + * these are invoked by wstartup at the appropriate times. + **/ +extern void winit_CallPreLibcFunctions(); +extern void winit_CallPreMainFunctions(); +extern void winit_CallShutdownFunctions(); + +#endif // #ifndef INCLUDED_WINIT diff --git a/source/lib/sysdep/win/wposix/crt_posix.h b/source/lib/sysdep/win/wposix/crt_posix.h new file mode 100644 index 0000000000..ada18d0484 --- /dev/null +++ b/source/lib/sysdep/win/wposix/crt_posix.h @@ -0,0 +1,28 @@ +/** + * see rationale in wposix.h. + * we need to have CRT functions (e.g. _open) declared correctly + * but must prevent POSIX functions (e.g. open) from being declared - + * they would conflict with our wrapper function. + * + * since the headers only declare POSIX stuff #if !__STDC__, a solution + * would be to set this flag temporarily. note that MSDN says that + * such predefined macros cannot be redefined nor may they change during + * compilation, but this works and seems to be a fairly common practice. + **/ + +// undefine include guards set by no_crt_posix +#if defined(_INC_IO) && defined(WPOSIX_DEFINED_IO_INCLUDE_GUARD) +# undef _INC_IO +#endif +#if defined(_INC_DIRECT) && defined(WPOSIX_DEFINED_DIRECT_INCLUDE_GUARD) +# undef _INC_DIRECT +#endif + + +#define __STDC__ 1 + +#include // _open etc. +#include // _getcwd, _rmdir + +#undef __STDC__ +#define __STDC__ 0 diff --git a/source/lib/sysdep/win/wposix/no_crt_posix.h b/source/lib/sysdep/win/wposix/no_crt_posix.h new file mode 100644 index 0000000000..50d4317627 --- /dev/null +++ b/source/lib/sysdep/win/wposix/no_crt_posix.h @@ -0,0 +1,17 @@ +/** + * see rationale in wposix.h. + * prevent subsequent includes of CRT headers (e.g. ) from + * interfering with previous declarations made by wposix headers (e.g. open). + * this is accomplished by #defining their include guards. + * note: #include "crt_posix.h" can undo the effects of this header and + * pull in those headers. + **/ + +#ifndef _INC_IO // include guard +# define _INC_IO +# define WPOSIX_DEFINED_IO_INCLUDE_GUARD +#endif +#ifndef _INC_DIRECT // include guard +# define _INC_DIRECT +# define WPOSIX_DEFINED_DIRECT_INCLUDE_GUARD +#endif diff --git a/source/lib/sysdep/win/wposix/waio.cpp b/source/lib/sysdep/win/wposix/waio.cpp index 6252b5b672..c57c4a156b 100644 --- a/source/lib/sysdep/win/wposix/waio.cpp +++ b/source/lib/sysdep/win/wposix/waio.cpp @@ -23,15 +23,15 @@ #include "precompiled.h" #include "waio.h" -#include -#include // _aligned_malloc +#include // _aligned_malloc +#include "crt_posix.h" // correct definitions of _open() etc. #include "wposix_internal.h" -#include "wfilesystem.h" // mode_t -#include "wtime.h" // timespec -#include "waio_internal.h" +#include "wfilesystem.h" // mode_t +#include "wtime.h" // timespec #include "lib/sysdep/cpu.h" + #pragma SECTION_PRE_LIBC(J) WIN_REGISTER_FUNC(waio_init); #pragma FORCE_INCLUDE(waio_init) @@ -418,12 +418,17 @@ int close(int fd) int read(int fd, void* buf, size_t nbytes) { - return _read(fd, buf, nbytes); + return _read(fd, buf, (int)nbytes); } int write(int fd, void* buf, size_t nbytes) { - return _write(fd, buf, nbytes); + return _write(fd, buf, (int)nbytes); +} + +off_t lseek(int fd, off_t ofs, int whence) +{ + return _lseek(fd, ofs, whence); } diff --git a/source/lib/sysdep/win/wposix/waio.h b/source/lib/sysdep/win/wposix/waio.h index 8a0b168b28..b99789f326 100644 --- a/source/lib/sysdep/win/wposix/waio.h +++ b/source/lib/sysdep/win/wposix/waio.h @@ -25,6 +25,8 @@ #include "wposix_types.h" +#include "no_crt_posix.h" + // Note: for maximum efficiency, transfer buffers, offsets, and lengths // should be sector aligned (otherwise, buffer is copied). @@ -53,15 +55,6 @@ struct sigevent // // -// values from MS _open - do not change! -#define O_RDONLY 0x0000 // open for reading only -#define O_WRONLY 0x0001 // open for writing only -#define O_RDWR 0x0002 // open for reading and writing -#define O_APPEND 0x0008 // writes done at eof -#define O_CREAT 0x0100 // create and open file -#define O_TRUNC 0x0200 // open and truncate -#define O_EXCL 0x0400 // open only if file doesn't already exist - // .. Win32-only (not specified by POSIX) #define O_TEXT_NP 0x4000 // file mode is text (translated) #define O_BINARY_NP 0x8000 // file mode is binary (untranslated) @@ -83,14 +76,13 @@ struct sigevent extern int open(const char* fn, int mode, ...); extern int close(int); - // // // extern int read (int fd, void* buf, size_t nbytes); // thunk extern int write(int fd, void* buf, size_t nbytes); // thunk -extern "C" _CRTIMP off_t lseek(int fd, off_t ofs, int whence); +extern off_t lseek(int fd, off_t ofs, int whence); // thunk // @@ -138,6 +130,7 @@ extern int lio_listio(int, struct aiocb* const[], int, struct sigevent*); extern int aio_close(int fd); extern int aio_reopen(int fd, const char* fn, int oflag, ...); + // allocate and return a file descriptor extern int aio_assign_handle(uintptr_t handle); diff --git a/source/lib/sysdep/win/wposix/waio_internal.h b/source/lib/sysdep/win/wposix/waio_internal.h index ecfdc7b50f..1e6303bf08 100644 --- a/source/lib/sysdep/win/wposix/waio_internal.h +++ b/source/lib/sysdep/win/wposix/waio_internal.h @@ -2,11 +2,6 @@ extern "C" { #endif -extern _CRTIMP int _open(const char* fn, int mode, ...); -extern _CRTIMP int _read (int fd, void* buf, size_t nbytes); -extern _CRTIMP int _write(int fd, void* buf, size_t nbytes); -extern _CRTIMP int _close(int); - #ifdef __cplusplus } #endif diff --git a/source/lib/sysdep/win/wposix/wfilesystem.h b/source/lib/sysdep/win/wposix/wfilesystem.h index fb7992d1d5..663b45053c 100644 --- a/source/lib/sysdep/win/wposix/wfilesystem.h +++ b/source/lib/sysdep/win/wposix/wfilesystem.h @@ -1,45 +1,29 @@ #ifndef INCLUDED_WFILESYSTEM #define INCLUDED_WFILESYSTEM +#include + +#include "no_crt_posix.h" + + // // sys/stat.h // -// already defined by MinGW +// stat is defined by (we allow this because VC8 declares +// inline macros that are worth keeping) + +// defined by MinGW but not VC #if MSC_VERSION typedef unsigned int mode_t; #endif -// VC libc includes stat, but it's quite slow. -// we implement our own, but use the CRT struct definition. -// rename the VC function definition to avoid conflict. -/* -#define stat vc_stat -// -// Extra hack for VC++ 2005, since it defines inline stat/fstat -// functions inside stat.h (which get confused by the -// macro-renaming of "stat") -# if MSC_VERSION >= 1400 -# define RC_INVOKED // stat.h only includes stat.inl if "!defined(RC_INVOKED) && !defined(__midl)" -# include -# undef RC_INVOKED -# else -# include -# endif -#undef stat -*/ -#include - -extern int mkdir(const char*, mode_t); - -// currently only sets st_mode (file or dir) and st_size. -//extern int stat(const char*, struct stat*); +// mkdir is defined by posix_filesystem #if !HAVE_MKDIR +// (christmas-tree values because mkdir mode is ignored anyway) #define S_IRWXO 0xFFFF #define S_IRWXU 0xFFFF #define S_IRWXG 0xFFFF -// stat.h _S_* values are wrong! disassembly shows _S_IWRITE is 0x80, -// instead of 0x100. define christmas-tree value to be safe. #define S_ISDIR(m) (m & S_IFDIR) #define S_ISREG(m) (m & S_IFREG) diff --git a/source/lib/sysdep/win/wposix/wmman.cpp b/source/lib/sysdep/win/wposix/wmman.cpp index 1aa88bd423..d68f11a337 100644 --- a/source/lib/sysdep/win/wposix/wmman.cpp +++ b/source/lib/sysdep/win/wposix/wmman.cpp @@ -2,6 +2,7 @@ #include "wmman.h" #include "wposix_internal.h" +#include "crt_posix.h" // _get_osfhandle //----------------------------------------------------------------------------- diff --git a/source/lib/sysdep/win/wposix/wposix.cpp b/source/lib/sysdep/win/wposix/wposix.cpp index 5a622f9fd3..16733782bc 100644 --- a/source/lib/sysdep/win/wposix/wposix.cpp +++ b/source/lib/sysdep/win/wposix/wposix.cpp @@ -24,6 +24,7 @@ #include "wposix.h" #include "wposix_internal.h" +#include "crt_posix.h" // _getcwd long sysconf(int name) @@ -104,7 +105,7 @@ long sysconf(int name) #endif char* getcwd(char* buf, size_t buf_size) { - return _getcwd(buf, buf_size); + return _getcwd(buf, (int)buf_size); } #ifdef REDEFINED_NEW # include "lib/mmgr.h" diff --git a/source/lib/sysdep/win/wposix/wposix.h b/source/lib/sysdep/win/wposix/wposix.h index 288aa081d1..6f3674b7d9 100644 --- a/source/lib/sysdep/win/wposix/wposix.h +++ b/source/lib/sysdep/win/wposix/wposix.h @@ -23,9 +23,30 @@ #ifndef INCLUDED_WPOSIX #define INCLUDED_WPOSIX +/** + * rationale: the Windows headers declare many POSIX functions (e.g. read). + * unfortunately, these are often slightly incorrect (size_t vs. uint). + * to avert trouble in user code caused by these differences, we declare + * all functions ourselves according to SUSv3 and do not use the headers. + * + * however, it does not end there. some other libraries (e.g. wxWidgets) + * will want to pull in these headers, which would conflict with our + * declarations. also, our implementation uses the actual CRT code, + * so we want those functions (e.g. _read) to be declared correctly even + * if switching compiler/CRT version. + * + * how can these conflicting requirements be reconciled? our headers #include + * "no_crt_posix.h" to #define the CRT headers' include guards and thus + * prevent them from declaring anything. the implementation files #include + * "crt_posix.h", which pulls in the CRT headers (even if "no_crt_posix.h" + * was previously included, e.g. in the PCH). note that the CRT headers + * would still cause conflicts with the POSIX function declarations, + * but we are able to prevent this via __STDC__. + **/ + + // misc routines -#undef getcwd extern char* getcwd(char*, size_t); // user tests if available via #ifdef; can't use enum. diff --git a/source/lib/sysdep/win/wposix/wposix_internal.h b/source/lib/sysdep/win/wposix/wposix_internal.h index 36a382914e..5345be6262 100644 --- a/source/lib/sysdep/win/wposix/wposix_internal.h +++ b/source/lib/sysdep/win/wposix/wposix_internal.h @@ -2,39 +2,9 @@ #define INCLUDED_WPOSIX_INTERNAL #include "lib/lib.h" -#include "../win_internal.h" - -#include "werrno.h" - - -// we define some CRT functions (e.g. access), because they're otherwise -// only brought in by win-specific headers (here, ). -// define correctly for static or DLL CRT in case the original header -// is included, to avoid conflict warnings. -// -// note: try to avoid redefining CRT functions - if building against the -// DLL CRT, the declarations will be incompatible. adding _CRTIMP to the decl -// is a last resort (e.g. if the regular CRT headers would conflict). -#ifndef _CRTIMP -# ifdef _DLL -# define _CRTIMP __declspec(dllimport) -# else -# define _CRTIMP -# endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -extern _CRTIMP intptr_t _get_osfhandle(int); -extern _CRTIMP int _open_osfhandle(intptr_t, int); -extern _CRTIMP char* _getcwd(char*, size_t); - -#ifdef __cplusplus -} -#endif - +#include "lib/sysdep/win/win_internal.h" +#include "lib/sysdep/win/winit.h" +#include "lib/sysdep/win/wutil.h" // cast intptr_t to HANDLE; centralized for easier changing, e.g. avoiding // warnings. i = -1 converts to INVALID_HANDLE_VALUE (same value). diff --git a/source/lib/sysdep/win/wposix/wposix_types.h b/source/lib/sysdep/win/wposix/wposix_types.h index c3a56a8971..d22cea4aaf 100644 --- a/source/lib/sysdep/win/wposix/wposix_types.h +++ b/source/lib/sysdep/win/wposix/wposix_types.h @@ -65,6 +65,8 @@ typedef unsigned long long uint64_t; // typedef long ssize_t; +// prevent wxWidgets from (incompatibly) redefining it +#define HAVE_SSIZE_T // diff --git a/source/lib/sysdep/win/wposix/wsock.h b/source/lib/sysdep/win/wposix/wsock.h index 6c869a6419..bd9cfe614d 100644 --- a/source/lib/sysdep/win/wposix/wsock.h +++ b/source/lib/sysdep/win/wposix/wsock.h @@ -23,7 +23,7 @@ #ifndef INCLUDED_WSOCK #define INCLUDED_WSOCK -#define IMP(ret, name, param) extern "C" __declspec(dllimport) ret __stdcall name param; +#define IMP(ret, name, param) EXTERN_C __declspec(dllimport) ret __stdcall name param; // @@ -225,6 +225,15 @@ IMP(ssize_t, sendto, (int, const void*, size_t, int, const struct sockaddr*, soc IMP(ssize_t, recvfrom, (int, void*, size_t, int, struct sockaddr*, socklen_t*)) +// WSAAsyncSelect event bits +// (values taken from winsock2.h - do not change!) +#define FD_READ BIT(0) +#define FD_WRITE BIT(1) +#define FD_ACCEPT BIT(3) +#define FD_CONNECT BIT(4) +#define FD_CLOSE BIT(5) + + #undef IMP #endif // #ifndef INCLUDED_WSOCK diff --git a/source/lib/sysdep/win/wposix/wterminal.cpp b/source/lib/sysdep/win/wposix/wterminal.cpp index da1275dcde..8f64a255d6 100644 --- a/source/lib/sysdep/win/wposix/wterminal.cpp +++ b/source/lib/sysdep/win/wposix/wterminal.cpp @@ -2,6 +2,7 @@ #include "wterminal.h" #include "wposix_internal.h" +#include "crt_posix.h" // _get_osfhandle int ioctl(int fd, int op, int* data) diff --git a/source/lib/sysdep/win/wsdl.cpp b/source/lib/sysdep/win/wsdl.cpp index 254f4e23ce..615cd1dab3 100644 --- a/source/lib/sysdep/win/wsdl.cpp +++ b/source/lib/sysdep/win/wsdl.cpp @@ -21,7 +21,7 @@ */ #include "precompiled.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" #include #include @@ -36,6 +36,8 @@ #include "lib/posix/posix_pthread.h" #include "lib/lib.h" #include "lib/ogl.h" // needed to pull in the delay-loaded opengl32.dll +#include "winit.h" +#include "wutil.h" // for easy removal of DirectDraw dependency (used to query total video mem) diff --git a/source/lib/sysdep/win/wsnd.cpp b/source/lib/sysdep/win/wsnd.cpp index c21769200a..d72fefca6e 100644 --- a/source/lib/sysdep/win/wsnd.cpp +++ b/source/lib/sysdep/win/wsnd.cpp @@ -32,6 +32,7 @@ #include "lib/res/file/file.h" #include "dll_ver.h" // dll_list_* #include "win_internal.h" +#include "wutil.h" // DirectSound header @@ -58,7 +59,7 @@ #else # define DS_OK 0 typedef BOOL (CALLBACK* LPDSENUMCALLBACKA)(void*, const char*, const char*, void*); -extern "C" __declspec(dllimport) HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA, void*); +EXTERN_C __declspec(dllimport) HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA, void*); #endif #if MSC_VERSION diff --git a/source/lib/sysdep/win/wstartup.cpp b/source/lib/sysdep/win/wstartup.cpp new file mode 100644 index 0000000000..4d11c98fe3 --- /dev/null +++ b/source/lib/sysdep/win/wstartup.cpp @@ -0,0 +1,133 @@ +/** + * ========================================================================= + * File : wstartup.cpp + * Project : 0 A.D. + * Description : windows-specific entry point and startup code + * + * @author Jan.Wassenberg@stud.uni-karlsruhe.de + * ========================================================================= + */ + +/* + * Copyright (c) 2003-2007 Jan Wassenberg + * + * Redistribution and/or modification are also permitted under the + * terms of the GNU General Public License as published by the + * Free Software Foundation (version 2 or later, at your option). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "precompiled.h" +#include "wstartup.h" + +#include "winit.h" +#include "wdbg.h" // wdbg_exception_filter +#include "win_internal.h" // GetExceptionInformation + +#if MSC_VERSION >= 1400 +#include // __security_init_cookie +#define NEED_COOKIE_INIT +#endif + +// this module is responsible for startup and triggering winit's calls to +// registered functions at the appropriate times. control flow overview: +// entry [-> RunWithinTryBlock] -> InitAndCallMain -> MainCRTStartup -> +// main -> wstartup_PreMainInit. +// our atexit handler is called as the last of them, provided constructors +// do not use atexit! (this requirement is documented) +// +// rationale: see declaration of wstartup_PreMainInit. + + +void wstartup_PreMainInit() +{ + winit_CallPreMainFunctions(); + + atexit(winit_CallShutdownFunctions); + + // no point redirecting stdout yet - the current directory + // may be incorrect (file_set_root not yet called). + // (w)sdl will take care of it anyway. +} + + +// these aren't defined in VC include files, so we have to do it manually. +#ifdef USE_WINMAIN +EXTERN_C int WinMainCRTStartup(void); +#else +EXTERN_C int mainCRTStartup(void); +#endif + +// (moved into a separate function because it's used by both +// entry and entry_noSEH) +static int InitAndCallMain() +{ + // perform all initialization that needs to run before _cinit + // (i.e. when C++ ctors are called). + // be very careful to avoid non-stateless libc functions! + winit_CallPreLibcFunctions(); + + int ret; +#ifdef USE_WINMAIN + ret = WinMainCRTStartup(); // calls _cinit and then our WinMain +#else + ret = mainCRTStartup(); // calls _cinit and then our main +#endif + return ret; +} + + +typedef int(*PfnIntVoid)(void); + +static int RunWithinTryBlock(PfnIntVoid func) +{ + int ret; + __try + { + ret = func(); + } + __except(wdbg_exception_filter(GetExceptionInformation())) + { + ret = -1; + } + return ret; +} + + +int entry() +{ +#ifdef NEED_COOKIE_INIT + // 2006-02-16 workaround for R6035 on VC8: + // + // SEH code compiled with /GS pushes a "security cookie" onto the + // stack. since we're called before _cinit, the cookie won't have + // been initialized yet, which would cause the CRT to FatalAppExit. + // to solve this, we must call __security_init_cookie before any + // hidden compiler-generated SEH registration code runs, + // which means the __try block must be moved into a helper function. + // + // NB: entry() must not contain local string buffers, either - + // /GS would install a cookie here as well (same problem). + // + // see http://msdn2.microsoft.com/en-US/library/ms235603.aspx + __security_init_cookie(); +#endif + return RunWithinTryBlock(InitAndCallMain); +} + + +// Alternative entry point, for programs that don't want the SEH handler +// (e.g. unit tests, where it's better to let the debugger handle any errors) +int entry_noSEH() +{ +#ifdef NEED_COOKIE_INIT + // see above. this is also necessary here in case pre-libc init + // functions use SEH. + __security_init_cookie(); +#endif + + return InitAndCallMain(); +} diff --git a/source/lib/sysdep/win/wstartup.h b/source/lib/sysdep/win/wstartup.h new file mode 100644 index 0000000000..f62d21d319 --- /dev/null +++ b/source/lib/sysdep/win/wstartup.h @@ -0,0 +1,58 @@ +/** + * ========================================================================= + * File : wstartup.h + * Project : 0 A.D. + * Description : windows-specific entry point and startup code + * + * @author Jan.Wassenberg@stud.uni-karlsruhe.de + * ========================================================================= + */ + +/* + * Copyright (c) 2003-2007 Jan Wassenberg + * + * Redistribution and/or modification are also permitted under the + * terms of the GNU General Public License as published by the + * Free Software Foundation (version 2 or later, at your option). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef INCLUDED_WSTARTUP +#define INCLUDED_WSTARTUP + +/** + * call at the beginning of main(). exact requirements: after _cinit AND + * before any use of sysdep/win/* or call to atexit. + * + * rationale: + * our Windows-specific init code needs to run before the rest of the + * main() code. ideally this would happen automagically. + * one possibility is using WinMain as the entry point, and then calling the + * application's main(), but this is expressly forbidden by the C standard. + * VC apparently makes use of this and changes its calling convention. + * if we call it, everything appears to work but stack traces in + * release mode are incorrect (symbol address is off by 4). + * + * another alternative is re#defining the app's main function to app_main, + * having the OS call our main, and then dispatching to app_main. + * however, this leads to trouble when another library (e.g. SDL) wants to + * do the same. + * + * moreover, this file is compiled into a static library and used both for + * the 0ad executable as well as the separate self-test. this means + * we can't enable the main() hook for one and disable it in the other. + * + * the consequence is that automatic init isn't viable. this is + * unfortunate because integration into new projects requires + * remembering to call the init function, but it can't be helped. + **/ +extern void wstartup_PreMainInit(); + +// entry points (normal and without SEH wrapper; see definition) +EXTERN_C int entry(); +EXTERN_C int entry_noSEH(); + +#endif // #ifndef INCLUDED_WSTARTUP diff --git a/source/lib/sysdep/win/wsysdep.cpp b/source/lib/sysdep/win/wsysdep.cpp index 169ab30925..ccfdeed8fc 100644 --- a/source/lib/sysdep/win/wsysdep.cpp +++ b/source/lib/sysdep/win/wsysdep.cpp @@ -28,6 +28,7 @@ #include "lib/lib.h" #include "error_dialog.h" +#include "wutil.h" #if MSC_VERSION diff --git a/source/lib/sysdep/win/win.cpp b/source/lib/sysdep/win/wutil.cpp similarity index 57% rename from source/lib/sysdep/win/win.cpp rename to source/lib/sysdep/win/wutil.cpp index 8bd4edef6c..d3ba43beff 100644 --- a/source/lib/sysdep/win/win.cpp +++ b/source/lib/sysdep/win/wutil.cpp @@ -1,15 +1,15 @@ /** * ========================================================================= - * File : win.cpp + * File : wutil.cpp * Project : 0 A.D. - * Description : various Windows-specific code and program entry point. + * Description : various Windows-specific utilities * * @author Jan.Wassenberg@stud.uni-karlsruhe.de * ========================================================================= */ /* - * Copyright (c) 2003-2004 Jan Wassenberg + * Copyright (c) 2003-2007 Jan Wassenberg * * Redistribution and/or modification are also permitted under the * terms of the GNU General Public License as published by the @@ -21,23 +21,30 @@ */ #include "precompiled.h" +#include "wutil.h" #include #include // __argc -#include "win_internal.h" #include "lib/path_util.h" #include "lib/posix/posix.h" +#include "win_internal.h" +#include "winit.h" -#if MSC_VERSION >= 1400 -#include // __security_init_cookie -#define NEED_COOKIE_INIT -#endif + +#pragma SECTION_PRE_LIBC(B) +WIN_REGISTER_FUNC(wutil_PreLibcInit); +#pragma FORCE_INCLUDE(wutil_PreLibcInit) +#pragma SECTION_POST_ATEXIT(Y) +WIN_REGISTER_FUNC(wutil_Shutdown); +#pragma FORCE_INCLUDE(wutil_Shutdown) +#pragma SECTION_RESTORE char win_sys_dir[MAX_PATH+1]; char win_exe_dir[MAX_PATH+1]; + // only call after a Win32 function indicates failure. static LibError LibError_from_GLE(bool warn_if_failed = true) { @@ -102,43 +109,6 @@ void win_free(void* p) } -//----------------------------------------------------------------------------- -// module init and shutdown -//----------------------------------------------------------------------------- - -typedef LibError (*Pfn)(void); - -// pointers to start and end of function tables. -// note: COFF tosses out empty segments, so we have to put in one value -// (zero, because call_func_tbl has to ignore NULL entries anyway). -#pragma SECTION_PRE_LIBC(A) -Pfn pre_libc_begin = 0; -#pragma SECTION_PRE_LIBC(Z) -Pfn pre_libc_end = 0; -#pragma SECTION_PRE_MAIN(A) -Pfn pre_main_begin = 0; -#pragma SECTION_PRE_MAIN(Z) -Pfn pre_main_end = 0; -#pragma SECTION_POST_ATEXIT(A) -Pfn shutdown_begin = 0; -#pragma SECTION_POST_ATEXIT(Z) -Pfn shutdown_end = 0; -#pragma SECTION_RESTORE -// note: /include is not necessary, since these are referenced below. - -#pragma comment(linker, "/merge:.LIB=.data") - -// call all non-NULL function pointers in [begin, end). -// note: the range may be larger than expected due to section padding. -// that (and the COFF empty section problem) is why we need to ignore zeroes. -static void call_func_tbl(Pfn* begin, Pfn* end) -{ - for(Pfn* p = begin; p < end; p++) - if(*p) - (*p)(); -} - - //----------------------------------------------------------------------------- // locking for win-specific code //----------------------------------------------------------------------------- @@ -176,7 +146,7 @@ int win_is_locked(uint idx) } -static void cs_init() +static void InitLocks() { for(int i = 0; i < NUM_CS; i++) InitializeCriticalSection(&cs[i]); @@ -184,7 +154,7 @@ static void cs_init() cs_valid = true; } -static void cs_shutdown() +static void ShutdownLocks() { cs_valid = false; @@ -195,35 +165,12 @@ static void cs_shutdown() //----------------------------------------------------------------------------- -// startup -//----------------------------------------------------------------------------- - -// entry -> pre_libc -> WinMainCRTStartup -> WinMain -> pre_main -> main -// at_exit is called as the last of the atexit handlers -// (assuming, as documented in lib.cpp, constructors don't use atexit!) -// -// rationale: we need to gain control after _cinit and before main() to -// complete initialization. -// note: this way of getting control before main adds overhead -// (setting up the WinMain parameters), but is simpler and safer than -// SDL-style #define main SDL_main. // explained where used. static HMODULE hUser32Dll; -static void at_exit(void) -{ - call_func_tbl(&shutdown_begin, &shutdown_end); - cs_shutdown(); - - // free the reference taken in win_pre_libc_init; - // this avoids Boundschecker warnings at exit. - FreeLibrary(hUser32Dll); -} - - -void win_pre_main_init() +static LibError wutil_PreLibcInit() { // enable memory tracking and leak detection; // no effect if !HAVE_VC_DEBUG_ALLOC. @@ -233,21 +180,6 @@ void win_pre_main_init() debug_heap_enable(DEBUG_HEAP_NORMAL); #endif - call_func_tbl(&pre_main_begin, &pre_main_end); - - atexit(at_exit); - - // no point redirecting stdout yet - the current directory - // may be incorrect (file_set_root not yet called). - // (w)sdl will take care of it anyway. -} - - -// perform all initialization that needs to run before _cinit -// (which calls C++ ctors). -// be very careful to avoid non-stateless libc functions! -static inline void pre_libc_init() -{ // enable low-fragmentation heap #if WINVER >= 0x0501 HMODULE hKernel32Dll = LoadLibrary("kernel32.dll"); @@ -265,7 +197,7 @@ static inline void pre_libc_init() } #endif // #if WINVER >= 0x0501 - cs_init(); + InitLocks(); GetSystemDirectory(win_sys_dir, sizeof(win_sys_dir)); @@ -287,62 +219,17 @@ static inline void pre_libc_init() // than documenting the problem and asking it not be delay-loaded. hUser32Dll = LoadLibrary("user32.dll"); - call_func_tbl(&pre_libc_begin, &pre_libc_end); + return INFO::OK; } -static int SEH_wrapped_entry() +static LibError wutil_Shutdown() { - int ret; - __try - { - pre_libc_init(); -#ifdef USE_WINMAIN - ret = WinMainCRTStartup(); // calls _cinit and then our main -#else - ret = mainCRTStartup(); // calls _cinit and then our main -#endif - } - __except(wdbg_exception_filter(GetExceptionInformation())) - { - ret = -1; - } - return ret; -} - - -int entry() -{ -#ifdef NEED_COOKIE_INIT - // 2006-02-16 workaround for R6035 on VC8: - // - // SEH code compiled with /GS pushes a "security cookie" onto the - // stack. since we're called before _cinit, the cookie won't have - // been initialized yet, which would cause the CRT to FatalAppExit. - // to solve this, we must call __security_init_cookie before any - // hidden compiler-generated SEH registration code runs, - // which means the __try block must be moved into a helper function. - // - // NB: entry() must not contain local string buffers, either - - // /GS would install a cookie here as well (same problem). - // - // see http://msdn2.microsoft.com/en-US/library/ms235603.aspx - __security_init_cookie(); -#endif - return SEH_wrapped_entry(); -} - - -// Alternative entry point, for programs that don't want the SEH handler -// (e.g. unit tests, where it's better to let the debugger handle any errors) -int entry_noSEH() -{ - int ret; - pre_libc_init(); -#ifdef USE_WINMAIN - ret = WinMainCRTStartup(); -#else - ret = mainCRTStartup(); -#endif - return ret; + ShutdownLocks(); + + // free the reference taken in win_PreInit; + // this avoids Boundschecker warnings at exit. + FreeLibrary(hUser32Dll); + + return INFO::OK; } diff --git a/source/lib/sysdep/win/wutil.h b/source/lib/sysdep/win/wutil.h new file mode 100644 index 0000000000..086e757190 --- /dev/null +++ b/source/lib/sysdep/win/wutil.h @@ -0,0 +1,88 @@ +/** + * ========================================================================= + * File : wutil.h + * Project : 0 A.D. + * Description : various Windows-specific utilities + * + * @author Jan.Wassenberg@stud.uni-karlsruhe.de + * ========================================================================= + */ + +/* + * Copyright (c) 2003-2007 Jan Wassenberg + * + * Redistribution and/or modification are also permitted under the + * terms of the GNU General Public License as published by the + * Free Software Foundation (version 2 or later, at your option). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef INCLUDED_WUTIL +#define INCLUDED_WUTIL + +#if !OS_WIN +#error "wutil.h: do not include if not compiling for Windows" +#endif + +#include "win_internal.h" + + +//----------------------------------------------------------------------------- +// locking + +// critical sections used by win-specific code +enum +{ + ONCE_CS, + WTIME_CS, + WAIO_CS, + WIN_CS, + WDBG_CS, + + NUM_CS +}; + +extern void win_lock(uint idx); +extern void win_unlock(uint idx); + +// used in a desperate attempt to avoid deadlock in wdbg_exception_handler. +extern int win_is_locked(uint idx); + + +//----------------------------------------------------------------------------- + +extern void* win_alloc(size_t size); +extern void win_free(void* p); + + +// thread safe, usable in constructors +#define WIN_ONCE(code)\ +{\ + win_lock(ONCE_CS);\ + static bool ONCE_init_; /* avoid name conflict */\ + if(!ONCE_init_)\ + {\ + ONCE_init_ = true;\ + code;\ + }\ + win_unlock(ONCE_CS);\ +} + +#define WIN_SAVE_LAST_ERROR DWORD last_err__ = GetLastError(); +#define WIN_RESTORE_LAST_ERROR STMT(if(last_err__ != 0 && GetLastError() == 0) SetLastError(last_err__);); + + +// return the LibError equivalent of GetLastError(), or ERR::FAIL if +// there's no equal. +// you should SetLastError(0) before calling whatever will set ret +// to make sure we do not return any stale errors. +extern LibError LibError_from_win32(DWORD ret, bool warn_if_failed = true); + + +extern char win_sys_dir[MAX_PATH+1]; +extern char win_exe_dir[MAX_PATH+1]; + +#endif // #ifndef INCLUDED_WUTIL diff --git a/source/lib/types.h b/source/lib/types.h index c398660fc3..1690ce7ea2 100644 --- a/source/lib/types.h +++ b/source/lib/types.h @@ -20,8 +20,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef __TYPES_H__ -#define __TYPES_H__ +#ifndef INCLUDED_TYPES +#define INCLUDED_TYPES #include "posix/posix_types.h" @@ -53,4 +53,4 @@ typedef unsigned int PS_uint; //# endif //#endif -#endif // #ifndef __TYPES_H__ +#endif // #ifndef INCLUDED_TYPES diff --git a/source/main.cpp b/source/main.cpp index 2a6d79f123..2c15b52cc5 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -12,10 +12,9 @@ that of Atlas depending on commandline parameters. // not for any PCH effort, but instead for the (common) definitions // included there. #include "lib/precompiled.h" -#include #include "lib/input.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" #include "lib/timer.h" #include "lib/res/file/vfs.h" #include "lib/res/sound/snd_mgr.h" @@ -41,7 +40,7 @@ that of Atlas depending on commandline parameters. #include "gui/GUI.h" #if OS_WIN -# include "lib/sysdep/win/win.h" +# include "lib/sysdep/win/wstartup.h" #endif #define LOG_CATEGORY "main" @@ -358,40 +357,32 @@ void kill_mainloop() } -#include "lib/res/file/trace.h" - int main(int argc, char* argv[]) { // If you ever want to catch a particular allocation: //_CrtSetBreakAlloc(321); - // see discussion at declaration of win_pre_main_init. + // see discussion at declaration of wstartup_PreMainInit. #if OS_WIN - win_pre_main_init(); + wstartup_PreMainInit(); #endif - { // scope for args + CmdLineArgs args(argc, argv); - CmdLineArgs args(argc, argv); + // run Atlas (if requested via args) + bool ran_atlas = ATLAS_RunIfOnCmdLine(args); + // Atlas handles the whole init/shutdown/etc sequence by itself, + // so just exit after it has run. + if(ran_atlas) + exit(EXIT_SUCCESS); - bool ran_atlas = ATLAS_RunIfOnCmdLine(args); + // run the game + Init(args, 0); + MainControllerInit(); + while(!quit) + Frame(); + Shutdown(0); + MainControllerShutdown(); - // Atlas handles the whole init/shutdown/etc sequence by itself, - // so we skip all this and just exit if Atlas was run - if (! ran_atlas) - { - Init(args, 0); - MainControllerInit(); - - while(!quit) - Frame(); - - Shutdown(0); - MainControllerShutdown(); - } - } - - debug_printf("Shutdown complete, calling exit() now\n"); - - exit(0); + exit(EXIT_SUCCESS); } diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index 5c3db974d6..2c4c0bcbcb 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -1,7 +1,7 @@ #include "precompiled.h" #include "lib/lib.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" #include "lib/ogl.h" #include "lib/timer.h" #include "lib/input.h" diff --git a/source/ps/Globals.h b/source/ps/Globals.h index 3b830dade8..af1efdd999 100644 --- a/source/ps/Globals.h +++ b/source/ps/Globals.h @@ -1,5 +1,5 @@ #include "lib/input.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" // thin abstraction layer on top of SDL. // game code should use it instead of SDL_GetMouseState etc. because diff --git a/source/ps/Hotkey.h b/source/ps/Hotkey.h index 12b7a495bf..572e6ffda0 100644 --- a/source/ps/Hotkey.h +++ b/source/ps/Hotkey.h @@ -19,7 +19,7 @@ #include "CStr.h" #include "lib/input.h" -#include "lib/sdl.h" // see note below +#include "lib/external_libraries/sdl.h" // see note below // note: we need the real SDL header - it defines SDL_USEREVENT, which is // required for our HOTKEY event type definition. this is OK since diff --git a/source/ps/KeyName.cpp b/source/ps/KeyName.cpp index 09b26b6edf..92fd363245 100644 --- a/source/ps/KeyName.cpp +++ b/source/ps/KeyName.cpp @@ -3,7 +3,7 @@ #include "precompiled.h" #include #include "CStr.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" static std::map keymap; diff --git a/source/ps/ProfileViewer.cpp b/source/ps/ProfileViewer.cpp index f833ee7093..6000830185 100644 --- a/source/ps/ProfileViewer.cpp +++ b/source/ps/ProfileViewer.cpp @@ -23,7 +23,7 @@ #include "lib/res/file/file.h" #include "Hotkey.h" #include "ps/CLogger.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" extern int g_xres, g_yres; diff --git a/source/ps/StringConvert.cpp b/source/ps/StringConvert.cpp index 6d0b1753d8..7c97fc94b7 100644 --- a/source/ps/StringConvert.cpp +++ b/source/ps/StringConvert.cpp @@ -1,7 +1,7 @@ #include "precompiled.h" #include "StringConvert.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" #include "scripting/SpiderMonkey.h" #if SDL_BYTEORDER == SDL_BIG_ENDIAN diff --git a/source/tools/atlas/GameInterface/GameLoop.cpp b/source/tools/atlas/GameInterface/GameLoop.cpp index 99fd9c465c..3cf1992b88 100644 --- a/source/tools/atlas/GameInterface/GameLoop.cpp +++ b/source/tools/atlas/GameInterface/GameLoop.cpp @@ -12,7 +12,7 @@ #include "InputProcessor.h" #include "lib/app_hooks.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" #include "lib/timer.h" #include "lib/res/file/vfs.h" #include "ps/CLogger.h" diff --git a/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp index 0c1c93b846..fb64c83b27 100644 --- a/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp @@ -11,7 +11,7 @@ #include "gui/CGUI.h" #include "gui/GUIbase.h" #include "lib/res/file/vfs.h" -#include "lib/sdl.h" +#include "lib/external_libraries/sdl.h" #include "maths/MathUtil.h" #include "ps/CConsole.h" #include "ps/Game.h"