Russian Qt Forum
Май 04, 2024, 00:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: Загрузка классов из динамических библиотек???  (Прочитано 36832 раз)
Dendy
Гость
« Ответ #30 : Январь 14, 2009, 21:57 »

Вы говорите "ну ДА!" и тут же описываете всё наоборот. От QObject'а интерфейс наследуется только зачем чтобы сделать qobject_cast() и убедиться что загрузили ту ДЛЛ что хотели. Точка. Это не плагин! Это - менеджер плагина, загрузчик, называйте его как хотите. Пусть вас не вводит в заблуждение что он отнаследован от QObject. Всё что этот менеджер должен сделать - создать вам ваш реальный плагин с помощью вызова create() или как вам заблагорассудится его назвать. Можете в его интерфейс включить получение номера версии ДЛЛ. Но никак не сам функционал.
Записан
ритт
Гость
« Ответ #31 : Январь 14, 2009, 23:59 »

вот поэтому и просил читать внимательнее...я же ещё на первой странице описывал плагины кутэ - скрытые инициализаторы -> интерфейс -> объект. интерфейс нужен для выбора метода работы с плагином (здесь под плагином я понимаю объект, унаследованный от интерфейса). в частности интерфейс может быть интерфейсом-фабрикой других интерфейсов (или фабрикой фабрик - извращаться можно как угодно). по сути сам интерфейс нужен лишь на этапе "знакомства" с дллкой (часто он может содержать информацию о плагине, авторе и т.п. - чтобы потом можно было отобразить в списке плагинов или в менюшке). а вот объект, с которым основная программа (сервер) будет работать, должен быть создан этой фабрикой. и если мы не хотим выдумывать колесо аки MyModuleDestroy, наследуем оъект от QObject и передаём в конструктор родителя (как я указывал на первой странице). здесь существует ещё один фактор - родительский поток - чтобы избежать нежелательных ситуаций, когда по каким-то причинам объект создался не в том потоке и наглухо блокирует обращения к нему и т.п., гораздо проще не вызывать обёртку-конструктор из нужного потока (как в твоём наброске), а указать родителя - объект переместится в родительский поток (главный поток для (родитель == 0)).
а вот абстракция (MyModuleBase в примере Dendy) - это и есть то, что тебе нужно! в фабрике ты создашь экземпляр произвольного наследника данного абстракта и будешь работать с ним по методам, описанным в декларации абстракта.
« Последнее редактирование: Январь 15, 2009, 00:01 от Константин » Записан
Steven_Orko
Гость
« Ответ #32 : Январь 15, 2009, 10:10 »

а серьезно - я хочу написать некое приложение (GPL) , наподобие SCADA... Оно бучет состоять из различных подсистем.. Каждая подсистема будет заниматься своим делом... Управлять подсистемами будет "ядро" ... Так вот, суть работы SCADA системы в кратце - сбор данных от различных источников, их обработка, архивирование и т.п. и. т.д.  Источники могут быть различные, например PLC, цифровые преобразователи (датчики), сервера, раб станции и все что угодно... Чтобы поиметь с них информацию - SCADA системе нужно знать что за источник и как с ним общаться....  т.е знать протокол обмена с неким девайсом... 
так вот, я могу впринципе все это реализовать без всяких плагинов, а чисто как некую подсистему приложения которая будет неотделима от него... но это не есть гут... поэтому я думаю эту подсистему вынести в отдельный модуль...

Например для начала хочу реализовать (как самое простое) некий модуль , который подключается к приложению и реализует протокол Modbus RTU... т.е этот модуль (после его подключения к приложению и его регистрации) должен позволять делать с ним следующее:
1. Стартовать его.
2.  Останавливать
3. Конфигурировать
4. Получать его статус , а также статусы его "подмодулей"
Модуль должен в зависимости от того как он сконфигурирован, САМ опрашивать источники данных (девайсы), вести статистику, БД и т.п. и. т.д..

А само приложение может получать нужные другим подсистемам данные от этого загруженного модуля посредством определенного API .. т.е приложению не нужны в принципе указатели на объекты в модуле... Ему нужны только АПИ!!!  (я так пока предварительно решил)

