Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Как вызвать ф-цию Register пакета BPL

19K
15 февраля 2007 года
Termi_uc
33 / / 13.02.2007
В каждом (в общем случае) пакете BPL есть ф-ция вида:
 
Код:
namespace Dbgridm
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TDBGridM)};
RegisterComponents("Data Controls", classes, 0);
}
}

она регистрирует пакет при подключении его к Builder'у (Delphi).

Но я в своей програме подключаю пакеты динамически, ф-цией LoadPackage и надо использовать компоненты которые в этом пакете, то надо зарегистрировать эти компоненты, вызвав ф-цию Register пакета.

[SIZE="3"]Так вот вопрос: как вызвать ф-цию Register пакета BPL???[/SIZE]
19K
15 февраля 2007 года
Termi_uc
33 / / 13.02.2007
[SIZE="3"]Зачем мне это нужно:[/SIZE]
1. Есть програма (моя), в неё надо встроить дизайнер, который читал / писал / редактировал бы dfm и создавал на основи их формы.
2. Для чтения dfm нужно зарегестрировать все компоненты, которые на ней могут быть.
3. Если в форме которая записана в dfm есть компонент, который не зарегестрирован в програме, то форма не загрузится.
4. Для того, чтобы грузить любые формы с програмой поставляется расширеный набор пакетов - стандартные Builder (VCLXX.bpl, RTLXX.bpl ...) и пакеты сторонних разработчиков.
Так вот, если все пакеты компелировать с програмой, то всё чики-пуки. Но тогда для добавления нового компонента надо заново компилировать прогу.
Я хочу подругому, в некую папку "BPLs" кидаю пакеты, и подгружаю их в момент запуска програмы.
Но как вызвать функцию регистрирующюю компоненты?

[SIZE="2"]+ Как узнать все Namespace в пакете?[/SIZE]
[SIZE="2"]Я знаю как узнать все ContainsUnit в пакете, может это одно и тоже?[/SIZE]
246
16 февраля 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: Termi_uc

...
[SIZE="3"]Так вот вопрос: как вызвать ф-цию Register пакета BPL???[/SIZE]


GetProcAddress?

19K
16 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: GIZMO
GetProcAddress?


Гы, я знаю. Но GetProcAddress("???") что?

_Register не находит.

19K
16 февраля 2007 года
Termi_uc
33 / / 13.02.2007
ВСЕ, КАК вызвать функцию регистрации, зная её имя, я знаю.
Но КАК её вызвать если их несколько, и я не знаю их по имени?
[SIZE="2"]Тоесь КАК найти все функции регистрации в пакете?[/SIZE]

Получается примерно так:
1. Так я нахожу все подключённые к програме пакеты и их ContainsUnit.
Код:
void __fastcall InfoProc1(const AnsiString Name, TNameType NameType, Byte Flags, void * Param)
{
 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. Так я нахожу функцию регистрации
 
Код:
if(!lModule)return;

 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.
1
17 февраля 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Termi_uc
ВСЕ, КАК вызвать функцию регистрации, зная её имя, я знаю.
Но КАК её вызвать если их несколько, и я не знаю их по имени?
...



По сути то о чем ты спрашиваешь (ИМХО) - тебе необходимо узнать имя функции, которую экспортирует данный модуль? Или сформулируй задачу более конкретно - не понятно с чем собственно ты борешься. Тот же tdump вполне способен показать необходимое имя функции, в принципе никто не запретит это выполнить в своей программе (в смысле получить имена ф-ций которые экспортятся) - т.е. если задача требует - то можно пытаться производить анализ ...

246
18 февраля 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: Termi_uc

Вот, тут-то и загвоздка. Я не знаю имени функции, знаю только, что у неё такой формат:
@НЕКОЕ_NameSpace@Register$qqrv


Да, название будет именно такое. Читай РЕ-заголовок, для каждого пакета (т.е. dll). И см. имена всех экспортируемых из пакета(dll) ф-ий, ищи ту которая оканчивается на - Register$qqrv.

19K
19 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: GIZMO
Да, название будет именно такое. Читай РЕ-заголовок, для каждого пакета (т.е. dll).


Не подскажеш как читать PE-заголовок?:confused: Если не сложно.
Лучше функцию, какую-нибуть, можно на паскале.
[QUOTE=kot_]
По сути то о чем ты спрашиваешь (ИМХО) - тебе необходимо узнать имя функции, которую экспортирует данный модуль? Или сформулируй задачу более конкретно - не понятно с чем собственно ты борешься.[/QUOTE]
Я сверху вполне конкретно изложил задачу.
Просто, если не сложно, объясните начинающиму, как получить список экспортированых функций? Я имею введу функцию, потому как внешние проги или батники меня не устраивают.

10
19 февраля 2007 года
Freeman
3.2K / / 06.03.2004
Цитата: Termi_uc
Я хочу подругому, в некую папку "BPLs" кидаю пакеты, и подгружаю их в момент запуска програмы.
Но как вызвать функцию регистрирующюю компоненты?


Задача похожа на донкихотовскую. Реализовать собственный OTA? Спасибо, не надо.

246
19 февраля 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: Termi_uc
Не подскажеш как читать PE-заголовок?:confused: Если не сложно.
Лучше функцию, какую-нибуть, можно на паскале.


Пока не знаю:) Там куча структур (правильней наверно говорить РЕ-формат) надо разобраться самому. Раньше с РЕ не имел дело. Если не горит подожди (пока занят, но самому интересно...) попробую разобраться если нет, то пусти в гугле "IMAGE_EXPORT_DIRECTORY"...

