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

 
Как вызвать ф-цию Register пакета BPL, ф-ция BPL, которая регистрирует классы
Termi_uc
  Отправлено: 14.02.2007, 20:01


Дежурный стрелочник

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



В каждом пакете BPL, есть функция которая регистрирует классы входящие в пакет. Это или Initialization, или Residter?

Смотрю исходники:
CODE

procedure Register;
begin
RegisterPropertyEditor(TypeInfo(string), TSsComponent, 'Version',
                        TSsVersionProperty);
...
 RegisterComponents('ShellShock',
   [
    TStShellAbout,
    ...
    TStDialogPanel
   ]);
end;

Но в других источниках читаю, что эта функция называется Initialization.

Вобщем как вызвать ф-цию пакета BPL, которая регистрирует все входящие в BPL классы???

Функция InitializePackage не подходит.

Если у кого есть наработки в области загрузки пакетов в run-tim'e и считывание / использование классов которые там хранятся — пажалуйста пришлите пример. Со своей стороны поделюсь своими наработками в этой области.
Зарание спасибо.
AVC
Отправлено: 15.02.2007, 10:13


Ветеран

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



RegisterComponent отношения к runtime не имеет.
По поводу RegisterClass и прочих регистраций есть в component registration routines.
InitializePackage, судя по названию, содержит коды, выполняющиеся при загрузке пакета в память.

CODE

// Пример регистрации компонента в палитре компонентов на вкладке Data Controls
namespace Dbgridm
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TDBGridM)};
RegisterComponents("Data Controls", classes, 0);
}
}

// пример регистрации нескольких визуальных компонентов
namespace Panlab
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[] = {__classid(TPanelBmp), __classid(TTileBmp), __classid(TLabelS) };
RegisterComponents("Standard", classes, 2);
}
}

// пример регистрации не визуального компонента
namespace Axrecord
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TAxRecord)};
RegisterNoIcon(classes, 0);
}
}
Termi_uc
Отправлено: 15.02.2007, 16:21


Дежурный стрелочник

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



QUOTE (AVC @ 15.02.2007, 10:13)
RegisterComponent отношения к runtime не имеет.

судя по:
CODE

procedure RegisterComponents(const Page: string;
const ComponentClasses: array of TComponentClass);
begin
if Assigned(RegisterComponentsProc) then
  RegisterComponentsProc(Page, ComponentClasses)
else
  raise EComponentError.CreateRes(@SRegisterError);
end;

можно установить свой RegisterComponentsProc (в приложении он обычно равен nil), а затем вызвать Register для всех юнитов (он экспортируется) пакета bpl.

Как вызвать Register?
Может я туплю, но найти (GetProcAddress) в BPL процедуры с названием "_Register" не удалось. Возможно я плохо искал.

Но я точно знаю, что в runtime можно подгрузить пакет и вызвать процедуру регистрирующюю все класы входящие в BPL. Видел готовые продукты, сам свой собственный пакет (написаный на CBuilder) подгружал и видел в палитре компонентов СВОИ.
AVC
Отправлено: 15.02.2007, 17:00


Ветеран

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



QUOTE

Может я туплю, но найти (GetProcAddress) в BPL процедуры с названием "_Register" не удалось. Возможно я плохо искал.

Нет. Искали вы хорошо, но вы ошибочно предположили, что Borland формирует имя глобального символа так же как и стандартный C. Искать надо было так
@Ваш_Namespace@Register$qqrv

QUOTE

Но я точно знаю, что в runtime можно подгрузить пакет и вызвать процедуру регистрирующюю все класы входящие в BPL.

В runtime чего? И где вы хотите их регистрировать?

Может я чего то не понимаю, но я веду речь о регистрации компонентов (своих или чужих) в среде Builder'а.

А может вы имеете ввиду COM регистрацию?


QUOTE

сам свой собственный пакет (написаный на CBuilder) подгружал и видел в палитре компонентов СВОИ.

В примере я и привел как СВОИ компоненты поставить в палитру BCB

Среда Builder'а (и Delphi) при старте сама просматривает список пакетов, ищет Regiser и делает свои "темные дела".
Termi_uc
Отправлено: 15.02.2007, 20:40


Дежурный стрелочник

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



QUOTE

В runtime чего? И где вы хотите их регистрировать?

Регистрировать компоненты в программе ф-цией RegisterClass
QUOTE

В примере я и привел как СВОИ компоненты поставить в палитру BCB

Среда Builder'а (и Delphi) при старте сама просматривает список пакетов, ищет Regiser и делает свои "темные дела".

Вот мне и надо при старте СВОЕЙ програмы просматривать список пакетов, искать Regiser и делать "темные дела".