Судя по написанному здесь и немного далее, необходимости в использовании плагинов вообще нет, как я понимаю задачу.
По данному описанию получается КП, который имеет постоянно загруженное ядро(со своим конфигом) и набор backend-ов с некоторой конфигурационной информацией. В соответствии с конфигом ядром запускает backend-ы. Хотя на самом деле здесь их лучше называть сервисы, т.к. ИМХО в данной ситуации лучше использовать сервисо-ориентированный подход.
В соответствии с общей схемой сервисы предоставляют интерфейс управления ими: старт, стоп, перезагрузка конфига, получение статуса, пауза и т.д. Придумать можно много.
Я сам реализовываю подобную штуку. Правда у меня нет реального времени. Для коммуникации между сервисами использую D-Bus, для управления и получения данных, а также извещений об изменении состояний так же D-Bus. Получается такое общее дерево объектов:

Код:
root
root->service_01
root->service_01->Method_01
root->service_01->Method_02
root->service_01->Method_03
root->service_02
root->service_01->Method_01
root->service_01->Method_02

Если по каким-то причинам такая схема не подходит, то... ))))))
Ну, а если подходит, то могу дальше подробнее описать архитектуру...

P.S. ИМХО, минус использования плагинов состоит в том, что если один из них рухнет, то пока всему приложению...
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #33 : Январь 15, 2009, 10:58 »

ну хорошо, например я послушаю ваш совет... и в приложении делаю так(примерно):

где-то в private класса MyDialog определен:
Код:
private:
  
ModuleBase  MyModuleBase;

Код:
void MyDialog::loadPlugins(const QString fileName)
{
    QPluginLoader loader(fileName);
    QObject *plugin = loader.instance();
    if (plugin) {
        PluginInterface*iMyModule = qobject_cast<PluginInterface*>(plugin);
        if (iMyModule ) {
            MyModuleBase = iMyModule ->create();
        }
    }
}

так код писать?
Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #34 : Январь 15, 2009, 11:15 »

2 Steven_Orko

дадада !! что то в этом роде!

но эти "сервисы" должны быть отдельными библами... я не знаю как это назвать по научному, поэтому и путаю понятия "плагин", "модуль" и т.п.

т.е сами сервисы подразумеваются пока как объект типа QThread !!! и чтобы в ядро их не сувать , мне надо как то придумать их сделать отдельно..

1. т.е в приложении например выбираем в менюшке - типа "подключить модуть"
2. открывается окошко с предложением "выберите файл модуля (т.е библиотеку)
3. выбираем к примеру Modbus.dll (so)
4. жмем "подключить(загрузить)
5. чпок - типа читаем в какой нить метке статус - типа загружен успешно + в каком нить месте приложения в списке появляется имя этого подключенного модуля и краткая характеристика..
6. при клике на название этого подключенного модуля - открывается другая форма, менюшка и т.п. в которой представлена возможность его конфигурирования и т.д. и.т.п.
т.е. применительно к Модбас - это выбрать тип канала, контроллер, точку, регистры, БД, куда все будет сохраняться, параметры опроса выбранных контроллеров, каналов, точек и т.п. и. т.д. (см. спецификацию на протокол Улыбающийся )
7. после конфигурирования всего этого дела там же в окошке к примеру жмакаем "запустить"
8. и все... типа смотрим как оно работает , можем посмотреть какие получаем данные из сконфигуренных у-в и т.п. и т.д.

У меня пока самая важная сейчас цель - понять, как мне подключать этот "модуль" к приложению!!! и это проблема!! Улыбающийся
но в принципе "легко" это можно сделать МОНОЛИТНЫМ!  НО НЕ БУДУ!

Цитировать
Судя по написанному здесь и немного далее, необходимости в использовании плагинов вообще нет, как я понимаю задачу.

ну а как обычно в приложениях такого рода это делают как подключают модули?


Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #35 : Январь 15, 2009, 11:24 »

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

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

ArchLinux x86_64 / Win10 64 bit
Steven_Orko
Гость
« Ответ #36 : Январь 15, 2009, 12:51 »

дадада !! что то в этом роде!

но эти "сервисы" должны быть отдельными библами... я не знаю как это назвать по научному, поэтому и путаю понятия "плагин", "модуль" и т.п.

т.е сами сервисы подразумеваются пока как объект типа QThread !!! и чтобы в ядро их не сувать , мне надо как то придумать их сделать отдельно..

Хм. Так я имел ввиду, что сервисы реализованы не в форме библиотеки, а в виде отдельного запускаемого бинарника, который при этом использует интерфейс (API) ядра.
На форуме трудно полностью объяснить архитектуру. Я могу создать небольшой документ с описанием и переслать. Однако, для этого необходимо время.


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