19K
19 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: Freeman
Задача похожа на донкихотовскую. Реализовать собственный OTA? Спасибо, не надо.


Не такая сложная задача. Всего-то разобратся в схеме загрузки пакетов:D . Тем более, что Borland оставила все инструменты для этого.

Убедился в этом сам, когда работал над собственным Object Inspector'ом.

19K
19 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: GIZMO
Пока не знаю:) Там куча структур (правильней наверно говорить РЕ-формат) надо разобраться самому. Раньше с РЕ не имел дело. Если не горит подожди (пока занят, но самому интересно...) попробую разобраться если нет, то пусти в гугле "IMAGE_EXPORT_DIRECTORY"...


Супер!!! Приятно встретить понимающего человека:) .
Впринцыпе не горит, и сам быду рытся:cool: . Но если будут наработки - пиши, буду очень признателен.

1
19 февраля 2007 года
kot_
7.3K / / 20.01.2000
Цитата: GIZMO
Пока не знаю:) Там куча структур (правильней наверно говорить РЕ-формат) надо разобраться самому. Раньше с РЕ не имел дело. Если не горит подожди (пока занят, но самому интересно...) попробую разобраться если нет, то пусти в гугле "IMAGE_EXPORT_DIRECTORY"...


.h

Код:
typedef struct{
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
Код:
void __fastcall TForm1::BitBtn2Click(TObject *Sender)
{
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;
}

выведет список экспортируемых функций в листвью.
1
19 февраля 2007 года
kot_
7.3K / / 20.01.2000
Естественно, перед тем как читать заголовок надо проверять - есть ли он вообще :) Но это уже сам реализуй.
19K
19 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Естественно, перед тем как читать заголовок надо проверять - есть ли он вообще :) Но это уже сам реализуй.


Супер! Респект и огромное спасибо kot_.:D

1
20 февраля 2007 года
kot_
7.3K / / 20.01.2000
Кстати, приведенный мной код имеет один баг - это первая версия. Билдеровские файлы она анализирует без проблем - а вот файлы вижуал студии (и соответственно винды)- выбивает ексепшин. Слабо модифицировать так что бы работало с обеими? ;)
19K
20 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: kot_
...Слабо модифицировать так что бы работало с обеими? ;)


Хм...
Ну пока слабо, но я уже накачал статей по PE формату. Но пока разберусь, время пройдёт.
Если у тебя есть уже готовая исправленная - то буду благодарен, если нету, и надо делать - то не напрягайся, я как-нибудь сам.
Или может GIZMO разберётся... :rolleyes:

1
20 февраля 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Termi_uc
Хм...
Ну пока слабо, но я уже накачал статей по PE формату. Но пока разберусь, время пройдёт.
Если у тебя есть уже готовая исправленная - то буду благодарен, если нету, и надо делать - то не напрягайся, я как-нибудь сам.
Или может GIZMO разберётся... :rolleyes:


Я думаю тебе будет интересней разобраться самому. Тем более что приведенный выше код твою задачу решает. Для тех кому интересно, подсказка - зачем в папке {$BCB}\bin есть утилита coff2omf?

19K
26 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: kot_
Я думаю тебе будет интересней разобраться самому. Тем более что приведенный выше код твою задачу решает. Для тех кому интересно, подсказка - зачем в папке {$BCB}\bin есть утилита coff2omf?


Зачем утилита coff2omf так и не разобрался, но не особо и старался.:rolleyes:

А вот, что получилось по-поводу нахождения export функций::)

Код:
if(!OpenDialog1->Execute())return;

 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, перед считыванием из него экспортных функций.
Из твоего кода:
 
Код:
void* __fastcall TForm1::MapFile(const char* File)

Так быстрее, надёжнее или правильней, или это просто, простите, понты?
19K
26 февраля 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: kot_
Кстати, приведенный мной код имеет один баг - это первая версия. Билдеровские файлы она анализирует без проблем - а вот файлы вижуал студии (и соответственно винды)- выбивает ексепшин. Слабо модифицировать так что бы работало с обеими? ;)


Да, кстати, до сих пор слабо...:( Именно модифицыравать твой (kot_) код. Написать свой с нуля оказалось прощще.
Выбивает Exepion. Я где-то, что-то не учитываю, и никак не могу понять где? Но я не оставляю попыток, т.к. твой код мне нравится больше. Ну он наворочиней, чтоли...

1
26 февраля 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Termi_uc

kot_ объясни непонятному зачем делать маппинг файла DLL, перед считыванием из него экспортных функций.
Из твоего кода:
 
Код:
void* __fastcall TForm1::MapFile(const char* File)

Так быстрее, надёжнее или правильней, или это просто, простите, понты?


Нет не понты. Смысл дважды выполнять одну и туже операцию? Вначале системный загрузчик проанализирует информацию о таблицах импорта/экспорта, загрузит связанные библиотеки, затем тоже самое делаешь ты. Экономичней спроецировать файл в память и работать с ним - это эффективней. Хотя может быть для твоей задачи, как раз более эффективно вызвать системный загрузчик, найти функцию и обратится к ней - хз.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог