Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2011.05.29;
Скачать: [xml.tar.bz2];

Вниз

Последовательный доступ к MMF   Найти похожие ветки 

 
Muxa/Ibl4   (2009-07-14 22:12) [0]

Уважаемые коллеги, прошу помочь в реализации.

Что_имеем: 2 программы(или более) на одном компе, каждая имеет некую DLL(по сути это одна библиотечка просто для портативности для каждой проги нужна копия DLL).

Что_нуна: Реализовать в DLL механизм чтения/записи данных в MMF (можно последовательный - но не обязательно).

Что_получилось: получилось реализовать 2 приложения работающие с DLL, и саму DLL. Но проблема в том что если 1приложение работает со совей копией DLL то 2 уже не может работать со своей.

Как быть? Если кто то швырнет в меня примером библиотечки (желательно с возможность последовательного доступа) - то я буду очень счастливым человеком.


 
Rouse_ ©   (2009-07-14 22:14) [1]


> если 1приложение работает со совей копией DLL то 2 уже не
> может работать со своей.

SHARE_ права выставилил при открытии?


 
Loginov Dmitry ©   (2009-07-14 22:29) [2]

Отсутствует наиболее важное:
Как пытался получить


 
Юрий Зотов ©   (2009-07-14 22:31) [3]

Не понял насчет копий DLL. Почему каждый EXE не может загрузить одну и ту же DLL и с ней работать?


 
Muxa/Ibl4   (2009-07-14 22:36) [4]

Долго объяснять но так требуют великие боги.


 
Muxa/Ibl4   (2009-07-14 22:36) [5]

Вот подобие моего говнокода

library DllMmfDate;
uses
 ShareMem,
 SysUtils,
 windows,
 md5 in "md5.pas";

type
   User = record
sName : string;
iId :   integer;
   end;
   
   aUser = array of User;

   Command = record
sTitle : string;
iId:     integer;
   end;

   aCommand = array of Command;

   info = record
ListUser : aUser;
       ListCommand: aCommand;
   end;
   

   tinfo = ^info;

var

 SendMMF: THandle;
 SendData: PChar;

const
 NameAreaForWwork = "trulala";

function writeMMF ( param : info ) : boolean;
var
 rw : tinfo;
begin
 if (MapViewOfFile(SendMMF, FILE_MAP_WRITE, 0, 0, 0) = nil ) then Begin
   SendMMF := CreateFileMapping( $FFFFFFFF, Nil, PAGE_READWRITE, 0, SizeOf(DWORD), NameAreaForWwork);
 end;

 rw := MapViewOfFile(SendMMF, FILE_MAP_WRITE, 0, 0, 0);
 rw^ := param;

 Result :=true;
end;

function readMMF() : tinfo;
begin
 if ( MapViewOfFile(SendMMF, FILE_MAP_READ, 0, 0, 0) = nil ) then Begin
     SendMMF := CreateFileMapping( $FFFFFFFF, Nil, PAGE_READWRITE, 0, SizeOf(DWORD), NameAreaForWwork);
 end else begin
     SendMMF := OpenFileMapping(FILE_MAP_READ, False, NameAreaForWwork);
 end;

     Result := MapViewOfFile(SendMMF, FILE_MAP_READ, 0, 0, 0);
end;

function addUser( sUserName, iIdUser : PChar ): PChar; stdcall;
var
 r : info;
 rp : tinfo;

 aUsers : aUser;
begin
 rp := readMMF();
 r := rp^;

 aUsers := r.aUser;

 setLength(termW, Length(aUsers)+1);
 termW[Length(aUsers)-1].sName := sUserName;
 termW[Length(aUsers)-1].terminalName := iIdUser;

 r.aUser := aUsers;

 writeMMF( r );

 //.........

 Result := "тут текстовый результ";
end;

function getUserAll(): aUser; stdcall;
var
 r : info;
 rp : tinfo;
begin
 rp := readMMF();
 r := rp^;
 Result := r.aUser;
end;

exports    addUser, getUserAll;
begin
end.


 
Игорь Шевченко ©   (2009-07-14 22:42) [6]

program files\borland\bds\x.0\demos\DelphiWin32\vclwin32\IPCDemos\*.*


 
Loginov Dmitry ©   (2009-07-14 22:44) [7]

Это именно говнокод. Все верно.

