Конференция "WinAPI" » Последовательный доступ к MMF [D7, XP]
 
  • Muxa/Ibl4 (14.07.09 22:12) [0]
    Уважаемые коллеги, прошу помочь в реализации.

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

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

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

    Как быть? Если кто то швырнет в меня примером библиотечки (желательно с возможность последовательного доступа) - то я буду очень счастливым человеком.
  • Rouse_ © (14.07.09 22:14) [1]

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

    SHARE_ права выставилил при открытии?
  • Loginov Dmitry © (14.07.09 22:29) [2]
    Отсутствует наиболее важное:
    Как пытался получить
  • Юрий Зотов © (14.07.09 22:31) [3]
    Не понял насчет копий DLL. Почему каждый EXE не может загрузить одну и ту же DLL и с ней работать?
  • Muxa/Ibl4 (14.07.09 22:36) [4]
    Долго объяснять но так требуют великие боги.
  • Muxa/Ibl4 (14.07.09 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.

  • Игорь Шевченко © (14.07.09 22:42) [6]
    program files\borland\bds\x.0\demos\DelphiWin32\vclwin32\IPCDemos\*.*
  • Loginov Dmitry © (14.07.09 22:44) [7]
    Это именно говнокод. Все верно.

    Здесь
    http://pda.delphimaster.net/?n=6&id=1247596906
    можно в целях изучения MMF посмотреть, что когда-то предлагали Тейксера и Пачека.
  • Muxa/Ibl4 (14.07.09 23:00) [8]
    спасибо за ссылки, но у меня вопросов пару
    подскажите
    при такой реализации (я про DLL) - я же не могу 1 раз создать mmf и хранить его Handle т.к. в dll это не получиться и мне необходимо каждый раз как то проверять есть ли уже созданный файл или нет. Я прав или неверно мыслю?
  • Muxa/Ibl4 (14.07.09 23:02) [9]
    после записи или чтения в mmf я тоже не могу "закрыть" его. Т.к. при следующем вызове функции мне тогда придется создавать его заново, т.е. потеря данных?
  • Игорь Шевченко © (14.07.09 23:04) [10]

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


    на время загрузки DLL вполне получится. в инициализации DLL создать MMF, дальше пользоваться, при выгрузке освободить
  • Игорь Шевченко © (14.07.09 23:04) [11]
    Muxa/Ibl4   (14.07.09 23:02) [9]

    MMF (и данные в нем) будут жить, пока не закроется последний его Handle
  • Muxa/Ibl4 (14.07.09 23:08) [12]
    но еще один момент, как я и сказал для каждой программы должна быть своя "личная" копия dll, как быть в этом случае?
  • Игорь Шевченко © (14.07.09 23:11) [13]
    Muxa/Ibl4   (14.07.09 23:08) [12]

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

    Я ссылку на Demos не просто так дал, а со смыслом.
  • Muxa/Ibl4 (14.07.09 23:22) [14]
    блин, вроде и понятно, но что то я запутался(
  • Loginov Dmitry © (15.07.09 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 можно сделать процедурой. Возвращаемый ею результат все-равно бесполезен.

    Итого - весь код с нуля нужно переделывать, учесть все замечания всех ответивших в этой ветке.
  • Юрий Зотов © (15.07.09 09:36) [16]
    > Muxa/Ibl4   (14.07.09 22:36) [4]

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

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

    PS
    По коду даже не говорю ничего. Потому что слишком много говорить придется. Документацию на используемые функции надо читать внимательнее.
  • Muxa/Ibl4 (21.07.09 22:33) [17]
    Все сдаюсь, прошу если есть возможность дать пример _dllки_ где есть метод чтения и метод записи MMF
  • Сергей М. © (21.07.09 22:39) [18]

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


    Что, вот прямо так и кричит "не могу" ?
  • Muxa/Ibl4 (21.07.09 22:52) [19]
    я уже согласен на такую реализацию, там конечно есть трудности но на это я забил.
 
Конференция "WinAPI" » Последовательный доступ к MMF [D7, XP]
Есть новые Нет новых   [134433   +24][b:0][p:0.002]