Форум: "Основная";
Текущий архив: 2007.06.03;
Скачать: [xml.tar.bz2];
ВнизDLL с совместно используемой памятью Найти похожие ветки
← →
Чайник © (2007-04-02 20:28) [0]Собственно задача: надо создать 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!
← →
Чайник © (2007-04-02 20:46) [1]Пока писал свой длинный-длинный вопрос, разобрался с ответом. У меня в блоке
finalization
юнитаP1202_Drivers
стоит инициализацияGlobalData
данными по умолчанию. При повторной загрузке DLL другим приложением эти данные сбрасывались обратно в ноль.
Но! В связи с этим родился другой вопрос: а как сделать так, чтобы GlobalData инициализировалась только ОДИН раз, то есть при первой загрузке DLL?
← →
{RASkov} (2007-04-02 23:34) [2]> чтобы GlobalData инициализировалась только ОДИН раз, то есть при первой загрузке DLL?
Может быть в dpr библиотеке код инициализации поместить в begin и end.
← →
Leonid Troyanovsky © (2007-04-02 23:40) [3]
> Чайник © (02.04.07 20:46) [1]
> Но! В связи с этим родился другой вопрос: а как сделать
> так, чтобы GlobalData инициализировалась только ОДИН раз,
> то есть при первой загрузке DLL?
Во-ще, initialization/finalization - это плохое место для
инициализации/финализации данных в длл.
Хотя, возможно, вернее сказать, что это, вообще, плохое место.
Попробуй построить логику так, чтобы необходимая инициализация/
финализация происходила, например, по явному вызову процедуры из длл.
(Однако, в случае финализации это не всегда возможно).
Отличить же первый вызов CreateFileMapping от последующих
можно с помощью GetLastError.
Кста, кроме самой проекции, должен существовать некий механизм
синхронизации доступа к ней, например, мьютекс.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2007-04-02 23:49) [4]
> {RASkov} (02.04.07 23:34) [2]
> Может быть в dpr библиотеке код инициализации поместить
> в begin и end.
За это место тоже лучше не трогать без острой нужды.
--
Regards, LVT.
← →
Сергей М. © (2007-04-03 08:32) [5]
> Чайник © (02.04.07 20:28)
Есть альтернативное решение - PE shared section
(см. http://msdn2.microsoft.com/en-us/library/ms809762.aspx)
Цитата :
Table 6. IMAGE_SECTION_HEADER Formats
..
DWORD Characteristics
..
0x10000000
This section is shareable. When used with a DLL, the data in this section will be shared among all processes using the DLL. The default is for data sections to be nonshared, meaning that each process using a DLL gets its own copy of this section"s data. In more technical terms, a shared section tells the memory manager to set the page mappings for this section such that all processes using the DLL refer to the same physical page in memory. To make a section shareable, use the SHARED attribute at link time. For example
← →
Loginov Dmitry © (2007-04-04 20:59) [6]> Во-ще, initialization/finalization - это плохое место для
> инициализации/финализации данных в длл.
> Хотя, возможно, вернее сказать, что это, вообще, плохое
> место.
Почему это место является плохим для инициализации/финализации данных в длл?
← →
Leonid Troyanovsky © (2007-04-04 22:15) [7]
> Loginov Dmitry © (04.04.07 20:59) [6]
> Почему это место является плохим для инициализации/финализации
> данных в длл?
http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx
--
Regards, LVT.
← →
Loginov Dmitry © (2007-04-04 23:26) [8]Что-ж, определенные ограничение имеются. Куда ж без них? Вот только меня не совсем убедило данное описание проблем, связанных с инициализацией в DLL. Если б был бы приведен простенький пример в Delphi, где б возникла ошибка загрузки DLL с часто используемыми функциями (да хоть LoadLibrary), тогда б другое дело.
А пока же не имел случая сталкиваться в этом плане с какими-либо серьезными проблемами.
← →
Leonid Troyanovsky © (2007-04-05 19:44) [9]
> Loginov Dmitry © (04.04.07 23:26) [8]
> DLL с часто используемыми функциями (да хоть LoadLibrary),
Это кто ж LL часто пользует таким образом?
Только, примеров не надо, а то я расстроюсь.
--
Regards, LVT.
← →
Чайник © (2007-04-06 03:19) [10]
> Во-ще, initialization/finalization - это плохое место для
> инициализации/финализации данных в длл.
> Хотя, возможно, вернее сказать, что это, вообще, плохое
> место.
Сделал так:var
AtomDLL : THandle;
....
initialization
{ Инициализация глобальных данных }
OpenSharedData;
AtomDLL := GlobalFindAtom(AtomStr);
IF AtomDLL=0 Then begin
GlobalAddAtom(AtomStr);
GlobalData^.IsInit := False;
GlobalData^.GlobalDataAdress := -1;
GlobalData^.SettingTime := 23;
end;
finalization
CloseSharedData;
GlobalDeleteAtom(AtomDLL);
Пока работает...
Leonid Troyanovsky © (02.04.07 23:40) [3]
Во-ще, initialization/finalization - это плохое место для
инициализации/финализации данных в длл.
Хотя, возможно, вернее сказать, что это, вообще, плохое место.
Так почему все-таки initialization/finalization - плохое место для инициализации/финализации? А где же тогда ее инициализировать, как не здесь?
← →
Loginov Dmitry © (2007-04-06 07:42) [11]> А где же тогда ее инициализировать, как не здесь?
Допустим, в функции InitData()
← →
Чайник (с другого компа) (2007-04-06 17:26) [12]
> Loginov Dmitry © (06.04.07 07:42) [11]
А зачем? Чем плохо в initialization?
← →
Loginov Dmitry © (2007-04-06 18:19) [13]Понятия не имею :)
Всегда в initialization инициализирую все, что нужно, а вот Леонид видет в этом проблемы :)
← →
_Аноним (2007-04-06 20:36) [14]Я сегодня налетел на проблемы, связанные с инициализацией в библиотеке в initialization.
Суть сводится к тому, что есть некий список плагинов, хост грузит их все подряд, и смотрит по наличию точек входа, "наш плагин или нет".
А в инициализации плагин регистрирует метакласс в глобальномм списке
ну так регистрация прошла непосредственно по LoadLibrary, потом выяснилось, что плагин грузить не надо, я его выгрузил. а егойный метакласс в глоб. списке остался. Пока сообразил, в чем дело, много времени ушло.
← →
Loginov Dmitry © (2007-04-06 20:58) [15]> Я сегодня налетел на проблемы, связанные с инициализацией
> в библиотеке в initialization.
Вот везунчик!
:)
← →
Leonid Troyanovsky © (2007-04-06 22:34) [16]
> Чайник (с другого компа) (06.04.07 17:26) [12]
> А зачем? Чем плохо в initialization?
См. [7]
--
Regards, LVT.
← →
Leonid Troyanovsky © (2007-04-06 22:56) [17]
> Loginov Dmitry © (06.04.07 18:19) [13]
> Всегда в initialization инициализирую все, что нужно, а
> вот Леонид видет в этом проблемы :)
Не один я, IMHO.
От секций initialization/finalization не так много пользы, как могло б показаться. По гамбургскому счету они, во-ще, противоречат
объектной модели, и есть проявление дельфийского дуализма
объекты-модули (ведь, юниты-то необъектны).
В длл эти секции, кроме того, могут вызывать и проблемы,
описанные в статье.
Если же стоять на правильной позиции, то (для начала)
надо вызывать экспортируемую функцию InitData.
Ну, а размышления о правильном месте вызова CloseData (эксп.)
позволят сделать полезные для будущего приложения выводы.
--
Regards, LVT.
← →
Loginov Dmitry © (2007-04-06 23:03) [18]По Вашему, DLL и VCL не совместимы в принципе?
← →
Leonid Troyanovsky © (2007-04-06 23:06) [19]
> Leonid Troyanovsky © (06.04.07 22:56) [17]
> От секций initialization/finalization не так много пользы,
Хотя, скажем, в D6 (изначальной) некоторое время
существовал баг, благодаря которому не вызывалась
DllProc with DLL_PROCESS_DETACH.
Спасти тогда могла лишь finalization.
Т.е., и терпентин на что-нибудь полезен.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2007-04-06 23:15) [20]
> Loginov Dmitry © (06.04.07 23:03) [18]
> По Вашему, DLL и VCL не совместимы в принципе?
Хотя, в этом (и параллельных) топиках я и старался
не касаться этого вопроса, но, если вопрос поставлен прямо,
то отвечу: в классическом виде - несовместимы в принципе.
Для скрещивания оных борландам потребовались bpl.
Т.е., отказ от универсальности (утопической) позволил
получить более или менее полезные результаты.
--
Regards, LVT.
← →
Суслик © (2007-04-07 16:47) [21]
> [20] Leonid Troyanovsky © (06.04.07 23:15)
Я так понял, Леонид, что Вы выступаете за НЕиспользование initialization в библиотеках в принципе. Я читал в свое время ссылку из [7] (вы же, если не ошибаюсь, ее и приводили).
Я не пользуюсь DLL - у меня только BPL. Я, признаться, не знаю другого способа при использовании BPL + LoadPackage заставить какой-то код из пакета выполниться, при загрузке оного. Такое может потребоваться, например, для того, чтобы дать возможность пакету зарегистрировать какой-нибудь класс.
Как Вы советуете поступать в указанном случае с инициализацией пакета?
← →
Leonid Troyanovsky © (2007-04-07 20:31) [22]
> Суслик © (07.04.07 16:47) [21]
> Как Вы советуете поступать в указанном случае с инициализацией
> пакета?
Не могу себя считать специалистом по пакетам, бо обладаю
лишь зачатками знаний в этом вопросе. Но, думаю, что
большинство возможных неприятностей, описанных в статье,
пакетам не грозит (если, конечно, не делать там нечто
подобное LoadPackage).
Остаются лишь (моя) легкая неприязнь к этим секциям.
В идеале, всякие загрузки, инициализации и т.п. должны
производиться по первому требованию (обращению к любой
функции, требующей инициализации некоторых данных).
Кроме того, для всех библиотек любую инициализацию
надо рассматривать совместно с финализацией, которая
более ответственна, чем в случае приложения, т.к.
после выгрузки библиотеки (пакета) приложение может
(или обязано) жить дальше.
--
Regards, LVT.
← →
Чайник © (2007-04-08 13:10) [23]Позволю вернуться к первоначальному вопросу:
1. BPL - это, конечно хорошо, но как быть, если по условиям требуется именно DLL (данная DLL пишется в замену существующей).
2. Введение каких-либо доп.функций типа InitData() (см.[11]) не получится, т.к. в исходной DLL их нет.
Прошу мастеров посмотреть внимательно на мой код в [10] и покритиковать.
← →
TStas © (2007-04-08 14:31) [24]Может, я чего-то не понимаю, но Фленов пишет, что дллки не могут хранить глобальные переменные.
← →
Loginov Dmitry © (2007-04-08 15:41) [25]Не верь всему, что пишут на заборе.
← →
Leonid Troyanovsky © (2007-04-09 11:08) [26]
> Чайник © (08.04.07 13:10) [23]
> Прошу мастеров посмотреть внимательно на мой код в [10]
Критика уже была, только ты ей не внимаешь.
Ключевые моменты: GetLastError, мьютекс (AtomDll - бред).
Инициализацию данных перенести в DriverInit,
финализацию - в DriverClose.
--
Regards, LVT.
← →
Суслик © (2007-04-09 11:15) [27]
> [22] Leonid Troyanovsky © (07.04.07 20:31)
>
> Не могу себя считать специалистом по пакетам, бо обладаю
> лишь зачатками знаний в этом вопросе. Но, думаю, что
> большинство возможных неприятностей, описанных в статье,
> пакетам не грозит (если, конечно, не делать там нечто
> подобное LoadPackage).
Очень интересует выделенная часть. Собстно пакеты на то они и пакеты, чтобы им делать LoadPackage. Что-то я не понял - Вы ничего не имеете против пакетов, если не делать LoadPackage?
ЗЫ. Признаюсь, что я сам недолюбливаю секции initialization и finalizatoin. Это связано с тем, что вечно вызывает вопросы порядок их выполнения в разных модулях. С другой стороны я не знаю *штатного* механизма кроме как initialiazation дать возможность модулю из пакеты выполнить какой-то код при загрузке. А это крайне необходимо - иначе как загруженный пакет сможет сказать хост-приложению о себе, о том, что есть в пакете?
← →
Leonid Troyanovsky © (2007-04-09 11:30) [28]
> Суслик © (09.04.07 11:15) [27]
> они и пакеты, чтобы им делать LoadPackage. Что-то я не понял
> - Вы ничего не имеете против пакетов, если не делать LoadPackage?
Речь шла о секции инициализации.
Просто, про LoadLibrary уже был треп.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2007-04-09 11:41) [29]
> Суслик © (09.04.07 11:15) [27]
> при загрузке. А это крайне необходимо - иначе как загруженный
> пакет сможет сказать хост-приложению о себе, о том, что
> есть в пакете?
Ну, ему же сделали LoadPackage?
Почему бы еще не опросить его (инициализировать).
А про допустимый в инициализации код ты, думаю, уже в курсе.
--
Regards, LVT.
← →
Суслик © (2007-04-09 12:55) [30]
> [29] Leonid Troyanovsky © (09.04.07 11:41)
> Ну, ему же сделали LoadPackage?
> Почему бы еще не опросить его (инициализировать).
Я так полагаю, что под "спросить" ты имеешь в виду вызов импортированной из пакета (он же dll) функции? Так?
Т.е. по твоему мнению лучший вариант такой:
1. Загрузил пакет в помощью LoadPackage.
2. Получил из загруженного пакета (он же dll) адрес СВОЕЙ функции инициализации, в которой ты делаешь явную инициализацию пакета.
3. Вызвал функцию.
Так?
← →
Leonid Troyanovsky © (2007-04-09 13:27) [31]
> Суслик © (09.04.07 12:55) [30]
> Так?
Да.
--
Regards, LVT.
← →
Чайник © (2007-04-09 13:38) [32]
> Leonid Troyanovsky © (09.04.07 11:08) [26]
>
> Ключевые моменты: GetLastError, мьютекс (AtomDll - бред).
>
Переведи...
← →
Leonid Troyanovsky © (2007-04-09 15:32) [33]
> Чайник © (09.04.07 13:38) [32]
> > Ключевые моменты: GetLastError, мьютекс (AtomDll - бред).
См. [3]
Использование Atom для определения факта инициализации
общих данных - бредовая идея.
--
Regards, LVT.
← →
Чайник © (2007-04-09 17:38) [34]Исренне благодарю за подробный, скрупулезно конкретный, а главное - аргументированный ответ
← →
Leonid Troyanovsky © (2007-04-09 18:48) [35]
> Чайник © (09.04.07 17:38) [34]
> Исренне благодарю за подробный, скрупулезно конкретный,
> а главное - аргументированный ответ
На здоровье. Каков вопрос - таков и ответ.
А сопли утирать допустимо "начинающим".
--
Regards, LVT.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2007.06.03;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.045 c