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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: как узнать какая dll использовала callback ?  (Прочитано 7033 раз)
admsasha
Гость
« : Июнь 02, 2011, 15:22 »

Есть программа с что-то типа плагинами, я через функцию библиотеки передаю callback функцию основной формы (как бы для обратной связи)
Как узнать, какая именно библиотека вызвала этот callback ? Естественно не передавая эту метку явно через функцию.

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Июнь 02, 2011, 16:33 »

"какая dll" не совсем так, приложение может иметь несколько экземпляров одного плагина использующих одну и ту же dll но с разными данными. Можно просто запомнить указатель на плагин (объект) перед вызовом dll ф-ции. Для multi-thread плюс еще ID нитки
Записан
admsasha
Гость
« Ответ #2 : Июнь 02, 2011, 16:56 »

"какая dll" не совсем так, приложение может иметь несколько экземпляров одного плагина использующих одну и ту же dll но с разными данными.
Да, действительно. Как-то не подумал

Можно просто запомнить указатель на плагин (объект) перед вызовом dll ф-ции.
А вот тут подробнее, пожалуйста
Вот я, например вызывал из библиотеки функцию SetCallback и назначил ей callback setText. Т.е. теперь сама библиотека может менять текст в основной программе.
Код:
QLibrary library;
while(...){
   ...
   ...
   library.setFileName(pluginsName);
   funcSetCallback = (protCallback) library.resolve("SetCallback");
   if (funcSetCallback){
      funcSetCallback(setText);
   }
}
Пример грубый, но я думаю понятно...

какой указатель запомнить ?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Июнь 02, 2011, 18:02 »

какой указатель запомнить ?
Простой/примитивный вариант
Код
C++ (Qt)
static QLibrary * theActiveLib = 0;
...
QLibrary library;
...
  if (funcSetCallback){
     theActiveLib = &library;
     funcSetCallback(setText);
     theActiveLib = 0;
  }
...
void setText( void )
{
 assert(theActiveLib);
 qDebug() << "caller is" << theActiveLib->fileName();
 ...
}
 
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Июнь 02, 2011, 18:12 »

Если можно поменять тело ф-ии в либе, то может проще сделать как нормальные люди - в ее сигнатуру добавить void *data ?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Июнь 02, 2011, 19:06 »

Если можно поменять тело ф-ии в либе, то может проще сделать как нормальные люди - в ее сигнатуру добавить void *data ?
На мой взгляд это не проще и не лучше

- перекомпилировать либу не всегда просто, да и ф-ция может быть не одна
- неск объектов зовут ту же dll
- dll вызываетcя через др dll, напр цепочка host->dll1->...->dll2->callback

А из хоста нужен по существу scoped_lock

Записан
BRE
Гость
« Ответ #6 : Июнь 02, 2011, 20:14 »

Простой/примитивный вариант
Не вариант.

Зачем сохранять указатель в переменной theActiveLib при установке callback-функции, а после этого ее обнулять?  Улыбающийся
Ведь вызываться установленная функция (setText) будет не в этот момент, а потом.

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Июнь 02, 2011, 20:51 »

Ведь вызываться установленная функция (setText) будет не в этот момент, а потом.
Ага, живой (а я уж думал Вы заболели  Улыбающийся)
Если "потом" то окружить те dll ф-ции из которых setText зовется, это несложно сделать в общем виде. Суть та же

Записан
BRE
Гость
« Ответ #8 : Июнь 02, 2011, 21:10 »

Ага, живой (а я уж думал Вы заболели  Улыбающийся)
Ну так, твоими молитвами...  Улыбающийся

Если "потом" то окружить те dll ф-ции из которых setText зовется, это несложно сделать в общем виде. Суть та же
Т.е. изменить все функции во всех библиотеках, которые будут использовать этот callback? Что-то мне подсказывает, что топикстартер хотел все это сделать меньшими усилиями.  Подмигивающий
Если есть возможность изменить все библиотеки, то проще изменить интерфейс и штатно передавать какой-то идентификатор библиотеки.
« Последнее редактирование: Июнь 02, 2011, 21:17 от BRE » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Июнь 02, 2011, 22:04 »

Т.е. изменить все функции во всех библиотеках, которые будут использовать этот callback?
Та нет, либы не трогать, просто поменять обертки. Напр есть dll ф-ция
Код
C++ (Qt)
int FuncDLL1( int param );
 
