Russian Qt Forum

Qt => Вопросы новичков => Тема начата: QuAzI от Февраль 28, 2012, 12:19



Название: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 12:19
Хоть через QLibrary, хоть через WINAPI LoadLibrary получаю одно и то же: приложение падает сразу после обращения к "полученным" из dll данным (конкретно на первой строке после qDebug() << "parse GetDLLInfo"; )
Если на виртуальной машине и из под отладчика Qt ещё прокатило натыкать qDebug() и кое как оно работало, то на реальной машине не получается выдернуть текст из GetDLLInfo ни из Qt-шной dll, ни из Delphi-шной.
Код:
{
    QStringList nameFilters;
    nameFilters << "ss3*.dll";

    QDir mainDir(qApp->applicationDirPath());
    QStringList files = mainDir.entryList(nameFilters, QDir::Files, QDir::Name);

//    QLibrary *myLib = new QLibrary();

    for (int i=0; i<files.count(); i++)
    {        
        HINSTANCE libHandle = LoadLibrary(QString(files.at(i)).toStdWString().c_str());
        if (libHandle)
        {
            typedef const char* (*MyPrototype)();
            qDebug() << "beforeResolved" << files.at(i);
//            MyPrototype myFunction = (MyPrototype) myLib->resolve(files.at(i), "GetDLLInfo");
            MyPrototype myFunction = (MyPrototype) GetProcAddress(libHandle, "GetDLLInfo");
            qDebug() << "afterResolved";
            if (myFunction)                
            {                                
                qDebug() << "functionDetected";
                const char* str = myFunction();                                
                if (str)
                {
                    qDebug() << "parse GetDLLInfo";
                    short sz =  static_cast<unsigned short>(str[0]);
                    qDebug() << "str size= " << sz;
                    QByteArray encodedString(str +1, sz);
                    qDebug() << "str = " << encodedString;
                    QTextCodec *codec = QTextCodec::codecForName("Windows-1251");
                    QString buff = codec->toUnicode(encodedString) ;
                    qDebug() << files.at(i) << sz << buff;
                    ui->textEdit->append( files.at(i) + "  : GetDLLInfo("+ QVariant(sz).toString() +") :  " + buff );                    
                }
            }
            qDebug() << "afterParse";
        }
    }
}
В Delphi функция объявлена так
Код:
function GetDLLInfo: ShortString; StdCall;
...
implementation

function GetDLLInfo: ShortString;
begin
 Result:=sDLLInfo;
end;
В DLL на Qt пока сделал так
Код:
#ifdef D_SHARED_LIB
        #define D_SHARED extern "C" __declspec(dllexport) Q_DECL_EXPORT
#else
        #define D_SHARED extern "C" __declspec(dllexport) Q_DECL_IMPORT
#endif

D_SHARED char* GetDLLInfo();

...

char* GetDLLInfo()
{
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

qInstallMsgHandler(myMessageOutput);

qDebug() << "GetDLLInfo";

QString tmp = "Типа плугин";

 QTextCodec *codec = QTextCodec::codecForName("Windows-1251");

 QByteArray text = codec->fromUnicode( tmp.toStdString().c_str() );
 char *data = new char[text.size() + 2];
 strcpy(data+1, text.data());
 data[0] = static_cast<unsigned short>(text.size());

    return data;
}
И если тестовая DLL из Delphi грузится в целевой проект (который тоже накорябан на Delphi), то писанная на Qt им упорно отпинывается. Жаль только исходников к нему нет и потому логов от него добиться вообще не получается.