ХМ...
Ладно по-порядку:
1. Есть програма (моя), в неё надо встроить дизайнер, который читал / писал / редактировал бы dfm и создавал на основи их формы.
2. Для чтения dfm нужно зарегестрировать все компоненты, которые на ней могут быть.
3. Если в форме которая записана в dfm есть компонент, который не зарегестрирован в програме, то форма не загрузится.
4. Для того, чтобы грузить любые формы с програмой поставляется расширеный набор пакетов — стандартные Builder (VCLXX.bpl, RTLXX.bpl ...) и пакеты сторонних разработчиков.
Так вот, если все пакеты компелировать с програмой, то всё чики-пуки. Но тогда для добавления нового компонента надо заново компилировать прогу.
Я хочу подругому, в некую папку "BPLs" кидаю пакеты, и подгружаю их в момент запуска програмы.
Но как вызвать функцию регистрирующюю компоненты?


Спасибо AVC, подсказал направление:
QUOTE

Нет. Искали вы хорошо, но вы ошибочно предположили, что Borland формирует имя глобального символа так же как и стандартный C. Искать надо было так
@Ваш_Namespace@Register$qqrv


Тогда как узнать все Namespace в пакете?
Я знаю как узнать все ContainsUnit в пакете, может это одно и тоже?

Отредактировано Termi_uc — 15.02.2007, 20:47
Termi_uc
Отправлено: 15.02.2007, 20:49


Дежурный стрелочник

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



Кстати AVC вы оставили без коментариев:
QUOTE

судя по:
CODE

procedure RegisterComponents(const Page: string;
const ComponentClasses: array of TComponentClass);
begin
if Assigned(RegisterComponentsProc) then
 RegisterComponentsProc(Page, ComponentClasses)
else
 raise EComponentError.CreateRes(@SRegisterError);
end;

можно установить свой RegisterComponentsProc (в приложении он обычно равен nil), а затем вызвать Register для всех юнитов (он экспортируется) пакета bpl.
AVC
Отправлено: 16.02.2007, 10:18


Ветеран

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



QUOTE (Termi_uc @ 15.02.2007, 19:40)

[b]Тогда как узнать все Namespace в пакете?

Я знаю как узнать все ContainsUnit в пакете, может это одно и тоже?

для просмотра чего и как экспортируется/импортируется я пользуюсь следующими батниками
CODE

// alltolst.bat
@Echo Off
Call DelDef.bat

Call tolst .  VclBde50  bpl
Call tolst .  AxLib  bpl

Call tolst .. hcenger  exe
Call tolst .. doa34c5  bpl
Call tolst .. fr5  bpl
Call tolst .. frdoa  bpl
Call tolst .. hcacount  bpl

// tolst.bat
IF Not Exist %1\%2.%3   GoTo Exit
Echo %1\%2.%3
Tdump      %1\%2.%3 %2.lst    > nul
rem Tdump  -em %1\%2.%3 %2.imp    > nul
Impdef -h  %2.def   %1\%2.%3  > nul
:Exit

Но это для глаз что бы знать как зовут то, чего ишешь.
Есть GetPackageInfo, но я с ней не работал.

QUOTE (Termi_uc @ 15.02.2007, 19:40)

Вот мне и надо при старте СВОЕЙ програмы просматривать список пакетов, искать Regiser и делать "темные дела".


Я такой задчи не решал.
Когда то понадобилось иметь в приложении элементы итспектора объектов (самые зачатки). Не по теме, но а вдруг пригодится, так как это может решать ту же задачу с другой стороны.
CODE

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

AnsiString __fastcall TF_ObjList::ObjPropsInfo  (TObject *obj)
{
if (!obj) return "NULL";

int cou = GetTypeData(PTypeInfo(obj->ClassInfo()))->PropCount;
if (cou <= 0) return "";

TStringList *slist = FTmpSList;
slist->Clear();

bool isok = true;
char *buf = new char[cou*sizeof(PPropInfo)];
try {

AnsiString name;
AnsiString tname;
AnsiString erstr = "Error: ";

PPropList proplist = (PPropList)(buf);
PPropInfo propinfo;
PTypeInfo typeinfo;

Typinfo::TTypeKind kind;
Variant  val;

GetPropInfos(PTypeInfo(obj->ClassInfo()), proplist);

for (int i=0; i < cou; i++)
{ propinfo = *(proplist+i);
if (!propinfo) continue;

name = AnsiString(propinfo->Name);

typeinfo = *(propinfo->PropType);
if (!typeinfo)
 { slist->Add(ClpPad(name,20) + erstr + "Bad TypeInfo");
 continue;
 }

kind  = typeinfo->Kind;
if  (kind == tkMethod  ) continue;

tname = AnsiString(typeinfo->Name).Trim().UpperCase();

try       { val = GetPropValue(obj, name, true);   }
catch (Exception &xcp)  { val = erstr + xcp.Message; isok = false; }

if (kind == tkClass )
 { try      { val = SObj ( (TObject*) (int(val)) );   }
 catch (Exception &xcp) { val = erstr + xcp.Message; isok = false; }
 }

slist->Add(ClpPad(name,30) + VarToString(val));
}

} // try buf
catch (Exception &xcp)
{ isok = false;
slist->Add(AnsiString("Error: ") + xcp.Message);
}

delete[] buf;

if (isok) slist->Sort();
return slist->Text;
}

