Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct
Подключение dll, написанной на С к проекту через класс QLibrary
-
Такая проблема, может кто уже сталкивался...Примерно пятый день ищу решение, но никак не могу найти.
Хочу загрузить DLL динамически через класс QLibrary абстрагировав все вызовы к библиотеке в отдельном классе.
В Debug версии всё прекрасно работает, в Release она падает до создания главного окна(В конструкторе вызывается конструктор класса, который вызывает функцию set_ephe_path и всё рушится) с ошибкой Segmentation fault. Я долго искал, где проблема, это оказалась библиотека.Привожу код класса библиотеки и код из сорса библиотеки, может кто может помочь?
П.с. Я так же установил, что swe_get_planet_name не вызывает падения, а swe_julday к примеру вызывает падение программы.
Буду очень благодарен, если кто поможет понять, что я делаю не так.
@#ifndef SWEDLL_H
#define SWEDLL_H
#include <QLibrary>class swedll
{
private:
QLibrary swedll32;
int isloaded;
int count;typedef void (* Swe_Set_Ephe_Path) (QString); typedef double(* Swe_Julday) (int, int, int, double, int); typedef double(* Swe_Deltat) (double); typedef char* (* Swe_Get_Planet_Name) (int, char *); typedef int (* Swe_Calc_Ut) (double, int, int, double*, char*); typedef double(* Swe_Sidtime) (double); typedef int (* Swe_Houses_Armc) (double, double, double, int, double*, double*); typedef int (* Swe_Houses) (double, double, double, int, double*, double*);
public:
swedll();
~swedll();
void swe_set_ephe_path(QString);
QString swe_get_planet_name(int);
double swe_julday(int, int, int, double);
double deltat(double);
double* swe_calc_ut(double, int);
double* swe_calc(double, int, int);
double swe_sidtime(double);
double* swe_houses_armc(double, double, double, int);
double* swe_houses(double, double, double, int);
};#endif // SWEDLL32_H
@@#include "swedll.h"
swedll::swedll()
{
swedll32.setFileName("swedll32");
}swedll::~swedll()
{}
void swedll::swe_set_ephe_path(QString Path)
{
swedll32.load();
Swe_Set_Ephe_Path set_ephe_path = (Swe_Set_Ephe_Path)swedll32.resolve("_swe_set_ephe_path@4");
if(set_ephe_path)set_ephe_path(Path);
}QString swedll::swe_get_planet_name(int Number)
{
swedll32.load();
char *x = new char[256];
Swe_Get_Planet_Name get_planet_name = (Swe_Get_Planet_Name)swedll32.resolve("_swe_get_planet_name@8");
QString result = "";
if(get_planet_name) result+= get_planet_name(Number, x);
return result;
}double swedll::swe_julday(int Day, int Month, int Year, double Hour)
{
swedll32.load();
Swe_Julday julday = (Swe_Julday)swedll32.resolve("_swe_julday@24");
if(julday)return julday(Day, Month, Year, Hour, 1); else return 0;
}double swedll::deltat(double Julday)
{
swedll32.load();
Swe_Deltat deltat = (Swe_Deltat)swedll32.resolve("_swe_deltat@8");
if(deltat)return deltat(Julday); else return 0;
}
double* swedll::swe_calc_ut(double Julday, int PlanetNumber)
{
return swe_calc(Julday, PlanetNumber, 256);
}double* swedll::swe_calc(double Julday, int PlanetNumber, int Ephe)
{
swedll32.load();
Swe_Calc_Ut calc_ut = (Swe_Calc_Ut)swedll32.resolve("_swe_calc_ut@24");
char *err;
err = new char[256];
double *result = new double[6];
if(calc_ut)calc_ut(Julday, PlanetNumber, Ephe, result, err);
return result;
}double swedll::swe_sidtime(double Time)
{
swedll32.load();
Swe_Sidtime sidtime = (Swe_Sidtime)swedll32.resolve("_swe_sidtime@8");
if(sidtime)return sidtime(Time); else return 0;
}double* swedll::swe_houses_armc(double ARMC, double geolat, double eps, int hsys)
{
swedll32.load();
double *cusps = new double[13];
double *ascmc = new double[10];
Swe_Houses_Armc houses_armc = (Swe_Houses_Armc)swedll32.resolve("_swe_houses_armc@36");
if(houses_armc)houses_armc(ARMC, geolat, eps, hsys, cusps, ascmc);
return cusps;
}double* swedll::swe_houses(double Julday, double geolat, double geolon, int hsys)
{
swedll32.load();
double *cusps = new double[13];
double *ascmc = new double[10];
Swe_Houses houses = (Swe_Houses)swedll32.resolve("_swe_houses@36");
if(houses)houses(Julday, geolat, geolon, hsys, cusps, ascmc);
return cusps;
}@Который грузит библиотеку swedll32.dll экспортирует функции и использует(не делает ничего другого).
Вот так выглядят функции из сорса библиотеки
@DllImport int32 FAR PASCAL swe_calc_ut(
double tjd, int ipl, int32 iflag,
double *xx,
char *serr);DllImport double FAR PASCAL swe_sidtime(double tjd_ut);
DllImport int FAR PASCAL swe_houses_armc(
double armc, double geolat, double eps, int hsys,
double *hcusps, double *ascmc);DllImport double FAR PASCAL swe_julday(
int year, int mon, int mday,
double hour,
int gregflag);DllImport char *FAR PASCAL swe_get_planet_name(int ipl, char *spname);
DllImport void FAR PASCAL swe_set_ephe_path(char *path);@
[Edit: @-tags for code snippets added /Vass]
-
Код не смог осилить, очень трудно читать без форматирования. Но идеи есть.
- Если программа в дебаге не падает, а в релизе падает, то может быть где-то ломается память (выход за границы буфера и т.д.)
- Не пробовали писать пробное приложение, которое вызывается только ту функцию, на которой происходит падение? Интересно как она себя ведет в дебаге/релизе.
-
Да, конечно, был бы очень рад, реально сложный баг....я уже теряю надежду найти ошибку и готовлюсь переписывать всё на яве.
Здесь много кода, но по сути, большая половина - сгенерирована Qt Creater-ом.
Вот здесь можно скачать саму библиотеку, которую я использовал: ftp://ftp.astro.com/pub/swisseph/sweph.zip - там же и лежит длл. Сама библиотека работает в С, работает в Дельфи(есть примеры, знаю несколько готовых продуктов на дельфи, одним из которых я и пользуюсь на данный момент вместо своей программы), сейчас я подключил библиотеку в яве и там она тоже работает(написал абстракцию библиотеки и планнирую разрабатывать программу теперь в яве, жаль в Qt не получилось!) - на английской версии Qt форума мне отвечали два сертифицированных Qt девелоупера, которые:- Либо не знают в чём ошибка(вероятнее всего)
- Не хотят вникать
Я уже давно сделал очень маленький пример программы, который старался сделать маленьким и закомментированным:
В дебаг моде работает правильно, в релиз падает всё с той же ошибкой.П.с. Я тоже использую vim)))))
-
Все строчки и куски программы, написанные мною - прокомментированы:
Значит вот это сгенерированный фаил для старта программы.
@#include <QtGui/QApplication>
#include "window.h"int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();return a.exec();
}@
Это мой Гуи класс на котором в дизайнере я вытащил одну DateTimeEdit и TextLabel
@#ifndef WINDOW_H
#define WINDOW_H#include <QMainWindow>
#include <lib.h> // Include my classnamespace Ui {
class Window;
}class Window : public QMainWindow
{
Q_OBJECTpublic:
explicit Window(QWidget *parent = 0);
~Window();private:
Ui::Window *ui;
};#endif // WINDOW_H@
Это реализация этого класса:
@#include "window.h"
#include "ui_window.h"Window::Window(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
QDateTime DT; // Берём QDateTime
DT = ui->dateTimeEdit->dateTime(); // копируем в QDateTime актуальное время
// Make operation to have day, month, year and hour
int day = DT.date().day(); // Достаём оттуда день
int month = DT.date().month(); // месяц
int year = DT.date().year(); // год
int hour = DT.time().hour(); // час
double min = (double)DT.time().minute() / 60.0; // Минуты в часах
double sec = (double)DT.time().second() / 3600; // Секунды в часах
double dhour = hour + min + sec; // Временя дня в часах
lib Lib; // Инициализирую мою библиотеку
double tjd = Lib.swe_julday(year, month, day, dhour); // Использую библиотеку, всё в порядке
tjd = Lib.swe_julday(year, month, day, dhour); // Использую второй раз библиотеку, вот здесь всё и падаетui->label->setText(QString::number(tjd, 'g', 8)); // На экран естественно не выводиться
}Window::~Window()
{
delete ui;
}@Моя абстракция библиотеки, весь код написан мною
@#ifndef LIB_H
#define LIB_H
#include <QLibrary>
#include <QDateTime>class lib
{
private:
QLibrary swedll;typedef double(* Swe_Julday) (int, int, int, double, int);
public:
lib();double swe_julday(int, int, int, double);
};
#endif // LIB_H@
@#include "lib.h"
lib::lib()
{
swedll.setFileName("swedll32");
}double lib::swe_julday(int Day, int Month, int Year, double Hour)
{
swedll.load();
Swe_Julday julday = (Swe_Julday)swedll.resolve("_swe_julday@24"); // П.с. эту часть я переносил в атрибуты класса, а ресолв в конструктор - не помогло
if(julday)return julday(Day, Month, Year, Hour, 1); else return 0;
}@Всего одна функция
А вот и фаил ксмл, сгенерированный Крейтером.
@<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Window</class>
<widget class="QMainWindow" name="Window">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Window</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QDateTimeEdit" name="dateTimeEdit">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>194</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>50</x>
<y>70</y>
<width>171</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>@
-
Похоже, что xml поломана... В 12-ой строке тег проперти закрывается, но до этого открыт нигде не был. Но не проблема, я окошко создал. Собрал, запустил, не падает. Потом увидел, что библиотека не грузится вовсе. Я на юниксе, а вы, как я понял, на винде пробуете. А что показывает бектрейс, когда приложение падает?
-
Мне не очень нравится что вы на каждом запросе заново лоадите и резолвите
@double swedll::swe_julday(int Day, int Month, int Year, double Hour)
{
swedll32.load(); // Это
Swe_Julday julday = (Swe_Julday)swedll32.resolve("_swe_julday@24"); .. И это выполняется при каждом обращении.
if(julday)return julday(Day, Month, Year, Hour, 1); else return 0;
}@Я бы вынес этот код (и все подобные) в некоторый метод инициализации, а указатели на функции сделал бы или статиками или членами класса. В самом же методе только вызов.
Т.е. что-то типа стало бы:
@double swedll::swe_julday(int Day, int Month, int Year, double Hour)
{
if(!m_julday)
initMethodsCall();if(m_julday) return julday(Day, Month, Year, Hour, 1); else return 0;
}@
-
Я использую линукс убунту в 80% случаев(работа и часто для себя). Программа была исключением, потому что расчитана была на пользователей виндоус.
На линуксе у меня та же проблема, что в Qt библиотека вообще не грузится. Хотя в линуксе в яве c JNA та же самая библиотека без проблем грузиться и работает(!).
Backtrace в релизмоде выглядит только так: www.adva.sama.ru/Backtrace.jpg
-
Vass, я тоже месяц назад думал, что повторная загрузка могла так повлиять и поэтому попробовал так:
@#ifndef LIB_H
#define LIB_H
#include <QLibrary>
#include <QDateTime>class lib
{
private:
QLibrary swedll;typedef double(* Swe_Julday) (int, int, int, double, int); Swe_Julday julday;
public:
lib();
double swe_julday(int, int, int, double);
};#endif // LIB_H@
@#include "lib.h"
lib::lib()
{
swedll.setFileName("swedll32");
julday = (Swe_Julday)swedll.resolve("_swe_julday@24");
}double lib::swe_julday(int Day, int Month, int Year, double Hour)
{
if(julday)return julday(Day, Month, Year, Hour, 1); else return 0;
}@Это не помогло...сейчас конечно попробую сделать статик переменные, но сомневаюсь, что это что-то изменит....
-
я напишу как я делал со своей библиотечкой:
@
typedef HRESULT (WINAPI *Qt_SetProgressState)(HWND hwnd, UINT state);
static Qt_SetProgressState qSetProgressState = 0;......
#ifdef Q_OS_WIN
hWnd = (HWND)winId();
QLibrary lib("Explorerframe");
if(lib.load()) {
qSetProgressState = (Qt_SetProgressState)lib.resolve("SetProgressState");
if (qSetProgressState != NULL)
qSetProgressState(hWnd, 0x00000001);
}
#endif
@
Может у тебя кидает ошибку из за того, что он какую то функцию не загрузил из библиотеки.
И не рационально с моей точки зрения каждый раз при вызове функции из класса, грузить функции из библиотеки...