Solved Using signals/slots as callback to show the main window
-
@Charlie_Hdz There's nothing wrong with using connect in main. I've done it before in similar situations as he's facing. In fact to not do it there means he would have to couple 2 classes which don't need coupling. He would have to pass his MainWindow to LicenseManager in order to connect the display inside there. Not something I would recommend at all.
and do a catch to retain the processing of the application
If by this you mean he should do a
try { } catch (...) { }
to catch a potential crash then most definitely you should never do that. If you meant something else and I just misunderstood then ignore that. :) -
@ambershark said in Using signals/slots as callback to show the main window:
If by this you mean he should do a try { } catch (...) { } to catch a potential crash then most definitely you should never do that.
Why is that? Certainly in a debug phase of your development, since things don't work as you want, this can only be useful, or what am I missing?
-
@Diracsbracket No catching unhandled exceptions is bad for debugging. You want the exception to be thrown and the program to crash that way the debugger can catch it.
Sometimes coders will add a global catch all, i.e.
catch (...)
to their apps in order to "stop" crashes. However if you have an unhandled exception, catching it doesn't really make your program stable. It won't crash but it won't be usable either.Mostly a global catchall will be used to present the user with an interface to send a bug report to the developers and capture whatever data it can from the exception. But it should never be used to try to "stop a crash".
-
@ambershark
Why is that a problem if you usetry/catch
in the DEBUGGING phase of your development, and in thecatch
part output some debug info with qDebug() ? If it crashes, you will immediately know where. Then of course, you can use the debugger to find the problem, no? -
@Diracsbracket Well in debugging you can, but if you are going to debug you wouldn't really need the try/catch since you let the debugger catch the exception and backtrace from there.
To be clear I'm just talking about a catch all, i.e.
catch (...)
not catching specific exceptions. There is very little extra info you would get fromcatch (...)
that you could not get by just catching the exception in a debugger and actually debugging.I'm not say doing catch specific exceptions, but you never really want to do a catch all unless you have a really good reason.
Also if you catch an exception the debugger doesn't break into the code there. Which imo makes debugging much harder than not having a caught exception. Unless you did something like rethrowing the exception after you log whatever you wanted to.
I'm not saying never use that no matter what, I'm sure there's a place for it, but usually any information you wanted would be available in your debugger if you just let it catch the exception. However I am saying never use this in production code except in the case I mentioned above.
-
@ambershark Thank you for confirming that the application shouldn't close even if there is no open window. The code executes properly when I have a window open but stops executing when I don't open a window. The code is awaiting feedback from the server and otherwise is in a wait state. Please see code below:
LicenseManager::LicenseManager(QWidget *parent) : clientsideLicenseState(LMS_CHECK_LICENSE), serversideLicenseState(LSS_NONE), lms_awaiting_response_cnt(0) { // Start the state machine which will walk through the licensing process lmStateTimer = new QTimer(this); lmStateTimer->setSingleShot(false); lmStateTimer->setInterval( 100 ); connect( lmStateTimer, SIGNAL(timeout()), SLOT(lmHTTPStateMachine()) ); lmStateTimer->start(); machineID = new MachineIDGenerator(); } LicenseManager::~LicenseManager() { delete machineID; } void LicenseManager::quit() { lmStateTimer->stop(); } void LicenseManager::lmHTTPStateMachine() { QMessageBox* msgBox; LicenseManagerFormDialog* form = new LicenseManagerFormDialog(); if( clientsideLicenseState != LMS_AWAITING_RESPONSE ) lms_awaiting_response_cnt = 0; qDebug() << "In state machine function with " + QString::number( clientsideLicenseState ); switch( clientsideLicenseState ) { case LMS_CHECK_LICENSE: // Is there a license if( loadLicense() ) { // Is the license valid if( validateKey() ) { // Is the key still valid if( validateLicense() ) { clientsideLicenseState = LMS_KEY_VALIDATED; emit licenseValidated(); quit(); // Return if license is present and valid break; // If key is expired, will have to renew it } else clientsideLicenseState = LMS_KEY_EXPIRED; // If there is a key but it isn't valid, inform user of invalid key } else { clientsideLicenseState = LMS_KEY_NOT_VALID; QMessageBox* msgBox = new QMessageBox(); msgBox->setStandardButtons( QMessageBox::Ok ); msgBox->setText( "Your license is invalid. Try deleting your license and starting the application again. " ); msgBox->exec(); quit(); break; } } clientsideLicenseState = LMS_ACQUIRE_DATA; case LMS_ACQUIRE_DATA: if( ! form->exec() ) { // get user's email address quit(); break; } email = form->getEmail(); // Todo: Validate email provided clientsideLicenseState = LMS_REQUESTING_STATUS; // fall through case LMS_REQUESTING_STATUS: retrieveServersideLicenseState(); clientsideLicenseState = LMS_AWAITING_RESPONSE; break; case LMS_AWAITING_RESPONSE: if( ++lms_awaiting_response_cnt < 60 ) break; quit(); msgBox = new QMessageBox(); msgBox->setStandardButtons( QMessageBox::Ok ); msgBox->setText( "The license request has timed out. Please check your network connection and restart the application." ); msgBox->exec(); clientsideLicenseState = LMS_FAILED; break; ... } } void LicenseManager::retrieveServersideLicenseState() { QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); connect( networkManager, SIGNAL( finished(QNetworkReply*) ), this, SLOT(finishedServersideLicenseStateRequest(QNetworkReply*)) ); QString url = QString("http://licenses.addhaptics.com/license_manager.php?mode=status"); url += QString("&email=") + email.toUtf8(); url += QString("&uuid=") + machineID->getUuid()->toUtf8(); QNetworkRequest request; request.setUrl( QUrl( url ) ); request.setRawHeader("User-Agent", "HDS/1.0 (+haptics; Qt)"); request.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); networkManager->get( request ); // This may have to be a post } // Process response void LicenseManager::finishedServersideLicenseStateRequest( QNetworkReply* reply ) { qDebug() << "Getting status reply"; if( reply->error() ) { qDebug() << "Retrieve license failed " << reply->errorString(); return; } qDebug() << reply->header(QNetworkRequest::ContentTypeHeader).toString(); qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();; qDebug() << reply->header(QNetworkRequest::ContentLengthHeader).toULongLong(); qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); QString reason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString(); if( ! reason.compare( QString("none") ) ) clientsideLicenseState = LMS_NONE_AVAILABLE; else if( ! reason.compare( QString("requested") ) ) clientsideLicenseState = LMS_VERIFY_EMAIL; else if( ! reason.compare( QString("assigned") ) || ! reason.compare( QString("validated" ) ) ) { clientsideLicenseState = LMS_RETRIEVING_KEY; retrieveLicenseKey(); } else if( ! reason.compare( QString("expired") ) ) clientsideLicenseState = LMS_LICENSE_EXPIRED; else if( ! reason.compare( QString("available") ) ) clientsideLicenseState = LMS_ASK_REQUEST; emit licenseStatusReceived(); }
By stepping through the code, I know the status request gets sent out but I don't get into the response handler if no window is open. And the only debug output I get is:
"In state machine function with 0"
"In state machine function with 8"
I believe you when you say the application is crashing but I don't think it is happening in my code.I am getting the following warnings:
qt.network.ssl: QSslSocket: cannot resolve SSL_set_psk_client_callback
qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_client_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_client_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_server_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_server_method
qt.network.ssl: QSslSocket: cannot resolve SSL_select_next_proto
qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
qt.network.ssl: QSslSocket: cannot resolve SSL_get0_next_proto_negotiatedbut since I'm not using https I have been ignoring these.
Any ideas?
Thanks also for pointing out the memory leakage in my main.
-
@mgreenish So isn't the licensemanager a window? It derives from QWidget. Does it close while it's waiting for a response? It's more than likely not crashing.
I see multiple places where
quit()
is called. One of these could be called and quitting the application in an area you don't expect it. What is the enum for 8? I.e. what license mode is it in when it prints that during debugging? That could cause aquit()
to be called.When it is not functioning properly, is it still running? Or does the process go away?
Have you tried setting
setQuitOnLastWindowClosed(false)
just to test and see if it's closing?I don't see any code that shows
LicenseManager
either. Is it really a QWidget? -
@ambershark So the QuiteOnLastWindowClosed seemed to be the problem. I added
a.setQuitOnLastWindowClosed(false);
and now it no longer closes.
Thanks to everyone for the help!!
-
@mgreenish If your problem is solved, couldl you please mark your post accordingly? thanks.
-
@mgreenish Just keep in mind you have to call quit() now when your mainwindow closes or your app will continue running after you think it's done.
Just make sure it's actually closing now when you expect it to and not staying hidden and running in the background.