Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];

Вниз

Доступ к компоненту из DLL   Найти похожие ветки 

 
Olegas   (2006-06-08 09:19) [0]

У меня есть приложение и в нем компоненты работающие с базой данных Interbase. Это прежде всего TTable и TQuery.
Мне нужно написать DLL, Функции из которой вызывались бы из приложения и чтобы изнутри таких функций можно было обращаться к компонентам TTable и TQuery созданным в основном приложении. Как получить к ним доступ из DLL?
Как это сделать?


 
DSKalugin ©   (2006-06-08 12:10) [1]

бред, изложи суть более внятно

П.С. С Interbase уже лет эдак 7 никто не работает через BDE


 
Olegas   (2006-06-09 08:30) [2]

Моя dll это что-то вроде плаггина.
Есть основная программа. И мне надо заложить на будущее средство для расширения ее возможностей за счет вызова внешних модулей.  
В основной программе есть датасеты. Мне надо:
1. Вызвать из Dll процедуру, которая выдает на экран форму для заполнения.  
2. Пользователь ее заполняет, а по кнопке ОК  
3. обновляются данные в датасетах (добавляются, удаляются, модифицируются записи). При этом датасеты есть объекты созданные в основной программе
4. После чего соответствующую процедуру можно выгрузить из памяти.
И как это сделать?


 
ANB ©   (2006-06-09 12:51) [3]

Создавать эти наборы данных в самой DLL.


 
Olegas   (2006-06-09 14:02) [4]

Это исключено


 
ANB ©   (2006-06-09 14:07) [5]


> Olegas   (09.06.06 14:02) [4]

Тогда готовься собирать AV в самых неожиданных местах.


 
дид Панас ©   (2006-06-10 11:40) [6]

определяй интерфейс, передавай в BPL (а не dll) хендлы базы данных и application, по интерфейсу получай что тебе нужно.


 
vvh   (2006-06-11 19:49) [7]

Подобная работа с DLL подробно расматривается в книге Ковязина - "Дельфи6/7, базы данных и приложения". У меня самого приложения построено именно так. Скажи что именно, у тебя не получается?


 
API ©   (2006-06-11 22:12) [8]

1. Вызвать из Dll процедуру, которая выдает на экран форму для заполнения.  
2. Пользователь ее заполняет, а по кнопке ОК  
3. обновляются данные в датасетах (добавляются, удаляются, модифицируются записи). При этом датасеты есть объекты созданные в основной программе
4. После чего соответствующую процедуру можно выгрузить из памяти.


1. Создать ClientDataSet := TClientDataset.Create();
2. Скопировать в ClientDataSet структуру таблицы из DataSet"а в основной программе.
3. При необходимости - скопировать запись (несколько записей) из DataSet"а в ClientDataSet.
4. Передать в DLL интерфейсную ссылку на ClientDataSet.DSBase (IDSBase)
5. Прилинковать переданную интерфейсную ссылку к внутреннему (DLL) TClientDataSet"у.
6. Далее - необходимые действия; TClientDataSet - потомок TDataSet.
7. Вернуть в основную программу интерфейсную ссылку на DSBase.
8. В  основной программе - прилинковать ссылку к ClientDataSet, и "перекачать" данные в DataSet основной программы.
9. Повторить... :-)

P.S. Или BPL.
P.S. А если без BPL, то без интерфейсов - никак. Иначе - [5].


 
Olegas   (2006-06-13 12:13) [9]

Я пробовал передать в процедуру, находящуюся в dll, в качестве параметра указатель на объект TTable. А в самой этой процедуре открываю форму и на ней определяю компонент Datasource, при этом свойству Datasource.dataset присваиваю полученный в качестве параметра Ttable. Дальше на форме есть Grid, Ему в качестве datasource присваиваю созданный компонент datasource. В результате выполнения получил runtime error.
Получается, так делать нельзя. Почему?


 
Сергей М. ©   (2006-06-13 12:25) [10]


> Olegas   (13.06.06 12:13) [9]


Собери оба проекта (проект хост-приложения и проект DLL) с опцией Build With Run-Time Packages и будь счастлив


 
kaif ©   (2006-06-13 13:19) [11]

Я сейчас пишу что-то подобное.
Правда у меня не TTable и TQuery, а IBDatabase + одна IBTransaction (read)
в основной программе.
Использую опцию проекта Build with runtime packages.
То есть *.bpl.
В формах (они у меня MDIChild, каждый плагин имеет одну такую "основную форму") использую IBDataSet или IBQuery + IBTransaction.
Модуль экспортирует функцию:

