How to return a new object created in node native code via asynchronous callback? - node-gyp

I am trying to create a node addon that does something like this:
// js
addon.makeObject((err, obj) => {
if (err) { /* handle error */ }
console.log('New object ID=%d', obj.getID());
:
});
The makeObject() is sort of an "asynchronous object factory" where a new instance is created inside the native C++ code in the background (using Nan::AsyncWorker) with necessary setups then returned back to NodeJS land via callback.
Here's a snippet of the native code:
// cpp
#include <nan.h>
#ifndef _WIN32
#include <unistd.h>
#define Sleep(x) usleep((x)*1000)
#endif
class MyClass : public Nan::ObjectWrap {
public:
class Worker : public Nan::AsyncWorker {
public:
friend class MyClass;
explicit Worker(Nan::Callback* callback) : Nan::AsyncWorker(callback) {}
private:
virtual void Execute() {/* some long running task */ Sleep(1000); }
virtual void HandleOKCallback() {
MyClass *mc = new MyClass();
v8::Local<v8::Object> obj = Nan::New<v8::Object>();
mc->Wrap(obj); // ==> Assertion failed: (object->InternalFieldCount() > 0)
v8::Local<v8::Value> argv[] = { Nan::Undefined(), obj };
callback->Call(2, argv);
}
};
explicit MyClass() : _id(idCtr++) {}
~MyClass() {}
static void Init(v8::Local<v8::Object> exports) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("MyClass").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Nan::SetPrototypeMethod(tpl, "getID", GetID);
constructor.Reset(tpl->GetFunction());
exports->Set(Nan::New("MyClass").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());
}
private:
int _id;
static Nan::Persistent<v8::Function> constructor;
static NAN_METHOD(New) {
if (info.IsConstructCall()) {
MyClass* mc = new MyClass();
mc->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
const int argc = 0;
v8::Local<v8::Value> argv[argc] = {};
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
}
}
static NAN_METHOD(GetID) {
MyClass *mc = ObjectWrap::Unwrap<MyClass>(info.Holder());
info.GetReturnValue().Set(Nan::New<v8::Integer>(mc->_id));
}
static int idCtr;
};
Nan::Persistent<v8::Function> MyClass::constructor;
int MyClass::idCtr = 0;
NAN_METHOD(MakeObject) {
// Check arguments here...
Nan::Callback *cb = new Nan::Callback(info[0].As<v8::Function>());
Nan::AsyncQueueWorker(new MyClass::Worker(cb)); // starts the worker
info.GetReturnValue().Set(Nan::Undefined());
}
void InitAll(v8::Local<v8::Object> exports) {
exports->Set( Nan::New("makeObject").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(MakeObject)->GetFunction());
MyClass::Init(exports);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
Although this compiles, it fails at this line:
mc->Wrap(obj);
This is the error:
Assertion failed: (object->InternalFieldCount() > 0), function Wrap, file ../node_modules/nan/nan_object_wrap.h, line 55.
What is InternalFieldCount? I've been googling to find a way but with no luck so far...

I found an answer myself. The key was to use Nan::NewInstance on a constructor - the same way to handle JS code calling constructor as a normal function.
Here's the complete code that works:
// addon.cpp
#include <nan.h>
#ifndef _WIN32
#include <unistd.h>
#define Sleep(x) usleep((x)*1000)
#endif
class MyClass : public Nan::ObjectWrap {
public:
class Worker : public Nan::AsyncWorker {
public:
friend class MyClass;
explicit Worker(Nan::Callback* callback) : Nan::AsyncWorker(callback) {}
private:
virtual void Execute() {/* some long running task */ Sleep(1000); }
virtual void HandleOKCallback() {
///////////////////////////////////////////////////////////
// Create MyClass instance and pass it to JS via callback
const int argc = 0;
v8::Local<v8::Value> argv[argc] = {};
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
v8::Local<v8::Object> obj = Nan::NewInstance(cons, argc, argv).ToLocalChecked();
v8::Local<v8::Value> _argv[] = { Nan::Undefined(), obj };
callback->Call(2, _argv);
}
};
explicit MyClass() : _id(idCtr++) {}
~MyClass() {}
static NAN_MODULE_INIT(Init) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("MyClass").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Nan::SetPrototypeMethod(tpl, "getID", GetID);
constructor.Reset(tpl->GetFunction());
target->Set(Nan::New("MyClass").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());
}
private:
int _id;
static Nan::Persistent<v8::Function> constructor;
static NAN_METHOD(New) {
if (info.IsConstructCall()) {
MyClass* mc = new MyClass();
mc->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
const int argc = 0;
v8::Local<v8::Value> argv[argc] = {};
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
}
}
static NAN_METHOD(GetID) {
MyClass *mc = ObjectWrap::Unwrap<MyClass>(info.Holder());
info.GetReturnValue().Set(Nan::New<v8::Integer>(mc->_id));
}
static int idCtr;
};
Nan::Persistent<v8::Function> MyClass::constructor;
int MyClass::idCtr = 0;
NAN_METHOD(MakeObject) {
// Check arguments here...
Nan::Callback *cb = new Nan::Callback(info[0].As<v8::Function>());
Nan::AsyncQueueWorker(new MyClass::Worker(cb)); // starts the worker
info.GetReturnValue().Set(Nan::Undefined());
}
NAN_MODULE_INIT(InitAll) {
target->Set( Nan::New("makeObject").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(MakeObject)->GetFunction());
MyClass::Init(target);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)

