#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <dos.h>

// Прототип функции извещения о том, что Windows
// планирует удалить блок памяти
// Так как функция NotifyProc составлена на языке
// программирования C (а не C++), мы описываем ее
// как extern "C"   
extern "C" BOOL CALLBACK _export NotifyProc(HGLOBAL hglbl);

#pragma argsused
int PASCAL
WinMain(HINSTANCE hInstance,
   HINSTANCE hPrevInstance,
   LPSTR     lpszCmdLine, int nCmdShow)
{
  BYTE szBuf[100];
  HGLOBAL hmemGlDiscard;
  LPVOID  lpvoidGlobal;
  LPVOID  lpvoidGlDiscard;
  DWORD   dwMaxFreeMem;

  // Определяем размер доступной памяти
  dwMaxFreeMem = GlobalCompact(-1l);

  wsprintf(szBuf, "Доступно памяти:\t%lu\n",
        dwMaxFreeMem);
  MessageBox(NULL, (LPSTR)szBuf, "Global Block", MB_OK);

  // Устанавливаем процедуру извещения, которая
  // получит управление при попытке удалить
  // блок памяти 
  GlobalNotify((GNOTIFYPROC)NotifyProc);

  // Заказываем удаляемый блок памяти размером 200000 байт
  // Для включения режима извещения необходимо
  // указать флаг GMEM_NOTIFY
  hmemGlDiscard =
      GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE | GMEM_NOTIFY,
      200000l);

  if(hmemGlDiscard != NULL)
  {
    // Если мы его получили, пытаемся удалить блок
    GlobalDiscard(hmemGlDiscard);

    // Фиксируем блок памяти
    lpvoidGlDiscard = GlobalLock(hmemGlDiscard);

    if(lpvoidGlDiscard != (LPVOID) NULL)
    {
      // Так как наша процедура извещения запрещает
      // удаление блока, попытка его фиксирования
      // должна закончится успешно. В этом случае
      // мы выводим идентификатор блока памяти и его
      // логический адрес
      wsprintf(szBuf, "hmemGlDiscard=\t%04.4X\n"
        "lpvoidGlDiscard=\t%04.4X:%04.4X",
        hmemGlDiscard,
        FP_SEG(lpvoidGlDiscard), FP_OFF(lpvoidGlDiscard));
      MessageBox(NULL, (LPSTR)szBuf, "Global Block", MB_OK);

      // Разрешаем перемещение блока
      GlobalUnlock(hmemGlDiscard);
    }
    else
    {
      // Если блок памяти не удалось зафиксировать,
      // проверяем, не был ли он удален
      if(GlobalFlags(hmemGlDiscard) & GMEM_DISCARDED)
      {
         // Так как мы запретили удаление блока, следующее
         // сообщение не должно появиться на экране
         MessageBox(NULL, "Блок удален и мы его восстанавливаем",
           "Global Block", MB_OK);

         // Восстанавливаем удаленный блок памяти
         hmemGlDiscard = GlobalReAlloc(hmemGlDiscard, 200000l,
           GMEM_MOVEABLE | GMEM_DISCARDABLE);

         // Фиксируем блок памяти
         lpvoidGlDiscard = GlobalLock(hmemGlDiscard);

         if(lpvoidGlDiscard != (LPVOID) NULL)
         {
           // Выводим идентификатор и логический адрес
           // зафиксированного блока памяти
           wsprintf(szBuf, "hmemGlDiscard=\t%04.4X\n"
             "lpvoidGlDiscard=\t%04.4X:%04.4X",
             hmemGlDiscard,
             FP_SEG(lpvoidGlDiscard), FP_OFF(lpvoidGlDiscard));
           MessageBox(NULL, (LPSTR)szBuf, "Global Block", MB_OK);

           // Освобождаем блок памяти
           GlobalUnlock(hmemGlDiscard);
         }
         else
         {
           MessageBox(NULL, "Ошибка при фиксировании блока",
           "Global Block", MB_OK);
         }
      }
    }

    // Отдаем удаляемый блок памяти операционной системе
    GlobalFree(hmemGlDiscard);
  }
  else
  {
    MessageBox(NULL, "Мало памяти для удаляемого блока",
      "Global Block", MB_OK);
  }
  return 0;
}