// =====================================================
// Работа с драйвером HIMEM.SYS
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =====================================================
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <string.h>

struct   XMM_Move 
{
  unsigned long  Length;
  unsigned short SourceHandle;
  unsigned long  SourceOffset;
  unsigned short DestHandle;
  unsigned long  DestOffset;
};

extern long XMM_Installed(void);
extern long XMM_Version(void);
extern long XMM_RequestHMA(unsigned);
extern long XMM_ReleaseHMA(void);
extern long XMM_GlobalEnableA20(void);
extern long XMM_GlobalDisableA20(void);
extern long XMM_EnableA20(void);
extern long XMM_DisableA20(void);
extern long XMM_QueryA20(void);
extern long XMM_QueryLargestFree(void);
extern long XMM_QueryTotalFree(void);
extern long XMM_AllocateExtended(unsigned);
extern long XMM_FreeExtended(unsigned);
extern long XMM_MoveExtended(struct XMM_Move *);
extern long XMM_LockExtended(unsigned);
extern long XMM_UnLockExtended(unsigned);
extern long XMM_GetHandleLength(unsigned);
extern long XMM_GetHandleInfo(unsigned);
extern long XMM_ReallocateExtended(unsigned, unsigned);
extern long XMM_RequestUMB(unsigned);
extern long XMM_ReleaseUMB(unsigned);

void error(char *msg, long rc);

int main(void) 
{
  long ver, rc, handle;
  static char testmsg[] = "Тестовое сообщение";
  char buf[80];
  char far *ptr;
  int i;
  struct XMM_Move move_d;

  // Проверяем, установлен ли драйвер HIMEM.SYS,
  // если установлен, выводим его версию
  if (XMM_Installed()) 
  {
    printf("\nHIMEM.SYS installed");
    ver = XMM_Version();
    printf("\nver XMM: %4X,%4x",
      (short)ver, (short)(ver >> 16));
  }

  else 
  {
    printf("\nHIMEM.SYS not found");
    exit(-1);
  }

  // Запрашиваем управление областью HMA
  rc = XMM_RequestHMA(0xffff);
  if(rc) 
    error("Request HMA error",rc);

  else 
  {
    // Открываем линию A20
    rc = XMM_GlobalEnableA20();
    if(rc) 
      error("Open A20 error",rc);

    // Копируем тестовое сообщение сначала из
    // стандартной памяти в область HMA,
    // затем обратно в стандартную память
    FP_SEG(ptr) = 0xffff;
    FP_OFF(ptr) = 0x0010;

    for(i=0; testmsg[i] != 0; i++)
      ptr[i] = testmsg[i];

    for(i=0; ptr[i] != 0; i++)
      buf[i] = ptr[i];
    
    buf[i] = 0;

    // Выводим сообщение для проверки
    printf("\n%s",buf);

    // Закрываем линию A20 и отдаем системе область HMA
    rc = XMM_GlobalDisableA20();
    if(rc) 
      error("Close A20 eror",rc);

    rc = XMM_ReleaseHMA();
    if(rc) 
      error("Free HMA error",rc);
  }

  // Получаем блок EMB размером в 1 Кбайт
  handle = XMM_AllocateExtended(1);
  if(handle < 0) 
    error("Request XMB error",handle);

  // Копируем тестовое сообщение сначала из
  // стандартной памяти в блок EMB,
  // затем обратно в стандартную память
  move_d.Length = strlen(testmsg) + 1;
  move_d.SourceHandle = 0;
  (char far*)move_d.SourceOffset = (char far*)testmsg;
  move_d.DestHandle = (short)handle;
  move_d.DestOffset = 0L;

  rc = XMM_MoveExtended(&move_d);
  if(rc < 0) 
    error("Copy in EMB error",rc);

  move_d.Length = strlen(testmsg) + 1;
  move_d.DestHandle = 0;
  (char far*)move_d.DestOffset = (char far*)buf;
  move_d.SourceHandle = (short)handle;
  move_d.SourceOffset = 0L;

  rc = XMM_MoveExtended(&move_d);
  if(rc < 0) 
    error("Copy from EMB error",rc);

  // Выводим сообщение для проверки
  printf("\n%s",buf);

  // Освобождаем блок EMB
  rc = XMM_FreeExtended((unsigned)handle);
  if(rc) 
    error("Free XMB error",rc);

  return 0;
}

// Функция для вывода сообщения об ошибке
// и кода ошибки
void error(char *msg, long rc) 
{
  rc = (unsigned char)(rc >> 24) ;
    printf("\n%s, error: %02.2X\n",
      msg, (unsigned char)rc);
  exit(-1);
}