function CreateModuleMainWindow(ADatabase: TIBDatabase): TForm.

В основном приложении имею процедурный тип:
type
 TCreateModuleMainWindow = function(ADatabase: TIBDatabase): TForm;


Загружаю *.bpl рантайм функцией LoadPackage.
Нахожу точку входа через GetProcAddress, приводя указатель на функцию к типу TCreateModuleMainWindow:

var
 MyModule: HMODULE = 0;
 CreateModuleMainForm: TCreateModuleMainForm;

...
begin
 if MyModule = 0 then
 begin
   MyModule := LoadPackage("MyPackage.bpl");
   CreateModuleMainForm := GetProcAddress(MyModule, "CreateModuleMainForm");
 end;
 //Вызываю функцию.
 Form := CreateModuleMainForm(MainConnection.MainDatabase);
 Form.Name := "MyPackage";
 Form.Caption := GetPackageDescription("MyPackage.bpl");
end;

У меня возникает дочернее окно. Компоненты на этом окне получают доступ к базе данных через параметр ADatabase, который я передаю при вызове функции (это присвоение осуществляется внутри пакета).

Все прекрасно работает.
Пакет потом можно выгрузить вызовом UnloadPackage.

Перекомпиляции основного приложения не требуется. Модули можно добавлять. Важно лишь чтобы приложение имело механизм узнать, какие модули еще добалены в систему, чтобы создать нужные пункты меню при старте. Я намерен эту информацию сохранять в реестре.


 
kaif ©   (2006-06-13 13:21) [12]

Пардон, описался.
Употребил два разных названия
TCreateModuleMainWindow и TCreateModuleMainForm.
На самом деле в проекте используется название  TCreateModuleMainForm.


 
Olegas   (2006-06-13 14:15) [13]

>Сергей М.
А что это собственно меняет? Ну собрал, с тем же результатом. Никакого счастья.


 
Olegas   (2006-06-13 15:16) [14]

>API
А примерчик можно?


 
Olegas   (2006-06-13 15:52) [15]

>kaif
А в функцию из bpl можно таким же образом передать доступ именно к TTable или TQuery?


 
kaif ©   (2006-06-13 16:27) [16]

Olegas   (13.06.06 15:52) [15]
>kaif
А в функцию из bpl можно таким же образом передать доступ именно к TTable или TQuery?

А почему бы нет?


 
Сергей М. ©   (2006-06-13 16:35) [17]


> Olegas   (13.06.06 14:15) [13]



> что это собственно меняет?


Это гарантирует использование обоими модулями единого экз-ра менеджера памяти. Гарантирует, естественно. при условии, что ты не намудрил с ShareMem.


 
Андрей Пазик   (2006-06-13 16:52) [18]

kaif, зочем ви так пишете? Да еще и учите неграмотные умы? В dll/bpl нужно передавать Handle объекта Database, а не сам Database (не важно, IBDatabase или FIBDatabase или еще что). После чего нужно в dll/bpl создать объект IBDatabase, и присвоить ему переданный Handle.


 
Olegas   (2006-06-13 16:56) [19]

Насчет sharemem поподробнее можно?


 
kaif ©   (2006-06-13 17:07) [20]

Андрей Пазик   (13.06.06 16:52) [18]
kaif, зочем ви так пишете? Да еще и учите неграмотные умы? В dll/bpl нужно передавать Handle объекта Database, а не сам Database (не важно, IBDatabase или FIBDatabase или еще что). После чего нужно в dll/bpl создать объект IBDatabase, и присвоить ему переданный Handle.


Кому нужно?
И почему нужно?

Я пишу то, что можно сделать без проблем, это совершенно грамотно, и это будет работать без проблем.

А вообще. конечно, можно вообще без компонентов обойтись.
И без *.bpl всяких.
Передавать только указатели, пчары, аллокировать память под строки, общаться исключительно по соглашению stdcall.
Грузить динамически руками gds32.dll и юзать ее функции и это будет еще ГРАМОТНЕЕ.

Одни сплошные хендлы и PChar-ы.

У меня нет цели "учить безграмотные умы".
Моя цель в данном случае - помочь человеку быстро решить его насущные проблемы. Дельфи для этого и был разработан. Для решения ЗАДАЧ.