ну а разве QT-шный подход с плагинами и их интерфейсами это не есть сие???
зачем они придумали интерфейсы, если можно все делать просто загружая динамическую библиотеку и беря из нее нужные ф-ции??
ИМХО, в данном случае применять плагины не разумно как минимум с точки зрения надежности. Хотя в виде плагинов можно оформить, например, GUI, для конфигурирования сервиса.
Записан
Dendy
Гость
« Ответ #37 : Январь 15, 2009, 12:57 »

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

Осознайте что пока вы так думаете - значит не разобрались в вопросе. Ставьте свои рассуждения под сомнение и примите на веру как вам говорят. Просветление прийдёт позже.
Выше вы спрашивали так ли писать код. Ответ - да.
Заметьте, что вашу ДЛЛ олицетворяет класс QPluginLoader, то-есть не QPlugin, а QPluginLoader - всего лишь загрузчик самого плагина. Как вы думаете, почему так? Подсказка: те кто придумывал названия классов - не идиоты.

Внимание, спойлер! Он должен быть перевёрнутым, но такого тега я не нашёл. Такая схема сделана потому что ваш плагин может быть загружен не только из ДЛЛ.
Записан
Steven_Orko
Гость
« Ответ #38 : Январь 15, 2009, 13:20 »

Ок. Решил написать сюда. Вот смотри.

Разбиваем весь програмный комплекс на две части:
1. Основная программа, так называемое ядро, и все, что с ним связано(настройки, библиотеки и т.д.).
2. Сервисы и все, что с ними связано (то же самое, что и в п.1, но для сервисов, если есть).

Весь программный пакет включает в себя общую директорию, где хранятся все необходимые файлы: конфиги, бинарники, иконки и т.д.
Директория примерно выглядит следующим образом:
Код:
root
root->bin   <---- Здесь лежжат основные бинарники для комплекса
root->config <-------Здесь лежат конфиги бинарников, описанных выше
root->config->plugins <-----Здесь лежат плагины форм (GUI) настройки сервисов
root->libs   <--Здесь лежат основные библиотеки комплеса
root->services   <-----Основная директория сервисов
root->services->bin  <---- бинарники сервисов
root->services->config <---Конфиги сервисов
root->services->libs  <--- Либы сервисов

Такая структура моя, придумана чисто из субъективных сображений. Можешь свою создать. Просто дальнейшее описание буду приводить, основываясь на ней.

Опишу немного общий процесс работы.
Загружается основная программа. Читает настройки. Создает (в терминах D-Bus) шину сообщений.
В соответствии с записями основного конфига программа запускает из директории services соответствующие сервисы.
При необходимости управления сервисами можно создать приблизительно следующий интерфейс.
Управление сервисами условно разделить на две группы:
1. Управление процессом сервиса
2. Управление конфигурацией сервиса

Пункт 1. Управление процессом.
Сервис можно добавлять, удалять в/из комплекса. Сервис можно автоматически стартовать, можно останавливать, получать статус работы.
Все настройки для этого хранятся в основном конфиге комплекса. Там же и хранится весь (ПОЛНЫЙ!!!!) список установленных в комплекс процессов.
Пункт 2. Управление конфигурацией сервиса.
При запуске указанного пользователем сервиса должен происходить следующий процесс. Сервис проверяет свой конфиг, считывает настройки, если конфиг есть, или создает файл конфига со стандартными настройками. Далее подключается к шине сообщений, созданной ядром (основной програмой). Каким-либо образом инициализирует и запускает основной алгоритм, т.е. делает то, для чего он предназначен.  При необходимости, в сервис можно добавить возможность рапортования об успешности запуска.
Конфигурация сервиса возможна только из окна главной программы. При этом когда пользователь запускает механизм конфигурирования, основная программа смотрит список инсталированных сервисов, проверяет наличие соответствующих плагинов для создания окна конфигурирования в папке config->plugins. Если там плагин есть, то загружает из него объект окна и выводит на экран. Если нет, то считать сервис не настраиваемым.
В плагине должны быть реализованы все функции по считыванию текущей конфигурации, сохранению новой, и, опять же если это надо, то извещению сервиса об изменении конфига.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #39 : Январь 15, 2009, 13:25 »

2 Dendy

хм.. но в моем случае тогда можно было бы обойтись и без QPluginLoader-a, т.е создать *.Dll в которой была бы аналогичная ф-я ModuleBase * create() ...

и я с помощью QLibrary загружал бы бибриотеку, вызывал бы из нее эту ф-ю и она мне создавала бы объект типа ModuleBase и возвращала на него указатель

и я бы из приложения его приводил к виду  ModuleBase  и работал бы с ним как хочу...

 Строит глазки  ?
Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #40 : Январь 15, 2009, 13:32 »

