Как вызвать ф-цию Register пакета BPL
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TDBGridM)};
RegisterComponents("Data Controls", classes, 0);
}
}
она регистрирует пакет при подключении его к Builder'у (Delphi).
Но я в своей програме подключаю пакеты динамически, ф-цией LoadPackage и надо использовать компоненты которые в этом пакете, то надо зарегистрировать эти компоненты, вызвав ф-цию Register пакета.
[SIZE="3"]Так вот вопрос: как вызвать ф-цию Register пакета BPL???[/SIZE]
1. Есть програма (моя), в неё надо встроить дизайнер, который читал / писал / редактировал бы dfm и создавал на основи их формы.
2. Для чтения dfm нужно зарегестрировать все компоненты, которые на ней могут быть.
3. Если в форме которая записана в dfm есть компонент, который не зарегестрирован в програме, то форма не загрузится.
4. Для того, чтобы грузить любые формы с програмой поставляется расширеный набор пакетов - стандартные Builder (VCLXX.bpl, RTLXX.bpl ...) и пакеты сторонних разработчиков.
Так вот, если все пакеты компелировать с програмой, то всё чики-пуки. Но тогда для добавления нового компонента надо заново компилировать прогу.
Я хочу подругому, в некую папку "BPLs" кидаю пакеты, и подгружаю их в момент запуска програмы.
Но как вызвать функцию регистрирующюю компоненты?
[SIZE="2"]+ Как узнать все Namespace в пакете?[/SIZE]
[SIZE="2"]Я знаю как узнать все ContainsUnit в пакете, может это одно и тоже?[/SIZE]
...
[SIZE="3"]Так вот вопрос: как вызвать ф-цию Register пакета BPL???[/SIZE]
GetProcAddress?
Гы, я знаю. Но GetProcAddress("???") что?
_Register не находит.
Но КАК её вызвать если их несколько, и я не знаю их по имени?
[SIZE="2"]Тоесь КАК найти все функции регистрации в пакете?[/SIZE]
Получается примерно так:
1. Так я нахожу все подключённые к програме пакеты и их ContainsUnit.
{
if(NameType == ntContainsUnit)MOMO1->Lines->Add(Name);
else if(NameType == ntRequiresPackage)MOMO2->Lines->Add(Name);
else /*if(NameType == ntDcpBpiName)*/MOMO3->Lines->Add(Name);
}
void * Param = NULL;
int Flag;
try {
GetPackageInfo((int)ListBox1->Items->Objects, Param, Flag, InfoProc1);
}
catch(...){}
2. Так я нахожу функцию регистрации
void (__stdcall * Register1)();
Register1 =
(void (__stdcall *)())
GetProcAddress(lModule, Edit3->Text.c_str());
if(Register1){Register1(); ShowMessage("BRRRRR");}
Вот, тут-то и загвоздка. Я не знаю имени функции, знаю только, что у неё такой формат:
@НЕКОЕ_NameSpace@Register$qqrv
[SIZE="2"]Так вот, я не догоняю как мне найти именно namespace'ы пакета?[/SIZE]
ContainsUnit похожы, но GetProcAddress чувствительна к регистру, а ContainsUnit отлицаются от namespace именно регистром (в общем случае). Например для: dclstd60.bpl, фунцкия регистрации Dde компонентов называется так: @Ddereg@Register$qqrv, а ContainsUnit с этими компонентами - DdeReg.
Но КАК её вызвать если их несколько, и я не знаю их по имени?
...
По сути то о чем ты спрашиваешь (ИМХО) - тебе необходимо узнать имя функции, которую экспортирует данный модуль? Или сформулируй задачу более конкретно - не понятно с чем собственно ты борешься. Тот же tdump вполне способен показать необходимое имя функции, в принципе никто не запретит это выполнить в своей программе (в смысле получить имена ф-ций которые экспортятся) - т.е. если задача требует - то можно пытаться производить анализ ...
Вот, тут-то и загвоздка. Я не знаю имени функции, знаю только, что у неё такой формат:
@НЕКОЕ_NameSpace@Register$qqrv
Да, название будет именно такое. Читай РЕ-заголовок, для каждого пакета (т.е. dll). И см. имена всех экспортируемых из пакета(dll) ф-ий, ищи ту которая оканчивается на - Register$qqrv.
Не подскажеш как читать PE-заголовок?:confused: Если не сложно.
Лучше функцию, какую-нибуть, можно на паскале.
[QUOTE=kot_]
По сути то о чем ты спрашиваешь (ИМХО) - тебе необходимо узнать имя функции, которую экспортирует данный модуль? Или сформулируй задачу более конкретно - не понятно с чем собственно ты борешься.[/QUOTE]
Я сверху вполне конкретно изложил задачу.
Просто, если не сложно, объясните начинающиму, как получить список экспортированых функций? Я имею введу функцию, потому как внешние проги или батники меня не устраивают.
Но как вызвать функцию регистрирующюю компоненты?
Задача похожа на донкихотовскую. Реализовать собственный OTA? Спасибо, не надо.
Лучше функцию, какую-нибуть, можно на паскале.
Пока не знаю:) Там куча структур (правильней наверно говорить РЕ-формат) надо разобраться самому. Раньше с РЕ не имел дело. Если не горит подожди (пока занят, но самому интересно...) попробую разобраться если нет, то пусти в гугле "IMAGE_EXPORT_DIRECTORY"...
Не такая сложная задача. Всего-то разобратся в схеме загрузки пакетов:D . Тем более, что Borland оставила все инструменты для этого.
Убедился в этом сам, когда работал над собственным Object Inspector'ом.
Супер!!! Приятно встретить понимающего человека:) .
Впринцыпе не горит, и сам быду рытся:cool: . Но если будут наработки - пиши, буду очень признателен.
.h
PDWORD PtrLnAOF;
PDWORD PtrLnAON;
WORD wNO;
}EXPORTDATA,*PEXPORTDATA;
class TForm1 : public TForm
{
__published: // IDE-managed Components
TBitBtn *BitBtn2;
TListView *ListView1;
TOpenDialog *OpenDialog1;
void __fastcall BitBtn2Click(TObject *Sender);
private: // User declarations
void __fastcall TForm1::LoadExportFunc(WORD NumberOfSections,PIMAGE_SECTION_HEADER ISH,int Offset);
void* __fastcall TForm1::MapFile(const char* File);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
.cpp
{
PIMAGE_DOS_HEADER IDH;
if(!OpenDialog1->Execute())return;
if((IDH = (PIMAGE_DOS_HEADER)MapFile(OpenDialog1->FileName.c_str()))==0) return;
PIMAGE_NT_HEADERS INTH = (PIMAGE_NT_HEADERS)((PBYTE)IDH+IDH->e_lfanew);
PIMAGE_SECTION_HEADER ISH = IMAGE_FIRST_SECTION(INTH);
int Offset = (int)ISH - (DWORD)IDH;
LoadExportFunc(INTH->FileHeader.NumberOfSections,ISH,Offset);
//EnumThreadWindows(0, &EnumThreadWndProc, 0);
UnmapViewOfFile((void*)IDH);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LoadExportFunc(WORD NumberOfSections,PIMAGE_SECTION_HEADER ISH,int Offset){
ListView1->Items->Clear();
DWORD Rva,Difference;
PIMAGE_EXPORT_DIRECTORY ExportOffset;
int i,j;
char buffer[0x400];
PDWORD PtrLnAOF,PtrLnAON,PtrLnAON_S;
PWORD PtrLnAONO,PtrLnAONO_S;
PIMAGE_DOS_HEADER IDH = (PIMAGE_DOS_HEADER)((int)ISH - Offset);
PIMAGE_NT_HEADERS INTH = (PIMAGE_NT_HEADERS)((PBYTE)IDH+IDH->e_lfanew);
Rva = INTH->OptionalHeader.DataDirectory[0].VirtualAddress;
for(i=0;i < NumberOfSections;i++,ISH++){
if(!strcmp(ISH->Name,".edata")){
i = NumberOfSections;
Difference = ISH->VirtualAddress - ISH->PointerToRawData;
}
}
PIMAGE_EXPORT_DIRECTORY IED = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)IDH+Rva - Difference);
PtrLnAOF = (DWORD*)((PBYTE)IDH+(DWORD)IED->AddressOfFunctions - Difference);
PtrLnAON = PtrLnAON_S = (DWORD*)((PBYTE)IDH+(DWORD)IED->AddressOfNames - Difference);
PtrLnAONO = PtrLnAONO_S = (WORD*)((PBYTE)IDH+(DWORD)IED->AddressOfNameOrdinals - Difference);
for(i = 0;i < IED->NumberOfFunctions;i++){
PEXPORTDATA ExportData = new EXPORTDATA;
ExportData->PtrLnAOF = PtrLnAOF;
j=0;
while((*PtrLnAONO != i)&& (++j < IED->NumberOfNames)){
PtrLnAON++;
PtrLnAONO++;
}
if(j <= IED->NumberOfNames ){
ExportData->PtrLnAON = PtrLnAON;
ExportData->wNO = i+IED->Base;
}
else{
ExportData->PtrLnAON = 0;
ExportData->wNO = i+IED->Base;
}
TListItem *LI = ListView1->Items->Add();
sprintf(buffer,"%08x",PtrLnAOF);
LI->Caption = buffer;
sprintf(buffer,"%04x",i+IED->Base);
LI->SubItems->Add(buffer);
if(j <= IED->NumberOfNames){
sprintf(buffer,"%s",((PBYTE)IDH +(DWORD)*PtrLnAON - Difference));
LI->SubItems->Add(buffer);
}
PtrLnAOF++;
PtrLnAON = PtrLnAON_S;
PtrLnAONO = PtrLnAONO_S;
}
}
void* __fastcall TForm1::MapFile(const char* File){
HANDLE hFile,hMappedFile;
void* MappedFile;
hFile = CreateFile(File,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == INVALID_HANDLE_VALUE)return 0;
hMappedFile = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
CloseHandle(hFile);
if(!hMappedFile)return 0;
MappedFile = MapViewOfFile(hMappedFile,FILE_MAP_READ,0,0,0);
CloseHandle(hMappedFile);
if(!MappedFile) return 0;
return MappedFile;
}
выведет список экспортируемых функций в листвью.
Супер! Респект и огромное спасибо kot_.:D
Хм...
Ну пока слабо, но я уже накачал статей по PE формату. Но пока разберусь, время пройдёт.
Если у тебя есть уже готовая исправленная - то буду благодарен, если нету, и надо делать - то не напрягайся, я как-нибудь сам.
Или может GIZMO разберётся... :rolleyes:
Ну пока слабо, но я уже накачал статей по PE формату. Но пока разберусь, время пройдёт.
Если у тебя есть уже готовая исправленная - то буду благодарен, если нету, и надо делать - то не напрягайся, я как-нибудь сам.
Или может GIZMO разберётся... :rolleyes:
Я думаю тебе будет интересней разобраться самому. Тем более что приведенный выше код твою задачу решает. Для тех кому интересно, подсказка - зачем в папке {$BCB}\bin есть утилита coff2omf?
Зачем утилита coff2omf так и не разобрался, но не особо и старался.:rolleyes:
А вот, что получилось по-поводу нахождения export функций::)
HMODULE hModule = LoadLibrary(OpenDialog1->FileName.c_str());
if(!hModule){ShowMessage("!hModule"); return;}
PIMAGE_DOS_HEADER pDOSHead = (PIMAGE_DOS_HEADER)hModule;
if(pDOSHead->e_magic != IMAGE_DOS_SIGNATURE)
{
ShowMessage("Error DOS Header signature");
return;
}
PIMAGE_NT_HEADERS pPEHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDOSHead + pDOSHead->e_lfanew);
if(pPEHeader->Signature != IMAGE_NT_SIGNATURE)
{
ShowMessage("Error PE Header signature");
return;
}
IMAGE_OPTIONAL_HEADER OptionalHeader = (IMAGE_OPTIONAL_HEADER)pPEHeader->OptionalHeader;
PIMAGE_EXPORT_DIRECTORY pExportDer =
(PIMAGE_EXPORT_DIRECTORY)((DWORD)hModule + OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
char ** FuckNames =
(char **)((DWORD)hModule + (DWORD)pExportDer->AddressOfNames);
ListView1->Items->Clear();
for(unsigned long i(0) ; i < pExportDer->NumberOfNames ; i++, FuckNames++)
{
char * buffer =
(char *)((DWORD)hModule + (DWORD)*FuckNames);
TListItem * LI = ListView1->Items->Add();
LI->SubItems->Add("");
LI->SubItems->Add(buffer);
}
FreeLibrary(hModule);
Код проще, чем у тебя (kot_), правда находит только имена функций, но для любой DLL или PE Executable (в общем случае).
kot_ объясни непонятному зачем делать маппинг файла DLL, перед считыванием из него экспортных функций.
Из твоего кода:
Так быстрее, надёжнее или правильней, или это просто, простите, понты?
Да, кстати, до сих пор слабо...:( Именно модифицыравать твой (kot_) код. Написать свой с нуля оказалось прощще.
Выбивает Exepion. Я где-то, что-то не учитываю, и никак не могу понять где? Но я не оставляю попыток, т.к. твой код мне нравится больше. Ну он наворочиней, чтоли...
kot_ объясни непонятному зачем делать маппинг файла DLL, перед считыванием из него экспортных функций.
Из твоего кода:
Так быстрее, надёжнее или правильней, или это просто, простите, понты?
Нет не понты. Смысл дважды выполнять одну и туже операцию? Вначале системный загрузчик проанализирует информацию о таблицах импорта/экспорта, загрузит связанные библиотеки, затем тоже самое делаешь ты. Экономичней спроецировать файл в память и работать с ним - это эффективней. Хотя может быть для твоей задачи, как раз более эффективно вызвать системный загрузчик, найти функцию и обратится к ней - хз.