Related

How to get pointer address in function that called through this pointer

I read this article but it doesn't answer my question.
file: hero.h
typedef struct {
int id;
void (*setId)();
int (*getId)();
} Hero, *HeroPtr;
file: hero.c
#include "hero.h"
static void setId(int id);
Hero obj = {
.setId = setId,
.getId = getId,
};
void setId(int id) {
HeroPtr hero_obj = 0x0; //TODO how get address: hero_obj1 (1 > ) OR
// hero_obj2 (2 > )
hero_obj->id = id;
}
void getId() {
HeroPtr hero_obj = 0x0; //TODO how get address: hero_obj1 (1 > ) OR
// hero_obj2 (2 > )
return hero_obj->id;
}
file: main.c
#include "hero.h"
int main() {
Hero hero_obj1, hero_obj2;
//1 >
hero_obj1->setId(1);
//2 >
hero_obj2->setId(2);
return 0;
}
You could do the equivalent of what C++ does behind the scenes.
file: hero.h
typedef struct hero {
int id;
void (*setId)(struct hero*, int);
int (*getId)(struct hero*);
} Hero, *HeroPtr;
void constructHero(HeroPtr this);
file: hero.c
#include "hero.h"
static void setId(HeroPtr this, int id);
static int getId(HeroPtr this);
Hero initObj = {
.setId = &setId,
.getId = &getId,
};
void constructHero(HeroPtr this)
{
*this = initObj;
}
void setId(HeroPtr this, int id) {
HeroPtr hero_obj = this;
hero_obj->id = id;
}
int getId(HeroPtr this) {
HeroPtr hero_obj = this;
return hero_obj->id;
}
file: main.c
#include "hero.h"
#include "stdio.h"
int main() {
Hero hero1;
Hero hero2;
HeroPtr hero_obj1=&hero1;
HeroPtr hero_obj2=&hero2;
constructHero(hero_obj1);
constructHero(hero_obj2);
hero_obj1->setId(hero_obj1, 1);
hero_obj2->setId(hero_obj2, 2);
printf("hero_obj1 id = %d\n", hero_obj1->getId(hero_obj1));
printf("hero_obj2 id = %d\n", hero_obj2->getId(hero_obj2));
return 0;
}
It looks like you are trying to implement virtual functions in C, by using function pointers. In object-oriented programming languages like C++ or Java such functions or methods inside classes have an implicit this pointer as argument, which is hidden. That means that the int getId() function actually has the signature int getId(Hero* this) and the void setId(int id) function actually has the form void setId(Hero* this, int id). As I have already said, in object-oriented programming languages you don't see or add the this pointer and you also don't pass the argument when you invoke the function. The compiler does this for you. It always automatically passes the pointer to the instance as this pointer, on which the function was invoked. In C, however, these features don't exist. So you have to add the this argument and pass it when invoking the function by yourself.