2 Steven_Orko

интересненько! Улыбающийся

а D-BUS он же "падучий" (у меня на PC по крайней мере раньше ошибки вылетали частенько с его участием) Улыбающийся т.е применять его - ненадежно в принципе (ИМХО)
Записан

ArchLinux x86_64 / Win10 64 bit
Steven_Orko
Гость
« Ответ #41 : Январь 15, 2009, 13:50 »

а D-BUS он же "падучий" (у меня на PC по крайней мере раньше ошибки вылетали частенько с его участием) Улыбающийся т.е применять его - ненадежно в принципе (ИМХО)

Сколько я его не ломал, пока учился использовать, сам демон у меня ни разу не упал. Все зависит от версии, плюс я его сам немного подправил, помнится, и собрал. Т.е. получается, что это уже моя версия D-Bus.

Но тебе не обязательно его использовать. Можно любую систему коммуникация между процессами, вплоть до самописного. Я просто привел пример архитектуры программного комплекса.
Записан
Dendy
Гость
« Ответ #42 : Январь 15, 2009, 14:04 »

хм.. но в моем случае тогда можно было бы обойтись и без QPluginLoader-a, т.е создать *.Dll в которой была бы аналогичная ф-я ModuleBase * create() ...
и я с помощью QLibrary загружал бы бибриотеку, вызывал бы из нее эту ф-ю и она мне создавала бы объект типа ModuleBase и возвращала на него указатель
и я бы из приложения его приводил к виду  ModuleBase  и работал бы с ним как хочу...

А вот и не угадали. Разница между QLibrary и QPluginLoader описана в Ассистанте:

Цитировать
A Qt plugin is stored in a shared library (a DLL) and offers these benefits over shared libraries accessed using QLibrary:
  • QPluginLoader checks that a plugin is linked against the same version of Qt as the application.
  • QPluginLoader provides direct access to a root component object (instance()), instead of forcing you to resolve a C function manually.
Записан
ритт
Гость
« Ответ #43 : Январь 15, 2009, 15:25 »

2 Steven_Orko

интересненько! Улыбающийся

а D-BUS он же "падучий" (у меня на PC по крайней мере раньше ошибки вылетали частенько с его участием) Улыбающийся т.е применять его - ненадежно в принципе (ИМХО)

фу, как оскорбительно. и твоё "имхо" совсем неуместно.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #44 : Январь 15, 2009, 15:54 »

Цитировать
фу, как оскорбительно. и твоё "имхо" совсем неуместно.
Улыбающийся 

в общем остановился пока на такой примерной реализации:

interfaces.h

Код:
#ifndef INTERFACES_H
#define INTERFACES_H

class MyModuleInterface
{
public:
    virtual ~MyModuleInterface() {}
    virtual void MyModuleStart() = 0;
    virtual void MyModuleStop() = 0;
};

Q_DECLARE_INTERFACE(MyModuleInterface, "mywww.My.MyModuleInterface/1.0")

#endif

myPlug.h

Код:
#ifndef MYPLUG_H
#define MYPLUG_H

#include <QObject>
#include <QThread>

#include "../app/interfaces.h"

//это собственно определение моего модуля, который должен чо-то выполнять
class TMyModule : public QThread
{
    Q_OBJECT

protected:
    void run();
//тут добавлю потом в public, private различные необхлдимые мне методы//
public:
    bool mabort;
};

//это как я понял плагин с интерфейсом
class MyModulePlugin : public QObject,
                       public MyModuleInterface
{
    Q_OBJECT
    Q_INTERFACES(MyModuleInterface)


public:
    void MyModuleStart();
    void MyModuleStop();
private:
    TMyModule Module;
};

#endif

myPlug.cpp

Код:
#include <QtGui>
#include "myPlug.h"


/****** МОДУЛЬ ******/
void TMyModule::run()
{
    printf("Module is Running \n");
    while (!mabort) {
sleep(1);
printf("Run \n");

    /*
    тут будет собственно реализован к примеру алгоритм работы модуля
    */
    }
    printf("Module is Stopped \n");
}

/****** ПЛАГИН ******/
void MyModulePlugin::MyModuleStart()
{
   Module.mabort = false;
   if (!Module.isRunning())
    Module.start();
}

void MyModulePlugin::MyModuleStop()
{
   Module.mabort = true;
}

Q_EXPORT_PLUGIN2(mymoduleplugin, MyModulePlugin)



Записан

ArchLinux x86_64 / Win10 64 bit
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.051 секунд. Запросов: 23.