Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.251 c
2-1179123062
проходил мимо решил заглянуть
2007-05-14 10:11
2007.06.03
как выключить чужую прогу


15-1178538421
db2admin
2007-05-07 15:47
2007.06.03
"Пиратство" оценили в пять тысяч рублей


2-1179133630
Zahadom
2007-05-14 13:07
2007.06.03
Копированиет с индикатором - ёлки-палки!


2-1179031389
pasenus
2007-05-13 08:43
2007.06.03
Как выполнить чужую процедуру в чужой программе


2-1179337555
N3xt_
2007-05-16 21:45
2007.06.03
Структуры





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский