![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
DLL с совместно используемой памятью [D7, WinXP]
Чайник © (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.