• Добро пожаловать на Форум пользователей ПО АСКОН. Пожалуйста, авторизуйтесь.
 

Уважаемые пользователи,

Хотим проинформировать вас о режиме работы регистрации на нашем сайте.

Зарегистрироваться возможно в рабочие дни, с 8:00 до 20:00 (мск).

Если у вас возникнут вопросы или потребуется дополнительная информация, не стесняйтесь обращаться к нашей службе поддержки. Вы можете связаться с нами по указанным контактным данным на нашем сайте.

Благодарим вас за понимание и сотрудничество. Мы ценим ваше терпение и стремимся предоставить вам лучший опыт использования нашего сервиса.

С уважением,
Команда Ascon

Ошибка 126 при загрузке DLL, созданной в Qt

Автор Kulikcha, 26.07.23, 10:29:58

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

Kulikcha

Добрый день! Проблема возникла такого плана. Занимаюсь разработкой плагина для Workflow, пришлось перейти на фреймворк Qt. Сделал там DLL, но при попытке загрузки DLL через ExecPluginFunction всё время возникает ошибка 126. Пока DLL имеет максимально простой функционал - просто выводит окно на экран. Окно создаётся из ui-формы, созданной в другом проекте и динамически подгружаемой в процессе выполнения. Экспортирую опять же функцию M().

Прикладываю код проекта.

kbm_bp_gui.h
#ifndef KBM_BP_GUI_H
#define KBM_BP_GUI_H
#include "KBM_BP_GUI_global.h"
#include <QtWidgets>
#include<QPushButton>
#include <QtUiTools/quiloader.h>

class KBM_BP_GUI : public QWidget
{
    Q_OBJECT
private:
    QPushButton* btn;
    QWidget* pwgtForm;
public:
    KBM_BP_GUI(QWidget* pwgt = 0) : QWidget(pwgt)
    {
        QUiLoader* puil = new QUiLoader(this);
        //QFile file("D:/Proj_WorkFlow/KBM_BP_GUI/widget.ui");
        QFile file("C:/ProgramData/ASCON/LOODSMAN/PluginStore/WorkFlow/PlugIns/KBM/widget.ui");
        pwgtForm = puil->load(&file);

        if(pwgtForm)
        {
            resize(pwgtForm->size());
            btn = pwgtForm->findChild<QPushButton*>("pushButton");
            connect(btn, SIGNAL(clicked()), qApp, SLOT(quit()));
        }
    }

    QWidget* getForm()
    {
        return pwgtForm;
    }
public slots:
    void slotPush()
    {
    }
};

extern "C" KBM_BP_GUI_EXPORT void M();
#endif // KBM_BP_GUI_H


KBM_BP_GUI_global.h
#ifndef KBM_BP_GUI_GLOBAL_H
#define KBM_BP_GUI_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(KBM_BP_GUI_LIBRARY)
#  define KBM_BP_GUI_EXPORT Q_DECL_EXPORT
#else
#  define KBM_BP_GUI_EXPORT Q_DECL_IMPORT
#endif

#endif // KBM_BP_GUI_GLOBAL_H



kbm_bp_gui.cpp
#include "kbm_bp_gui.h"
void M() {
    QWidget* form = new QWidget;
    KBM_BP_GUI* KBG = new KBM_BP_GUI(form);
    QWidget* UI = KBG->getForm();
    UI->show();
}

.def-файл
LIBRARY "KBM_BP_GUI"

     EXPORTS
     M


.pro файл
QT += widgets
QT += uitools

TEMPLATE = lib
DEFINES += KBM_BP_GUI_LIBRARY

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    kbm_bp_gui.cpp

HEADERS += \
    KBM_BP_GUI_global.h \
    kbm_bp_gui.h

FORMS += \
    C:/ProgramData/ASCON/LOODSMAN/PluginStore/WorkFlow/PlugIns/KBM/widget.ui