Вместо нее использовать
Код
C++ (Qt)
int FuncDLL1_( int param, const QLibrary * theLib, void *  )
{
// удобно и resolve свалить сюда
static TFunc FuncDLL1 = 0;
if (!FuncDLL1)
 FuncDLL1 = theLib->resolve("FuncDLL1");
assert(FuncDLL1);
 
// запоминаем либу и/или вызываюшего
theActLib = theLib;
...
 
// вызываем
int result = FuncDLL1(param);
 
theActLib = 0;
return result;
}
 
Записан
BRE
Гость
« Ответ #10 : Июнь 02, 2011, 22:13 »

Та нет, либы не трогать, просто поменять обертки. Напр есть dll ф-ция
Код
C++ (Qt)
int FuncDLL1( int param );
 
На самом деле в библиотеке есть функция, которая регистрирует callback-функцию. Далее эта функция будет вызвана и уже в ней нужно определить кто ее дернул.
Записан
admsasha
Гость
« Ответ #11 : Июнь 03, 2011, 02:10 »

Простой/примитивный вариант
Это подходит, если бы вызывающая библиотека была одна. А как сделать, если их, например, 10 ? В моем примере, они все считываются из какой то условной папки. А потом ждем вызов функции setText(). Ну а в ней нужно сделать, например, лог. "Такая то dll вызвала эту функцию".

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

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Июнь 03, 2011, 10:00 »

На самом деле в библиотеке есть функция, которая регистрирует callback-функцию. Далее эта функция будет вызвана и уже в ней нужно определить кто ее дернул.
Можно дать каждой dll свою callback, но это случай частный, так можно отследить только dll (модуль), да и регистрации никто не обещал

Это подходит, если бы вызывающая библиотека была одна. А как сделать, если их, например, 10 ? В моем примере, они все считываются из какой то условной папки. А потом ждем вызов функции setText().
Без разницы 1, 10 или 100. Приложение (хост) всегда знает когда оно отдает управление в dll (плагин) и всегда знает в какой именно. Нужно только перед отдачей управления (вызовом dll ф-ции) сохранить эту информацию. Что сохранять - дело хозяйское. Напр если интересно только имя файла  
Код
C++ (Qt)
std::maр <void *, QString> theMap;
QString theActiveDLL;
 
// получаем dll ф-цию которая вызовет setText
TFunc FuncDLL1 = library.resolve("FuncDLL1");
 
// запоминаем из какого файла эта ф-ция
theMap[(void *) FuncDLL1] = library.fileName();
...
// перед вызовом ф-ции устанавливаем имя dll
theActiveDLL = theMap.find((void *) FuncDLL1)->second;
// вызываем
FuncDLL1(..);
 
Записан
BRE
Гость
« Ответ #13 : Июнь 03, 2011, 11:44 »

Небольшой набросок:
Код
C++ (Qt)
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
 
// Наша callback-функция
void setText( const std::string &str )
{
std::cout << "Call setText( " << str << " )" << std::endl;
}
 
typedef boost::function<void ( const std::string & )> CallbackFunc;
 
// ========================================================================
// Этот класс просто эмитирует разделяемую библиотеку
class Dll
{
public:
void setCallback( const CallbackFunc &fn )
{
m_func = fn;
}
 
void run()
{
if( !m_func.empty() )
m_func( "Test string" );
}
 
private:
CallbackFunc m_func;
};
 
// ========================================================================
// Класс адаптор
// Объект этого класса служит переходником, который сохраняет идентификатор
// библиотеки
class Adaptor
{
public:
Adaptor( const std::string &dllName, const CallbackFunc &fn ) :
m_dllName( dllName ), m_func( fn )
{
}
 
void recall( const std::string &str )
{
m_func( m_dllName + ";" + str );
}
 
private:
std::string m_dllName;
CallbackFunc m_func;
};
 
// ========================================================================
 
 
 
int main( int argc, char **argv )
{
Dll dll1;
Dll dll2;
 
// Варианты с адаптором или без.
#if 1
dll1.setCallback( boost::bind( &setText, _1 ) );
dll2.setCallback( boost::bind( &setText, _1 ) );
 
#else
Adaptor a1( "first.dll", boost::bind( &setText, _1 ) );
Adaptor a2( "second.dll", boost::bind( &setText, _1 ) );
 
dll1.setCallback( boost::bind( &Adaptor::recall, &a1, _1 ) );
dll2.setCallback( boost::bind( &Adaptor::recall, &a2, _1 ) );
#endif
 
dll1.run();
dll2.run();
 
return 0;
}
 
Записан
admsasha
Гость
« Ответ #14 : Июнь 03, 2011, 12:22 »

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

Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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