C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Экспорт VCL классов из DLL, как создать экземпляр класса из DLL?
klen
Отправлено: 16.03.2004, 16:53


Машинист паровоза

Группа: Участник
Сообщений: 239



Здравствуйте.

Задача следующая, есть DLL в ней код класса, например формы, ecтественно класс экспортируется в DLL. Каким образом извлеч оттуда клас и создать экземпляр класса.
Библиотечного файла нет. Можно использовать только таблицу экспорта и название класса. Короче скажем так, тип обьекта не известен, имя его класса известно, класс экспортируестся.

Попутный вопрос.
Чето не пойму с экземпляром TApplication для DLL, он создается и неинициализируется, не создается, является обьектом исполняемого модуля??? А то у меня компоненты привязанные к TAplication при переносе в DLL перестают работать.

Я к примеру думаю что имея class reference както можно вызвать конструктор, но я не знаю как.

Отредактировано klen — 17/03/2004, 01:47
klen
Отправлено: 20.03.2004, 12:12


Машинист паровоза

Группа: Участник
Сообщений: 239



Кому понадобится — спросите. Обсосал проблему вроде до молекулярного состава. Можно классы в DLL хранить, и собственно их и экспортировать, и никаких функций не экспортировать вообще.
Asher
Отправлено: 20.03.2004, 12:23


Мастер участка

Группа: Модератор
Сообщений: 550



Привет.
Если можно с этого места медленно и по-подробнее.
klen
Отправлено: 20.03.2004, 13:49


Машинист паровоза

Группа: Участник
Сообщений: 239



Дело было так:

Пишу программу — среду разработки приложений для нашей однокристалки кр1878ве1. Среда будет похожа на билдер — редактор кода, отладчик, менеджер проектов, эксперт кода, дизассемблер....и вся такая байда числом пока 12 обьектов. Мне всегда хотелось засунуть в библиотеки классы, а создавать экземпляры в модуле котором я хочу, а не в модуле самой библиотеке ( раньше я писал функцию типа GetForm и экспортировал ее, вызвав ее она крейтила форму и возвращала) но это меня не устраивала чисто эстетической точки зрения, да и с освобождением памяти и экземпляром Application созданном в dll вечные проблемы были.

Эсли обратите внимание, то обнаружите в списке экспортируемых dll символов находися куча всего (если не убрать опции отладки RTTI , RTL и т.д ) помимо прочего там емеются конструкторы экспортируемых классов и д.р Возник вопрос как его извлечь в модуле подгрузившем dll?
Он меня долго мучил:) Я догадался что можно провести экспорт всеголишь одного символа !! в dll в процедуре DllEntryPoint (точка входа проинициализировать экспортитруюмою переменную будет хранить адрес начала VMT экспортируемого класса, ее считываешь и по таблице виртуальных методов находишь конструктор объекта, вызываешь его и получаешь объект. Все , счастье. Так как я пишу свою среду в виде совокупности модулей с открытой архитектурой(плагины) то мне така схема была очень удобна, также я в опубликованой секции определяю метод типа GetObjInterface который мне раскажет че за обьект и как с ним работать.

Кстате камнем преткновения была необходимость в такой схеме явно вызвать конструктор!!! Что в С++ нормальные люди не умеют делать, потомучто это не надо. От этого комплекса неполноценности избавили меня мужики с форума www.bcbdev.ru ОГРОМНОЕ СПАСИБО ГЛАЗА ОТКРЫЛИ Я РАНЬШЕ ДУМАЛ ЧТО Я крут.

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


CODE


TComponent* __fastcall TSplashForm::CreateComponent(TComponentClass CClass, TComponent* AOwner)
{
 typedef TComponent *( __fastcall  *TConstructor)( TComponentClass, bool, TComponent *);
 TConstructor constructor = ((TConstructor *)CClass)[ vmtCreateObject — 1];
 return constructor( CClass, true, AOwner);
}


void __fastcall TSplashForm::LoadModule( AnsiString ModulePath )
{
 if ( !IsExecuteble (ModulePath) ) return;
 HMODULE hMod = LoadLibrary ( ModulePath.c_str() );
 if ( hMod )
      {
       // инициализируем модуль и получаем __classid ()
       STURTUOPROC SturtupModule = (STURTUOPROC) GetProcAddress ( hMod , "StartupModule" );
       TFormClass ObjClassRef = (TFormClass)SturtupModule (Application);
       TScrollingWinControl* Obj = (TScrollingWinControl*)CreateComponent ( ObjClassRef , Application );



       // "Пожимаем руки" обьекту модуля про который нам нихера еще неизвестно
       TModuleInfo* ModuleInfo = new TModuleInfo;
       ModuleInfo -> Handle = hMod;
       ModuleInfo -> ModuleObj = Obj;

       // Вытаскиваем интерфейсную функцию
       typedef void __fastcall (*GETMODINFO) ( TModuleInfo*);
       char MethodName[255] = "GetModuleInfo";
       GETMODINFO GetModuleInfo = (GETMODINFO)Obj -> MethodAddress ( MethodName );

       // вызываем метод в контексте объекта (в момент написания этих     строк уже знаю как без ассемблера вызвать, про это написано на www.bcbdev.ru)
     
 __asm
         {
           mov edx , ModuleInfo
           mov eax , Obj
           call GetModuleInfo;
         }
       // Отображаем если это форма
       if ( dynamic_cast<TComponent*> (Obj)  )
          ((TCustomForm*)Obj) -> Show ();
       //размещаем гденибудь если это фрейм
       if ( dynamic_cast<TCustomFrame*> (Obj)  )
          ((TCustomFrame*)Obj) -> Parent = TargetParent ;

       // запоминаем в списке загруженные модули
       LoadedModulesList -> Add( ModuleInfo );
      }
}


в dll код следущий
CODE

TApplication* NativeApp;

extern "C"
{
   void* __export StartupModule ( void* App )  ;
}
//----------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
 switch ( reason )
 {
   case DLL_PROCESS_ATTACH :
     {
      NativeApp = Application;
      break;
     }
   case DLL_PROCESS_DETACH :
     {
      Application = NativeApp;
      break;
     }
 }
 return 1;
}
//---------------------------------------------------------------------------
void* __export StartupModule ( void* App )
{
 Application = (TApplication*)App;
 return __classid (TAllEditorForm);
}


В первоночальном варианте у меня было __export ClassRef
TComponentClass ClassRef = __classid (TAllEditorForm) и из dll вытаскивалась TComponentClass Ref = (TComponentClass)GetProcAddress( hMod, "ClassRef " ) , а далее CreteComponent.

Вродебы все, если че то спрашивай, я на форуме сижу непрерывно, даже ночью

Вернуться в Вопросы программирования в C++Builder