How to build standalone wxWidgets application

Do you have a question about makefiles, a compiler or IDE you are using and need to know how to set it up for wxWidgets or why it doesn't compile but other IDE's do ? Post your questions here.
ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Fri Mar 15, 2019 12:29 pm

Thank you very, very much for your help. I managed to do it and finish the application. :D

If I will have other questions I will open new thread.

ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Wed Mar 20, 2019 3:30 pm

doublemax wrote:
Thu Mar 14, 2019 7:04 pm
If I put it at the start of Main.cpp file:
You should never have any instance of a wxWidgets object as a global variable.

The usual way is this:
- add a member variable to your wxApp class, e.g. wxFileConfig *m_conf;

- in MyApp::OnInit():

Code: Select all

m_conf = new wxFileConfig("", "", "path-to-inifile.ini");
wxConfigBase::Set(m_conf);           // this sets the global configuration object
Now, anywhere in your program you can use this to get the pointer:

Code: Select all

wxConfigBase *conf = wxConfigBase::Get(false); 
in MyApp::OnExit()

Code: Select all

wxConfigBase::Set(NULL);
delete m_conf;
I get segmentation fault when exiting application. I think here:

Code: Select all

#if wxUSE_CONFIG
    // delete the config object if any (don't use Get() here, but Set()
    // because Get() could create a new config object)
    delete wxConfigBase::Set(NULL);
#endif // wxUSE_CONFIG
In appbase.app file, function name int wxAppConsoleBase::OnExit().


What I have is:
-in projApp.h:

Code: Select all

class DataGetterApp : public wxApp
{
    public:
        virtual bool OnInit();

        wxFileConfig *conf;
};
-in projApp.cpp:

Code: Select all

bool DataGetterApp::OnInit()
{
    //(*AppInitialize
    bool wxsOK = true;
    wxInitAllImageHandlers();
    if ( wxsOK )
    {
    	MainFrame = new DataGetterFrame(0);
    	MainFrame->Show();
    	SetTopWindow(MainFrame);
    }
    //*)
    wxConfigBase::Set(conf);
    return wxsOK;
}
-in projMain.cpp:
global variable

Code: Select all

wxConfigBase *conf = wxConfigBase::Get(false);
somewhere in code I have

Code: Select all

conf = new wxFileConfig("", "", FileDialog1->GetPath());
-in projMain.cpp:

Code: Select all

void DataGetterFrame::OnQuit(wxCommandEvent& event)
{
    if (conf)
    {
        wxConfigBase::Set(NULL);
        delete conf;
    }
    Close();
    //event.Skip(TRUE);
    //Destroy();
}

Is this allright? What can make error at quit?

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3366
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to build standalone wxWidgets application

Post by ONEEYEMAN » Wed Mar 20, 2019 3:37 pm

Hi,
What line is failing exactly?
And what is the backtrace?

Also, why do you need to set it to NULL? Is deleting it not enough?

Thank you.

User avatar
doublemax
Moderator
Moderator
Posts: 13903
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to build standalone wxWidgets application

Post by doublemax » Wed Mar 20, 2019 5:31 pm

With the little fragments of code without context, it's a little hard to guess.
My guess is:
If you call "wxConfigBase::Set(conf);" in DataGetterApp::OnInit(), conf might not be initialized yet and be a garbage pointer.

IIRC you don't use wxFileConfig for preferences, but for parsing other files. In that case it may not be the best idea to set it globally. Usually you would create the wxFileConfig instance in wxApp::OnInit (with a generated path) and delete it in wxApp::OnExit. But this doesn't work if you have to ask the user for the path to the file.

In this case i would suggest you create the wxFileConfig when you need it, parse your file, and delete it afterwards. Don't use wxConfigBase::Get/Set.

Sorry for making a bad suggestion.
Use the source, Luke!

ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Thu Mar 21, 2019 7:30 am

ONEEYEMAN wrote:
Wed Mar 20, 2019 3:37 pm
Hi,
What line is failing exactly?
And what is the backtrace?

Also, why do you need to set it to NULL? Is deleting it not enough?

