#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;
}