deleting Objects from MObjectArray in undo

As per below code first I am trying to append objects to MObjectArray , which I
want to delete in undo functionality.
Undo,Redo works fine .. But undo is deleting only first element of array/object
not all of them. Would like to know what's going wrong and what's best way to delete objects in Undo function.
.h
#include <maya/MPxCommand.h>
#include <maya/MArgList.h>
#include <maya/MObject.h>
#include <maya/MGlobal.h>
#include <maya/MSelectionList.h>
#include <maya/MDagPath.h>
#include <maya/MFnMesh.h>
#include <maya/MPointArray.h>
#include <maya/MIntArray.h>
#include <maya/MItSelectionList.h>
#include <maya/MItMeshEdge.h>
#include <maya/MDagModifier.h>
class deleteObj : public MPxCommand
{
public:
deleteObj() {};
virtual MStatus doIt(const MArgList& argList);
static void* creator();
virtual MStatus redoIt();
virtual MStatus undoIt();
MObjectArray objectTransforms;
virtual bool isUndoable() const { return true; }
};
.cpp
#include <maya\MFnPlugin.h>
#include "undoredo.h"
MStatus deleteObj::doIt(const MArgList & argList)
{
return redoIt();
}
MStatus deleteObj::redoIt()
{
for (int j = 0; j < 3; j++)
{
MString cmd("maya.cmds.polyCube()");
MGlobal::executePythonCommand(cmd);
MSelectionList selection;
MGlobal::getActiveSelectionList(selection);
MObject selObj;
selection.getDependNode(j, selObj);
objectTransforms.append(selObj);
}
return MS::kSuccess;
}
MStatus deleteObj::undoIt()
{
for (unsigned int i = 0; i <objectTransforms.length(); i++)
{
MGlobal::deleteNode(objectTransforms[i]);
}
return MS::kSuccess;
}
void * deleteObj::creator()
{
return new deleteObj;
}
MStatus initializePlugin(MObject obj)
{
MFnPlugin plugin(obj, "Atri Dave", "1.0", "Any");
MStatus status = plugin.registerCommand("deleteObj", deleteObj::creator);
CHECK_MSTATUS_AND_RETURN_IT(status);
return status;
}
MStatus uninitializePlugin(MObject obj)
{
MFnPlugin plugin(obj);
MStatus status = plugin.deregisterCommand("deleteObj");
CHECK_MSTATUS_AND_RETURN_IT(status);
return status;
}

QML Combobox reports ReferenceError: modelData is not defined