Кувыркаюсь с этим: Qt SDK 2010.5; Qt Creator 2.0.1 ; Qt 4.7.0 и его родной MinGW (не перелинковывал под MS VC)


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: mutineer от Февраль 28, 2012, 12:22
Припиши явно к указателю на функцию __stdcall


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 12:32
После указания __stdcall в экспорте имён появляются @<длинна входных параметров> и с такими именами во первых в упор DLL не грузит дельфовый проект, во вторых довольно смутно представляю, как потом самому по именам через QLibrary без указания всей белиберды за знаком "@" грузить.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: mutineer от Февраль 28, 2012, 12:35
Ну соглашение вызова в любом случае надо явно указывать и при экспорте и при импорте. А вот с именами гугл поможет как никто другой


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 12:39
Беда в том, что не помог (хотя в английском я тоже не силён). Как раз и читал про то, что в зависимости от соглашений вызова будет разное именование в экспортах. И как сменить именование не нашёл. Странно, что в Delphi без бубнов получаются такие "красивые" имена.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: mutineer от Февраль 28, 2012, 12:43
Везде могут получиться такие имена, насколько я понял это от соглашения вызова зависит. Странно, другим гугл в этом помог


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 12:47
Гугль то помог... да не там... если бы речь стояла о том, как мне из моего приложения юзать собственную функцию, вопроса бы небыло... а сейчас по сути моё приложение - это только тестер для DLL пишущейся для чужого приложения. И я не могу менять имена.

Переписал, теперь оно дёргает и GetDLLInfo@0 через __stdcall и GetDLLInfo. Теперь моя кривулька на Qt возвращает тестовый текст... а писанный на Delphi вариант (который на ура определяется прогой для которой вся эта кухня и делается) - фигушки. Адрес по GetDLLInfo получает, но опять таки после обращения в туда - валится всё приложение.
Код:
{
    QStringList nameFilters;
    nameFilters << "ss3*.dll";

    QDir mainDir(qApp->applicationDirPath());
    QStringList files = mainDir.entryList(nameFilters, QDir::Files, QDir::Name);

//    QLibrary *myLib = new QLibrary();

    for (int i=0; i<files.count(); i++)
    {       
//        myLib->setFileName( files.at(i) );
//        if (myLib->load())
        HINSTANCE libHandle = LoadLibrary(QString(files.at(i)).toStdWString().c_str());
        if (libHandle)
        {
            typedef __stdcall const char* (*MyPrototype)();
            qDebug() << "beforeResolved" << files.at(i);
//            MyPrototype myFunction = (MyPrototype) myLib->resolve(files.at(i), "GetDLLInfo");
            MyPrototype myFunction = (MyPrototype) GetProcAddress(libHandle, "GetDLLInfo@0");
            qDebug() << "afterResolved";

            if (!myFunction)
            {
                qDebug() << "Using GetDLLInfo";
                myFunction = (MyPrototype) GetProcAddress(libHandle, "GetDLLInfo");
            } else qDebug() << "Using GetDLLInfo@0";

            if (myFunction)
            {                               
                qDebug() << "functionDetected";
                const char* str = myFunction();                               
                if (str)
                {
                    qDebug() << "parse GetDLLInfo";
                    short sz =  static_cast<unsigned short>(str[0]);
                    qDebug() << "str size= " << sz;
                    QByteArray encodedString(str +1, sz);
                    qDebug() << "str = " << encodedString;
                    QTextCodec *codec = QTextCodec::codecForName("Windows-1251");
                    QString buff = codec->toUnicode(encodedString) ;
                    qDebug() << files.at(i) << sz << buff;
                    ui->textEdit->append( files.at(i) + "  : GetDLLInfo("+ QVariant(sz).toString() +") :  " + buff );                   
                }
            }
            qDebug() << "afterParse";
        }
//        else qDebug() << "Can't load DLL: " << files.at(i);
                    /* if (myLib->isLoaded())
                    {
                        myLib->unload();
                    } */
    }
}


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 13:24
Если внимательно прочесть код, то можно увидеть что в этом самом массиве нулевой символ как раз длинной и подменяется.
Хотя если покажете более красивое/правильное решение с этой структуркой, буду признателен.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 14:19
Опа, супер, наконец-то это как-то да зашевелилось. Дельфовое приложение схавало DLL с этим:
Код:
struct ShortString {
    unsigned char Length;
    char Data[255];
};

D_SHARED __stdcall ShortString GetDLLInfo();

...

// function GetDLLInfo: ShortString;
ShortString GetDLLInfo()
{
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

qDebug() << "GetDLLInfo";

ShortString st;

QString tmp = "Типа плугин";

 QTextCodec *codec = QTextCodec::codecForName("Windows-1251");

 QByteArray text = codec->fromUnicode( tmp.toStdString().c_str() );
 char *data = new char[text.size() + 2];
 strcpy( st.Data, text.data());
 st.Length = text.size();

    return st;
}
Спасибо.

Кстати вроде и с def-файлами маленько разобрался. В PRO-файл кинул
Код:
DEF_FILE += ss3plugin-qt-example.def
Сам DEF в директории сборки
Код:
EXPORTS    GetDLLInfo          
Оно линкуется, но в DLL в итоге попадают ОБА наименования, GetDLLInfo и GetDLLInfo@0. Ну хоть работает маленько и то добро.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 15:17
AnsiString в проектине Qt теперь получаю так. Вроде всё красиво.
Код:
            typedef __stdcall const ShortString (*MyPrototype)();
            MyPrototype myFunction = (MyPrototype) GetProcAddress(libHandle, "GetDLLInfo");

            if (myFunction)
            {                                               
                const ShortString str = myFunction();
                if (str.Length>0)
                {
                    short sz = str.Length;
                    QByteArray encodedString(str.Data, str.Length);
Теперь воюю с передачей параметров не из, а в DLL.
В оригинале было так
procedure ShowFormFromDLL(AppHandle: THandle; DBName, LibName: PChar); StdCall;
У себя я это экспортирую так
D_SHARED __stdcall void ShowFormFromDLL(HINSTANCE AppHandle, char* DBName, char* LibName);
И собственно сама функция:
Код:
void ShowFormFromDLL(HINSTANCE AppHandle, char* DBName, char* LibName)
{
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));   

    HINSTANCE GlobHinstDLL = AppHandle;

    int argc = 0;char* argv[1];
    argv[0]="ss3plugin-qt-example1.dll";
    QApplication* pApp = new QApplication(argc, argv);

    QString m_DBName = DBName, m_LibName = LibName;

        Widget w(m_DBName, m_LibName);
        w.show();

        pApp->exec();
    qDebug() << "ShowFormFromDLL" << DBName << LibName;
}
Т.е. берём хэндл "родителя", ещё пару параметров, создаём, рисуем виджет и на него кидаем DBName и LibName, чтобы убедиться, что они нормально прилетели. Всё нормально передаётся-рисуется, но при закрытии этого плагина-виджета падает родительское приложение. Неужели и тут где-то стэк надо подчищать?


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 28, 2012, 15:20
Разобрался. Надо было прибить QApplication.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Февраль 29, 2012, 16:29
Рано радовался. Из приложения Delphi создал свой QApplication, побаловался, убил. Всё хорошо. А если грузить эту же DLL из Qt-шного графического приложения, то виджет только мигнуть успевает и сразу исчезает. Разумеется не отработав. Оно понятно, что QApplication должно быть одно для всего приложения и его библиотек, но не понятно, как с ним воевать. Сейчас пытаюсь воевать так
Код:
    qDebug() << argv[0] << "ShowFormFromDLL" << DBName << LibName;

    /// Создаём при необходимости свой экземпляр QApplication, без него не работает GUI
    bool mainQApp = false;
    QApplication* pApp = (QApplication*) qApp->instance();
            if (!pApp)
            {
                pApp = new QApplication(argc, argv);
                mainQApp = true;
            }

        Widget w(m_DBName, m_LibName);
        w.show();

        if (mainQApp) {
        pApp->exec();
            delete qApp; /// Удаляем свой экземпляр QApplication
        }


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Март 01, 2012, 01:32
Забавно что при использовании QxtApp поведение виджета идентично. По логам (перенаправил qDebug и qWarning в файл) вижу что отработали конструктор и деструктор виджета, а между ними выскакивает qWarning о том что QApplicationCore::EventFilter уже проинсталлирован.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Март 03, 2012, 16:19
В аттаче полные исходники тестера и плагина.
Плагин выбивает если раскомментировать в main.cpp строку 87, в которой виджет отображается. MessageBox перед ним показывается и отрабатывает отлично, а именно на отображении диалога падает.
И ещё почему-то крэшится release-сборка запущенная не из под QtCreator при закрытии тестера, но только если вызывались функции из Qt-плагина. Если вызывались функции из плагина написанного на Delphi, тестер нормально закрывается.

