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

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

DLL с совместно используемой памятью [D7, WinXP]


Страницы:   1 2

Чайник ©   (2007-04-02 20:28:00) 

Собственно задача: надо создать DLL с областью общей памяти, к которой могут обращаться все приложения, использующие данную DLL (по крайней мере два приложения). По рекомендациям Тейксейры и Пачеки использую отображение файла в память.

Собственно DLL:

library P1202_Im;

uses
 ShareMem, Windows, SysUtils, Classes,
 P1202_Drivers in 'P1202_Drivers.pas';

procedure GetDLLData(var AGlobalData: PGlobalDLLData); StdCall;
begin
 AGlobalData := GlobalData;
end;

{************************************************}
exports GetDLLData;
// Function of Driver
exports
 P1202_DriverInit, P1202_DriverCloseж

begin
end.


Юнит к данной DLL-ке:

unit P1202_Drivers;

interface

uses Windows, SysUtils, Classes;

// Function of Driver
function  P1202_DriverInit(Var wTotalBoards:Word):WORD ; stdCall;
procedure P1202_DriverClose; stdCall;

implementation

{************************************************}
procedure OpenSharedData;
var
  Size: Integer;
begin
 Size := SizeOf(TGlobalDLLData);
 MapHandle := CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, Size, cMMFileName);

 if MapHandle = 0 then
   RaiseLastOSError;
 GlobalData := MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, Size);
 if GlobalData = nil then begin
   CloseHandle(MapHandle);
   RaiseLastOSError;
   Beep;
 end;
end;

{************************************************}
procedure CloseSharedData;
begin
 UnmapViewOfFile(GlobalData);
 CloseHandle(MapHandle);
end;

{************************************************}
function  P1202_DriverInit(Var wTotalBoards:Word):WORD ;
begin
  GlobalData^.IsInit := True;
  GlobalData^.GlobalDataAdress := Integer(GlobalData);
  wTotalBoards := 1;
  Result := NoError;
end;

{************************************************}
procedure P1202_DriverClose;
begin
  GlobalData.IsInit := False;

end;

{************************************************}

initialization
 { Инициализация глобальных данных }
 OpenSharedData;
 GlobalData^.IsInit := False;
 GlobalData^.GlobalDataAdress := 1;

finalization
 CloseSharedData;

end.


Заголовочный файл к DLL-ке:

unit P1202_Im;

interface

uses
 Windows, Messages, SysUtils, Classes;

{$I DLLDATA.INC}  

// Function of Driver
procedure GetDLLData(var AGlobalData: PGlobalDLLData); StdCall;
function  P1202_DriverInit(Var wTotalBoards:Word):WORD ; stdCall;
procedure P1202_DriverClose; stdCall;

implementation

// Function of Driver
procedure GetDLLData(var AGlobalData: PGlobalDLLData); External 'P1202_IM.DLL';
function  P1202_DriverInit(Var wTotalBoards:Word):WORD ; External 'P1202_IM.DLL';
procedure P1202_DriverClose; External 'P1202_IM.DLL';

end.


Основное приложение:

unit UFlotator;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 ExtCtrls, StdCtrls, P1202_Im;

//{$I DLLDATA.INC}

