Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как передать коннект к базе Firebird из программы в dll? [D7, Firebird]


Akris ©   (2005-08-27 20:11:00) 

Подскажите, пожалуйста, как передать коннект к базе данных Firebird из основной программы в dll так, чтобы было только одно соединение с базой.
Пробовал передавать компонент TpFIBDataBase -  вылетает Access Violation по адресу в библиотеке.

Я использую компоненты FibPlus 4.8.


Akris   (2005-08-29 16:49:00) [1]

1. DM.DataBase в вызывающем модуле - это компонент TpFIBDataBase в DataModule.
3. Form1 в DLL глобальная переменная - я понял и убрал.
4. Выгрузка библиотеки стоит на except - такова логика программы.
5. Закрываю форму я другой процедурой, которая вызывается из dll.

Спасибо всем, кто ответил. Рабочий код следующий:


type
//Объявление процедурного типа для вызова формы из DLL
TShowForm = procedure (AppHandle: THandle;BaseHandle: TISC_DB_HANDLE); stdcall;

{...}

//Вызов формы из DLL
procedure TfrMain.Button1Click(Sender: TObject);
var
LibHandle: THandle;
LibFunction: TShowForm;
begin
{Делаем попытку загрузить Dll}
LibHandle := LoadLibrary(PChar(ExtractFileDir(ParamStr(0))+'\PenniesDll\PenniesLib.dll'));
try
  {Если загрузка Dll окажется неудачной, переменная LibHandle будет иметь
   нулевое значение. В этом случае возникнет исключительная ситуация}
   if (LibHandle = 0) then
     begin
       raise EDLLLoadError.Create('Не могу загрузить Dll');
     end;
   {Устанавливаем связь с экспортируемой функцией}
   @LibFunction := GetProcAddress(LibHandle, 'ShowForm');
   {Если функция экспортируется удачно, тогда возвращаем результат}
   if not(@LibFunction = nil) then
     LibFunction(Application.Handle, DM.DataBase.Handle)
   else
     RaiseLastWin32Error;
except
  //Выгружаем библиотеку
  FreeLibrary(LibHandle);
end;
end;


Код в DLL, который создает форму. На форме DBGrid, DataSource, FIBDataSet, FIBTransaction.


//------------------------------------------------------------------------------
procedure ShowForm(AppHandle: THandle;BaseHandle: TISC_DB_HANDLE); stdcall;
begin
 Application.Handle := AppHandle;
 DM := TDM.Create(Application);

 Form1 := TForm1.Create(Application);
 Form1.Show;

 DM.DataBase.Handle := BaseHandle;
 DM.dstTemp.Database := DM.DataBase;
 DM.dstTemp.SelectSQL.Add('SELECT * FROM USERS');
 DM.dstTemp.Open;

 Form1.ds.DataSet := DM.dstTemp;
 Form1.DBGrid1.Align := alClient;
end;


Причина вылета: не было создания DataModule.

Спасибо Peter за помощь.


Desdechado   (2005-08-29 16:30:00) [2]

1. DM.DataBase в вызывающем модуле - неизвестно что
2. я бы передал в DLL еще и Application.Handle, а в DLL присвоил бы его ейному Application.Handle (а перед завершением DLL-функции и восстановил бы)
3. Form1 в DLL похоже на глобальную переменную. Есть неплохой шанс использовать ее ненароком несколько раз, нахватавшись глюков
4. выгрузку библиотеки я поставил бы не на except, а на finally, а так у тебя она остается болтаться в случае неошибки, что приведет к ошибке при следующем ее вызове
5. я бы еще для ShowForm возвращал статус или Handle формы, чтоб ее потом закрыть корректно можно было


Akris   (2005-08-29 15:37:00) [3]

Код приложения, который вызывает форму из DLL:

type
 //Объявление процедурного типа для вызова формы из DLL
 TShowForm = procedure (DataBase: Pointer); stdcall;

{...}

//Вызов формы из DLL
procedure TfrMain.Button1Click(Sender: TObject);
var
 LibHandle: THandle;
 LibFunction: TShowForm;
begin
 {Делаем попытку загрузить Dll}
 LibHandle := LoadLibrary(PChar(ExtractFileDir(ParamStr(0))+'\PenniesDll\PenniesLib.dll'));
 try
   {Если загрузка Dll окажется неудачной, переменная LibHandle будет иметь
    нулевое значение. В этом случае возникнет исключительная ситуация}
    if (LibHandle = 0) then
      begin
        raise EDLLLoadError.Create('Не могу загрузить Dll');
      end;
    {Устанавливаем связь с экспортируемой функцией}
    @LibFunction := GetProcAddress(LibHandle, 'ShowForm');
    {Если функция экспортируется удачно, тогда возвращаем результат}
    if not(@LibFunction = nil) then
      LibFunction(Pointer(DM.DataBase))
    else
      RaiseLastWin32Error;
 except
   //Выгружаем библиотеку
   FreeLibrary(LibHandle);
 end;
end;


Код в DLL, который создает форму. На форме DBGrid, DataSource, FIBDataSet, FIBTransaction.


//------------------------------------------------------------------------------
procedure ShowForm(aDataBase: Pointer); stdcall;
begin
  Form1 := TForm1.Create(Application);
  Form1.Show;
//Здесь вылетает Access Violetion in module PenniesLib
  DM.DataBase := TpFIBDatabase(aDataBase);

  DM.dstTemp.Database := DM.DataBase;
  DM.dstTemp.SelectSQL.Add('SELECT * FROM USERS');
  DM.dstTemp.Open;
  Form1.ds.DataSet := DM.dstTemp;
  Form1.DBGrid1.Align := alClient;
