I have a C++/Qt application which loads a plugin (.dll/.so) using QPluginLoader facilities.
This plugin is basically an embedded python interpreter which allows to inspect Qt objects in the main application via the PyQt4 module.
Problem is the command PyQt4.QtCore.QCoreApplication.instance(), executed from the plugged-in python interpreter, returns None even though the QCoreApplication instance has been created by the C++ application.
This is only on windows in debug mode.
On linux or on release mode on windows, the command PyQt4.QtCore.QCoreApplication.instance() correctly returns the QCoreApplication instance that was created by the C++ application.
Following is some minimalist code showing the problem.
When compiled in release mode:
$ ./a.out
1+1
2
import PyQt4
import PyQt4.QtCore
PyQt4.QtCore.QCoreApplication.instance()
<PyQt4.QtCore.QCoreApplication object at 0x00C69198>
=> Ok
When compiled in debug mode:
$ ./a.out
import PyQt4
import PyQt4.QtCore
PyQt4.QtCore.QCoreApplication.instance()
=> Not ok (returned None)
File main.cpp
#include <QCoreApplication>
#include <QPluginLoader>
#include <QDebug>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QPluginLoader loader("plugin.dll");
loader.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);
loader.load();
if(!loader.isLoaded()) {
qDebug() << loader.errorString();
return 1;
}
(void)loader.instance();
return app.exec();
}
File plugin.h
#ifndef PLUGIN_H
#define PLUGIN_H
#include <QObject>
#include <Python.h>
class Plugin : public QObject
{
public:
Plugin();
~Plugin();
private:
PyThreadState *m_ts;
};
class InterpInput : public QObject
{
Q_OBJECT
public:
InterpInput(QObject *parent = 0) : QObject(parent) { }
public slots:
void monitorInput();
signals:
void done();
void inputReady();
};
class InterpOutput : public QObject
{
Q_OBJECT
public:
InterpOutput(QObject *parent = 0) : QObject(parent) { }
public slots:
void processLine();
public:
PyThreadState *m_ts;
};
#endif
File plugin.cpp
#include "plugin.h"
#include <QCoreApplication>
#include <QThread>
#include <QtPlugin>
#include <QPluginLoader>
Q_EXPORT_PLUGIN2(Plugin, Plugin)
Plugin::Plugin()
{
Py_Initialize();
PyEval_InitThreads();
InterpInput *in = new InterpInput();
InterpOutput *out = new InterpOutput(this);
in->connect(in, SIGNAL(inputReady()), out, SLOT(processLine()));
in->connect(in, SIGNAL(done()), QCoreApplication::instance(), SLOT(quit()));
QThread *thr = new QThread(this);
in->moveToThread(thr);
thr->connect(thr, SIGNAL(started()), in, SLOT(monitorInput()));
m_ts = PyEval_SaveThread();
out->m_ts = m_ts;
thr->start();
}
Plugin::~Plugin()
{
PyEval_RestoreThread(m_ts);
Py_Finalize();
}
void InterpInput::monitorInput()
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
int ret = PyRun_SimpleString("import sys\nimport code\nic = code.InteractiveConsole()");
assert(ret == 0);
while(true) {
ret = PyRun_SimpleString("line = ic.raw_input()");
if(ret) { break; }
inputReady();
}
done();
PyGILState_Release(gstate);
}
void InterpOutput::processLine()
{
PyEval_RestoreThread(m_ts);
int ret = PyRun_SimpleString("ic.push(line)");
PyRun_SimpleString("sys.stdout.flush()");
PyRun_SimpleString("sys.stderr.flush()");
(void)PyEval_SaveThread();
assert(ret == 0);
}
File Makefile
MOC=/cygdrive/c/Qt/4.8.4/bin/moc
GCC=/cygdrive/c/MinGW/bin/mingw32-g++.exe
FLAGS=-Ic:/Qt/4.8.4/include -Ic:/Qt/4.8.4/include/QtCore -Lc:/Qt/4.8.4/lib -Lc:/Qt/4.8.4/bin -lQtCore4 -Lc:/Python27/libs -lpython27 -Ic:/Python27/include -DQT_NO_DEBUG
#FLAGS=-Ic:/Qt/4.8.4/include -Ic:/Qt/4.8.4/include/QtCore -Lc:/Qt/4.8.4/bin -lQtCored4 -Lc:/Python27/libs -lpython27 -Ic:/Python27/include -g
LIBFLAGS=-shared
all:
$(MOC) plugin.h > plugin_moc.cpp
$(GCC) -o a.out main.cpp $(FLAGS)
$(GCC) -o plugin.dll $(LIBFLAGS) plugin.cpp plugin_moc.cpp $(FLAGS)
The explanation is the following.
In debug version, the C++ application and plugin link to debug Qt libraries (QtCored4.dll, etc.)
Whereas the installed PyQt4 modules (QtCore.pyd, etc.) link to release Qt libraries (QtCore4.dll, etc.)
It follows that the C++ application, and the PyQt4 module, each see a QCoreApplication instance but each see a different one, which lives in a different library (respectively the debug, and the release, version of the Qt library).
It follows that the instance living in the PyQt4 module is not initialized when the C++ application is initialized, and is thus null.
This is verified by compiling the PyQt4 modules specifying that they should be linked to the debug Qt libraries: the problem then disappears as the debug-mode C++ application and the PyQt4 modules link to the same Qt library.
Related
I apologize for the somewhat lengthy discussion. Also, this is my first submission to StackOverflow, so please forgive my unfamiliarity.
I usually use C++/Qt Widget or C++/QML with Linux. This time, I need to create or write files with root privileges, and I am using the following URL (PolKit-Qt-1) to create and test my own C++/Qt Widget software.
https://api.kde.org/polkit-qt-1/html/
I am using polkit-qt-gui-1 to create software (C++/Qt) to create and write files with root privileges when a button is pressed.
However, a permission error occurs because the file cannot be created or written as root, but has been created or written as the executing user.
Perhaps there is a mistake in some configuration file, or there is a missing or incorrect part of the source code.
I want to create or write a file with root privileges when a button is pressed. How do I create or write files with root privileges using C++/Qt and PolKit-Qt-1?
Thank you for your cooperation.
My own source code is shown below. The action file for polkit-1 is also shown below.
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
PolkitQt1::Gui::ActionButton *bt = new PolkitQt1::Gui::ActionButton(ui->pushButton, "org.qt.policykit.examples.write", this);
bt->setText("Run with administrative privileges");
bt->setVisible(true, PolkitQt1::Gui::Action::No | PolkitQt1::Gui::Action::Auth | PolkitQt1::Gui::Action::Yes);
bt->setEnabled(true, PolkitQt1::Gui::Action::No | PolkitQt1::Gui::Action::Auth | PolkitQt1::Gui::Action::Yes);
connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
connect(bt, SIGNAL(authorized()), this, SLOT(onBtnClicked()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::activateAction()
{
PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());
action->activate();
}
void MainWindow::onBtnClicked()
{
PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());
qDebug() << "pretending to be the mechanism for action:" << action->actionId();
PolkitQt1::UnixProcessSubject subject(static_cast<uint>(QCoreApplication::applicationPid()));
PolkitQt1::Authority::Result result = PolkitQt1::Authority::instance()->checkAuthorizationSync(action->actionId(), subject, PolkitQt1::Authority::AllowUserInteraction);
if (result == PolkitQt1::Authority::Yes)
{
// Write /opt/sample.txt file with root privilege.
writeTextFile("/opt/sample.txt", "foo bar");
}
else
{
return;
}
return;
}
void MainWindow::writeTextFile(QString FileName, QString strOutputData)
{
QFileInfo FileInfo(FileName);
QFile File(FileName);
if(!File.open(QIODevice::WriteOnly))
{
QString strErrMsg = "File(" + FileInfo.fileName() + ") Open Error: " + File.errorString();
qDebug() << strErrMsg;
return;
}
QTextStream OutStream(&File);
OutStream << strOutputData;
File.close();
return;
}
mainwindow.h:
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDBusContext>
#include <QDBusMessage>
#include <QDBusConnection>
#include <polkit-qt5-1/polkitqt1-gui-action.h>
#include <polkit-qt5-1/polkitqt1-gui-actionbutton.h>
#include <polkit-qt5-1/polkitqt1-gui-actionbuttons.h>
#include <polkit-qt5-1/polkitqt1-authority.h>
#include <dbus/dbus.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow, protected QDBusContext
{
Q_OBJECT
private:
void writeTextFile(QString FileName, QString strOutputData);
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
private Q_SLOTS:
void activateAction();
void onBtnClicked();
};
#endif // MAINWINDOW_H
/usr/share/polkit-1/actions/org.qt.policykit.examples.policy:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE policyconfig PUBLIC '-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN' 'http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd'>
<policyconfig>
<vendor>KDE</vendor>
<vendor_url>http://www.kde.org</vendor_url>
<action id="org.qt.policykit.examples.write">
<description>Write</description>
<message>Prevents PolKit-Qt-1 example from writing</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
</policyconfig>
Sorry for the long wait.
After much trial and error, the following source code allows the program to run with administrative privilege (root) only when a specific button is pressed.
Please forgive the somewhat lengthy post.
Main executable
Main executable is GUI software that sends D-Bus messages by pressing a button.
main.cpp:
main.cpp has the same source code as above.
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onAuthBtnClicked()
{
QDBusConnection bus = QDBusConnection::systemBus();
if (!bus.isConnected())
{
QMessageBox(QMessageBox::Critical, tr("D-Bus error"), tr("Cannot connect to the D-Bus session bus."), QMessageBox::Close, this).exec();
}
// this is our Special Action that after allowed will call the helper
QDBusMessage message;
message = QDBusMessage::createMethodCall("org.qt.policykit.examples", "/", "org.qt.policykit.examples", QLatin1String("write"));
// If a method in a helper file has arguments, enter the arguments.
//QList<QVariant> ArgsToHelper;
//ArgsToHelper << QVariant::fromValue("foo") << QVariant::fromValue("bar");
//message.setArguments(ArgsToHelper);
// Send a message to DBus. (Execute the helper file.)
QDBusMessage reply = QDBusConnection::systemBus().call(message);
// Receive the return value (including arguments) from the helper file.
// The methods in the helper file have two arguments, so check them.
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().size() == 2)
{
// the reply can be anything, here we receive a bool
if (reply.arguments().at(0).toInt() == 0)
{ // If the helper file method completes successfully after successful authentication
QMessageBox(QMessageBox::NoIcon, tr("Successed"), tr("The file was written successfully."), QMessageBox::Close, this).exec();
}
else if (reply.arguments().at(0).toInt() == -1)
{ // If the helper file method fails after successful authentication
QString strErrMsg = reply.arguments().at(1).toString();
QMessageBox(QMessageBox::Critical, tr("Failed"), tr("Failed to write file.\n") + strErrMsg, QMessageBox::Close, this).exec();
}
else
{ // If the authentication is canceled
QMessageBox(QMessageBox::NoIcon, tr("Cancelled"), tr("Writing of the file was canceled."), QMessageBox::Close, this).exec();
}
}
else if (reply.type() == QDBusMessage::MethodCallMessage)
{
QMessageBox(QMessageBox::Warning, tr("Time out"), tr("Message did not receive a reply (timeout by message bus)."), QMessageBox::Close, this).exec();
}
else if (reply.type() == QDBusMessage::ErrorMessage)
{
QMessageBox(QMessageBox::Critical, tr("D-Bus error"), tr("Could not send message to D-Bus."), QMessageBox::Close, this).exec();
}
return;
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QtGui>
#include <QDBusContext>
#include <QDBusMessage>
#include <QDBusConnection>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public: // Public Functions
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private: // Private Variables
Ui::MainWindow *ui;
private Q_SLOTS:
void onAuthBtnClicked();
};
#endif // MAINWINDOW_H
Helper executable
Helper executable is software that receives messages from D-Bus and creates files with root privileges.
main.cpp:
#include <QCoreApplication>
#include "SampleHelper.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SampleHelper sample(argc, argv);
return a.exec();
}
SampleHelper.cpp:
#include <QTimer>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include "SampleHelper.h"
#include "SampleAdaptor.h"
#define MINUTE 30000
SampleHelper::SampleHelper(int &argc, char **argv) : QCoreApplication(argc, argv)
{
(void) new SampleAdaptor(this);
// Register the DBus service
if (!QDBusConnection::systemBus().registerService("org.qt.policykit.examples"))
{
QTextStream ErrStream(stderr);
ErrStream << QDBusConnection::systemBus().lastError().message();
QTimer::singleShot(0, this, SLOT(quit()));
return;
}
if (!QDBusConnection::systemBus().registerObject("/", this))
{
QTextStream ErrStream(stderr);
ErrStream << "unable to register service interface to dbus";
QTimer::singleShot(0, this, SLOT(quit()));
return;
}
// Normally you will set a timeout so your application can
// free some resources of the poor client machine ;)
QTimer::singleShot(MINUTE, this, SLOT(quit()));
}
SampleHelper::~SampleHelper()
{
}
int SampleHelper::write(QString &strErrMsg)
{
// message().service() is the service name of the caller
// We can check if the caller is authorized to the following action
PolkitQt1::Authority::Result result;
PolkitQt1::SystemBusNameSubject subject(message().service());
result = PolkitQt1::Authority::instance()->checkAuthorizationSync("org.qt.policykit.examples.write", subject , PolkitQt1::Authority::AllowUserInteraction);
if (result == PolkitQt1::Authority::Yes)
{ // Caller is authorized so we can perform the action
return writeValue(strErrMsg);
}
else
{ // Caller is not authorized so the action can't be performed
return 1;
}
}
int SampleHelper::writeValue(QString &strErrMsg)
{
// This action must be authorized first. It will set the implicit
// authorization for the Shout action by editing the .policy file
try
{
QFileInfo FileInfo("/opt/sample.txt");
QFile File("/opt/sample.txt");
if(!File.open(QIODevice::WriteOnly))
{
strErrMsg = "File(" + FileInfo.fileName() + ") Open Error: " + File.errorString();
return -1;
}
QDateTime current_date_time =QDateTime::currentDateTime();
QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
QTextStream OutStream(&File);
OutStream << current_date;
File.close();
}
catch (QException &err)
{
strErrMsg = err.what();
}
return 0;
}
SampleHelper.h:
#ifndef SAMPLE_HELPER_H
#define SAMPLE_HELPER_H
#include <QDBusConnection>
#include <QDBusContext>
#include <QDBusMessage>
#include <QCoreApplication>
#include <polkit-qt5-1/polkitqt1-authority.h>
class SampleHelper : public QCoreApplication, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qt.policykit.examples")
private:
int writeValue(QString &strErrMsg);
public:
SampleHelper(int &argc, char **argv);
~SampleHelper() override;
public Q_SLOTS:
int write(QString &strErrMsg);
};
#endif
Execute the qdbusxml2cpp command (using the D-Bus interface file at this time) to generate the adapter source code file and header files for the helper.
qdbusxml2cpp -a SampleAdaptor -c SampleAdaptor -i SampleHelper.h -l SampleHelper org.qt.policykit.examples.xml
In this example, SampleAdaptor.cpp and SampleAdaptor.h are generated.
Add this file to the helper executable's project.
If this is done automatically :
Qt .pro file, the following commands were written.
system(qdbusxml2cpp -a SampleAdaptor -c SampleAdaptor -i SampleHelper.h -l SampleHelper org.qt.policykit.examples.xml)
CMake file, the following commands were written.
qt_add_dbus_adaptor(
SampleAdaptor_SRC
org.qt.policykit.examples.xml
SampleHelper.h
SampleHelper
SampleAdaptor
SampleAdaptor
)
Create Polkit policy file
/usr/share/polkit-1/actions/org.qt.policykit.examples.policy:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE policyconfig PUBLIC '-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN' 'http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd'>
<policyconfig>
<vendor>presire</vendor>
<vendor_url></vendor_url>
<action id="org.qt.policykit.examples.write">
<description>Write</description>
<message>Prevents PolKit-Qt-1 example from writing</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
</action>
</policyconfig>
Create D-Bus configuration files
/usr/share/dbus-1/interfaces/org.qt.policykit.examples.xml:
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.qt.policykit.examples">
<method name="write" >
<!-- OUT: whether the user gained the authorization -->
<arg direction="out" type="i" name="code" />
<arg direction="out" type="s" name="msg" />
</method>
</interface>
</node>
/usr/share/dbus-1/system-services/org.qt.policykit.examples.service:
[D-BUS Service]
Name=org.qt.policykit.examples
Exec=/<Path>/<to>/<Helper executable file>
User=root
/etc/dbus-1/system-local.conf:
or
/etc/dbus-1/system.d/org.qt.policykit.examples.conf:
or
/usr/share/dbus-1/system.d/org.qt.policykit.examples.conf:
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- This configuration file specifies the required security policies
for the PolicyKit examples to work. -->
<!-- Only user root can own the PackageKit service -->
<policy user="root">
<allow own="org.qt.policykit.examples"/>
</policy>
<!-- Allow anyone to call into the service - we'll reject callers using PolicyKit -->
<policy context="default">
<allow send_destination="org.qt.policykit.examples"/>
</policy>
</busconfig>
This is a Qt program. I am trying to run gcc command and get the result using _popen(on Windows). However, I get no output.
After debugging, I find that gcc command runs ok.
void editor::on_action_Compile_triggered()
{
QString str = "gcc \""+curFile+"\" -o \""+outputFile+"\" 2>&1"; //compile curFile
FILE *fp = _popen(str.toStdString().data(),"r");
if (!fp)
{
ui->Log->setText("Error."); //Log is a text browser
}
else
{
QString tmpStr = "";
char tmp[1024] = { 0 };
while (fgets(tmp, 1024, fp) != NULL) //read fp
tmpStr += (QString)tmp;
ui->Log->setText(tmpStr); //print to screen
}
_pclose(fp);
}
According to me, you are not having a problem. Your above code is working for me (as long as I declare a correct curfile and outputFile). You are not having an ouput because gcc has successfully compiled the file. You may want to verify if the file called outputFile has been produced. Indeed, when gcc succeeds, it does not ouput anything.
Otherwise, you might be having a problem with your signal/slot connexion which does not trigger the slot on_action_Compile_triggered(then please read on the complete code provided below)
To test it try to modify your curFile to point to an inexisting file and you will get an ouput error typical of gcc.
To check this, as for me, I created a QmainWindow with a QPushButton button (called pushbutton) and a QtextEdit (called Log). I provide my complete code below.
When I have an error (for instance the compiled file is not found. to emulate this, rename your curFile into a wrong file), I obtain this (using your code above).
When I do not have any error, I obtain nothing in the QTextEditcontrol but the outputFile executable file is produced by gcc in the directory:
Here is my code:
// QMainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void compile();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
// QMainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::compile);
}
MainWindow::~MainWindow()
{
QObject::disconnect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::compile);
delete ui;
}
void MainWindow::compile()
{
QString curFile("..\\..\\T0180694\\test.c");
QString outputFile("..\\..\\T0180694\\test.exe");
//copied all from your code
QString str = "gcc \""+curFile+"\" -o \""+outputFile+"\" 2>&1"; //compile curFile
FILE *fp = _popen(str.toStdString().data(),"r");
if (!fp)
{
ui->Log->setText("Error."); //Log is a text browser
}
else
{
QString tmpStr = "";
char tmp[1024] = { 0 };
while (fgets(tmp, 1024, fp) != NULL) //read fp
tmpStr += (QString)tmp;
ui->Log->setText(tmpStr); //print to screen
}
_pclose(fp);
//until here
}
//main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I can't figure out how to link FTDI library in my Qt project. I copied ftd2xx.h file to my project directory. The file I want to link is dll: ftd2xx.lib which is stored in F:\Workspace\qt\libs\ftdi\amd64
I get error:
release/testftdi.o:testftdi.cpp:(.text+0x6f8): undefined reference to `_imp__FT_Open#8'
collect2.exe: error: ld returned 1 exit status
I have QtWidget application with one PushButton:
TestFtdi.pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = TestFtdi
TEMPLATE = app
LIBS += -L"F:\Workspace\qt\libs\ftdi\amd64" -lftd2xx
INCLUDEPATH += f:/Workspace/qt/libs/ftdi/amd64
SOURCES += main.cpp\
testftdi.cpp
HEADERS += testftdi.h
FORMS += testftdi.ui
main.cpp file:
#include "testftdi.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestFtdi w;
w.show();
return a.exec();
}
testftdi.h file:
#ifndef TESTFTDI_H
#define TESTFTDI_H
#include <QMainWindow>
namespace Ui {
class TestFtdi;
}
class TestFtdi : public QMainWindow
{
Q_OBJECT
public:
explicit TestFtdi(QWidget *parent = 0);
~TestFtdi();
private slots:
void on_pushButton_clicked();
private:
Ui::TestFtdi *ui;
};
#endif // TESTFTDI_H
testftdi.cpp file:
#include "testftdi.h"
#include "ui_testftdi.h"
#include <QDebug>
#include "windows.h"
#include "ftd2xx.h"
TestFtdi::TestFtdi(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TestFtdi)
{
ui->setupUi(this);
}
TestFtdi::~TestFtdi()
{
delete ui;
}
void TestFtdi::on_pushButton_clicked()
{
FT_HANDLE ftHandle;
FT_STATUS ftStatus;
ftStatus = FT_Open(0, &ftHandle);
if(ftStatus != FT_OK) { // FT_Open failed
qDebug() << "FT_Open failed";
}
}
The compiler command looks in this situation like this:
g++ -Wl,-s -Wl,-subsystem,windows -mthreads -o release\TestFtdi.exe release/main.o release/testftdi.o release/moc_testftdi.o -lmingw32 -LC:/Qt/5.5/mingw492_32/lib -lqtmain -lshell32 -LF:\Workspace\qt\libs\ftdi\Static\amd64 -lftd2xx -lQt5Widgets -lQt5Gui -lQt5Core
Could you help me with this?
My guess is, compiler might be looking for ftd2xx rather than ftd2xx.lib (file name is ftd2xx.lib.dll, right?). Have you tried changing the LIBS line to
LIBS += -L"F:\Workspace\qt\libs\ftdi\amd64" -lftd2xx.lib
I created two dialogs "listdialog.ui" and "editdialog.ui" using QtDesigner, shipped
with Qt5.3.1, and then added to project "phone book.pro" "with source code" using
wizard.
Everytime I start my compiled phone book.exe with all needed dll’s, when i try
to start the program in the QtCreator (or individually), There comes an Runtime
Error with some problem details and there it says:
Problem Event Name: APPCRASH
Fault Module Name: Qt5Cored.dll
other programms which uses GUI are fine working(earlier complied .exe files).
Also when debugging(in win7) ( and running in centos6.4 ) it displays a message box :-
The inferior stopped because it recieved a signal from the operating system.
signal name : SIGSEGV
signal meaning : segmentation fault
files codes are :-
file - 1 : Editdialog.cpp :-
#include <QDialog>
#include "ui_EditDialog.h"
class EditDialog : public QDialog, public Ui::EditDialog
{
public :
EditDialog (QWidget *parent=0 );
const QString name() const;
void setName( const QString& );
const QString number() const;
void setNumber( const QString& );
private :
EditDialog *ui;
};
file - 2 : listdialog.h
#ifndef LISTDIALOG_H
#define LISTDIALOG_H
#include <QDialog>
#include "ui_ListDialog.h"
class ListDialog : public QDialog, public Ui::ListDialog
{
Q_OBJECT
public :
//ListDialog(QObject *parent = 0);
ListDialog(QWidget *parent = 0);
//I don't know when to write "QWidget *parent=0" and when "QObject *parent=0)
private slots :
void addItem();
void editItem();
void deleteItem();
private :
ListDialog *ui;
};
#endif //LISTDIALOG_H
file - 3 : ListDialog.cpp
#include "ListDialog.h"
#include "EditDialog.h"
ListDialog::ListDialog(QWidget *parent) : QDialog(parent), ui(new ListDialog)
{
ui->setupUi(this);
connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addItem()) );
connect(ui->editButton, SIGNAL(clicked()), this, SLOT(editItem()) );
connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteItem()) );
}
void ListDialog::addItem()
{
//EditDialog *dlg = EditDialog(this);
EditDialog dlg(this);
if(QDialog::Accepted == dlg.exec())
ui->listDialogWidget->addItem(dlg.name() + " -- " + dlg.number());
}
void ListDialog::deleteItem()
{
delete ui->listDialogWidget->currentItem();
}
void ListDialog::editItem()
{
if(!ui->listDialogWidget->currentItem())
return;
QStringList parts = ui->listDialogWidget->currentItem()->text().split("--");
EditDialog dlg(this);
dlg.setName(parts[0].trimmed());
dlg.setNumber(parts[1].trimmed());
if(dlg.exec() == QDialog::Accepted)
ui->listDialogWidget->currentItem()->setText(dlg.name() + " -- " + dlg.number());
}
file - 4 : EditDialog.cpp
#include "EditDialog.h"
EditDialog :: EditDialog(QWidget *parent) : QDialog(parent)
{
ui->setupUi(this);
}
const QString EditDialog::name() const
{
return ui->nameLineEdit->text().replace("--","").trimmed();
}
void EditDialog::setName(const QString &name)
{
ui->nameLineEdit->setText(name);
}
const QString EditDialog::number() const
{
return ui->numberLineEdit->text().replace("--","").trimmed();
}
void EditDialog::setNumber(const QString &number)
{
ui->numberLineEdit->setText(number);
}
Along with them project has :- "ui_editdialog.h" and "ui_listdialog.h" generated by QtDesigner.
file - 5 : main.cpp
#include "EditDialog.h"
#include "ListDialog.h"
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//QObject parent;
QWidget parent;
/*
ListDialog *listdlg = new ListDialog;
listdlg->show();
*/
ListDialog dlg(&parent);
dlg.show();
return a.exec();
}
please any one tell me - how to overcome this problem. I searched in some sites
that this is a problem of pointer which is set to null or memory accessing outside
of its domain. I think it may be *parent=0 set by constructor ( file - 2 : listdialog.h -
ListDialog(QWidget *parent = 0); ) but how to overcome, I don't know.
#PeterT Thank you veryy much for giving me a way. I changed code of constructor as you said to "ListDialog::ListDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ListDialog)"
and "EditDialog :: EditDialog(QWidget *parent) : QDialog(parent),ui(new Ui::EditDialog)"
program is now fine working. Thanx a LOT.
In C, I can autoconnect signals with this code:
gtk_builder_connect_signals (builder, NULL)
How to do this in C++ with GTKmm?
You cannot use Glade to connect your signals when using gtkmm, you need to do that manually.
Glib::RefPtr builder = Gtk::Builder::create_from_file("glade_file.ui");
Gtk::Window *window1 = 0;
builder->get_widget("window1", window1);
Gtk::Button *button1 = 0;
builder->get_widget("button1", button1);
// get other widgets
...
button1->signal_clicked().connect(sigc::mem_fun(*this, &button1_clicked));
Have a look at these answers :
https://stackoverflow.com/a/3191472/1673000
https://stackoverflow.com/a/1637058/1673000
Of course you can, there is nothing wrong with mixing C and C++ code.
here is an example code that assumes the signal handler onComboBoxSelectedItemChange is set from glade on a GtkComboBox.
#include <gtkmm.h>
#include <string>
namespace GUI{
int init(){
auto app = Gtk::Application::create();
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("./res/GUI.glade");
gtk_builder_connect_signals(builder->gobj(), NULL);
Gtk::Window* mainWindow = nullptr;
builder->get_widget("mainWindow", mainWindow);
return app->run(*mainWindow);
}
extern "C"
void onComboBoxSelectedItemChange(GtkComboBox *widget, gpointer user_data){
int selectedIndex = gtk_combo_box_get_active(widget);
Gtk::MessageDialog dialog(std::to_string(selectedIndex).c_str());
dialog.run();
}
}
int main(){
return GUI::init();
}
you can build using
g++ -rdynamic -std=c++11 test.cpp $(pkg-config --cflags --libs gtkmm-3.0)