Using signals in Qt breaks DLL - c++

I'm running a simulation program in Visual Studio 2013 for which I wanted a simple GUI to output/input data.
Since I know some Qt I decided to write a small Qt5 program in Qt Creator, build it as a .dll and link this .dll in my program. The program then calls an initialization function to start the GUI.
Overall this works quite well. The GUI works just like a stand-alone Qt program would. However, once I added a custom signal to my Qt .dll like this:
//File.h
class MainGui : public QMainWindow
{
Q_OBJECT
public:
explicit MainGui(QWidget *parent = 0);
~MainGui();
signals:
void addItemSignal(QGraphicsView* it);
private slots:
void addItemImpl(QGraphicsView* it);
private:
Ui::MainGui *ui;
};
//File.cpp
void MainGui::addItemImpl(QGraphicsView *it)
{
//do anything
}
MainGui::MainGui(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainGui)
{
QObject::connect(this, &MainGui::addItemSignal,
this, &MainGui::addItemImpl);
}
MainGui::~MainGui()
{
delete ui;
}
I ended up getting the following error message when trying to start my main program:
The procedure entry point could not be located in the dynamic link library e:\...\...\MyQtLibrary.dll.
The two spaces between "point" and "could" are not a mistake - it seems like, for some reason, the entry point is not set to anything at all.
After some testing I discovered that the issue lies with using Qt classes within the signals. The following works fine:
//File.h
class MainGui : public QMainWindow
{
Q_OBJECT
public:
explicit MainGui(QWidget *parent = 0);
~MainGui();
signals:
void addItemSignal(void* it);
private slots:
void addItemImpl(void* it);
private:
Ui::MainGui *ui;
};
//File.cpp
void MainGui::addItemImpl(void*it)
{
//do anything
}
MainGui::MainGui(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainGui)
{
QObject::connect(this, &MainGui::addItemSignal,
this, &MainGui::addItemImpl);
}
MainGui::~MainGui()
{
delete ui;
}
This doesn't just affect custom signals but built-in ones too:
QObject::connect(models, &QStandardItemModel::dataChanged,[this](a b, x y){
//do something
});
This breaks the .dll as well.
I also noticed that I had to completely rebuild the .dll in Qt Creator to fix the problem. Removing any problematic signals and just building didn't fix the issue.
The error only happens when the Qt .dll is built in Debug configuration. Release config works well. Whether the MSVC program is Debug or Release seems to have no effect. I haven't changed any of the default settings for either of those configurations (other than a few things that definitely have nothing to do with it).
The only difference I found in Qt Creator between the two configurations is the call of qmake:
qmake.exe "D:\Dev\Qt Workspace\ArduGui\ArduGui.pro" -r -spec win32-msvc2013 "CONFIG+=debug" "CONFIG+=qml_debug"
This is the call for the Debug configuration. In Release the two debug config flags are missing. But when I messed around with the qmake arguments the result did not change. Debug config would always cause the entry point error, regardless of the presence of CONFIG+=debug or CONFIG+=qml_debug. Likewise, Release would always work even if the two flags are added.
So at this point I'm running against a wall. Does anyone have experience with this or can suggest options on how to debug the problem?
Some more info:
I'm using Windows 10, MSVC 2013 and Qt Creator 3.6 with Qt 5.5.1. Both the .exe and .dll are compiled with the MSVC++ 12.0 compiler through their respective IDEs.

If it works fine with void* but doesn't work with QT class pointer passed as argument, I guess you have not registered the class to be able to use it in signal/slot mechanism:
qRegisterMetaType<QGraphicsView *>("QGraphicsView*");
Be sure to call this function before your first use of this signal.
Though I'm not sure this is the cause of all your issues.

Related

How to solve the "no Qt platform plugin could be initialized" problem?