Здесь
http://delphimaster.net/view/16-1247596906/
можно в целях изучения MMF посмотреть, что когда-то предлагали Тейксера и Пачека.


 
Muxa/Ibl4   (2009-07-14 23:00) [8]

спасибо за ссылки, но у меня вопросов пару
подскажите
при такой реализации (я про DLL) - я же не могу 1 раз создать mmf и хранить его Handle т.к. в dll это не получиться и мне необходимо каждый раз как то проверять есть ли уже созданный файл или нет. Я прав или неверно мыслю?


 
Muxa/Ibl4   (2009-07-14 23:02) [9]

после записи или чтения в mmf я тоже не могу "закрыть" его. Т.к. при следующем вызове функции мне тогда придется создавать его заново, т.е. потеря данных?


 
Игорь Шевченко ©   (2009-07-14 23:04) [10]


> при такой реализации (я про DLL) - я же не могу 1 раз создать
> mmf и хранить его Handle т.к. в dll это не получиться и
> мне необходимо каждый раз как то проверять есть ли уже созданный
> файл или нет. Я прав или неверно мыслю?


на время загрузки DLL вполне получится. в инициализации DLL создать MMF, дальше пользоваться, при выгрузке освободить


 
Игорь Шевченко ©   (2009-07-14 23:04) [11]

Muxa/Ibl4   (14.07.09 23:02) [9]

MMF (и данные в нем) будут жить, пока не закроется последний его Handle


 
Muxa/Ibl4   (2009-07-14 23:08) [12]

но еще один момент, как я и сказал для каждой программы должна быть своя "личная" копия dll, как быть в этом случае?


 
Игорь Шевченко ©   (2009-07-14 23:11) [13]

Muxa/Ibl4   (14.07.09 23:08) [12]

А какая разница - у объекта FileMapping есть имя - пусть каждая DLL открывает его, кто не открыл по OpenFileMapping, пусть создает по CreateFileMapping.

Я ссылку на Demos не просто так дал, а со смыслом.


 
Muxa/Ibl4   (2009-07-14 23:22) [14]

