Программирование для Windows NT (том 2)

       

Приложение Fmap/Server


Для иллюстрации методики обмена данными мжеду различными процессами с использованием файлов, отображаемых на память, мы подготовили исходные тексты двух консольных приложений: Fmap/Server и Fmap/Client. Эти приложения работают в паре (рис. 2.1).

Рис. 2.1. Взаимодействие консольных приложений Fmap/Server и Fmap/Client

Приложение Fmap/Server создает отображение и два объекта-события. Первый объект предназначен для работы с клавиатурой, второй - для обнаружения момента завершения приложения Fmap/Client. Объекты-события были описаны нами в предыдущем томе “Библиотеки системного программиста”, посвященном программированию для операционной системы Microsoft Windows NT.

Приложение Fmap/Client открывает созданное отображение и объекты-события, а затем в цикле вводит символы с клавиатуры, переключая один из объектов-событий в отмеченное состояние при вводе каждого символа. Коды введенных символов записываются в отображенную память.

По мере того как пользователь вводит символы в окне приложения Fmap/Client, приложение Fmap/Server отображает их в своем окне, получая коды введенных символов из отображенной памяти. Для синхронизации используется объект-событие, выделенное для работы с клавиатурой.

Если пользователь нажимает клавишу <Esc> в окне приложения Fmap/Client, это приложение отмечает оба события и завершает свою работу. Приложение Fmap/Server, обнаружив, что второй объект-событие оказался в отмеченном состоянии, также завершает свою работу. Таким образом, если завершить работу приложения Fmap/Client, то приложение Fmap/Server также будет завершено.

Исходный текст приложения Fmap/Server представлен в листинге 2.1.

Листинг 2.1. Файл fmap/server/server.c

#include <windows.h>

#include <stdio.h>

#include <conio.h>

// Идентификаторы объектов-событий, которые используются

// для синхронизации задач, принадлежащих разным процессам

HANDLE hEventChar;

HANDLE hEventTermination;

HANDLE hEvents[2];

// Имя объекта-события для синхронизации ввода и отображения


CHAR lpEventName[] =

  "$MyVerySpecialEventName$";

// Имя объекта-события для завершения процесса

CHAR lpEventTerminationName[] =

  "$MyVerySpecialEventTerminationName$";

// Имя отображния файла на память

CHAR lpFileShareName[] =

  "$MyVerySpecialFileShareName$";

// Идентификатор отображения файла на память

HANDLE hFileMapping;

// Указатель на отображенную область памяти

LPVOID lpFileMap;

int main()