I have following simple QML Combobox:
import QtQuick 2.0
import QtQuick.Controls 1.4
import si.mikroelektronika 1.0
Item
{
id: ueStaffSelector
width: 256
height: 96
ComboBox
{
model: uePeopleModel
editable: false
anchors.fill: parent
} // ComboBox
} // Item
As you can see, I assign uePeopleModel to it, which is working ok already in app. Once the app is executed, I get following QML runtime errors:
file:///opt/QtOpenSource55/5.5/gcc_64/qml/QtQuick/Controls/ComboBox.qml:562:
ReferenceError: modelData is not defined
file:///opt/QtOpenSource55/5.5/gcc_64/qml/QtQuick/Controls/ComboBox.qml:562:
ReferenceError: modelData is not defined
file:///opt/QtOpenSource55/5.5/gcc_64/qml/QtQuick/Controls/ComboBox.qml:562:
ReferenceError: modelData is not defined
file:///opt/QtOpenSource55/5.5/gcc_64/qml/QtQuick/Controls/ComboBox.qml:562:
ReferenceError: modelData is not defined
file:///opt/QtOpenSource55/5.5/gcc_64/qml/QtQuick/Controls/ComboBox.qml:562:
ReferenceError: modelData is not defined
Whole application is constructed in main.cpp:
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QTimer>
#include "database/uepeoplemodel.h"
#include "core/ueapplicationstatus.h"
#include "core/uedatabaseconnectionstatus.h"
#include "core/uebluetoothmanager.h"
#include "core/uebluetoothprinterconnectionstatus.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeApplicationStatus* ueApplicationStatus=new UeApplicationStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
UeBluetoothManager* ueBtManager=new UeBluetoothManager(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSlotDatabaseConnectionChanged(UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus)));
QObject::connect(ueBtManager,
SIGNAL(ueSignalBtPrinterConnectionChanged(UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus)),
ueApplicationStatus,
SLOT(ueSlotBtPrinterConnectionChanged(UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus)));
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.rootContext()->setContextProperty("ueBtManager",
ueBtManager);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
qmlRegisterUncreatableType<UeDatabaseConnectionStatus>("si.mikroelektronika",
1,
0,
"UeTypeDatabaseConnectionStatus",
"Database Connection Status");
qmlRegisterUncreatableType<UeBluetoothPrinterConnectionStatus>("si.mikroelektronika",
1,
0,
"UeTypeBluetootPrinterConnectionStatus",
"Bluetooth Printer Connection Status");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
uePeopleModel->ueConnectToDatabase();
ueBtManager->ueStartPairing();
//ueApplicationStatus->ueUpdate(uePeopleModel->ueFetchUsers());
return app.exec();
}
Here is also UePeopleModel header, file UePeopleModel.h:
#ifndef UEPEOPLEMODEL_H
#define UEPEOPLEMODEL_H
#include <QImage>
#include <QVariant>
#include <QStringList>
#include <QHash>
#include <QByteArray>
#include <QSqlError>
#include <QSqlQueryModel>
#include <QSqlRecord>
#include <QModelIndex>
#include <QQuickImageProvider>
#include <QByteArray>
#include <QSqlRecord>
#include <QSqlQuery>
#include "../settings/uedefaults.h"
#include "../core/uedatabaseconnectionstatus.h"
#include "../core/uetypes.h"
#include "../core/ueapplicationstatus.h"
#include "../core/ueuserrecord.h"
class UePeopleModel : public QSqlQueryModel,
public QQuickImageProvider
{
Q_OBJECT
private:
QSqlDatabase m_ueDb;
private:
QSqlDatabase ueDatabase() const
{ return this->m_ueDb; }
void ueSetDatabase(const QSqlDatabase& database)
{ this->m_ueDb=database; }
QImage ueImage(const QString& id) const;
public:
UePeopleModel(QObject *parent=0);
~UePeopleModel();
QVariant data(const QModelIndex &index,
int role) const Q_DECL_OVERRIDE;
QImage requestImage(const QString &id,
QSize *size,
const QSize &requestedSize);
UeTypeRoles roleNames() const;
void ueConnectToDatabase();
UeTypeUsers* ueFetchUsers();
public:
static const int ueRoleName=Qt::UserRole+1;
static const int ueRoleImage=Qt::UserRole+2;
static const int ueRolePassword=Qt::UserRole+3;
signals:
void ueSignalDatabaseConnectionChanged(const UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus& newStatus);
};
#endif // UEPEOPLEMODEL_H
and its implementation, file UePeopleModel.cpp:
#include "uepeoplemodel.h"
UePeopleModel::UePeopleModel(QObject* parent)
: QSqlQueryModel(parent),
QQuickImageProvider(QQmlImageProviderBase::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::NOT_CONNECTED);
} // default constructor
UePeopleModel::~UePeopleModel()
{
QString connName=this->ueDatabase().connectionName();
this->ueDatabase().close();
this->ueSetDatabase(QSqlDatabase());
this->ueDatabase().removeDatabase(connName);
emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::NOT_CONNECTED);
} // default destructor
QVariant UePeopleModel::data(const QModelIndex &index,
int role) const
{
switch(role)
{
case ueRoleImage:
{
return QString::number(index.row());
} break; // case
case ueRoleName:
{
return this->record(index.row()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_NAME).toString();
} break; // case
case ueRolePassword:
{
return this->record(index.row()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_APPPASSWORD).toString();
} break; // case
default:
{
return QSqlQueryModel::data(index,
role);
} break; // default
} // switch
return QVariant();
} // data
QImage UePeopleModel::ueImage(const QString &id) const
{
return QImage::fromData(this->record(id.toInt()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_IMAGE).toByteArray(),
"PNG").scaled(UeDefaults::UeGraphics::PEOPLE_IMAGE_WIDTH,
UeDefaults::UeGraphics::PEOPLE_IMAGE_HEIGHT,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
} // ueImage
QImage UePeopleModel::requestImage(const QString &id,
QSize *size,
const QSize &requestedSize)
{
Q_UNUSED(size)
Q_UNUSED(requestedSize);
// if(size)
// {
// *size=QSize(UeDefaults::UeGraphics::PEOPLE_IMAGE_WIDTH,
// UeDefaults::UeGraphics::PEOPLE_IMAGE_HEIGHT);
// } // if
//return this->ueImage(id);
return QImage::fromData(this->record(id.toInt()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_IMAGE).toByteArray(),
"PNG").scaled(UeDefaults::UeGraphics::PEOPLE_IMAGE_WIDTH,
UeDefaults::UeGraphics::PEOPLE_IMAGE_HEIGHT,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
} // requestImage
UeTypeRoles UePeopleModel::roleNames() const
{
UeTypeRoles roles;
const int iRoleName=UePeopleModel::ueRoleName;
const int iRoleImage=UePeopleModel::ueRoleImage;
const int iRolePassword=UePeopleModel::ueRolePassword;
roles.insert(iRoleName,
"ueRoleName");
roles.insert(iRoleImage,
"ueRoleImage");
roles.insert(iRolePassword,
"ueRolePassword");
return roles;
} // roleNames
void UePeopleModel::ueConnectToDatabase()
{
if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
Qt::CaseInsensitive))
{
this->ueSetDatabase(QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE));
} // if
this->ueDatabase().setHostName(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
this->ueDatabase().setDatabaseName(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
this->ueDatabase().setUserName(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
this->ueDatabase().setPassword(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);
if(this->ueDatabase().open())
{
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::CONNECTED);
}
else
{
emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::NOT_CONNECTED);
} // if
} // ueConnectToDatabase
UeTypeUsers* UePeopleModel::ueFetchUsers()
{
UeTypeUsers* users=new UeTypeUsers();
for(int iIndex=0; iIndex<this->record().count(); iIndex++)
{
users->append(new UeUserRecord(this,
this->record(iIndex).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_ID).toString(),
this->record(iIndex).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_NAME).toString(),
this->record(iIndex).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_APPPASSWORD).toString()));
} // for
return users;
} // ueFetchUsers
Why am I getting this error?
You need to tell the combobox which role to use. Try adding textRole: "ueRoleName" to your ComboBox.