блин, вроде и понятно, но что то я запутался(


 
Loginov Dmitry ©   (2009-07-15 00:36) [15]

> блин, вроде и понятно, но что то я запутался


То, что в [5] долго еще будешь распутывать. А ведь
обмен между процессамы задумывается, верно?
Я лишь предложу перечень замечаний по [5], но, думаю, они
помогут разобраться в ошибках и уйти от них. Нет так нет.

1. По допустимым типам данных. Переменная rw : tinfo это по сути
указатель на разделяемую между приложениями область памяти. И что
мы хотим хранить в этой области памяти? Переменные ListUser : aUser и
ListCommand: aCommand. НО! Обе переменные - это массивы. Динамические.
(Их размер можно менять). По сути обе переменные - это указатели на области
памяти, в которых хранятся массивы. НО! Области памяти, в которых хранятся
массивы мы не расшариваем! Таким образом если какой-то обмен и будет - то
только ссылками на неизвестно что, взятое из чужого адресного пространства.
Выход: использовать статические массивы и короткие строки.

2. По использованию функции CreateFileMapping(). Что мы получим при таком вызове:
SendMMF := CreateFileMapping( $FFFFFFFF, Nil, PAGE_READWRITE, 0, SizeOf(DWORD), NameAreaForWwork);
будет создан соответствующий объект Windows, про который известно, что он не будет хранится в каком-либо
файле на диске, и его размер = 4 байта. В итоге получим хэндл этого объекта. И что дальше? А дальше идет
rw := MapViewOfFile(SendMMF, FILE_MAP_WRITE, 0, 0, 0);
что в данном случае приведет либо к выделению области памяти в 4 байта для записи, причем эта память будет
доступна для любого приложения, либо же функция вернет указатель на область памяти, которая ранее уже была
выделена для другого приложения. Причем функция может вернуть и вовсе NIL, если ей неправильно воспользовались.
(это - пояснение, а не замечание).

3. По реализации readMMF. Здесь все просто. Можно использовать одну лишь функцию CreateFileMapping(). Функцию
OpenFileMapping() используют немного в других ситуациях: когда требуется получить хэндл файлового отображения,
которое ранее уже было создано (а если оно не создано, то выполняется соответствующая обработка, а в каких-то
ситуациях может и CreateFileMapping). Если же просто нужен хэндл на файловое отображение не зависимо от того,
было ли одно до этого, или нет, то достаточно функции CreateFileMapping(). Она либо создаст объект, либо вернет
хэндл для существующего объекта.

4. По реализации addUser. Нельзя возвращать результат как PChar, предварительно не выделив под него память. В
данном случае ошибки может не возникнуть, поскольку есть явное присвоение
Result := "тут текстовый результ". Строка является константной, она всегда находится в памяти в
одном и том же месте. А вот если вместо константной строки передать динамическую строку, то скорее всего будет
капут, т.к. память, выделенная под динамическую строку, освободится сразу же, как только завершится функция, и
в итоге функция вернет указатель на ничто. Вместо PChar нужно использовать string, тем более что подключен модуль
ShareMem.

5. Совсем мелкие замечания:
   - имена типов в Delphi обычно начинаются с буквы T (например, TInfo)
   - указатели на типизированные структуры начинаются с буквы P (например PInfo)
   - stdcall определяет порядок вызова фукнции, при этом для передачи параметров используется стэк вместо
     высокоскоростных регистров процессора. В данном случае оно ни в EXE ни в DLL не нужно.
   - функцию writeMMF можно сделать процедурой. Возвращаемый ею результат все-равно бесполезен.

Итого - весь код с нуля нужно переделывать, учесть все замечания всех ответивших в этой ветке.


 
Юрий Зотов ©   (2009-07-15 09:36) [16]

> Muxa/Ibl4   (14.07.09 22:36) [4]

Богам, возможно, виднее, но даже и простым смертным известно, что каждая запущенная в Windows программа грузит библиотеку Kernel32.dll. Запустили 100 программ - библиотека 100 раз загружена.

Одна и та же. И никаких копий. И все замечательно работает. И так со всеми DLL. И непонятно, на кой ляд богам понадобилось принимать такие (skipped) решения.

PS
По коду даже не говорю ничего. Потому что слишком много говорить придется. Документацию на используемые функции надо читать внимательнее.


 
Muxa/Ibl4   (2009-07-21 22:33) [17]

Все сдаюсь, прошу если есть возможность дать пример _dllки_ где есть метод чтения и метод записи MMF


 
Сергей М. ©   (2009-07-21 22:39) [18]


> 2 уже не может работать со своей


Что, вот прямо так и кричит "не могу" ?


 
Muxa/Ibl4   (2009-07-21 22:52) [19]

я уже согласен на такую реализацию, там конечно есть трудности но на это я забил.


 
Сергей М. ©   (2009-07-21 23:04) [20]

Михалыч, ты на вопрос в [18] соизволишь ответить ?)


 
antonn ©   (2009-07-22 00:29) [21]

вместо $FFFFFFFF правильнее использовать INVALID_HANDLE_VALUE


 
Игорь Шевченко ©   (2009-07-22 01:11) [22]

antonn ©   (22.07.09 00:29) [21]


> вместо $FFFFFFFF правильнее использовать INVALID_HANDLE_VALUE


const
 INVALID_HANDLE_VALUE = DWORD(-1);

почему правильнее ?


 
antonn ©   (2009-07-22 01:22) [23]

потому что на 64-битной системе будет не -1 :)


 
Игорь Шевченко ©   (2009-07-22 02:05) [24]

antonn ©   (22.07.09 01:22) [23]

До Delphi 64 еще дожить надо. Хотя специально посмотрел в своих промышленных проектах - таки INVALID_HANDLE_VALUE использую.

Значит, ты прав :)


 
Юрий Зотов ©   (2009-07-22 02:06) [25]

> Muxa/Ibl4   (21.07.09 22:33) [17]

Лови, я сегодня добрый. И давно на Delphi не писал, соскучился даже - вот и захотелось размяться слегка. Писал в Delphi 7.

Только не копируй бездумно - разберись в каждой строчке и в каждой букве - что она делает, зачем она это делает,  как она это делает и почему она это делает именно тут, а не в другом месте. Справка и MSDN тебе в помощь, там все описано. А что останется неясным - спрашивай здесь.

1. Полный код общего юнита (используется и в DLL, и в тестовой программе)

unit DataType;

interface

type
 TData = packed record
   Int: integer;
   Str: ShortString
 end;

 PData = ^TData;

 TWriteData = procedure(Source: PData); stdcall;
 TReadData = function: PData; stdcall;

const
 DLL_NAME = "MMF_DLL";
 ReadDataProcName = "ReadData";
 WriteDataProcName = "WriteData";