I'm trying to run a simple template in release mode on Visual Studio with the Qt extension. So far I've always been running projects in debug mode (never had trouble). Recently, I started with a browser application using webengine its widgets, but it's very slow on debug mode, so. I wanted to make sure it's possible to run with higher performance (on release mode), before continuing.
I was surprised, because the application throws 4 error message pop-ups after each other after trying to run it:
The procedure entry point ?endl#QTextStreamFunctions##YAAEAVQTextStream##AEAV2##Z could not be located in the dynamic link library C:\Qt\5.14.1\msvc2017_64\bin\Qt5WebChannel.dll.
The procedure entry point ?argToQString#QQtPrivate...QString...QStringView... could not be located in the dynamic link library C:\Qt\5.14.1\msvc2017_64\bin\Qt5WebChannel.dll.
Two more similar ones for QDebug and QRhiDepthStencilClearValue.
So instead, I tried to compile a simple project (the direct QtWidgetsApplication template) and it gave me this:
This application failed to start because no Qt Platform plugin could be initialized. Reinstalling the application may fix this problem.
I've been looking for a solution for quite some time now, but I didn't find a clear answer.
My directory: C:\Qt\5.14.1\msvc2017_64
My template code:
#include "QtWidgetsApplication2.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtWidgetsApplication2 w;
w.show();
return a.exec();
}
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication2.h"
class QtWidgetsApplication2 : public QMainWindow
{
Q_OBJECT
public:
QtWidgetsApplication2(QWidget *parent = Q_NULLPTR);
private:
Ui::QtWidgetsApplication2Class ui;
};
#include "QtWidgetsApplication2.h"
QtWidgetsApplication2::QtWidgetsApplication2(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
I have no clue of how to fix this problem. Could you please help me out? Thanks in advance!
See if this helps.
Are you trying to start the program by double clicking the .exe ?
I tried to reproduce it:
build a simple project in release mode
run windeployqt ... and delete the generated folder ./platforms
double click on .exe to run it.
and prompts the error message you got.

Cannot open source file "ui_QtGuiApplication.h" in default Qt project

I installed the latest QT version and the QT tool for Visual Studio. When creating a new GUI project in Qt, the default program should create an empty window, but it seems that I'm getting an E1696 error in Visual Studio Community: "cannot open source file "ui_QtGuiApplication4.h".
The error takes place in the default header class created for the project:
#include <QtWidgets/QMainWindow>
#include "ui_QtGuiApplication4.h"
class QtGuiApplication4 : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication4(QWidget *parent = Q_NULLPTR);
private:
Ui::QtGuiApplication4Class ui;
};
The Ui tag is also not recognized.
I added the additional include directiories for the QT path and I tried switching up between the 64bit and 32bit version of QT, but I'm getting the same error.
Any help would be appreciated!
The ui_<YourClass>.h header file is a file that only gets generated for you when you compile your project. Qt's User Interface Compiler uic will read your .ui file(s) and create the corresponding ui_ headers before the actual C++ compiler is invoked.
So you have to give it at least one compile run to generate the file. Then your IDE should be smart enough to find it.
FYI: Using QtCreator 4.12 you won't even have to compile. The clang backend process will generate the file in a temp folder somewhere probably to give you the proper code inspections (regarding code completion and so on). As I read from your question you're using Visual Studio which doesn't seem to do that.

Issue with Qt button, I can't find it in UI

#include "DatacommAss1.h"
DatacommAss1::DatacommAss1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui->pushButton, SIGNAL(released()), this, SLOT(handleButton()));
}
void DatacommAss1::handleButton()
{
// change the text
ui->pushButton->setText("Ding Dong");
}
See my code above, I have a button in my ui file called pushButton, but I cannot access it.
I get and error on 'ui' that says "expression must have pointer type".
I'm new to Qt and have no idea how to fix this, any help is appreciated.
Try rebuilding your solution, that should work.
QtCreator sometimes "forget" to rerun qmake. Save all your files (especially .ui) and do Build -> Run QMake (or CMake depending on what you use).
That will regenerate cpp files for your UI. Try rebuilding the project after that.

Error linking Qt based app