type

 TMainForm = class(TForm)
   memLog: TMemo;
   procedure FormCreate(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 public
   GlobalData: PGlobalDLLData;
 end;

var
 MainForm: TMainForm;

implementation

{$R *.DFM}

{************************************************}
procedure TMainForm.FormCreate(Sender: TObject);
var wTotalBoards : Word;
   GData : PGlobalDLLData;
begin
 GetDLLData(GData);
 P1202_DriverInit(wTotalBoards);

 wBoardActive := P1202_WhichBoardActive;
 memLog.Lines.Clear;
 memLog.Lines.Add('wTotalBoards ='+IntToStr(wTotalBoards));
 memLog.Lines.Add('GlobalDataAdress ='+IntToStr(GData^.GlobalDataAdress));

end;

{************************************************}
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 P1202_DriverClose;
end;

end.


И, наконец, утилитка для отображения состояния общих данных:

unit USets;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls,
 Forms, Dialogs, StdCtrls, ExtCtrls, Mask;

{$I DLLDATA.INC}

type

 TMainForm = class(TForm)
   edtGlobDataStr: TEdit;
   btnGetDllData: TButton;
   meGlobDataInt: TMaskEdit;
   procedure btnGetDllDataClick(Sender: TObject);
   procedure FormCreate(Sender: TObject);
 public
   GlobalData: PGlobalDLLData;
 end;

var
 MainForm: TMainForm;

procedure GetDLLData(var AGlobalData: PGlobalDLLData); StdCall External 'P1202_IM.DLL';

implementation

{$R *.DFM}

{************************************************}
procedure TMainForm.btnGetDllDataClick(Sender: TObject);
begin
 { Get a pointer to the DLL's data }
 GetDLLData(GlobalData);
 { Now update the controls to reflect GlobalData's field values }
 IF GlobalData.IsInit Then edtGlobDataStr.Text := 'Драйвер инициализирован'
                      Else edtGlobDataStr.Text := 'Драйвер НЕ инициализирован';
 meGlobDataInt.Text  := IntToStr(GlobalData^.GlobalDataAdress);
end;

{************************************************}
procedure TMainForm.FormCreate(Sender: TObject);
begin
 btnGetDllDataClick(nil);
end;

end.


Структура глобальных данных описана в файле DLLDATA.INC:

type

 PGlobalDLLData = ^TGlobalDLLData;
 TGlobalDLLData = record
   IsInit: Boolean;
   GlobalDataAdress: Integer;
 end;


Так вот, когда я запускаю сначала утилиту USets, то все работает: при запуске основной программы Flotator текст в окне 'Äðàéâåð èíèöèàëèçèðîâ&# 224;í' и адрес GlobalData, при закрытии - сооветственно наоборот.
Но если я запускаю сначала Flotator, а затем утилиту, то общие данные не видны.
Help me!


Leonid Troyanovsky   (2007-04-09 18:48:00) [1]


> Чайник ©   (09.04.07 17:38) [34]

> Исренне благодарю за подробный, скрупулезно конкретный,
> а главное - аргументированный ответ

На здоровье. Каков вопрос - таков и ответ.
А сопли утирать допустимо "начинающим".

--
Regards, LVT.


Чайник   (2007-04-09 17:38:00) [2]

Исренне благодарю за подробный, скрупулезно конкретный, а главное - аргументированный ответ


Leonid Troyanovsky   (2007-04-09 15:32:00) [3]


> Чайник ©   (09.04.07 13:38) [32]

> > Ключевые моменты: GetLastError, мьютекс (AtomDll - бред).

См. [3]

Использование Atom для определения факта инициализации
общих данных - бредовая идея.

--
Regards, LVT.


Чайник   (2007-04-09 13:38:00) [4]


> Leonid Troyanovsky ©   (09.04.07 11:08) [26]
>
> Ключевые моменты: GetLastError, мьютекс (AtomDll - бред).
>

Переведи...


Leonid Troyanovsky   (2007-04-09 13:27:00) [5]


> Суслик ©   (09.04.07 12:55) [30]

> Так?

Да.

--
Regards, LVT.


Суслик   (2007-04-09 12:55:00) [6]


>  [29] Leonid Troyanovsky ©   (09.04.07 11:41)
> Ну, ему же сделали LoadPackage?
> Почему бы еще не опросить его (инициализировать).


Я так полагаю, что под "спросить" ты имеешь в виду вызов импортированной из пакета (он же dll) функции? Так?

Т.е. по твоему мнению лучший вариант такой:
1. Загрузил пакет в помощью LoadPackage.
2. Получил из загруженного пакета (он же dll) адрес СВОЕЙ функции инициализации, в которой ты делаешь явную инициализацию пакета.
3. Вызвал функцию.
Так?


Leonid Troyanovsky   (2007-04-09 11:41:00) [7]


> Суслик ©   (09.04.07 11:15) [27]

> при загрузке. А это крайне необходимо - иначе как загруженный
> пакет сможет сказать хост-приложению о себе, о том, что
> есть в пакете?

Ну, ему же сделали LoadPackage?
Почему бы еще не опросить его (инициализировать).

А про допустимый в инициализации код ты, думаю, уже в курсе.

--
Regards, LVT.


Leonid Troyanovsky   (2007-04-09 11:30:00) [8]


> Суслик ©   (09.04.07 11:15) [27]

> они и пакеты, чтобы им делать LoadPackage. Что-то я не понял
> - Вы ничего не имеете против пакетов, если не делать LoadPackage?

Речь шла о секции инициализации.
Просто, про LoadLibrary уже был треп.

--
Regards, LVT.


Суслик   (2007-04-09 11:15:00) [9]


> [22] Leonid Troyanovsky ©   (07.04.07 20:31)
>
> Не могу себя считать специалистом по пакетам, бо обладаю
> лишь зачатками знаний в этом вопросе. Но, думаю, что
> большинство возможных неприятностей, описанных в статье,
> пакетам не грозит (если, конечно, не делать там нечто
> подобное LoadPackage)
.


Очень интересует выделенная часть. Собстно пакеты на то они и пакеты, чтобы им делать LoadPackage. Что-то я не понял - Вы ничего не имеете против пакетов, если не делать LoadPackage?

ЗЫ. Признаюсь, что я сам недолюбливаю секции initialization и finalizatoin. Это связано с тем, что вечно вызывает вопросы порядок их выполнения в разных модулях. С другой стороны я не знаю *штатного* механизма кроме как initialiazation дать возможность модулю из пакеты выполнить какой-то код при загрузке. А это крайне необходимо - иначе как загруженный пакет сможет сказать хост-приложению о себе, о том, что есть в пакете?


Leonid Troyanovsky   (2007-04-09 11:08:00) [10]


> Чайник ©   (08.04.07 13:10) [23]

> Прошу мастеров посмотреть внимательно на мой код в [10]

Критика уже была, только ты ей не внимаешь.
Ключевые моменты: GetLastError, мьютекс (AtomDll - бред).
Инициализацию данных перенести в DriverInit,
финализацию - в DriverClose.

--
Regards, LVT.


Loginov Dmitry   (2007-04-08 15:41:00) [11]

Не верь всему, что пишут на заборе.


TStas   (2007-04-08 14:31:00) [12]

Может, я чего-то не понимаю, но Фленов пишет, что дллки не могут хранить глобальные переменные.


Чайник   (2007-04-08 13:10:00) [13]

Позволю вернуться к первоначальному вопросу:

1. BPL - это, конечно хорошо, но как быть, если по условиям требуется именно DLL (данная DLL пишется в замену существующей).
2. Введение каких-либо доп.функций типа InitData() (см.[11]) не получится, т.к. в исходной DLL их нет.

Прошу мастеров посмотреть внимательно на мой код в [10] и покритиковать.


Leonid Troyanovsky   (2007-04-07 20:31:00) [14]


> Суслик ©   (07.04.07 16:47) [21]

> Как Вы советуете поступать в указанном случае с инициализацией
> пакета?

Не могу себя считать специалистом по пакетам, бо обладаю
лишь зачатками знаний в этом вопросе. Но, думаю, что
большинство возможных неприятностей, описанных в статье,
пакетам не грозит (если, конечно, не делать там нечто
подобное LoadPackage).
Остаются лишь (моя) легкая неприязнь к этим секциям.

В идеале, всякие загрузки, инициализации и т.п. должны
производиться по первому требованию (обращению к любой
функции, требующей инициализации некоторых данных).

Кроме того, для всех библиотек любую инициализацию
надо рассматривать совместно с финализацией, которая
более ответственна, чем в случае приложения, т.к.
после выгрузки библиотеки (пакета) приложение может
(или обязано) жить дальше.

--
Regards, LVT.


Суслик   (2007-04-07 16:47:00) [15]


>  [20] Leonid Troyanovsky ©   (06.04.07 23:15)

Я так понял, Леонид, что Вы выступаете за НЕиспользование initialization в библиотеках в принципе. Я читал в свое время ссылку из [7] (вы же, если не ошибаюсь, ее и приводили).

Я не пользуюсь DLL - у меня только BPL. Я, признаться, не знаю другого способа при использовании BPL + LoadPackage заставить какой-то код из пакета выполниться, при загрузке оного. Такое может потребоваться, например, для того, чтобы дать возможность пакету зарегистрировать какой-нибудь класс.

Как Вы советуете поступать в указанном случае с инициализацией пакета?


Leonid Troyanovsky   (2007-04-06 23:15:00) [16]


> Loginov Dmitry ©   (06.04.07 23:03) [18]

> По Вашему, DLL и VCL не совместимы в принципе?

Хотя, в этом (и параллельных) топиках я и старался
не касаться этого вопроса, но, если вопрос поставлен прямо,
то отвечу: в классическом виде - несовместимы в принципе.
Для скрещивания оных борландам потребовались bpl.
Т.е., отказ от универсальности (утопической) позволил
получить более или менее полезные результаты.

--
Regards, LVT.


Leonid Troyanovsky   (2007-04-06 23:06:00) [17]


> Leonid Troyanovsky ©   (06.04.07 22:56) [17]

> От секций initialization/finalization не так много пользы,

Хотя, скажем, в D6 (изначальной) некоторое время
существовал баг, благодаря которому не вызывалась
DllProc with DLL_PROCESS_DETACH.
Спасти тогда могла лишь finalization.

Т.е., и терпентин на что-нибудь полезен.

--
Regards, LVT.


Loginov Dmitry   (2007-04-06 23:03:00) [18]

По Вашему, DLL и VCL не совместимы в принципе?


Leonid Troyanovsky   (2007-04-06 22:56:00) [19]


> Loginov Dmitry ©   (06.04.07 18:19) [13]

> Всегда в initialization инициализирую все, что нужно, а
> вот Леонид видет в этом проблемы :)

Не один я, IMHO.
От секций initialization/finalization не так много пользы, как могло б показаться. По гамбургскому счету они, во-ще, противоречат
объектной модели, и есть проявление дельфийского дуализма
объекты-модули (ведь, юниты-то необъектны).
В длл эти секции, кроме того, могут вызывать и проблемы,
описанные в статье.

Если же стоять на правильной позиции, то (для начала)
надо вызывать экспортируемую функцию InitData.
Ну, а размышления о правильном месте вызова CloseData (эксп.)
позволят сделать полезные для будущего приложения выводы.

--
Regards, LVT.


Leonid Troyanovsky   (2007-04-06 22:34:00) [20]


> Чайник (с другого компа)   (06.04.07 17:26) [12]

> А зачем? Чем плохо в initialization?

См. [7]

--
Regards, LVT.


Страницы:   1 2

Наверх

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