Thank you.
Exactly where I said in my previous comment. In file "appbase.cpp", in function "int wxAppConsoleBase::OnExit()" there is line "delete wxConfigBase::Set(NULL);". On this line, the debugger stops after I close the application.

doublemax wrote:
Wed Mar 20, 2019 5:31 pm
With the little fragments of code without context, it's a little hard to guess.
My guess is:
If you call "wxConfigBase::Set(conf);" in DataGetterApp::OnInit(), conf might not be initialized yet and be a garbage pointer.

IIRC you don't use wxFileConfig for preferences, but for parsing other files. In that case it may not be the best idea to set it globally. Usually you would create the wxFileConfig instance in wxApp::OnInit (with a generated path) and delete it in wxApp::OnExit. But this doesn't work if you have to ask the user for the path to the file.

In this case i would suggest you create the wxFileConfig when you need it, parse your file, and delete it afterwards. Don't use wxConfigBase::Get/Set.

Sorry for making a bad suggestion.
>With the little fragments of code without context, it's a little hard to guess.

You are right, sorry. I just posted where I have lines that have to do with wxFileConfig, but forgot to explain the context. Wanted I had in mind to do is, make a global variable of wxFileConfig, ask user for appropriate INI file, load data from file into my variable, and use it elsewere to process it.

So I suppose I have to follow your line:
>In this case i would suggest you create the wxFileConfig when you need it, parse your file, and delete it afterwards. Don't use wxConfigBase::Get/Set.

But I don't know how to do that, since asking user for the path to the file is bound to one button ("browse INI file"), but parsing is bound on different button ("parse data").



What I did now is remove "wxConfigBase::Set(conf);" from OnInit(), and add it right after I load the file, chosen by the user:

Code: Select all

conf = new wxFileConfig("", "", FileDialog1->GetPath());
wxConfigBase::Set(conf);
Now the application doesn't crash anymore when I run it from IDE, but crashes when I run it as standalone application (starting .exe file). Honestly, this "works in IDE but not as standalone" is starting to piss me off with wxWidgets. Shouldn't environment be the same?


Other thing I think I could do is use "wxConfigBase *conf = wxConfigBase::Get(false);" everytime I need to use the conf anywhere in the code.

User avatar
doublemax
Moderator
Moderator
Posts: 13903
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to build standalone wxWidgets application

Post by doublemax » Thu Mar 21, 2019 9:33 am

Honestly, this "works in IDE but not as standalone" is starting to piss me off with wxWidgets. Shouldn't environment be the same?
I don't think this is a wxWidgets problem. First you need to find out why it crashes, then we can talk who's fault it is ;)

Try this: Don't use a global "conf" variable, just use wxConfigBase::Set/Get. Each time you load a new .INI, delete the old one and set the new instance.

Code: Select all

wxFileConfig *conf = new wxFileConfig("", "", FileDialog1->GetPath());
delete wxConfigBase::Set(conf);
Remove all other code that deletes conf or calls wxConfigBase::Set
Use the source, Luke!

ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Thu Mar 21, 2019 11:58 am

You are right, I shouldn't assume anything, I just blamed the closest thing to me.


Alright, so now I have this where user chooses INI file:

Code: Select all

if (FileDialog1->ShowModal() == wxID_OK)
{
    ....
}

wxConfigBase *confPrev = wxConfigBase::Get(false);
if (confPrev != NULL)
{
    wxConfigBase::Set(NULL);
    delete confPrev;
}

wxFileConfig *conf = new wxFileConfig("", "", FileDialog1->GetPath());
wxConfigBase::Set(conf);
For going through conf I am using your code from previous forum page.

Code: Select all

wxConfigBase *conf = wxConfigBase::Get(false);
wxString group;
long group_index;
conf->SetPath("/");
bool has_group = conf->GetFirstGroup(group, group_index);
while(has_group)
{
    ...
}
In OnQuit() function I have:

Code: Select all

wxConfigBase *conf = wxConfigBase::Get(false);
if (conf)
{
    wxConfigBase::Set(NULL);
}      
I am using no other code. I removed

Code: Select all

wxFileConfig *conf;
from DataGetterApp.h and global variable

Code: Select all

wxConfigBase *conf = wxConfigBase::Get(false);
from DataGetterMain.cpp

Sadly, the program still crashes when I run .exe file. Same thing happens if I comment the last code (from onQuit() function). It doesn't crash, nor show me any error, when I debug it.

User avatar
doublemax
Moderator
Moderator
Posts: 13903
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to build standalone wxWidgets application

Post by doublemax » Thu Mar 21, 2019 12:55 pm

Code: Select all

if (FileDialog1->ShowModal() == wxID_OK)
{
    ....
}

wxConfigBase *confPrev = wxConfigBase::Get(false);
if (confPrev != NULL)
{
    wxConfigBase::Set(NULL);
    delete confPrev;
}

wxFileConfig *conf = new wxFileConfig("", "", FileDialog1->GetPath());
wxConfigBase::Set(conf);
The middle part is not necessary.

This is enough (calling delete on a NULL pointer is a safe operation):

Code: Select all

wxFileConfig *conf = new wxFileConfig("", "", FileDialog1->GetPath());
delete wxConfigBase::Set(conf);
Sadly, the program still crashes when I run .exe file.
Are you sure it's related to the wxFileConfig code? What's the complete backtracke/call stack?

Can you post the complete code (or upload it somewhere)?
Use the source, Luke!

ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Thu Mar 21, 2019 1:18 pm

Isn't your code supposed to be the other way around? First delete, than new wxFileConfig()?

I put break point on Close() (so before application closes), and copy pasted callstack:

Code: Select all

#0 ??	DataGetterFrame::OnQuit (this=0x5ada2d8, event=...) (C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp:238)
#1 0x5a1b2e	wxAppConsoleBase::HandleEvent (this=0x5acb158, handler=0x5ada2d8, func=(void (wxEvtHandler::*)(wxEvtHandler * const, wxEvent &) (../../src/common/appbase.cpp:657)
#2 0x5a1b8a	wxAppConsoleBase::CallEventHandler(this=0x5acb158, handler=0x5ada2d8, functor=..., event=...) (../../src/common/appbase.cpp:669)
#3 0x63b8f3	wxEvtHandler::ProcessEventIfMatchesId(entry=..., handler=0x5ada2d8, event=...) (../../src/common/event.cpp:1396)
#4 0x63c4cd	wxEvtHandler::SearchDynamicEventTable(this=0x5ada2d8, event=...) (../../src/common/event.cpp:1868)
#5 0x63bd1b	wxEvtHandler::TryHereOnly(this=0x5ada2d8, event=...) (../../src/common/event.cpp:1589)
#6 0x713c60	wxEvtHandler::TryBeforeAndHere(this=0x5ada2d8, event=...) (../../include/wx/event.h:3892)
#7 0x63bbaf	wxEvtHandler::ProcessEventLocally(this=0x5ada2d8, event=...) (../../src/common/event.cpp:1526)
#8 0x63bb50	wxEvtHandler::ProcessEvent(this=0x5ada2d8, event=...) (../../src/common/event.cpp:1499)
#9 0x51025b	wxWindowBase::TryAfter(this=0x5ae2498, event=...) (../../src/common/wincmn.cpp:3444)
#10 0x63bb7b	wxEvtHandler::ProcessEvent(this=0x5ae2498, event=...) (../../src/common/event.cpp:1512)
#11 0x63bdef	wxEvtHandler::SafelyProcessEvent(this=0x5ae2498, event=...) (../../src/common/event.cpp:1617)
#12 0x50b1dc	wxWindowBase::HandleWindowEvent(this=0x5ae2498, event=...) (../../src/common/wincmn.cpp:1539)
#13 0x4db2e7	wxMenuBase::DoProcessEvent(menu=0x0, event=..., win=0x5ada2d8) (../../src/common/menucmn.cpp:675)
#14 0x4db21a	wxMenuBase::SendEvent(this=0x5ae2638, itemid=107, checked=-1) (../../src/common/menucmn.cpp:643)
#15 0x4a4fdf	wxFrameBase::ProcessCommand(this=0x5ada2d8, item=0x5ae2800) (../../src/common/framecmn.cpp:294)
#16 0x457e9e	wxFrame::HandleCommand(this=0x5ada2d8, id=107, cmd=0, control=0x0) (../../src/msw/frame.cpp:805)
#17 0x458099	wxFrame::MSWWindowProc(this=0x5ada2d8, message=273, wParam=107, lParam=0) (../../src/msw/frame.cpp:855)
#18 0x441af3	wxWndProc(hWnd=0x2a0af0, message=273, wParam=107, lParam=0) (../../src/msw/window.cpp:2909)
#19 0x756e62fa	gapfnScSendMessage() (C:\Windows\syswow64\user32.dll:??)
#20 0x2a0af0	?? () (??:??)
#21 0x756e6d3a	USER32!GetThreadDesktop() (C:\Windows\syswow64\user32.dll:??)
#22 0x441a4a	wxWindowCreationHook::~wxWindowCreationHook(this=0x756e6d3a <USER32!GetThreadDesktop+215>, __in_chrg=<optimized out>) (../../src/msw/window.cpp:2870)
#23 0x2a0af0	?? () (??:??)
#24 0x756e77c4	USER32!CharPrevW() (C:\Windows\syswow64\user32.dll:??)
#25 0x756e788a	USER32!DispatchMessageW() (C:\Windows\syswow64\user32.dll:??)
#26 0x44b406	wxGUIEventLoop::ProcessMessage(this=0x5ae4628, msg=0x28fca8) (../../src/msw/evtloop.cpp:167)
#27 0x44b682	wxGUIEventLoop::Dispatch(this=0x5ae4628) (../../src/msw/evtloop.cpp:227)
#28 0x5bf349	wxEventLoopManual::ProcessEvents(this=0x5ae4628) (../../src/common/evtloopcmn.cpp:237)
#29 0x5bf3f3	wxEventLoopManual::DoRun(this=0x5ae4628) (../../src/common/evtloopcmn.cpp:283)
I am doing this (posting callstack) for the first time, so I don't know what else I must do.


The complete project code is pretty big, with other .cpp and .h files and I don't want to use too much of your time. :shock:

User avatar
doublemax
Moderator
Moderator
Posts: 13903
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to build standalone wxWidgets application

Post by doublemax » Thu Mar 21, 2019 1:33 pm

Isn't your code supposed to be the other way around? First delete, than new wxFileConfig()?
Not necessary. But of course it doesn't hurt to do it the way you did.
I put break point on Close() (so before application closes), and copy pasted callstack:
That's not helpful. I need a callstack when the actual crash happens.

Deleting the fileconfig in OnQuit is relatively early (as opposed to in wxApp::OnExit(). Are you sure you're not accessing the conf object in the destructor or any other class?
Use the source, Luke!

ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Thu Mar 21, 2019 2:01 pm

That's not helpful. I need a callstack when the actual crash happens.
How do I do that, since I only get crash message only if I run .exe file (not in IDE)?

Deleting the fileconfig in OnQuit is relatively early (as opposed to in wxApp::OnExit()
I dont have OnExit() anywhere in DataGetterApp.cpp (or the project).

Are you sure you're not accessing the conf object in the destructor or any other class?
Positive, I searched throughout the project for "conf" and only found it in DataGetterMain.cpp

Is there a reason why release .exe file crashes on exit, bug debug .exe file does not?

User avatar
doublemax
Moderator
Moderator
Posts: 13903
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to build standalone wxWidgets application

Post by doublemax » Thu Mar 21, 2019 2:55 pm

What happens if you start the debug .exe directly?
Is there a reason why release .exe file crashes on exit, bug debug .exe file does not?
The most common reasons are:

- when starting an .exe directly, the working directory is the directory where the .exe is. But when starting from the IDE, the working directory is usually the one where the source files are. (At least in Visual Studio, i don't know about other IDEs). But this normally leads to crashes when you start the program, because it doesn't find external files. Not when you exit the application.

- another difference between a debug and a release build is that in a debug build all variables are initialized to 0. In a release build they are not and can contain random garbage. Do you get any warning messages about "variable used before initialized" when building?
Use the source, Luke!

ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Thu Mar 21, 2019 3:15 pm

What happens if you start the debug .exe directly?
Application works ok, I get no crash errors.
- another difference between a debug and a release build is that in a debug build all variables are initialized to 0. In a release build they are not and can contain random garbage. Do you get any warning messages about "variable used before initialized" when building?
Sadly no, I only get warning about classes not having destructor method.

Code: Select all

||=== Build: Release in DataGetter (compiler: GNU GCC Compiler) ===|
||warning: ./wx_pch.h.gch/Debug_wx_pch_h_gch: not used because `__WXDEBUG__' not defined [-Winvalid-pch]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp||In member function 'void DataGetterFrame::OnQuit(wxCommandEvent&)':|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|235|warning: deleting object of polymorphic class type 'Tmod_CANopen' which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp||In function 'int initPCAN()':|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|301|warning: deleting object of polymorphic class type 'mod_PCAN' which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|319|warning: deleting object of polymorphic class type 'mod_PCAN' which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|321|warning: deleting object of abstract class type 'Tif_CommInterface' which has non-virtual destructor will cause undefined behavior [-Wdelete-non-virtual-dtor]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp||In function 'int initIsCAN()':|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|345|warning: deleting object of polymorphic class type 'Tmod_CAN' which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|347|warning: deleting object of abstract class type 'Tif_CommInterface' which has non-virtual destructor will cause undefined behavior [-Wdelete-non-virtual-dtor]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|363|warning: deleting object of polymorphic class type 'Tmod_CAN' which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp||In function 'void napolniDrevo()':|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\DataGetterMain.cpp|571|warning: comparison between signed and unsigned integer expressions [-Wsign-compare]|
C:\Users\M0097932\Desktop\firstTest\DataGetter mono\debug in release\mod_isCAN.h|150|warning: 'void IFAK_MsgHandler(BYTE, void*)' declared 'static' but never defined [-Wunused-function]|
||=== Build finished: 0 error(s), 10 warning(s) (0 minute(s), 6 second(s)) ===|

I will check it again tomorrow, with fresh mind.

User avatar
doublemax
Moderator
Moderator
Posts: 13903
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to build standalone wxWidgets application

Post by doublemax » Thu Mar 21, 2019 3:18 pm

I only get warning about classes not having destructor method.
This is definitely something you should look into. Especially since you're trying to track down a crash that happens when the .exe is terminated (and all objects get destructed).
Use the source, Luke!

ValeV
Experienced Solver
Experienced Solver
Posts: 68
Joined: Wed Jan 30, 2019 1:39 pm

Re: How to build standalone wxWidgets application

Post by ValeV » Mon Apr 01, 2019 8:18 am

Hi,

I apologize reviving old thread, but I still haven't found the problem.

I checked the destructors and created them where needed. So I don't get those error anymore.

My app sadly still crashes.

Is it possible, that my global pointer to Frame can cause the crash?

In my DataGetterApp.cpp i have:

Code: Select all

DataGetterFrame* MainFrame;
In same file, in funtion OnInit():

Code: Select all

MainFrame = new DataGetterFrame(0);
MainFrame->Show();
SetTopWindow(MainFrame);
And in DataGetterMain.cpp:

Code: Select all

extern DataGetterFrame* MainFrame;
I don't delete this pointer in OnQuit() method because than app crashes in CodeBlocks as well (when I close my application).

Although I know global variables are bad, I use it to print to wxTextCtrl, like this (Results is wxTextCtrl component):

Code: Select all

void printTxt(wxString s){MainFrame->Results->AppendText(s);};

EDIT: I MANAGED TO "FIX" IT. I don't know if it's fixed, but it stopped crashing. In CodeBlocks went to build options and unchecked "Optimize even more" (4th flag under Optimization).

Post Reply