зАКЛАДКА вОЗМОЖНОСТИ иСПОЛЬЗОВАНИЯ пЛАГИНОВ в пРОГУ
RE: может просто сделать голую форму кот. будет искать в папке plugins в корневом относительно себя каталоге другие формы и все какие найдет - подключать? хотя как-то замороченно получается, но согласитесь тоже вариант.
RE2: тогда встречный вопрос, это вообще сильно сложно, чтобы одна форма подключала другую просто найдя ее файл, хм, ведь с таким успехом можно вообще неизвестно что "наподключать", если это свалено в соотвт. папку.
Как бы это сделать, поделитесь идеями
Можно сделать как угодно, лишь бы задачу решало и клиент был доволен.
Мы, например, на работе используем потомков TFrame для экспорта из плагинов.
Можно сделать как угодно, лишь бы задачу решало и клиент был доволен.
Мы, например, на работе используем потомков TFrame для экспорта из плагинов.
Почитаю что-нибудь на эту тему. Проблема с формами, например, в том, что для того чтобы головная форма знала ту которую будет вызывать, нужно включить заголовочный файл включаемой формы в заголовочный файл вызывающей формы на этапе разработки, а если это новая форма...? кстати с фреймами наверное что-то похожее тоже есть, как вы такую проблему обошли?
Почитаю что-нибудь на эту тему. Проблема с формами, например, в том, что для того чтобы головная форма знала ту которую будет вызывать, нужно включить заголовочный файл включаемой формы в заголовочный файл вызывающей формы на этапе разработки, а если это новая форма...? кстати с фреймами наверное что-то похожее тоже есть, как вы такую проблему обошли?
А кто сказал, что туда нужно, что-то включать, так бы ни один плагин никогда не заработал. Определяешь хэндл окна и все.
А кто сказал, что туда нужно, что-то включать, так бы ни один плагин никогда не заработал. Определяешь хэндл окна и все.
тоже вариант... тут кстати поступило вне этого форума такое предложение: наштопать из потенциальных форм дллек и складировать их в одну папку например plug-ins, но с окнами тоже можно, короче на самом деле вариантов достаточно, интересно какой из них проще, впрочем проработать попробую все, хотя бы для самообразования
Почитаю что-нибудь на эту тему. Проблема с формами, например, в том, что для того чтобы головная форма знала ту которую будет вызывать, нужно включить заголовочный файл включаемой формы в заголовочный файл вызывающей формы на этапе разработки, а если это новая форма...? кстати с фреймами наверное что-то похожее тоже есть, как вы такую проблему обошли?
У нас фрейм имеет виртуальные методы, определенные в предке как абстрактные, и реализованные в потомках. И потом, не надо забывать тот факт, что компоненты имеют виртуальный конструктор, и могут быть созданы через RTTI. Наши плагины как раз используют данный метод. Они экпортируют фукнцию, возвращающую класс плагина, а в памяти создает его уже вызывающая программа.
И потом, наши плагины, и сама программа работают в единой среде выполнения, обеспечиваемой BPL-ами. Если не использовать BPL-ы, ИМХО, работать не будет. Будут возникать глупые ошибки, вроде "Cannont assign TFont to TFont".
Добавление пользователей, добавление новых пунктов меню, указание папки для LiveUpdate, указание папки в которой хранятся плугины.
В каждой dll помимо функций реализующих непосредственно БП есть две функции о которых знает хост-программа. ВОт через них то она их и вызывает.
Меню в хост грузим из БД. У всех пунктов меню назначаем один и тот же обработчик:
void __fastcall TfrmMain::DllMenuClick(TObject * Sender)
{
AnsiString A,S = ((TMenuItem*)Sender)->Name;
typedef AnsiString (__import *Prop)();
typedef HWND (__import *Sh)(AnsiString &Capt, void *Conn);
Prop MyProp;
Sh ShowMy;
HINSTANCE Dll;
for (int i = 0; i < Dlls->Count; i++)
{
Dll = LoadLibrary(Dlls->Strings.c_str());
if(Dll != NULL)
{
MyProp = (Prop)GetProcAddress(Dll,"_ReturnProperty");
A = MyProp();
}
if (S != A)
{
FreeLibrary(Dll);
}
else
{
ShowMy = (Sh)GetProcAddress(Dll,"_ShowDllForm");
AnsiString B = ((TMenuItem*)Sender)->Caption;
HWND in;
ShowMy(B,MTODm->ADOConnection1);
break;
}
}
}
В каждой dll соответсвенно есть функции:
ReturnProperty
и
ShowDllForm
для примера:
//---------------------------------------------------------------------------
//"zavspecfunc.cpp"
#include <vcl.h>
#pragma hdrstop
#include "zavspecfunc.h"
#include "ZavodSpec.h"
//---------------------------------------------------------------------------
AnsiString ReturnProperty()
{
return Name;
}
//---------------------------------------------------------------------------
HWND ShowDllForm(AnsiString &Capt, void *AC)
{
if(Application->MainForm->Menu->Items->Find("Окна")->Find(Capt))
{
ShowWindow(FindWindow("TfrmZavodSpec",Capt.c_str()),SW_SHOW);
SetForegroundWindow(FindWindow("TfrmZavodSpec",Capt.c_str()));
return 0;
}
else{
TfrmZavodSpec *frmZavodSpec = new TfrmZavodSpec(Application, AC, Capt);
frmZavodSpec->Show();
return frmZavodSpec->Handle;
}
}
#pragma package(smart_init)
А это хидер
//---------------------------------------------------------------------------
//"zavspecfunc.h"
#ifndef zavspecfuncH
#define zavspecfuncH
//---------------------------------------------------------------------------
AnsiString Name = "ZavodSpec";
extern "C" __declspec(dllexport) AnsiString ReturnProperty();
extern "C" __declspec(dllexport) HWND ShowDllForm(AnsiString &Capt, void *AC);
#endif
В БД сохраняется не только Caption пункта меню но и его Name. А Name назначается равным AnsiString Name = "ZavodSpec";
RE:
Можно пояснить, для особо тупых типа меня?
Внутри TfrmZavodSpec должна быть работа с переданным соединением, например получение каких-нибудь параметров формы. Я правильно понимаю?
RE:
Можно пояснить, для особо тупых типа меня?
Таблица из которой грузится меню имеет следующую структуру:
[menu_id] [int] IDENTITY (1, 1) NOT NULL ,
[Naim] [char] (30) COLLATE Cyrillic_General_CS_AS NOT NULL ,
[Owner] [int] NULL ,
[Caption] [varchar] (100) COLLATE Cyrillic_General_CS_AS NOT NULL ,
[OnClick] [varchar] (100) COLLATE Cyrillic_General_CS_AS NULL
) ON [PRIMARY]
Где Naim - название пункта меню, совпадающее с переменной Name в dll отвечающей за обработку клика по данному пункту меню.
Для примера если в БД Naim = MyDll, то и в выше приведенном листинге было бы не AnsiString Name = "ZavodSpec" , а AnsiString Name = "MyDll";
Owner - указывает на пункт меню подпунктом которого является текущий пункт.
Caption - соответсвенно Caption пункта меню.
OnClick - название обработчика.
В dll, как нетрудно заметить из листинга:
ShowMy(B,MTODm->ADOConnection1);
Я передаю указатель на соединение с БД, и название пункта меню.Работа с хостом из dll спокойно осуществляется через Application->MainForm.
main poga---------->
typedef TForm* (__stdcall *GETNEWTAB)(TWinControl*);
typedef char* (__stdcall *GETNAME)();
...
void __fastcall TForm1::FormCreate(TObject *Sender)
{
LoadedPluginsCount=0;
PlugList=new TList();
AnsiString names[]={"Project_11.dll","Project_11b.dll","Project_11c.dll"};
for(int i=0;i<sizeof(names)/sizeof(names[0]);i++){
PlugObj PlugIn=new PlugInfo;
PlugIn->lib=LoadLibrary(names.c_str());
if(PlugIn->lib)
try{
GETNEWTAB GetNewTab=(GETNEWTAB)GetProcAddress(PlugIn->lib,"_GetNewTab");
GETNAME GetName=(GETNAME)GetProcAddress(PlugIn->lib,"_GetName");
if(GetNewTab&&GetName){
TTabSheet *newTab=new TTabSheet(this);
newTab->PageControl=MainPC;
newTab->Caption=AnsiString(GetName());
PlugIn->TabForm=GetNewTab(newTab);
PlugIn->newTab=newTab;
}
LoadedPluginsCount++;
PlugList->Add(PlugIn);
}catch(...){ FreeLibrary(PlugIn->lib);}
}
}
//-----------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
for(int i=0;i<LoadedPluginsCount;i++){
PlugObj PlugIn=(PlugObj)PlugList->Items;
if(PlugIn->lib!=NULL){
delete PlugIn->TabForm;
delete PlugIn->newTab;
FreeLibrary(PlugIn->lib);
}
delete PlugIn;
}
delete PlugList;
}
//-----------------------------------------------
header--->
TPageControl *MainPC;
....
TList *PlugList;
typedef struct PlugInfo{
HINSTANCE lib;
TForm *TabForm;
TTabSheet *newTab;
} *PlugObj;
int LoadedPluginsCount;
... ---------------------------------------------
ну и собсно в dll----------->
#include "Unit_121.h"// в Unit_121.срр наш класс для новой закладки
extern "C" __declspec(dllexport) TForm* GetNewTab(TWinControl* owner);
extern "C" __declspec(dllexport) char* GetName();
...
TForm* GetNewTab(TWinControl* owner)
{
TForm1 * form=new TForm1(owner);
form->Parent=owner;
form->Left=0;
form->Top=0;
form->Visible=true;
return form;
}
...