Exception thrown when closing window Topic is solved
Exception thrown when closing window
I am getting a read access violation error when attempting to close my main window, right after pressing a button (see screenshot attached). Is this expected behaviour, and can it be overcome? Or should I simply place a control statement in my OnClose callback, to stop the window from being closed if a button has just been pressed?
Re: Exception thrown when closing window
No, that shouldn't happen, but without more information it's hard to tell what the problem is. Does it only happen for one or a few buttons, or for all. What exactly does your app do after pressing that button?
Post a full callstack.
Post a full callstack.
Use the source, Luke!
Re: Exception thrown when closing window
Here is the call stack:
After the button is pressed, it immediately becomes disabled. A flag is set that signals a helper thread that the button has been pressed. On its next iteration (the thread loops every 100ms or so), the helper thread writes values to a slave device via a Modbus protocol, and resets the flag. A one-shot timer is then started (in the thread event handler, never the thread itself) and after about 1.5 seconds the button is re-enabled in the timer callback.
There are two buttons in my main window which do pretty much the same thing (only send a different Modbus message) - see screenshot attached. Here is also my entire .cpp file for reference:
It seems that the timer might be causing the problem, perhaps I should ensure it is stopped when closing a window?
Regards,
Ksawery
Code: Select all
> PomiarWiazki_wxWidgets.exe!wxEvtHandler::SafelyProcessEvent(wxEvent & event) Line 1617 C++
PomiarWiazki_wxWidgets.exe!wxTimerImpl::SendEvent() Line 52 C++
PomiarWiazki_wxWidgets.exe!wxTimer::Notify() Line 107 C++
PomiarWiazki_wxWidgets.exe!wxTimerImpl::Notify() Line 47 C++
PomiarWiazki_wxWidgets.exe!wxProcessTimer(wxMSWTimerImpl & timer) Line 160 C++
PomiarWiazki_wxWidgets.exe!wxTimerWndProc(HWND__ * hWnd, unsigned int message, unsigned int wParam, long lParam) Line 173 C++
[External Code]
user32.dll![Frames below may be incorrect and/or missing, no symbols loaded for user32.dll] Unknown
PomiarWiazki_wxWidgets.exe!wxGUIEventLoop::PreProcessMessage(tagMSG * msg) Line 96 C++
PomiarWiazki_wxWidgets.exe!wxGUIEventLoop::ProcessMessage(tagMSG * msg) Line 163 C++
PomiarWiazki_wxWidgets.exe!wxGUIEventLoop::Dispatch() Line 227 C++
PomiarWiazki_wxWidgets.exe!wxEventLoopManual::ProcessEvents() Line 237 C++
PomiarWiazki_wxWidgets.exe!wxEventLoopManual::DoRun() Line 283 C++
PomiarWiazki_wxWidgets.exe!wxEventLoopBase::Run() Line 90 C++
PomiarWiazki_wxWidgets.exe!wxAppConsoleBase::MainLoop() Line 380 C++
PomiarWiazki_wxWidgets.exe!wxAppConsoleBase::OnRun() Line 301 C++
PomiarWiazki_wxWidgets.exe!wxAppBase::OnRun() Line 336 C++
PomiarWiazki_wxWidgets.exe!wxEntryReal(int & argc, wchar_t * * argv) Line 507 C++
PomiarWiazki_wxWidgets.exe!wxEntry(int & argc, wchar_t * * argv) Line 184 C++
PomiarWiazki_wxWidgets.exe!wxEntry(HINSTANCE__ * hInstance, HINSTANCE__ * __formal, char * __formal, int nCmdShow) Line 305 C++
PomiarWiazki_wxWidgets.exe!WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow) Line 3 C++
[External Code]
There are two buttons in my main window which do pretty much the same thing (only send a different Modbus message) - see screenshot attached. Here is also my entire .cpp file for reference:
Code: Select all
#include "cMain.h"
wxBEGIN_EVENT_TABLE(cMain, wxFrame)
EVT_BUTTON(10001, OnButtonClickedWsun)
EVT_BUTTON(10002, OnButtonClickedWysun)
EVT_MENU(wxID_NETWORK, OnMenuClickedConnect)
EVT_MENU(wxID_VIEW_DETAILS, OnMenuClickedDiagnostics)
EVT_MENU(wxID_INFO, OnMenuClickedInformation)
EVT_MENU(wxID_EXIT, OnMenuClickedExit)
EVT_TIMER(10004, OnWriteTimer)
EVT_TIMER(10005, OnWriteErrorTimer)
EVT_CLOSE(OnClose)
wxEND_EVENT_TABLE()
/* Frame constructor */
cMain::cMain(const char* mbPort, int mbSlaveAddress, int mbSlaveNum) : wxFrame(nullptr, wxID_ANY, " ", wxPoint(200, 160), wxSize(870, 630), (wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER & ~wxMAXIMIZE_BOX))
{
//Set title
this->SetTitle(wxT("Pomiar Wiązki w Linii Iniekcyjnej: MB" + std::to_string(mbSlaveNum) + " (COM" + mbPort[mbPortCharLength - 1] + ")"));
//Shift window
this->SetPosition(this->GetPosition() + ((mbSlaveNum - 1) * wxPoint(120, 120)));
//Bind helper thread dynamically
Bind(wxEVT_THREAD, &cMain::OnThreadUpdate, this);
//Store modbus connection settings
this->mbPort = mbPort;
this->mbSlaveNum = mbSlaveNum;
this->mbSlaveAddress = mbSlaveAddress;
//Pointer initialization
m_pMenuBar = nullptr;
m_pToolsMenu = nullptr;
m_pHelpMenu = nullptr;
m_btn_wsun = nullptr;
m_btn_wysun = nullptr;
pngHandler = nullptr;
backgroundImage = nullptr;
m_static_txt_adc1 = nullptr;
m_static_txt_adc2 = nullptr;
m_static_txt_adc3 = nullptr;
m_static_txt_adc4 = nullptr;
m_static_txt_mberror_read = nullptr;
m_static_txt_mberror_write = nullptr;
m_static_txt_adcerror = nullptr;
ctx = nullptr;
m_frame_diag = nullptr;
//Variables initialization
mbADCErrorsRegister = 0;
//Modbus status flags initialization
mbStatusConnected = 0;
mbStatusReadADC = 0;
mbStatusWriteCoil = 0;
mbStatusReadDiagnostics = 0;
mbStatusResetDiagnostics = 0;
//Other flags initialization
mbModeWriteCoil = -1;
mbDiagnosticsEnabled = FALSE;
mbDiagnosticsResetEnabled = FALSE;
mbDiagnosticsResetting = FALSE;
mbDiagnosticsOpenWindowEnabled = FALSE;
mbDiagnosticsWindowIsOpen = FALSE;
//Construct custom Modbus diagnostics message
mbDiagRawRequest[0] = (uint8_t)mbSlaveAddress;
mbDiagRawRequest[1] = 0x08;
mbDiagRawRequest[2] = 0x00;
mbDiagRawRequest[3] = 0x02;
mbDiagRawRequest[4] = 0x00;
mbDiagRawRequest[5] = 0x00;
//Construct custom Modbus diagnostics reset message
mbDiagResetRawRequest[0] = (uint8_t)mbSlaveAddress;
mbDiagResetRawRequest[1] = 0x08;
mbDiagResetRawRequest[2] = 0x00;
mbDiagResetRawRequest[3] = 0x01;
mbDiagResetRawRequest[4] = 0xFF;
mbDiagResetRawRequest[5] = 0x00;
//Set window background colour
this->SetBackgroundColour(wxColour(225, 225, 225));
//Create buttons
m_btn_wsun = new wxButton(this, 10001, "Wsuń", wxPoint(670, 230), wxSize(150, 50));
m_btn_wysun = new wxButton(this, 10002, "Wysuń", wxPoint(670, 290), wxSize(150, 50));
if (m_btn_wsun != nullptr) m_btn_wsun->SetBackgroundColour(wxColour(210, 210, 210));
if (m_btn_wysun != nullptr) m_btn_wysun->SetBackgroundColour(wxColour(210, 210, 210));
//Add background image
pngHandler = new wxPNGHandler;
wxImage::AddHandler(pngHandler);
backgroundImage = new wxStaticBitmap(this, wxID_ANY, wxBitmap("concentric-circles.png", wxBITMAP_TYPE_PNG), wxPoint(130, 30), wxSize(510, 510));
//Create menu bar
m_pMenuBar = new wxMenuBar();
//Tools menu
m_pToolsMenu = new wxMenu();
if (m_pToolsMenu != nullptr)
{
m_pToolsMenu->Append(wxID_NETWORK, _T("&Polącz"));
m_pToolsMenu->Append(wxID_VIEW_DETAILS, _T("&Diagnostyka"));
m_pToolsMenu->AppendSeparator();
m_pToolsMenu->Append(wxID_EXIT, _T("&Wyjdź"));
m_pMenuBar->Append(m_pToolsMenu, _T("&Narzędzia"));
//About menu
m_pHelpMenu = new wxMenu();
m_pHelpMenu->Append(wxID_INFO, _T("&Informacje"));
m_pMenuBar->Append(m_pHelpMenu, _T("&Pomoc"));
//Set menu bar
SetMenuBar(m_pMenuBar);
}
//Initialize static texts
m_static_txt_device = new wxStaticText(this, wxID_ANY, wxT("MB" + std::to_string(mbSlaveNum) + "(COM" + mbPort[mbPortCharLength - 1] + ")"), wxPoint(20, 20), wxSize(110, 30), wxALIGN_CENTRE_HORIZONTAL);
m_static_txt_adc1 = new wxStaticText(this, wxID_ANY, "N/A", wxPoint(20, 270), wxSize(110, 30), wxALIGN_CENTRE_HORIZONTAL);
m_static_txt_adc2 = new wxStaticText(this, wxID_ANY, "N/A", wxPoint(330, 70), wxSize(110, 30), wxALIGN_CENTRE_HORIZONTAL);
m_static_txt_adc3 = new wxStaticText(this, wxID_ANY, "N/A", wxPoint(330, 155), wxSize(110, 30), wxALIGN_CENTRE_HORIZONTAL);
m_static_txt_adc4 = new wxStaticText(this, wxID_ANY, "N/A", wxPoint(330, 270), wxSize(110, 30), wxALIGN_CENTRE_HORIZONTAL);
m_static_txt_mberror_read = new wxStaticText(this, wxID_ANY, "Błąd w komunikacji Modbus:\nRead Error", wxPoint(590, 20), wxSize(100, 10), wxALIGN_CENTRE_HORIZONTAL);
m_static_txt_mberror_write = new wxStaticText(this, wxID_ANY, "Błąd w komunikacji Modbus:\nWrite Error", wxPoint(590, 20), wxSize(100, 10), wxALIGN_CENTRE_HORIZONTAL);
if (m_static_txt_adc2 != nullptr) m_static_txt_adc2->SetBackgroundColour(wxColour(0, 170, 250));
if (m_static_txt_adc3 != nullptr) m_static_txt_adc3->SetBackgroundColour(wxColour(98, 204, 254));
if (m_static_txt_adc4 != nullptr) m_static_txt_adc4->SetBackgroundColour(wxColour(214, 242, 254));
//Set sub-title font
myFont = wxFont(14, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_MEDIUM);
if (m_static_txt_device != nullptr) m_static_txt_device->SetFont(myFont);
//Set ADC readings font
myFont = wxFont(17, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
if (m_static_txt_adc1 != nullptr) m_static_txt_adc1->SetFont(myFont);
if (m_static_txt_adc2 != nullptr) m_static_txt_adc2->SetFont(myFont);
if (m_static_txt_adc3 != nullptr) m_static_txt_adc3->SetFont(myFont);
if (m_static_txt_adc4 != nullptr) m_static_txt_adc4->SetFont(myFont);
//Set Modbus read error message font
myFont = wxFont(11, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_MEDIUM);
if (m_static_txt_mberror_read != nullptr)
{
m_static_txt_mberror_read->SetFont(myFont);
m_static_txt_mberror_read->SetForegroundColour(wxColour(255, 0, 0));
m_static_txt_mberror_read->Hide();
}
//Set Modbus write error message font
if (m_static_txt_mberror_write != nullptr)
{
m_static_txt_mberror_write->SetFont(myFont);
m_static_txt_mberror_write->SetForegroundColour(wxColour(255, 0, 0));
m_static_txt_mberror_write->Hide();
}
//Create Modbus write timer
mbWriteTimer = new wxTimer(this, 10004);
mbWriteErrorTimer = new wxTimer(this, 10005);
//Initialize Modbus communication
ctx = modbus_new_rtu(this->mbPort, mbBaudRate, mbParity, mbNumBits, mbNumStopBits);
modbus_set_slave(ctx, this->mbSlaveAddress);
modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
modbus_set_response_timeout(ctx, 1, 0);
modbus_set_byte_timeout(ctx, 0, 200000);
mbStatusConnected = modbus_connect(ctx);
if (mbStatusConnected != -1)
{
//Disable Connect menu item
if (m_pToolsMenu->IsEnabled(wxID_NETWORK)) m_pToolsMenu->Enable(wxID_NETWORK, FALSE);
//Enable buttons
if (!(m_btn_wsun->IsEnabled())) m_btn_wsun->Enable();
if (!(m_btn_wysun->IsEnabled())) m_btn_wsun->Enable();
}
else
{
//Show read error
if (!(m_static_txt_mberror_write->IsShown()))
{
if (!(m_static_txt_mberror_read->IsShown())) m_static_txt_mberror_read->Show();
}
//Disable buttons and menu items
if (m_btn_wsun->IsEnabled()) m_btn_wsun->Disable();
if (m_btn_wysun->IsEnabled()) m_btn_wysun->Disable();
}
//Start Modbus communication in background thread
StartModbusThread();
}
//"Connect" menu item callback
void cMain::OnMenuClickedConnect(wxCommandEvent& evt)
{
//Initialize Modbus communication
ctx = modbus_new_rtu(mbPort, mbBaudRate, mbParity, mbNumBits, mbNumStopBits);
modbus_set_slave(ctx, mbSlaveAddress);
modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
mbStatusConnected = modbus_connect(ctx);
if (mbStatusConnected != -1) //connection successfull
{
//Check if thread already exists and is running
if (GetThread() && GetThread()->IsRunning())
{
GetThread()->Delete();
}
//Disable Connect menu item
if (m_pToolsMenu->IsEnabled(wxID_NETWORK)) m_pToolsMenu->Enable(wxID_NETWORK, FALSE);
//Re-enable buttons
if (!(m_btn_wsun->IsEnabled())) m_btn_wsun->Enable();
if (!(m_btn_wysun->IsEnabled())) m_btn_wsun->Enable();
//Start new thread
StartModbusThread();
}
else
{
//Show read error
if (!(m_static_txt_mberror_write->IsShown()))
{
if (!(m_static_txt_mberror_read->IsShown())) m_static_txt_mberror_read->Show();
}
//Disable buttons and menu items
if (m_btn_wsun->IsEnabled()) m_btn_wsun->Disable();
if (m_btn_wysun->IsEnabled()) m_btn_wysun->Disable();
//Reset button colours
if ((m_btn_wysun->GetBackgroundColour()) != wxColour(210, 210, 210)) m_btn_wysun->SetBackgroundColour(wxColour(210, 210, 210));
if ((m_btn_wsun->GetBackgroundColour()) != wxColour(210, 210, 210)) m_btn_wsun->SetBackgroundColour(wxColour(210, 210, 210));
}
evt.Skip();
}
void cMain::OnMenuClickedDiagnostics(wxCommandEvent& evt)
{
//Disable Diagnostics menu item
if (m_pToolsMenu->IsEnabled(wxID_VIEW_DETAILS)) m_pToolsMenu->Enable(wxID_VIEW_DETAILS, FALSE);
mbDiagnosticsEnabled = TRUE; //send command to Modbus helper thread
mbDiagnosticsOpenWindowEnabled = TRUE; //send command to Modbus helper thread (open window once data is available)
evt.Skip();
}
void cMain::OnMenuClickedInformation(wxCommandEvent& evt)
{
informationWindowIsOpen = TRUE;
if (m_pHelpMenu->IsEnabled(wxID_INFO)) m_pHelpMenu->Enable(wxID_INFO, FALSE);
m_frame_info = new cInformation(m_pHelpMenu, &informationWindowIsOpen);
m_frame_info->SetPosition(this->GetPosition());
m_frame_info->Show();
}
/* "Wsun" button callback */
void cMain::OnButtonClickedWsun(wxCommandEvent& evt)
{
if (m_btn_wysun->IsEnabled()) //only respond when other button has not been pressed
{
m_btn_wsun->Disable();
mbModeWriteCoil = 1; //set flag, event handled in Modbus thread
}
evt.Skip();
}
/* "Wysun" button callback */
void cMain::OnButtonClickedWysun(wxCommandEvent& evt)
{
if (m_btn_wsun->IsEnabled()) //only respond when other button has not been pressed
{
m_btn_wysun->Disable();
mbModeWriteCoil = 0; //set flag, event handled in Modbus thread
}
evt.Skip();
}
/* Start of Modbus helper thread */
void cMain::StartModbusThread()
{
if (CreateThread(wxTHREAD_JOINABLE) != wxTHREAD_NO_ERROR)
{
wxLogError("Could not create the worker thread!");
return;
}
if (GetThread()->Run() != wxTHREAD_NO_ERROR)
{
wxLogError("Could not run the worker thread!");
return;
}
}
/* Modbus helper thread */
wxThread::ExitCode cMain::Entry()
{
while (!GetThread()->TestDestroy())
{
{
//Enter critical section
wxCriticalSectionLocker lock(ModbusCS);
//Read input registers
mbStatusReadADC = modbus_read_input_registers(ctx, 3001, int(mbNumADCRegisters), mbADCRegisters);
mbADCErrorsRegister = mbADCRegisters[mbNumADCRegisters - 1];
wxThread::Sleep(20); //20ms delay
//Read diagnostics
if (mbDiagnosticsEnabled)
{
modbus_send_raw_request(ctx, mbDiagRawRequest, 6 * sizeof(uint8_t));
mbStatusReadDiagnostics = modbus_receive_raw_confirmation(ctx, mbDiagRawResponse);
wxThread::Sleep(20); //20ms delay
//Update diagnostics
if (mbStatusReadDiagnostics != -1)
{
for (uint8_t i = 0; i < mbNumDiagnostics; i++)
{
mbDiagnosticsRegister[i] = (uint16_t)mbDiagRawResponse[i * 2 + 4] << 8;
mbDiagnosticsRegister[i] |= (uint16_t)mbDiagRawResponse[i * 2 + 5];
}
}
}
//Reset diagnostics
if (mbDiagnosticsResetEnabled)
{
//Send diagnostics reset request
modbus_send_raw_request(ctx, mbDiagResetRawRequest, 6 * sizeof(uint8_t));
mbStatusResetDiagnostics = modbus_receive_raw_confirmation(ctx, mbDiagRawResponse);
wxThread::Sleep(20); //20ms delay
//Clear diagnostic register in preparation for new data
if (mbStatusResetDiagnostics != -1)
{
for (uint8_t i = 0; i < mbNumDiagnostics; i++)
{
mbDiagnosticsRegister[i] = 0;
}
}
//Clear reset flags
mbDiagnosticsResetting = FALSE;
mbDiagnosticsResetEnabled = FALSE;
}
//Write to coil
if (mbModeWriteCoil != -1)
{
mbStatusWriteCoil = modbus_write_bit(ctx, 1, mbModeWriteCoil);
wxThread::Sleep(20); //20ms delay
}
//Read configuration coil
mbStatusReadCoil = modbus_read_bits(ctx, 1, 1, &mbConfigurationCoil);
//Signal to main thread that new data has been received
wxQueueEvent(GetEventHandler(), new wxThreadEvent());
}
//Delay next Modbus message cycle by 200ms
wxThread::Sleep(mbScanRate);
}
//Destroy thread
return (wxThread::ExitCode)0;
}
/* Event handler for the Modbus helper thread */
void cMain::OnThreadUpdate(wxThreadEvent& evt)
{
//Enter critical section
wxCriticalSectionLocker lock(ModbusCS);
//Set button colors
if (mbStatusReadCoil != -1)
{
if (mbConfigurationCoil == 1)
{
if ((m_btn_wsun->GetBackgroundColour()) != wxColour(0, 210, 0)) m_btn_wsun->SetBackgroundColour(wxColour(0, 210, 0));
if ((m_btn_wysun->GetBackgroundColour()) != wxColour(210, 210, 210)) m_btn_wysun->SetBackgroundColour(wxColour(210, 210, 210));
}
else
{
if ((m_btn_wysun->GetBackgroundColour()) != wxColour(0, 210, 0)) m_btn_wysun->SetBackgroundColour(wxColour(0, 210, 0));
if ((m_btn_wsun->GetBackgroundColour()) != wxColour(210, 210, 210)) m_btn_wsun->SetBackgroundColour(wxColour(210, 210, 210));
}
}
//Handle holding register write errors
if (mbModeWriteCoil != -1)
{
if (mbStatusWriteCoil == -1)
{
//Show Modbus write error
m_static_txt_mberror_write->Show();
if (!(mbWriteErrorTimer->IsRunning())) mbWriteErrorTimer->Start(3000, wxTIMER_ONE_SHOT); //start error message timer
}
//If coil write is successful, reset flag, otherwise try again
if (mbModeWriteCoil == mbConfigurationCoil)
{
if (!(mbWriteTimer->IsRunning())) mbWriteTimer->Start(1250, wxTIMER_ONE_SHOT); //start button pressed timer
mbModeWriteCoil = -1;
}
}
//Open diagnostics window
if (mbDiagnosticsOpenWindowEnabled && !mbDiagnosticsWindowIsOpen)
{
m_frame_diag = new cDiagnostics(
&mbPortCharLength,
mbPort,
mbSlaveNum,
&mbDiagnosticsWindowIsOpen,
&mbDiagnosticsEnabled,
&mbDiagnosticsResetEnabled,
&mbDiagnosticsResetting,
&mbStatusReadDiagnostics,
&mbStatusResetDiagnostics,
mbDiagnosticsRegister,
&mbADCErrorsRegister,
m_pToolsMenu);
m_frame_diag->SetPosition(this->GetPosition());
m_frame_diag->Show();
mbDiagnosticsOpenWindowEnabled = FALSE;
}
if (mbStatusReadADC == -1)
{
//Reset button colours
if ((m_btn_wysun->GetBackgroundColour()) != wxColour(210, 210, 210)) m_btn_wysun->SetBackgroundColour(wxColour(210, 210, 210));
if ((m_btn_wsun->GetBackgroundColour()) != wxColour(210, 210, 210)) m_btn_wsun->SetBackgroundColour(wxColour(210, 210, 210));
if (mbDiagnosticsWindowIsOpen)
{
//Disable Diagnostics menu item
if (m_pToolsMenu->IsEnabled(wxID_VIEW_DETAILS)) m_pToolsMenu->Enable(wxID_VIEW_DETAILS, FALSE);
}
//Show read error
if (!(m_static_txt_mberror_write->IsShown()))
{
if (!(m_static_txt_mberror_read->IsShown())) m_static_txt_mberror_read->Show();
}
//Disable buttons
if (m_btn_wsun->IsEnabled()) m_btn_wsun->Disable();
if (m_btn_wysun->IsEnabled()) m_btn_wysun->Disable();
//Update static text
m_static_txt_adc1->SetLabel(wxT("N/A"));
m_static_txt_adc2->SetLabel(wxT("N/A"));
m_static_txt_adc3->SetLabel(wxT("N/A"));
m_static_txt_adc4->SetLabel(wxT("N/A"));
//Enable "connect" menu item
if (!(m_pToolsMenu->IsEnabled(wxID_NETWORK))) m_pToolsMenu->Enable(wxID_NETWORK, TRUE);
}
else if (mbADCErrorsRegister != 0)
{
//Hide error
if (m_static_txt_mberror_read->IsShown()) m_static_txt_mberror_read->Hide();
//Disable "connect" menu item
if (m_pToolsMenu->IsEnabled(wxID_NETWORK)) m_pToolsMenu->Enable(wxID_NETWORK, FALSE);
//Enable buttons
if (!(mbWriteTimer->IsRunning()) && mbModeWriteCoil == -1)
{
if (!(m_btn_wsun->IsEnabled())) m_btn_wsun->Enable();
if (!(m_btn_wysun->IsEnabled())) m_btn_wysun->Enable();
}
//Update static text
wxString adc1_label = ((mbADCErrorsRegister >> 0) & 0x0001) ? wxT("N/A") : wxT("" + std::to_string(mbADCRegisters[0]));
wxString adc2_label = ((mbADCErrorsRegister >> 1) & 0x0001) ? wxT("N/A") : wxT("" + std::to_string(mbADCRegisters[1]));
wxString adc3_label = ((mbADCErrorsRegister >> 2) & 0x0001) ? wxT("N/A") : wxT("" + std::to_string(mbADCRegisters[2]));
wxString adc4_label = ((mbADCErrorsRegister >> 3) & 0x0001) ? wxT("N/A") : wxT("" + std::to_string(mbADCRegisters[3]));
m_static_txt_adc1->SetLabel(adc1_label);
m_static_txt_adc2->SetLabel(adc2_label);
m_static_txt_adc3->SetLabel(adc3_label);
m_static_txt_adc4->SetLabel(adc4_label);
}
else
{
if (!mbDiagnosticsWindowIsOpen)
{
//Disable Diagnostics menu item
if (!(m_pToolsMenu->IsEnabled(wxID_VIEW_DETAILS))) m_pToolsMenu->Enable(wxID_VIEW_DETAILS, FALSE);
}
//Hide error
if (m_static_txt_mberror_read->IsShown()) m_static_txt_mberror_read->Hide();
//Disable "connect" menu item
if (m_pToolsMenu->IsEnabled(wxID_NETWORK)) m_pToolsMenu->Enable(wxID_NETWORK, FALSE);
//Enable buttons
if (!(mbWriteTimer->IsRunning()) && mbModeWriteCoil == -1)
{
if (!(m_btn_wsun->IsEnabled())) m_btn_wsun->Enable();
if (!(m_btn_wysun->IsEnabled())) m_btn_wysun->Enable();
}
//Update static text
m_static_txt_adc1->SetLabel(wxT("" + std::to_string(mbADCRegisters[0])));
m_static_txt_adc2->SetLabel(wxT("" + std::to_string(mbADCRegisters[1])));
m_static_txt_adc3->SetLabel(wxT("" + std::to_string(mbADCRegisters[2])));
m_static_txt_adc4->SetLabel(wxT("" + std::to_string(mbADCRegisters[3])));
}
}
/* Timer event - write to configuration coil */
void cMain::OnWriteTimer(wxTimerEvent& evt)
{
//Re-enable buttons
if (!(m_btn_wsun->IsEnabled())) m_btn_wsun->Enable();
if (!(m_btn_wysun->IsEnabled())) m_btn_wysun->Enable();
}
/* Timer event - write to configuration coil error message*/
void cMain::OnWriteErrorTimer(wxTimerEvent& evt)
{
//Hide Modbus write error
if (m_static_txt_mberror_write->IsShown()) m_static_txt_mberror_write->Hide();
}
/* Frame closed - Modbus thread destruction */
void cMain::OnClose(wxCloseEvent&)
{
//Close diagnostics window and delete diagnostics thread
if (mbDiagnosticsWindowIsOpen)
{
m_frame_diag->GetThread()->Delete();
m_frame_diag->Close();
}
//Close information window
if (informationWindowIsOpen)
{
m_frame_info->Close();
}
//Check if thread exists and is running
if (GetThread() && GetThread()->IsRunning())
{
GetThread()->Delete();
}
//Close Modbus connection and free resources
modbus_close(ctx);
modbus_free(ctx);
Destroy();
}
/* Frame closed from menu - Modbus thread destruction */
void cMain::OnMenuClickedExit(wxCommandEvent& evt)
{
//Close diagnostics window and delete diagnostics thread
if (mbDiagnosticsWindowIsOpen)
{
m_frame_diag->GetThread()->Delete();
m_frame_diag->Close();
}
//Close information window
if (informationWindowIsOpen)
{
m_frame_info->Close();
}
//Check if thread exists and is running
if (GetThread() && GetThread()->IsRunning())
{
GetThread()->Delete();
}
//Close Modbus connection and free resources
modbus_close(ctx);
modbus_free(ctx);
Destroy();
}
Regards,
Ksawery
- Attachments
-
- Annotation 2019-08-07 111643.jpg (39.82 KiB) Viewed 707 times
Re: Exception thrown when closing window
I added the following lines of code to disable all timers when closing the window, and the issue seems to have disappeared:
I don't know whether that is the correct solution to the problem, so I'm not marking this as solved yet.
Regards,
Ksawery
Code: Select all
//Stop any running timers
if (mbWriteTimer->IsRunning()) mbWriteTimer->Stop();
if (mbWriteErrorTimer->IsRunning()) mbWriteErrorTimer->Stop();
Regards,
Ksawery
Re: Exception thrown when closing window
Yes. Otherwise it's possible that the timer event handler gets called, but a control that is accessed is already destroyed.I added the following lines of code to disable all timers when closing the window, and the issue seems to have disappeared:
Use the source, Luke!