Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Exe, dll и соединение с БД, Серия#2 
:(
    Опции темы
Serggggg
  Дата 15.6.2004, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 12.12.2003
Где: Донецк, Украина

Репутация: нет
Всего: нет



И ещё раз здравствуйте!
Приключения продолжаются. Возникают все новые и новые проблемы.
1. Handle базы данных все-таки передается в dll – для этого надо в uses подключить BDE – тогда Delphi распознают тип hDBIDb. У меня есть пара обработчиков, связанных с таймером:
Код

// Это после соединения с БД в основной программе.
procedure TFMain.DBAfterConnect(Sender: TObject);
begin
ConnTime:=Time;   //Засекается время
Tmr.Enabled:=True;  //Врубается таймер
StatBar.Refresh;  //Обновляется строка статуса
end;

// А это обработчик OnTimer
procedure TFMain.TmrTimer(Sender: TObject);
begin
// Вычисляется время соединения с БД
StatBar.Panels[2].Text:=' Время соединения:  ' + TimeToStr(Time-ConnTime);
StatBar.Refresh;  // Обновляется строка статуса
end;

Без подключения в список USES модуля BDE все это работало. Теперь – ошибка. Судя по всему – при обращении к виндовой функции Time.
‘(’ expected, but ‘;’ found
Вопрос следующий: Что это за глюк и как с этим бороться?

2. Как я уже сказал, в dll передается хэндлер БД. Строка вызова процедуры такая:
Код

// Application и Screen передаются для нормальной работы дочерних MDI-форм
InitPlugin(integer(Application), integer(Screen), DB.Handle);

После этого в самой DLL внутри InitPlugin происходит присвоение глобальной переменной типа hDBIDb нашего хэндлера (дескриптора).
После InitPlugin срабатывает такая функция
Код

function CreateMDI: integer; StdCall;
begin
// Создали дочернее MDI-окно
Result:=integer(TFComp.Create(Application));
// А теперь компоненту TQuery на этой форме прописываем сей дескриптор
FComp.Query1.Database.Handle:=HDB_;
end;

Интересно то, что работает только строка
FComp.Query1.Database.Handle:=HDB_;
Строчка FComp.Query1.DBHandle:=HDB_; выдает ошибку – нельзя присвоить что-то свойству объекта, которое ReadOnly

После этого (т.к. форма MDI – после Create она сразу становится видимой) в обработчике OnShow происходит открытие запроса.
Но до метода OnShow мы не добираемся – при присвоении дескриптора вылетает Access Violation……
Вопрос тот же: Что это за глюк и как с этим бороться?
Огромное спасибо за внимание. Подскажите, кто знает.
--------------------
C уважением, Serggggg.
PM MAIL ICQ   Вверх
Pakshin A. S.
Дата 15.6.2004, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 5056
Регистрация: 16.2.2003

Репутация: 21
Всего: 61



Свойство доступно только для чтения!!! Присваивание не покатит!

Вообще: забей на dll: засунь форму в приложение, настрой связи и работай спокойно...
PM   Вверх
Serggggg
Дата 15.6.2004, 12:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 12.12.2003
Где: Донецк, Украина

Репутация: нет
Всего: нет



Pakshin A. S., я бы с удовольствием, но НАДО сделать это через DLL - если бы все было так просто, я бы и не спрашивал.

--------------------
C уважением, Serggggg.
PM MAIL ICQ   Вверх
Pakshin A. S.
Дата 15.6.2004, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 5056
Регистрация: 16.2.2003

Репутация: 21
Всего: 61



По-моему, нужна связь такая:
Database1.DataSource -> DataSource1 <- Query1.DataSource
(*Мог и ошибку написать, работаю по памяти*)
Следовательно надо создать переменную
DS: TDataSource;

вызов процедуры ....(...DataSource1...);

в процедуре
YourForm.Query1.DataSource:=DS;

P. S.
Интересная задачка, надо будет теорию на практику переложить. Получится - выложу.
Добавлено @ 12:53
Даа, давно не работал с БД, такую фигню написать.

В Query заполни только DatabaseName ( тип string)
В Database есть то самое DatabaseName. => выбираешь Alias, заполняешь DatabaseName и запоминаешь, передаешь в Dll, заполняешь в Query и должно заработать...

и ещё
Может делать отдельный коннект?

Это сообщение отредактировал(а) Pakshin A. S. - 15.6.2004, 13:15
PM   Вверх
Serggggg
Дата 15.6.2004, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 12.12.2003
Где: Донецк, Украина

Репутация: нет
Всего: нет



Если не юзать MDI, то элементарно!
В таком случае нужно передать в DLL login и password и законнектиться автоматом (в DLL компоненте TDatabase присваивается LoginPromt=False, забиваются полученные параметры login и password, а потом Connected:=True - работает, как часы).
А при работе с MDI это не совсем удобно. Чтобы законнектиться, надо сделать компоненте TDatabase Create. Это возможно при создании формы. А при создании MDI-формы её уже не спрячешь. Пихать по 1 компоненту TDatabase на каждую форму, ИМХО, не совсем рационально.

А по поводу передачи датасетов - сейчас буду пробовать. Спасибо.
--------------------
C уважением, Serggggg.
PM MAIL ICQ   Вверх
Pakshin A. S.
Дата 15.6.2004, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 5056
Регистрация: 16.2.2003

Репутация: 21
Всего: 61



Не Сет'ы, а Имя Базы Данных в компоненте DataBase
Добавлено @ 14:19
Может это одно и то же?!
PM   Вверх
Serggggg
Дата 15.6.2004, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 12.12.2003
Где: Донецк, Украина

Репутация: нет
Всего: нет



Именно DataBaseName предлагаешь передать?
sad.gif Пробовал - не работает.
Кто-то когда-то говорил мне, что под dll выделяется другое адресное пространство, а для нормальной работы с соединением надо, чтобы было одно адресное пространство. В принципе, я полагал, что передача TScreen и TApplication эту проблему решат, но, видимо, ошибался.
Короче, я в тупике. butbut.gif
--------------------
C уважением, Serggggg.
PM MAIL ICQ   Вверх
Pakshin A. S.
Дата 15.6.2004, 17:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 5056
Регистрация: 16.2.2003

Репутация: 21
Всего: 61



Может наладить мосты с робительским окном напрямую, ведь у MDI-формы есть "родитель", к которому можно свободно обращаться... А в родителе есть компоненты доступа к БД и т. п...
Добавлено @ 17:25
Ещё идея.
В DLL делаешь фенкцию с возвратом TFrom. У любой формы есть такая штука: MDIChildren[i:integer]:TFrom. Значит управлять дочерней формой можно из родительской, а самое главное - это проще!
PM   Вверх
Serggggg
Дата 16.6.2004, 08:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 12.12.2003
Где: Донецк, Украина

Репутация: нет
Всего: нет



Pakshin A. S., буду весьма благодарен, если поможешь куском кода в качестве примера.
А последняя твоя идея весьма неплоха. Единственное - как именно? Я первый разработаю с MDI в DLL.
--------------------
C уважением, Serggggg.
PM MAIL ICQ   Вверх
Pakshin A. S.
Дата 16.6.2004, 10:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 5056
Регистрация: 16.2.2003

Репутация: 21
Всего: 61



Код

(*DLL*)
function ShowForm(<>):TForm;
<>
begin
<>
Result:=YourForm;
end;

(*EXE*)
// Есть свойство, отвечающее за кол-во MDI-форм
Form1.MDIChildren[10]:=ShowForm(<>);
<>
Form1.MDIChildren[10].Query1...


Идея такова...
PM   Вверх
Serggggg
Дата 16.6.2004, 17:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 12.12.2003
Где: Донецк, Украина

Репутация: нет
Всего: нет



Выход из ситуации был найден. Только, правда, пришлось задействовать 2 коннекта. baaa.gif
Если кому пригодится, буду очень рад.
Итак, внутри dll объявляется переменная типа TDatabase, которая в дальнейшем коннектится с сервером и позволяет нормально работать всем запросам и таблицам, находящимся внутри dll. Привожу мой код. Если кто-то найдет более рациональное решение, поделитесь пожалуйста.

EXE-файл, главный модуль.
Код

// Объявляем типы процедур: инициализация dll, выход из нее, создание окна
type
 TInitProc   = procedure(App, Scr: integer; log, pass: string); StdCall;
 TDoneProc   = procedure; StdCall;
 TCreateProc = function: integer; StdCall;
..........
// Секция PRIVATE
private
   LibHandle  : THandle;
   InitPlugin : TInitProc;
   DonePlugin : TDoneProc;
   CreateMDI  : TCreateProc;
..........
procedure TFMain.MTopCompClick(Sender: TObject);
begin
// Только при условии, что мы соединены с БД
if DB.Connected then begin
   // Загружаем dll в память
   LibHandle := LoadLibrary(PChar('Topics.dll'));
   // Определяем адреса нужных процедур
   @InitPlugin := GetProcAddress(LibHandle, PChar('InitPlugin'));
   @DonePlugin := GetProcAddress(LibHandle, PChar('DonePlugin'));
   @CreateMDI  := GetProcAddress(LibHandle, PChar('CreateMDI'));
   // Запускаем процедуру инициализации, передаем LOGIN и PASSWORD
   InitPlugin(integer(Application), integer(Screen), DB.Params.Values['USER NAME'], DB.Params.Values['PASSWORD']);
   // А это флаг того, что библиотека загружена в память
   TopFlag:=True;
   // Запускаем процедуру создания окна
   CreateMDI;
end
else ShowMessage('Установите соединение с БД!');
end;
..........
// А это происходит при выгрузке главной формы из памяти
procedure TFMain.FormDestroy(Sender: TObject);
begin
// Если dll была загружена, то она освобождается
if TopFlag=True then begin
   DonePlugin;
   FreeLibrary(LibHandle);
   end;
end;


Теперь то, что происходит внутри dll (код целиком):
Код

library Topics;

uses
 SysUtils,
 DB,
 DBTables,
 DBGrids, // Кстати, без этого модуля нельзя присвоить TDatabase свойство Connected=True - вылетит ошибка
 Forms,
 Dialogs,
 Classes,
 Comp in 'Comp.pas' {FComp};

{$R *.res}

var
TopDB :TDatabase;
DA : TApplication;
DS : TScreen;
Flag : Boolean;

procedure Connect(login,password:string);
begin
with TopDB do begin
// Присваиваем все необходимые параметры
 AliasName:='TKD';
 DatabaseName:=AliasName;
// Окно диалога нам не нужно
 LoginPrompt:=False;
// Зачистка параметров
 Params.Clear;
// Добавляем полученные из основной программы LOGIN и PASSWORD
 Params.Add('USER NAME=' + login);
 Params.Add('PASSWORD=' + password);
 Connected:=True;
// Законнектились и устанавливаем признак коннекта  равным True
 Flag:=True;
end;
end;

procedure InitPlugin(App, Scr: integer; log, pass: string); StdCall;
var DA: TApplication;
     DS: TScreen;
begin
// Переприсваиваем значения Screen и Application из полученных
DS:=Screen;
Screen:=TScreen(Scr);
DA:=Application;
Application:=TApplication(App);
// Если соединение ещё не устанавливалось
if Flag=False then begin
   TopDB:=TDatabase.Create(Application);
   Connect(log, pass);
   end;
end;

procedure DonePlugin; StdCall;
begin
// Присваиваем Screen и Application обратно
Screen:=DS;
Application:=DA;
end;

function CreateMDI: integer; StdCall;
begin
// Просто создаем MDI-окно - соединение с БД УЖЕ есть - при старте окно само откроет запрос
Result:=integer(TFComp.Create(Application));
end;

exports
InitPlugin,
DonePlugin,
CreateMDI;

begin
end.


Надеюсь, кому-то это поможет. cool.gif Pakshin A. S., спасибо за участие.
--------------------
C уважением, Serggggg.
PM MAIL ICQ   Вверх
Pakshin A. S.
Дата 16.6.2004, 17:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 5056
Регистрация: 16.2.2003

Репутация: 21
Всего: 61



Всегда рад подкинуть идейки... если что, обращайся. biggrin.gif
PM   Вверх
_hunter
Дата 17.6.2004, 20:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: 15
Всего: 98



Сорри что раньше не писал ( сесия sad.gif )

ссылка на DataSource ( о которой я раньше писал ) -- просто параметр типа Db::TDataSource
т.е. создаеш где-то DataSource ( можно и на форме )
и передаеш в dll его
в dll: Query.DataSourc = DataSource ( ссылка )

должно работать


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1530 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.