Подключение 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
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.