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]



  • Код не смог осилить, очень трудно читать без форматирования. Но идеи есть.

    1. Если программа в дебаге не падает, а в релизе падает, то может быть где-то ломается память (выход за границы буфера и т.д.)
    2. Не пробовали писать пробное приложение, которое вызывается только ту функцию, на которой происходит падение? Интересно как она себя ведет в дебаге/релизе.


  • Да, конечно, был бы очень рад, реально сложный баг....я уже теряю надежду найти ошибку и готовлюсь переписывать всё на яве.
    Здесь много кода, но по сути, большая половина - сгенерирована Qt Creater-ом.
    Вот здесь можно скачать саму библиотеку, которую я использовал: ftp://ftp.astro.com/pub/swisseph/sweph.zip - там же и лежит длл. Сама библиотека работает в С, работает в Дельфи(есть примеры, знаю несколько готовых продуктов на дельфи, одним из которых я и пользуюсь на данный момент вместо своей программы), сейчас я подключил библиотеку в яве и там она тоже работает(написал абстракцию библиотеки и планнирую разрабатывать программу теперь в яве, жаль в Qt не получилось!) - на английской версии Qt форума мне отвечали два сертифицированных Qt девелоупера, которые:

    1. Либо не знают в чём ошибка(вероятнее всего)
    2. Не хотят вникать

    Я уже давно сделал очень маленький пример программы, который старался сделать маленьким и закомментированным:
    В дебаг моде работает правильно, в релиз падает всё с той же ошибкой.

    П.с. Я тоже использую vim)))))



  • Все строчки и куски программы, написанные мною - прокомментированы:

    Значит вот это сгенерированный фаил для старта программы.
    @#include <QtGui/QApplication>
    #include "window.h"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Window w;
    w.show();

    return a.exec&#40;&#41;;
    

    }@

    Это мой Гуи класс на котором в дизайнере я вытащил одну DateTimeEdit и TextLabel

    @#ifndef WINDOW_H
    #define WINDOW_H

    #include <QMainWindow>
    #include <lib.h> // Include my class

    namespace Ui {
    class Window;
    }

    class Window : public QMainWindow
    {
    Q_OBJECT

    public:
    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
    @
    Может у тебя кидает ошибку из за того, что он какую то функцию не загрузил из библиотеки.
    И не рационально с моей точки зрения каждый раз при вызове функции из класса, грузить функции из библиотеки...


Log in to reply