//---------------------------------------------------------------------------

AnsiString __fastcall TF_ObjList::SObj  (TObject *obj)
{
if (!obj) return "NULL";
return AnsiString(obj->ClassName()) + "*";
}

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
Termi_uc
Отправлено: 16.02.2007, 17:08


Дежурный стрелочник

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



Спасибо AVC, за подсказку:
QUOTE
Искать надо было так
@Ваш_Namespace@Register$qqrv


ВСЁ РАЗОБРАЛСЯ с Register.

Но осталась одна БОЛШАЯ проблема: Как получить список всех функций регистрации в пакете. Но это уже по другой теме.
Тему можно считать закрытой


Да вот окончательный вариант и проект, если кому надо.
Например для пакета CBuilder6\Bin\dclstd60.bpl, одна из функций регистрации — @Stdreg@Register$qqrv.
Если будут наработки пишите...
CODE

//Функция регистрации компонентов в свою палитру
void __fastcall MyRegisterComponentsProc1(const AnsiString Page,
  TMetaClass* const * ComponentClasses,
  const int ComponentClasses_Size)
{
TTabSheet * tsh(NULL);

if(Form1)//Форма на которой находится палитра
{
 for(int j(0); j < Form3->pcPallete->PageCount; j++)
  if(Form3->pcPallete->Pages[j]->Caption == Page)
  {
   tsh = Form3->pcPallete->Pages[j];
   break;
  }

 if(!tsh)
 {
  tsh = new TTabSheet(Form3);
  tsh->PageControl = Form3->pcPallete;
  tsh->Caption = Page;

//MEMOS объявлен в *.h файле формы с палитрой как:
//TMemo * MEMOS[40];
  MEMOS[tsh->TabIndex] = new TMemo(Form1);
  MEMOS[tsh->TabIndex]->Parent = tsh;
  MEMOS[tsh->TabIndex]->Align = alClient;
 }
}

for(int i(-1); i < ComponentClasses_Size; i++)
{
// ShowMessage(ComponentClasses[i + 1]->ClassName());
 if(Form1)MEMOS[tsh->TabIndex]->Lines->Add(ComponentClasses[i + 1]->ClassName());
 RegisterClass(ComponentClasses[i + 1]);
}
}

//...
HINSTANCE lModule(NULL);

//Загрузка пакета
void __fastcall TForm1::LoadPackClick(TObject *Sender)
{
if(!OpenDialog1->Execute())return;

if(lModule)UnloadPackage((unsigned)lModule);
lModule = (void *)LoadPackage(OpenDialog1->FileName);
}

//---------------------------------------------------------------------------

//Найти указаную в Edit3->Text функцию ренистрации и вызвать
void __fastcall TForm1::Button8Click(TObject *Sender)
{
//Поставить свою функцию, как функцию регистрации пакетов
// для всего приложения
RegisterComponentsProc = MyRegisterComponentsProc1;

if(!lModule)return;

void (__stdcall * Register1)();
Register1 =
 (void (__stdcall *)())
  GetProcAddress(lModule, Edit3->Text.c_str());

  if(Register1){Register1(); ShowMessage("BRRRRR");}
}
//---------------------------------------------------------------------------

//Не забудте выгрузить пакет
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if(lModule)UnloadPackage((unsigned)lModule);
}
Termi_uc
Отправлено: 16.02.2007, 17:12


Дежурный стрелочник

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



QUOTE (AVC @ 16.02.2007, 10:18)
QUOTE (Termi_uc @ 15.02.2007, 19:40)

Вот мне и надо при старте СВОЕЙ програмы просматривать список пакетов, искать Regiser и делать "темные дела".


Я такой задчи не решал.
Когда то понадобилось иметь в приложении элементы итспектора объектов (самые зачатки). Не по теме, но а вдруг пригодится, так как это может решать ту же задачу с другой стороны.

Спасибо, но инспектор объектов я почти сделал. Только осталось как-то вызывать зарегестрированые редакторы свойств (PropertyEditors).
Termi_uc
Отправлено: 16.02.2007, 17:18


Дежурный стрелочник

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



Да, и обещяный проект — Тестовый полигон загрузки пакетов.
Не забывайте:
Для пакета CBuilder6\Bin\dclstd60.bpl, одна из функций регистрации — @Stdreg@Register$qqrv. — Для примера.

User Attached Image Скачать файл
Палитра_компонентов_test.zip



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