We're using a really old version of Qt, 1.1, I think. Circa 2000. It's for in-house use only, so there's little concern to upgrade at this time. Program is built on Windows using Visual Studio 2005. I know very little of Qt, other than what I've been researching over the last couple days.
The (very basic) architecture is:
main() creates a QApplication instance.
main() also creates a pointer to a custom subclass of QWidget called Wizard.
Wizard creates a number of Controller objects, which are subclassed from QThread.
I am trying to implement a new class / thread, launched from main(), the purpose of which is to monitor a service and signal an action to be carried out in the Controller objects / threads.
My new class / Thread definition:
#include "qthread.h"
class ServiceMonitor : public QThread
{
Q_OBJECT
public:
ServiceMonitor(int p) : port(p) {}
~ServiceMonitor() {};
private:
void run();
void TerminateProgram();
signals:
void SomethingBadHappened();
private:
int port;
};
And in my cpp file:
void ServiceMonitor::TerminateProgram()
{
...
emit SomethingBadHappened();
...
}
When I compile the app, I receive a linker error:
error LNK2019: unresolved external symbol "protected: void __thiscall ServiceMonitor::SomethingBadHappened(void)"
(?SomethingBadHappened#ServiceMonitor##IAEXXZ) referenced in function "private: void __thiscall ServiceMonitor::TerminateProgram(void)"
(?TerminateProgram#ServiceMonitor##AAEXXZ) ServiceMonitor.obj
I notice that all of our other objects (which have signals) are not derived from Qthread, so I have no examples to follow. The rest (which do use signals) are derived from QWidget or QObject). I notice those use the moc.exe in a custom compile step to generate an output file which is included in the project. I did try to run moc on the header containing the class above and including the output file, where I received:
Error 1 error C2039: 'className' : is not a member of 'QThread'
Error 2 error C3861: 'badSuperclassWarning': identifier not found
Error 3 error C2039: 'staticMetaObject' : is not a member of 'QThread'
Error 4 error C3861: 'activate_signal': identifier not found
What am I doing wrong?
EDIT:
Tried RA's proposal, worked a treat (Once I remembered to include qobject.h). Thanks!
New definition:
#include "qthread.h"
#include "qobject.h"
class ServiceMonitor : public QObject, public QThread
...
For versions of Qt prior to Qt 4.0, the QThread class did not inherit from QObject. As such, if you want to create a class derived from QThread that has signals, you must inherit from both QObject and QThread:
#include "qobject.h"
#include "qthread.h"
class ServiceMonitor : public QObject, public QThread
{
Q_OBJECT
// Rest of class
};
Note that QObject must be listed as the first class derived from.
Also remember to run moc on the class and to compile the generated moc code.
The missing part is the implementation of all the signals, and of the staticMetaObject structure that's declared as part of Q_OBJECT macro. Those are generated by moc. Moc-ing of the headers would normally be handled by a Qt add-in for Visual Studio. Unfortunately, there are no Qt-5 add-ins for VS 2005.
Your options are, in order of decreasing desirability.
Use qmake to generate a VS 2005 project file that invokes moc for you, and includes the necessary files. That would be the best way for you to use Qt.
Manually run moc on all of the header files that contain the Q_OBJECT macro, and add the generated code to your project.
Upgrade to at least VS 2008 (not Express), so that you can use the Qt 5 add-in.
Try Qt 4, which has an add-in for VS 2005.
Since you can have multiple versions of Qt installed at the same time, you can pursue multiple approaches in parallel. For example, #1 and #4.

Qt Signals and Slots break when converting Visual C++ project to boost build makefile project

I created a Visual C++ Project using MSVS and I just made another project in MSVS so that the same code can be built using boost build. I can currently build my project using a Visual C++ project as well as a Makefile project that uses boost build.
There is a difference between the two builds though concerning QT Signals and Slots.For the following code,when I call MyThread::Start() the onTimeout() slot is called when the project is built in visual studio, but not called when built using boost build.
class MyThread: public QObject{
Q_OBJECT
public:
bool start();
public Q_SLOTS:
void onTimeout();
private:
QThread m_thread;
QTimer m_timer;
};
void MyThread::start()
{
m_timer.start(1000);
m_thread.setObjectName(QString("GigeControl"));
m_thread.start();
m_timer.moveToThread(&m_thread);
}
void MyThread::onTimeout()
{
//Do Stuff
}
I am really having a hard time trying to figure out the differences between the two
builds,especially since I need those signals and slots to work.
One major difference that I have noticed so far is that the Visual C++ project is built using /Zp1 so all structures are 1 byte alligned. This is not done in the boost project as I don't know how to. I've seen people on the internet mentioning that structure allignments (especially using #pragma pack can cause problems with QT).
If anyone has some experience they might be able to share it would be greatly appreciated.
It looks like the problem was in fact the structure packing. I am writing code for a couple of code bases that are being merged and there coincidentally happens to be some packing conflicts.
To fix the packing for building with boost-build all I had to to was add this to the lib being generated in the Jamfile:
lib foo
:
...
:
...
<target-os>linux:<cxxflags>-fpack-struct=1
<target-os>windows:<cxxflags>-Zp1
;
This worked for me so hopefully it will help someone else out if they get stuck here too