Если Вы уверены, что указатель типа TIBDatabase нельзя передавать в качестве параметра при вызове функции из bpl, покажите мне запрет на такой вызов в ДОКУМЕНТАЦИИ ДЕЛЬФИ.

:(


 
Olegas   (2006-06-14 08:38) [21]

>kaif
Еще маленький вопрос. Как сделать вместо dll bpl?
До сих пор я сталкивался с bpl  при компиляции библиотеки компонентов. Создавался проект dpk и в него помещались исходники форм и модулей.
Как экспортировать процедуры и функции в этом случае?
Если можно, небольшой пример.


 
Сергей М. ©   (2006-06-14 08:46) [22]


> Olegas   (13.06.06 16:56) [19]
>
> Насчет sharemem поподробнее можно?


Юнит ShareMem может быть использован в случаях, когда модули, разработанные в борладовских средах (Делфи и BСС), должны обмениваться данными дин.типов (память под которые распределяется динамически в ходе работы приложения, явно или неявно) при условии невозможности по тем или иным причинам сборки этих взаимодействующих модулей с использованием пакетов времени выполнения.

ShareMem является интерфейсом для используемой в этом случае библиотеки borlandmm.dll, в которой реализован единый для взаимодействующих модулей менеджер памяти.

ShareMem должен быть указан первым юнитам  в секции uses проектов взаимодействующих модулей.


 
Olegas   (2006-06-14 12:04) [23]

Так что, никто не подскажет пример, как вместо dll построить bpl?


 
Сергей М. ©   (2006-06-14 13:35) [24]


> Olegas   (14.06.06 12:04) [23]


смю. File -> New -> Other.. -> Package


 
Olegas   (2006-06-14 13:57) [25]

как из него экспортировать процедуры и функции?


 
kaif ©   (2006-06-14 15:22) [26]

Я лично просто объявил в секции export модуля:

unit UsersMain;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, IBDatabase;

type
 TUsersMainForm = class(TForm)
   IBTransaction1: TIBTransaction;
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   ....
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 UsersMainForm: TUsersMainForm;

implementation

{$R *.dfm}
{$R UsersImages.res}

function CreateModuleMainForm(ADatabase: TIBDatabase): TForm;
begin
 Result := TUsersMainForm.Create(nil);
 TUsersMainForm(Result).IBTransaction1.DefaultDatabase := ADatabase;
end;

procedure TUsersMainForm.FormClose(Sender: TObject;
 var Action: TCloseAction);
begin
 Action := caFree;
end;

exports
 CreateModuleMainForm;
end.


Все работает.
Проверил с помощью tdump.
Экспорт как экспорт.

Не знаю, наверно это тоже безграмотно.
Я уже ни в чем не уверен.
С пакетами я раньше дела не имел.

Если есть кто грамотный на этот счет - отзовитесь.


 
Панас   (2006-06-15 11:10) [27]

unit1;
//форма в DLL, на ней лежит TpFIBDatabase

 procedure ShowFormFromDLL(AppHandle: THandle; DBHandle: TISC_DB_HANDLE); StdCall;

exports
 ShowFormFromDLL;

implementation

procedure ShowFormFromDLL(AppHandle: THandle; DBHandle: TISC_DB_HANDLE);
begin
 try
   Application.Handle := AppHandle;
   Form1 := TForm1.Create(Application);
   Form1.db.Handle := DBHandle;
   Form1.dt.Open;
   Form1.ShowModal;
 finally
   Form1.dt.Close;
   Application.Handle := 0;
   Form1.Free;
 end;
end;

/////////////////////////////////////
//вызывающий модуль

type
 TShowFormFromDLL = procedure (AppHandle: THandle; DBHandle: TISC_DB_HANDLE); stdcall;
 TDisconnectInDLL = procedure;  stdcall;
 EDLLLoadError = class(Exception);
// на кнопку грузим DLL и вызываем ее метод для отображения формы
procedure TForm1.Button1Click(Sender: TObject);
var
 DLLHandle: THandle;
 ShowFormFromDLL: TShowFormFromDLL;
 ExePath: string;
begin
 ExePath := ExtractFilePath(Application.ExeName);
 DLLHandle := LoadLibrary(PChar(ExePath + "testdll.dll"));
 try
   if DLLHandle <= 0 then
     MessageDlg("Error loading " + QuotedStr(ExePath + "testdll.dll"),
       mtError, [mbOk], 0);

   @ShowFormFromDLL := GetProcAddress(DLLHandle, "ShowFormFromDLL");

   if Assigned(ShowFormFromDLL)
   then ShowFormFromDLL(Application.Handle, db.Handle)
   else MessageDlg("Error execute ShowFormFromDLL", mtError, [mbOk], 0);

 finally
   Application.ProcessMessages;
   FreeLibrary(DLLHandle);
 end;
end;


 
kaif ©   (2006-06-15 13:10) [28]

2 Панас   (15.06.06 11:10) [27]
У меня практически то же самое.
Кроме способа передачи данных о базе.
Я передаю непосредственно указатель типа TIBDatabase. В пакетах (BPL) это возможно.

===============================
Правда после двух дней экспериментов меня стали мучать сомнения насчет того, что это оптимальный способ написать систему, работающую с базой данных.
Дело в том что при развитии системы если она состоит из версии EXE и версии базы, то их можно сравнивать и либо апгредить базу до EXE - для этого я обычно поставляю новую dbupdate.dll вместе с новым EXE (внутри этой dbupdate.dll лежит кумулятивный код всех апдейтов базы), либо просить скачать новый EXE + dbupdate.dll, если база имеет более позднюю версию. В случае же множества модулей задача апдейтов начинает не упрощаться, а усложняться.
Так что я склоняюсь к мысли о том, чтобы в EXE запихнуть все модули, кроме отчетов. Так как основные модули (ввод данных и т.п.) изменяются редко и как правило в связи с изменением структуры базы.
А вот отчеты как раз лучше видимо добавлять через механизм BPL.

Отчеты неправильных версий, хотя и чувствительны к структуре базы, но не так фатально опасны для нее, так как работают в режиме "только чтение".

Так что пока что я в раздумьях. Жаль выкидывать столько работы. Хотя для отчетов этот механизм, я думаю, окажется оптимальным. К тому же BPL для отчетов хороши тем, что можно добавлять новые отчеты, не останавливая работу пользователей.


 
kaif ©   (2006-06-15 13:38) [29]

Вообще Ваш способ (Form1.db.Handle := DBHandle;) мне больше нравится. Я чувствую, что наличие компонента db на форме может помочь при дизайне и отладке модуля.


 
ANB ©   (2006-06-15 14:57) [30]

Отчеты с помощью чего выводим ?


 
zorik ©   (2006-06-15 15:48) [31]

http://delphimaster.net/view/3-1149574520/


 
kaif ©   (2006-06-15 15:52) [32]

ANB ©   (15.06.06 14:57) [30]
Отчеты с помощью чего выводим ?

Я попробовал с помощью FastReport - работает из BPL без проблем. Даже в MDI - режиме.


 
kaif ©   (2006-06-15 16:47) [33]

У меня есть еще один вопрос. Надеюсь, он не будет выглядеть как оффтопик.
Допустим я хочу построить систему так:
1. Сделать на сервере папку MY_PROGRAM\BIN и расшарить ее на чтение.
2. Сунуть туда my_program.exe + *.bpl, которые входят в мою систему.
3. Сунуть туда клиента Firebird (gds32.dll) для того чтобы настройка компьютера пользователя сводилась только к настройке ярлыка к my_program.exe.
----------------------------
Так вот такой вопрос.
Могу ли я все системные BPL-ы (vcl60.bpl,rtl60.bpl и им подобные) тоже сунуть в эту директорию \BIN на сервере или я обязан их устанавливать в Windows\System каждого клиентского компьютера и регистрировать эти bpl-ы?
Мне почему-то кажется, что могу все сунуть в директорию программы \BIN на сервере.
Или я неправ?



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.6 MB
Время: 0.041 c
1-1151564301
II
2006-06-29 10:58
2006.08.20
Почему не вызывается OnIdle


15-1153768987
Ketmar
2006-07-24 23:23
2006.08.20
навеяно языком Petrovich


15-1153382099
novoalex
2006-07-20 11:54
2006.08.20
Небольшой провайдер...


9-1133300574
Ricks
2005-11-30 00:42
2006.08.20
Переключение между Direct3D и OpenGL


1-1152179934
Dmitry_177
2006-07-06 13:58
2006.08.20
Как можно прочитать сообщения из окна icq?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский