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.
Вродебы все, если че то спрашивай, я на форуме сижу непрерывно, даже ночью |
|
|