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!


Loginov Dmitry   (2007-04-06 20:58:00) [21]

> Я сегодня налетел на проблемы, связанные с инициализацией
> в библиотеке в initialization.


Вот везунчик!

:)


_Аноним   (2007-04-06 20:36:00) [22]

Я сегодня налетел на проблемы, связанные с инициализацией в библиотеке в initialization.
Суть сводится к тому, что есть некий список плагинов, хост грузит их все подряд, и смотрит по наличию точек входа, "наш плагин или нет".
А в инициализации плагин регистрирует метакласс в глобальномм списке
ну так регистрация прошла непосредственно по LoadLibrary, потом выяснилось, что плагин грузить не надо, я его выгрузил. а егойный метакласс в глоб. списке остался. Пока сообразил, в чем дело, много времени ушло.


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

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


Чайник (с другого компа)   (2007-04-06 17:26:00) [24]


> Loginov Dmitry ©   (06.04.07 07:42) [11]


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


Loginov Dmitry   (2007-04-06 07:42:00) [25]

> А где же тогда ее инициализировать, как не здесь?


Допустим, в функции InitData()


Чайник   (2007-04-06 03:19:00) [26]


> Во-ще, 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 - плохое место для инициализации/финализации? А где же тогда ее инициализировать, как не здесь?


Leonid Troyanovsky   (2007-04-05 19:44:00) [27]


> Loginov Dmitry ©   (04.04.07 23:26) [8]

> DLL с часто используемыми функциями (да хоть LoadLibrary),

Это кто ж LL часто пользует таким образом?
Только, примеров не надо, а то я расстроюсь.

--
Regards, LVT.


Loginov Dmitry   (2007-04-04 23:26:00) [28]

Что-ж, определенные ограничение имеются. Куда ж без них? Вот только меня не совсем убедило данное описание проблем, связанных с инициализацией в DLL. Если б был бы приведен простенький пример в Delphi, где б возникла ошибка загрузки DLL с часто используемыми функциями (да хоть LoadLibrary), тогда б другое дело.
А пока же не имел случая сталкиваться в этом плане с какими-либо серьезными проблемами.


Leonid Troyanovsky   (2007-04-04 22:15:00) [29]


> 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 20:59:00) [30]

> Во-ще, initialization/finalization - это плохое место для
> инициализации/финализации данных в длл.
> Хотя, возможно, вернее сказать, что это, вообще, плохое
> место.


Почему это место является плохим для инициализации/финализации данных в длл?


Сергей М.   (2007-04-03 08:32:00) [31]


> Чайник ©   (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


Leonid Troyanovsky   (2007-04-02 23:49:00) [32]


> {RASkov}   (02.04.07 23:34) [2]

> Может быть в dpr библиотеке код инициализации поместить
> в begin и end.

За это место тоже лучше не трогать без острой нужды.

--
Regards, LVT.


Leonid Troyanovsky   (2007-04-02 23:40:00) [33]


> Чайник ©   (02.04.07 20:46) [1]

> Но! В связи с этим родился другой вопрос: а как сделать
> так, чтобы GlobalData инициализировалась только ОДИН раз,
>  то есть при первой загрузке DLL?

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

Отличить же первый вызов CreateFileMapping от последующих
можно с помощью GetLastError.

Кста, кроме самой проекции, должен существовать некий механизм
синхронизации доступа к ней, например, мьютекс.

--
Regards, LVT.


{RASkov}   (2007-04-02 23:34:00) [34]

> чтобы GlobalData инициализировалась только ОДИН раз, то есть при первой загрузке DLL?

Может быть в dpr библиотеке код инициализации поместить в begin и end.


Чайник   (2007-04-02 20:46:00) [35]

Пока писал свой длинный-длинный вопрос, разобрался с ответом. У меня в блоке finalizationюнита P1202_Driversстоит инициализация GlobalDataданными по умолчанию. При повторной загрузке DLL другим приложением эти данные сбрасывались обратно в ноль.

Но! В связи с этим родился другой вопрос: а как сделать так, чтобы GlobalData инициализировалась только ОДИН раз, то есть при первой загрузке DLL?


Страницы:   1 2

Наверх

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