p.s. Ну и вообще любые плевки в сторону дизайна кода, как что переделать стоит, были бы уместны


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: AlexWMF от Март 03, 2012, 18:47
поправил где-то как-то, сравни файлы со своими и поймешь. Всё в аттаче.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Март 03, 2012, 23:22
Спасибо, зашуршало на ура! Как-то я не додумался сделать new Widget(). А DllMain там и вовсе ненужен. Я его добавлял только чтобы отследить, когда библиотека аттачится и отаттачивается, ну и в ходе бодания с виджетом пихнул туда qApp, как было в некоторых примерах.
А по коду ничего не скажешь? Сильно криво или терпимо? Быстро разобрался, чего я там пытаюсь сделать? И для зачем ты добавлял LIBS += user32.lib ?


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: AlexWMF от Март 03, 2012, 23:42
по коду хз, не разбирался особо, чисто сделал чтоб компились и не падало, user32.lib для линкера.. что-то там не нашло...
в qsqlunibase.cpp замел были строчки кода
Код:
     if ( (uid == "root") and (pwd=="")) /// Определение пары "логин/пароль" по умолчанию для текущего драйвера
and и or, у меня под визуалкой не захотело компилиться, это у тя дефайны есть для них?


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Март 04, 2012, 00:22
Их наверное можно заменить на && и || и должно быть то же самое. Я обычно так и пишу, это просто в попыхах воткнул and (пережитки Pascal и FoxPro сказываются)


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: AlexWMF от Март 04, 2012, 00:39
и компилилось?


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: BuRn от Март 04, 2012, 00:42
Цитировать
Их наверное можно заменить на && и ||
учим , учим C , нельзя заменить на ||


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Март 04, 2012, 00:54
Каюсь, в Си я чайник. Но полез, проверил.
Вот это в лог не пишет
        if ( (2<1) || (2>4))
            qDebug() << "test or ok";
        if ( (2<1) && (4>2))
            qDebug() << "test and ok";
А вот это пишет.
        if ( (2>1) || (2>4))
            qDebug() << "test or ok";
        if ( (2>1) && (4>2))
            qDebug() << "test and ok";
Почему, если || не должно работать как or ?


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: AlexWMF от Март 04, 2012, 01:01
Цитировать
Их наверное можно заменить на && и ||
учим , учим C , нельзя заменить на ||
хочешь сказать что
Код:
and  => &&
or => ||
не верно?


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: BuRn от Март 04, 2012, 01:17
Цитировать
Их наверное можно заменить на && и ||
учим , учим C , нельзя заменить на ||
хочешь сказать что
Код:
and  => &&
or => ||
не верно?
верно, но сравнение при passwd = "bla bla bla " username = "bla bla bla " должно быть if(pass == password && user == username ) return true; а никак ни if(pass == password || user == username )


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: mutineer от Март 04, 2012, 01:20
верно, но сравнение при passwd = "bla bla bla " username = "bla bla bla " должно быть if(pass == password && user == username ) return true; а никак ни if(pass == password || user == username )

кто говорил, что and надо заменять на || ?
and и or, у меня под визуалкой не захотело компилиться, это у тя дефайны есть для них?

Их наверное можно заменить на && и || и должно быть то же самое.


Название: Re: Загрузка DLL слинкованной в Delphi (Access Violation)
Отправлено: QuAzI от Март 15, 2012, 12:19
Дожимаю маленько старую тему. Вроде всё работает, захотелось красивостей, а конкретно форму плагина отрисовывать по тем же координатам, что и родитель. Если родитель на Qt, то катит такой фокус
Код:
this->setGeometry( QRect( qApp->activeWindow()->geometry().topLeft(), qApp->activeWindow()->geometry().bottomRight() ));
А если родитель не на Qt, придётся дёргать WinApi или есть что-нить более родное для Qt ?