{

  DWORD dwRetCode;

  printf(" Mapped and shared file, server process\n"

    "(C) A. Frolov, 1996, Email: frolov@glas.apc.org\n");

 

  // Создаем объект-событие для синхронизации

  // ввода и отображения, выполняемого в разных процессах

  hEventChar = CreateEvent(NULL, FALSE, FALSE, lpEventName);

 

  // Если произошла ошибка, получаем и отображаем ее код,

  // а затем завершаем работу приложения

  if(hEventChar == NULL)

  {

    fprintf(stdout,"CreateEvent: Error %ld\n",

      GetLastError());

    getch();

    return 0;

  }

  // Если объект-событие с указанным именем существует,

  // считаем, что приложение EVENT уже было запущено

  if(GetLastError() == ERROR_ALREADY_EXISTS)

  {

    printf("\nApplication EVENT already started\n"

      "Press any key to exit...");

    getch();

    return 0;

  }

  // Создаем объект-событие для определения момента

  // завершения работы процесса ввода

  hEventTermination = CreateEvent(NULL,

    FALSE, FALSE, lpEventTerminationName);

  if(hEventTermination == NULL)

  {

    fprintf(stdout,"CreateEvent (Termination): Error %ld\n",

      GetLastError());

    getch();

    return 0;

  }

 

  // Создаем объект-отображение

  hFileMapping = CreateFileMapping((HANDLE)0xFFFFFFFF,

    NULL, PAGE_READWRITE, 0, 100, lpFileShareName);

  // Если создать не удалось, выводим код ошибки

  if(hFileMapping == NULL)

  {

    fprintf(stdout,"CreateFileMapping: Error %ld\n",



      GetLastError());

    getch();

    return 0;

  }

  // Выполняем отображение файла на память.

  // В переменную lpFileMap будет записан указатель на

  // отображаемую область памяти

  lpFileMap = MapViewOfFile(hFileMapping,

    FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);

  // Если выполнить отображение не удалось,

  // выводим код ошибки

  if(lpFileMap == 0)

  {

    fprintf(stdout,"MapViewOfFile: Error %ld\n",

      GetLastError());

    getch();

    return 0;

  }

 

  // Готовим массив идентификаторов событий

  // для функции WaitForMultipleObjects

  hEvents[0] = hEventTermination;

  hEvents[1] = hEventChar;

 

  // Цикл отображения. Этот цикл завершает свою работу

  // при завершении процесса ввода

  while(TRUE)

  {

    // Выполняем ожидание одного из двух событий:

    //   - завершение клиентского процесса;

    //   - завершение ввода символа

    dwRetCode = WaitForMultipleObjects(2,

      hEvents, FALSE, INFINITE);

    // Если ожидание любого из двух событий было отменено,

    // если произошло первое событие (завершение клиентского

    // процесса) или если произошла ошибка, прерываем цикл

    if(dwRetCode == WAIT_ABANDONED_0    

       dwRetCode == WAIT_ABANDONED_0 + 1

       dwRetCode == WAIT_OBJECT_0       

       dwRetCode == WAIT_FAILED)

      break;

    // Читаем символ из первого байта отображенной

    // области памяти, записанный туда клиентским

    // процессом, и отображаем его в консольном окне

    putch(*((LPSTR)lpFileMap));

  }

 

  // Закрываем идентификаторы объектов-событий 

  CloseHandle(hEventChar);

  CloseHandle(hEventTermination);

  // Отменяем отображение файла

  UnmapViewOfFile(lpFileMap);

  // Освобождаем идентификатор созданного

  // объекта-отображения

  CloseHandle(hFileMapping);

  return 0;

}

В глобальных переменных hEventChar и hEventTermination хранятся идентификаторы объектов-событий, предназначенных, соответственно, для работы с клавиатурой и для фиксации момента завершения работы приложения Fmap/Client. Эти же идентификаторы записываются в глобальный массив hEvents, который используется функцией WaitForMultipleObjects.



Глобальные имена объектов-событий хранятся в переменных lpEventName и lpEventTerminationName.

Имя отображения записывается в массив lpFileShareName, а идентификатор этого отображения - в глобальную переменную hFileMapping.

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

Функция main приложения Fmap/Server создает два объекта-события, пользуясь для этого функцией CreateEvent. Описание этой функции вы найдете в предыдущем томе “Библиотеки системного программиста”.

Далее функция main создает объект-отображение и выполняет отображение, вызывая для этого, соответственно, функции CreateFileMapping и MapViewOfFile. Так как в качестве идентификатора файла функции CreateFileMapping передается значение (HANDLE)0xFFFFFFFF, отображение будет создано непосредственно в виртуальной памяти без использования файла, расположенного на диске.

После инициализации массива hEvents функция main запускает цикл, в котором выполняется ожидание событий и вывод символов, записанных приложением Fmap/Client в отображенную область виртуальной памяти.

Для ожидания двух событий используется функция WaitForMultipleObjects. Через третий параметр этой функции передается значение FALSE, поэтому ожидание прекращается в том случае, если любое из событий переходит в отмеченное состояние.

В том случае, когда в отмеченное состояние перешел объект-событие hEventTermination, функция WaitForMultipleObjects возвращает значение WAIT_OBJECT_0. Обнаружив это, функция main завершает свою работу, потому что событие hEventTermination отмечается при завершении работы клиентского приложения Fmap/Client.

Если же в отмеченное состояние переходит объект-событие hEventChar, функция WaitForMultipleObjects возвращает значение WAIT_OBJECT_0 + 1. В этом случае функция main читает первый байт из отображенной области памяти и выводит его в консольное окно при помощи хорошо знакомой вам из программирования для MS-DOS функции putch:

putch(*((LPSTR)lpFileMap));

Перед своим завершением функция main закрывает идентификаторы объектов-событий, отменяет отображение и освобождает идентификатор этого отображения.


Содержание раздела