Шаг 75.
Совместное использование памяти разными процессами

    На этом шаге мы приведем пример использования динамически подключаемой библиотеки различными процессами.

    Рассмотрим теперь вопрос о том, как используют динамическую библиотеку различные экземпляры приложения или разные процессы. Если вы немного знакомы с принципом функционирования операционной системы Windows, то, возможно, такая постановка вопроса у вас вызовет недоумение. "У каждого приложения свое адресное пространство, куда загружается DLL", - скажете вы. Конечно, это не совсем рационально, но зато безопасно. О памяти мы еще подробно будем говорить, здесь же заметим, что, вообще говоря, приложение может инициализировать так называемую разделяемую память. Мы вернемся к этому вопросу еще неоднократно, сейчас же рассмотрим этот вопрос чисто технически, применительно к DLL. Рассмотрим конкретную ситуацию. Запускаемое приложение загружает динамически подключаемую библиотеку и вызывает процедуру из DLL, которая меняет данные, расположенные опять же в динамически подключаемой библиотеке. Запустим теперь второй экземпляр приложения. Оно загружает еще один экземпляр DLL. Могут быть ситуации, когда желательно, чтобы второе запущенное приложение "знало", что по команде первого приложения данные уже изменились. Ясно, что в этом случае данные, которыми оперирует DLL, должны быть общими. Технически это делается очень просто. У редактора свзей LINK eсть опция /section: имя, атрибуты, которая позволяет объявить явно свойства данной секции. Мы будем говорить о секциях далее, здесь же достаточно сказать, секция - это просто сегмент в старом понимании. В редакторе связей TLINK32 то же действие можно осуществить с помощью DEF-файла.

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

    Файл pr75_1.asm - динамически подключаемая библиотека.

.386P
;Плоская модель.
IFDEF MASM
.MODEL FLAT, STDCALL
ELSE
.MODEL FLAT
ENDIF
PUBLIC DLLP1
IFDEF MASM
;MASM
;Прототипы внешних процедур.
    EXTERN  MessageBoxA@16: NEAR
;Директивы компоновщику для подключения библиотек.
;Для компоновщика  LINK.EXE.
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
ELSE
;TASM
    EXTERN  MessageBoxA@: NEAR
    MessageBoxA@16 = MessageBoxA
;Для компоновщика  TLINK32.EXE.
    includelib c:\tasm32\lib\import32.lib
ENDIF
;------------------------------------------------
;Сегмент данных. 
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
     TEXT   DB   'В  динамической библиотеке',0
     MS     DB   'Сообщение',0
_DATA ENDS 
;Сегмент кода.
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
; [EBP+10H] - Резервный параметр.
; [ЕВР+0СН] - Причина вызова.
; [ЕВР+8]   - Идентификатор DLL-модуля.
DLLENTRY:
     MOV  EAX,1
     RET  12
;-------------------------------------
;Адреса параметров
; [EBP+8]	
; [ЕВР+0СН]	
DLLP1 PROC EXPORT
      PUSH EBP
      MOV  EBP,ESP
      PUSH 0
      PUSH OFFSET MS
      PUSH OFFSET TEXT
      PUSH 0
      CALL MessageBoxA@16 
;Изменим строку, расположенную в разделяемой памяти.
      MOV  TEXT,'И'
      MOV  TEXT+1,'з'
      MOV  TEXT+25,'и'
      POP  EBP
      RET
DLLP1 ENDP 
_TEXT ENDS 
      END DLLENTRY

    Файл pr75_2.asm - основной модуль, вызывающий процедуру из DLL.

.386P
;Плоская модель.
.MODEL FLAT, STDCALL
;Константы.
;Прототипы внешних процедур.
IFDEF MASM
;MASM
     EXTERN  GetProcAddress@8:NEAR
     EXTERN  LoadLibraryA@4:NEAR
     EXTERN  FreeLibrary@4:NEAR
     EXTERN  ExitProcess@4:NEAR
     EXTERN  MessageBoxA@16:NEAR
;Директивы компоновщику для подключения библиотек.
;Для компоновщика  LINK.EXE.
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
ELSE
;TASM
     EXTERN  GetProcAddress:NEAR
     EXTERN  LoadLibraryA:NEAR
     EXTERN  FreeLibrary:NEAR
     EXTERN  ExitProcess:NEAR
     EXTERN  MessageBoxA:NEAR
     GetProcAddress@8 = GetProcAddress
     LoadLibraryA@4   = LoadLibraryA
     FreeLibrary@4    = FreeLibrary
     ExitProcess@4    = ExitProcess
     MessageBoxA@16   = MessageBoxA
;Для компоновщика  TLINK32.EXE.
    includelib c:\tasm32\lib\import32.lib
ENDIF
;------------------------------------------------
;Сегмент данных. 
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
     TXT  DB   'Ошибка динамической библиотеки',0
     MS   DB   'Сообщение',0
     LIBR DB   'pr75_1.DLL',0
     HLIB DD   ?
IFDEF MASM	
     NAMEPROC  DB   '_DLLP1@0',0
ELSE	
     NAMEPROC  DB   'DLLP1',0
ENDIF	
_DATA ENDS 
;Сегмент кода.
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
; [EBP+10H] - Резервный параметр.
; [ЕВР+0СН] - Причина вызова.
; [ЕВР+8]   - Идентификатор DLL-модуля.
START:	
;Загрузить  библиотеку.
      PUSH  OFFSET  LIBR
      CALL  LoadLibraryA@4
      CMP   EAX,0
      JE    _ERR
      MOV   HLIB,EAX
;Получить адрес процедуры.
      PUSH  OFFSET  NAMEPROC
      PUSH  HLIB
      CALL  GetProcAddress@8
      CMP   EAX,0
      JNE   YES_NAME
;Сообщение об ошибке.
_ERR:	
      PUSH  0
      PUSH  OFFSET MS
      PUSH  OFFSET TXT
      PUSH  0
      CALL  MessageBoxA@16
      JMP   _EXIT
YES_NAME:	
      CALL  EAX
      PUSH  0
      PUSH  OFFSET MS
      PUSH  OFFSET MS
      PUSH  0
      CALL MessageBoxA@16 
;Закрыть библиотеку.
;Библиотека автоматически закрывается также 
;при выходе из программы. 
      PUSH  OFFSET  NAMEPROC
      PUSH  HLIB
      CALL  FreeLibrary@4
;Выход. 
_EXIT:
      PUSH  0
      CALL  ExitProcess@4 
_TEXT ENDS 
      END START
Тексты этих файлов можно взять здесь.

    Результат работы приложения изображен на рисунке 1:


Рис.1. Результат работы приложения

    Трансляция динамической библиотеки:

    Трансляция программы:

    Со следующего шага мы начнем рассматривать взаимодействие с ресурсами локальной сети.




Предыдущий шаг Содержание Следующий шаг