end;


Akris   (2005-08-29 15:36:00) [4]

Код приложения, который вызывает форму из DLL:

type
 //Объявление процедурного типа для вызова формы из DLL
 TShowForm = procedure (DataBase: Pointer); stdcall;

{...}

//Вызов формы из DLL
procedure TfrMain.Button1Click(Sender: TObject);
var
 LibHandle: THandle;
 LibFunction: TShowForm;
begin
 {Делаем попытку загрузить Dll}
 LibHandle := LoadLibrary(PChar(ExtractFileDir(ParamStr(0))+'\PenniesDll\PenniesLib.dll'));
 try
   {Если загрузка Dll окажется неудачной, переменная LibHandle будет иметь
    нулевое значение. В этом случае возникнет исключительная ситуация}
    if (LibHandle = 0) then
      begin
        raise EDLLLoadError.Create('Не могу загрузить Dll');
      end;
    {Устанавливаем связь с экспортируемой функцией}
    @LibFunction := GetProcAddress(LibHandle, 'ShowForm');
    {Если функция экспортируется удачно, тогда возвращаем результат}
    if not(@LibFunction = nil) then
      LibFunction(Pointer(DM.DataBase))
    else
      RaiseLastWin32Error;
 except
   //Выгружаем библиотеку
   FreeLibrary(LibHandle);
 end;
end;


Код в DLL, который создает форму. На форме DBGrid, DataSource, FIBDataSet, FIBTransaction.


//------------------------------------------------------------------------------
procedure ShowForm(aDataBase: Pointer); stdcall;
begin
  Form1 := TForm1.Create(Application);
  Form1.Show;
//Здесь вылетает Access Violetion in module PenniesLib
  DM.DataBase := TpFIBDatabase(aDataBase);

  DM.dstTemp.Database := DM.DataBase;
  DM.dstTemp.SelectSQL.Add('SELECT * FROM USERS');
  DM.dstTemp.Open;
  Form1.ds.DataSet := DM.dstTemp;
  Form1.DBGrid1.Align := alClient;
end;


Domkrat   (2005-08-29 12:24:00) [5]

У нас реализован вариант: exe (1 конект) + BPL.
Экзешка реализует интерфейс, который возвращает конекшн, который можно вызвать из BPL.


Desdechado   (2005-08-29 12:05:00) [6]

а млжет, при вызове DLL ты в ней не указываешь вызвавшее приложение в качестве Application?
или с разными версиями компонентов компилируешься - тогда 100% глюки будут


DrPass   (2005-08-28 13:13:00) [7]

Скорее всего, проблема в отсутствии пресловутого ShareMem. Я в свое время делал такой финт с DLL (только не с FIBPlus, а с IBExpress). В принципе, жалоб и подводных камней не было (была, правда, проблема с обработкой событий - но это уже "особенности" архитектуры IBExpress)


sniknik   (2005-08-28 13:01:00) [8]

> Согласен что не проблема, но для SuperServer.
для любого сервера десяток соеденений не проблема. имхо. если только лицензия не на 5-ть ;о)).

проблема будет если использовать персонал(ембедед) версию... гдe возможно всего одно подключение.

но в общем не понятно в чем проблема, не скажу за TpFIBDataBase но ADOconnection и Database(BDE) в dll передавал (просто тесты. в реальных программах такой нужды не возникало) все отлично передается... не думаю что FIB-ы глючат, скорее твоя реализация их использования "с брачком".
1-е проверь соглашения о вызовах, чтобы совпадали в dll и exe.
2-e внимательно прочитай коментарий при создании dll создающийся, там явное указание насчет менеджера памяти, и что делать, чтобы передавались строки и обьекты.
впечатление что ты это сообщение проигнорировал.
3-е описывай проблему подробно, с примерами и кодом. пока по твоему описанию ничего не понять.


Akris   (2005-08-28 12:39:00) [9]

> На фига справочники в dll?

Потому что нужно сделать возможность вида и содержимого справочника. А поскольку справочник в dll тода можно менять только одну отдельную dll вместо замены всего приложения.

> Ну и что? Хоть 10 соединений - для FB это, имхо, не проблема.

Согласен что не проблема, но для SuperServer. Да и к тому же на каждое соединение с базой будет уходить время, а при использовании уже открытого соединения нет этих затрат.


}{ander   (2005-08-27 22:01:00) [10]

> будем иметь четыре соединения с базой данных

Ну и что? Хоть 10 соединений - для FB это, имхо, не проблема.


Sergey Masloff   (2005-08-27 22:00:00) [11]

Использовать пакеты (package) а не dll, но работоспособностья лично не проверял. На фига справочники в dll? Тоже непонятно


Akris   (2005-08-27 21:09:00) [12]

Тогда как решить следующую задачу:
есть основное приложение, которое реализует подключение к базе данных и есть три справочника - которые реализуются dll. Если не передавать коннект, тогда при открытии всех трех справочников будем иметь четыре соединения с базой данных: одно соединение из основного приложения и по одному из каждого справочника. А это не есть гуд!!!

Кстати, какие есть грабли?


Sergey Masloff   (2005-08-27 20:54:00) [13]

Не надо это делать. Просто на такие грабли наступишь...


Наверх

Титульная страница Поиск, карта сайта Написать письмо