http page isn't downloaded fully QT

Hello I wrote program that should download web page and save it as a file. It does it but partially only. Have anybody encounterd such a problem?
mainwindow.cpp source file:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QNetworkAccessManager>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
netManager = new QNetworkAccessManager;
setFile("myPage");
}
MainWindow::~MainWindow()
{
netManager->deleteLater();
delete ui;
}
void MainWindow::setFile(QString fileURL)
{
QString savePath;
savePath = QString("D:/page.html");
QNetworkRequest request;
request.setUrl(QUrl(fileURL));
reply = netManager->get(request);
file = new QFile;
file->setFileName(savePath);
file->open(QIODevice::WriteOnly);
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onProgress(qint64,qint64)));
connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
connect(reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
}
void MainWindow::onProgress(qint64 bRead, qint64 bTotal)
{
qDebug(QString::number(bRead).toLatin1() + " - " + QString::number(bTotal).toLatin1());
}
void MainWindow::onFinished(QNetworkReply *reply)
{
switch (reply->error())
{
case QNetworkReply::NoError:
{
qDebug("File downloaded");
qDebug() << file->size();
}break;
default:
{
qDebug(reply->errorString().toLatin1());
}
}
if(file->isOpen())
{
file->close();
file->deleteLater();
}
}
void MainWindow::onReadyRead()
{
file->write(reply->readAll());
}
void MainWindow::onReplyFinished()
{
if(file->isOpen())
{
file->close();
file->deleteLater();
}
}
mainwindow.h header source file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QFile>
#include <QNetworkReply>
#include <QNetworkReply>
#include <QStringList>
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setFile(QString fileURL);
private slots:
void onFinished(QNetworkReply *);
void onProgress(qint64 bRead, qint64 bTotal);
void onReadyRead();
void onReplyFinished();
private:
Ui::MainWindow *ui;
QNetworkAccessManager *netManager;
QNetworkReply *reply;
QFile *file;
};
#endif // MAINWINDOW_H
I tried to solve it myself but after many tries I failed. I'm beginner in QT, so propably I've made a mistake somewhere, and I don't even see it. Can anybody drive me to a proper way to fix the problem?
You should put this:
connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
before:
reply = netManager->get(request);
Works fine after this modification ;)