# Default rules for deployment.
unix {
    target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    resource.qrc

DISTFILES += \
    KBM_BP_GUI.def


А вот что дальше делать, не вполне понятно. Dependency Walker определяет отсутствие в зоне видимости Qt-вских DLL. Пытался использовать для своей DLL windeployqt, всё действительно было собрано в один каталог. Потом перекинул его в папку с плагинами Workflow. Результат на скрине.
Но всё равно продолжает вылетать ошибка 126. Может, я чего не подгрузил или так вообще нельзя было? Или надо куда-то отдельно прописать пути к этому каталогу? Или, может, структура DLL неправильная?
Каталог плагина.jpg

Chaa

Ваши DLL не лежат там, где ОС может их увидеть.
Поиск DLL выполняется примерно по таким путям:
1. Папка с EXE-файлом
2. Папка System32 (SysWOW64)
3. Текущая папка
4. Папки из переменной окружения PATH
(на самом деле все несколько сложнее, https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order)

На текущую папку полагаться нельзя, она меняется во время работы приложения, например диалогами открытия и сохранения файлов.

Можно для начала добавить в PATH вашу папку с Qt.
+ Благодарностей: 1

Kulikcha

Добавил папку в Path. Не помогло, выдаётся та же ошибка.

Doom

Цитата: Kulikcha от 26.07.23, 10:29:58А вот что дальше делать, не вполне понятно. Dependency Walker определяет отсутствие в зоне видимости Qt-вских DLL. Пытался использовать для своей DLL windeployqt, всё действительно было собрано в один каталог.

Использую Process Monitor с фильтром на PATH - по содержимому или по results на содержание NOT FOUND - так отслеживаю где программа ищет или проверяет на наличие файлов  https://learn.microsoft.com/en-us/sysinternals/downloads/procmon

Цитата: Kulikcha от 26.07.23, 10:29:58пришлось перейти на фреймворк Qt.
Дорогое удовольствие..

$5508 в год на одного разработчика (для стартапов и малых предприятий - $499 в год
+ Благодарностей: 1

Kulikcha

А если брать сам код - там всё нормально? Это именно проблема с ненахождением конкретных DLL-ок?

Doom

с QT не работал и не знаю его организацию и все подводные камни.. Использую в основном бесплатные аналоги.

Воспользуйтесь монитором и наидите все то что программа пытается найти..
+ Благодарностей: 1

Chaa

Qt, он, мягко говоря, не для начинающих.

Лучше возьмите C# от старой Visual Studio 2013 (потому что там есть Unmanaged Exports), как именно я писал здесь: https://achechulin.blogspot.com/2018/10/plugin-c-sharp.html

Или Delphi Community Edition, и можно потом постепенно перейти на Lazarus, хотя это тоже не просто.
+ Благодарностей: 1

Kulikcha

Проверял с помощью Process Monitor. Конкретно на сам файл плагина имеется две ошибки: FAST IO DISSALOWED и FILE LOCKED WITH ONLY READERS.

И ещё хотел спросить. Если стоит задача создать кроссплатформенный плагин(в недалёкой перспективе маячит переход на Linux), то насколько хорош С++ в этом плане? Имеет ли смысл так надрываться и проще выбрать другой язык?

Doom

Цитата: Kulikcha от 28.07.23, 11:27:34FAST IO DISSALOWED
- операция ввода/вывода с использованием устаревшего запроса к драйверу запрещена (интерфейс "fast I/O" в большинстве современных драйверов не поддерживается и заменен на интерфейс IRP - I/o Request Packet - пакет запроса на ввод/вывод).

Цитата: Kulikcha от 28.07.23, 11:27:34FILE LOCKED WITH ONLY READERS.
Означает, что файл или отображение файла заблокировано и всем пользователям разрешено только чтение данного файла.
(видимо стоит галочка только для чтения на файле)

В сети можно найти инструменты которые будут работать интегрировано с языком  который ближе - да это огород но огород возможностей по соизмерению функциональности и времени. отсюда и есть возможность использовать то чего знаешь или чего достаточно для реализации.

+ Благодарностей: 1

Kulikcha

А может галочка "только для чтения" быть реальной причиной происходящего?

Chaa

Цитата: Kulikcha от 28.07.23, 11:27:34Если стоит задача создать кроссплатформенный плагин(в недалёкой перспективе маячит переход на Linux), то насколько хорош С++ в этом плане? Имеет ли смысл так надрываться и проще выбрать другой язык?
Все зависит от того, какой будет Лоцман под Linux - вы ведь пишете плагин.
Возможно, это будет веб-интерфейс для работы в браузере. Хотя мне кажется это неудачной идеей.

Сейчас 80% от Лоцмана написано на Delphi, и еще 20% на C#. Поэтому проще всего использовать что-то из этих двух.

Цитата: Kulikcha от 28.07.23, 13:42:05А может галочка "только для чтения" быть реальной причиной происходящего?
Не должна.

Kulikcha

Кажется, проблему устранил. Теперь Лоцман нормально запускает плагин. Но почему-то падает при попытке выполнять конструкцию вида QWidget *form = new Qwidget; . Просто зависает на несколько секунд и закрывается. Хотя если я напишу условно QWidget *form = 0, всё работает нормально. Выходит, ему чему-то конструкция new не нравится.

Chaa

Цитата: Kulikcha от 01.08.23, 10:41:23Кажется, проблему устранил
Как решили проблему?

Цитата: Kulikcha от 01.08.23, 10:41:23Выходит, ему чему-то конструкция new не нравится.
Не находит другие DLL, типа тех, что лежат в папке platforms.

Kulikcha

Некоторых библиотек не оказалось в каталоге с плагином. Пришлось их искать, некоторые из интернета скачал. После этого плагин запустился. Ну и в Path, само собой, прописал путь.

Kulikcha

Ко всем библиотекам пути прописаны. Всё равно то же самое - Лоцман ломается.

Chaa

Цитата: Kulikcha от 01.08.23, 13:59:22Пришлось их искать, некоторые из интернета скачал. После этого плагин запустился
Это так не работает. Сначала нужно нормально установить Qt, в PATH прописать путь к его библиотекам.

Потом нужно обернуть весь код внутри M() в try/catch(...), потому что исключений функция не должна выбрасывать.

Kulikcha

А установить Qt где? На компьютере, где плагин Workflow будет работать? По-хорошему хотелось бы избежать этого. Перенёс пока только то, что собрал windeployqt.

Doom

Цитата: Kulikcha от 28.07.23, 13:42:05А может галочка "только для чтения" быть реальной причиной происходящего?

Дело в том что библиотеку не просто выгрузить из памяти приложения и приходится завершать это приложение - что неудобно для отладки..
Поэтому скорее всего доступ к библиотекам реализован иначе и поэтому там не пройдут файлы с пометкой только для чтения.
Может быть..

Обычно Process Monitor - это 100% отображение где и какие файлы пытается найти приложение..

Еще способ - если есть другой плагин то посмотреть как там реализовано - например там же где качали Process Monitor есть еще Process Hacker - там отображается в реальном времени тоже какие библиотеки приложение грузит и когда их грузит..