implementation

end.


2. Полный код DLL

library MMF_DLL;

uses
 Windows,
 SysUtils,
 DataType in "DataType.pas";

const
 MMF_NAME = "MySharedData";

var
 HData: THandle = 0;
 DataPtr: PData = nil;

procedure EntryProc;
begin
 HData := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TData), MMF_NAME);
 Win32Check(HData <> 0);
 DataPtr := MapViewOfFile(HData, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 Win32Check(DataPtr <> nil)
end;

procedure ExitProc;
begin
 UnmapViewOfFile(DataPtr);
 CloseHandle(HData)
end;

procedure MyDllProc(Reason: integer);
begin
 case Reason of
   DLL_PROCESS_ATTACH: EntryProc;
   DLL_PROCESS_DETACH: ExitProc
 end
end;

procedure WriteData(Source: PData); stdcall;
begin
 DataPtr^ := Source^
end;

function ReadData: PData; stdcall;
begin
 Result := DataPtr
end;

exports
 ReadData name ReadDataProcName,
 WriteData name WriteDataProcName;

begin
 if @DllProc = nil then
   DllProc := MyDllProc;
 MyDllProc(DLL_PROCESS_ATTACH)
end.


3. Код главной формы тестовой программы (на форму бросить 2 кнопки и назначить им OnClick)

uses
 DataType;

var
 Data: TData;
 HLib: THandle = 0;
 ReadData: TReadData = nil;
 WriteData: TWriteData = nil;

procedure TForm1.FormCreate(Sender: TObject);
begin
 HLib := LoadLibrary(DLL_NAME);
 Win32Check(HLib <> 0);
 @ReadData := GetProcAddress(HLib, ReadDataProcName);
 Win32Check(@ReadData <> nil);
 @WriteData := GetProcAddress(HLib, WriteDataProcName);
 Win32Check(@WriteData <> nil);
 Randomize
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 FreeLibrary(HLib)
end;

procedure TForm1.ReadButtonClick(Sender: TObject);
begin
 Data := ReadData^;
 Caption := Format("Прочитано: < %d %s >", [Data.Int, Data.Str])
end;

procedure TForm1.WriteButtonClick(Sender: TObject);
begin
 Data.Int := Random(10);
 if Data.Int > 4 then
   Data.Str := "Привет Богам!"
 else
   Data.Str := "А DLL-то одна!";
 WriteData(@Data);
 Caption := Format("Записано: < %d %s >", [Data.Int, Data.Str])
end;


4. Что с этим делать.

Вначале все компилируем в один каталог (любой). Потом запускаем 2 копии тестовой программы и в обоих жмем кнопки Write и Read. Убеждаемся, что каждая программа читает из MMF точно то, что перед этим в MMF записала либо она сама же, либо другая программа.

PS
И богам своим покажи. Решение они приняли, панимашь... обхохотаться можно над такими решениями.


 
Германн ©   (2009-07-22 02:48) [26]


> Юрий Зотов ©   (22.07.09 02:06) [25]
>
> > Muxa/Ibl4   (21.07.09 22:33) [17]
>
> Лови, я сегодня добрый. И давно на Delphi не писал

Я точно не буду таким добрым. :)


 
Юрий Зотов ©   (2009-07-22 02:49) [27]

Небольшой комментарий. По сути, процедура WriteData не нужна. После загрузки DLL тестовая программа может вызвать функцию ReadData, от нее получить указатель на общую область памяти и запомнить этот указатель - таким образом, она получает прямой доступ к этой общей области и может писать в нее (и читать из нее) что угодно, без всяких посредников.

В таком варианте функцию ReadData правильнее было бы обозвать, например, GetDataAddress, а в тестовой программе вместо переменной Data:TData ввести переменную DataAddress:PData.



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2011.05.29;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.004 c
9-1189349370
Dib@zol
2007-09-09 18:49
2011.05.29
Проблема с текстурами


15-1297671239
Неокубинец
2011-02-14 11:13
2011.05.29
где починиться, в Москве?


15-1297413223
Mephistos
2011-02-11 11:33
2011.05.29
перевод фразы


15-1297379189
Кто б сомневался
2011-02-11 02:06
2011.05.29
Возможно ли технически поймать вирус без браузера


9-1189415446
Help me!
2007-09-10 13:10
2011.05.29
Есть какая-нибудь разница в способе создания MIPMAP?





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