How to implement a stack containing function call for a PIC in C

I'm currently programming a PIC in C with MPLAB X (+ compiler XC8)
In my code, I have some interruptions (inter1, inter2, ..) which are each composed of urgent and non-urgent operations (urg1, urg2, .., n_urg1, n_urg2, ..).
So I'd like a code with the following structure :
stack s; // FIFO or other
main() {
while (true) {
if (!isEmpty(s)) {
doNextFunction(s);
}
}
}
void interrupt inter1() {
urg1(); // urgent code
addStack(n_urg1);
}
void n_urg1() {
// non-urgent code
}
How can I implement that kind of stack ? Is there something in the standard library ?
If I remember correct, then that compiler is rather primitive, I don't think you can use the std library.
If you need to implement it all by yourself, you can use an array of function pointers:
#include <string.h> // for memmove()
#define STACK_MAX 10
typedef enum
{
Int,
Boolean
} VariantType;
typedef struct
{
VariantType type;
union {
int intValue;
bool booleanValue;
} value;
} Variant;
typedef bool (*FunctionPtr)(Variant data);
typedef struct
{
FunctionPtr ptr;
Variant var;
} FunctionCall;
FunctionCall functionStack[STACK_MAX];
int functionStackUse = 0;
bool addStack(FunctionPtr ptr, Variant var)
{
if (functionStackUse >= STACK_MAX)
return false; // stack full
functionStack[functionStackUse].ptr = ptr;
functionStack[functionStackUse].var = var;
functionStackUse++;
return true;
}
bool callNextFunction(void)
{
// TODO: disable inter1
if (functionStackUse > 0)
{
// get first function on stack
FunctionCall functionCall = functionStack[0];
functionStackUse--;
// remove first function from stack
memmove((void*)functionStack, (void*)(functionStack + 1), functionStackUse * sizeof(functionStack[0]));
// TODO: re-enable inter1
// call function with arguments
return (*functionCall.ptr)(functionCall.var);
}
else
{
// TODO: re-enable inter1
return false; // no more functions
}
}
void main()
{
while (1)
{
callNextFunction();
// TODO add some delay otherwise you're constantly disabling inter1 (in doNextFunction)
}
}
bool n_urg1(Variant var)
{
if (var.type == Int)
{
int i = var.value.intValue;
// do something
return true;
}
return false;
}
void inter1(void)
{
Variant var;
var.type = Int;
var.value.intValue = 45;
addStack(n_urg1, var);
}

Resources