#define STRICT
#include <windows.h>
#include <commdlg.h>
#include <mem.h>
#include <string.h>
#include <stdlib.h>

#include "toolbar.hpp"
#include "smartpad.hpp"

// ======================================================
// Прототипы функций
// ======================================================

BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

BOOL CALLBACK _export
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK _export
EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

HFILE OpenFile(void);
HFILE OpenSaveFile(void);
int SaveFileAs(HWND hwnd);
int SaveFile(HWND hwnd);
int SelectFile(HWND hwnd);

// ======================================================
// Глобальные переменные
// ======================================================

// Имя класса окна
char const szClassName[]   = "SmartPadAppClass";

// Заголовок окна
char const szWindowTitle[] = "Smart Pad";

// Глобальная переменная для хранения идентификатора
// текущей копии приложения
HINSTANCE hInst;

// Указатель на объект органа управления TOOLBAR
Toolbar *Tb;

// Переменные для хранения идентификаторов меню
HMENU hmenuAppMenu;
HMENU hmenuSystemMenu;

// Идентификатор таблицы акселераторов
HACCEL haccel;

// Идентификатор редактора текста
HWND hEdit;

// Признак внесения изменений в текст 
BOOL bNeedSave;

// Путь к редактируемому файлу
char szCurrentFileName[128];

// Временный буфер
char szTempBuffer[128];

// Признак запрета редактирования
BOOL bReadOnly = FALSE;

// Идентификаторы файлов
HFILE hfSrcFile, hfDstFile;

// Переменные для хранения адресов функций
DLGPROC lpfnDlgProc;
WNDPROC lpfnEditOldWndProc;
WNDPROC lpfnEditWndProc;

// Идентификатор главного окна
HWND    hwndMain;


// ======================================================
// Функция WinMain
// ======================================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance, 
	HINSTANCE hPrevInstance,
	LPSTR     lpszCmdLine, 
	int       nCmdShow)   
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  // Сохраняем идентификатор текущей копии приложения
  hInst = hInstance;

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  // Загружаем основное меню приложения
  hmenuAppMenu = LoadMenu(hInstance, "APP_MENU");

  // После успешной инициализации приложения создаем
  // главное окно приложения
  hwnd = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // задаем размеры и расположение
    CW_USEDEFAULT,       // окна, принятые по умолчанию 
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    0,                   // идентификатор родительского окна
    hmenuAppMenu,        // идентификатор меню
    hInstance,           // идентификатор приложения
    NULL);               // указатель на дополнительные
			 // параметры
  // Если создать окно не удалось, завершаем приложение
  if(!hwnd)
    return FALSE;

  // Сохраняем идентификатор главного окна в
  // глобальной переменной
  hwndMain = hwnd;

  // Рисуем главное окно
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  // Создаем орган управления TOOLBAR
  Tb = new Toolbar(hInstance, hwnd, TB_FIRST);

  // Создаем кнопки в органе управления TOOLBAR
  Tb->InsertButton(0,
     MAKEINTRESOURCE(IDB_NEWUP),
     MAKEINTRESOURCE(IDB_NEWDOWN), MAKEINTRESOURCE(IDB_NEWUP));
  
  Tb->InsertButton(1,
     MAKEINTRESOURCE(IDB_OPENUP),
     MAKEINTRESOURCE(IDB_OPENDOWN), MAKEINTRESOURCE(IDB_OPENGR));

  Tb->InsertButton(2,
     MAKEINTRESOURCE(IDB_SAVEUP),
     MAKEINTRESOURCE(IDB_SAVEDOWN), MAKEINTRESOURCE(IDB_SAVEGR));

  Tb->InsertButton(4,
     MAKEINTRESOURCE(IDB_CUTUP),
     MAKEINTRESOURCE(IDB_CUTDOWN), MAKEINTRESOURCE(IDB_CUTGR));

  Tb->InsertButton(5,
     MAKEINTRESOURCE(IDB_COPYUP),
     MAKEINTRESOURCE(IDB_COPYDOWN), MAKEINTRESOURCE(IDB_COPYGR));

  Tb->InsertButton(6,
     MAKEINTRESOURCE(IDB_PASTUP),
     MAKEINTRESOURCE(IDB_PASTDOWN), MAKEINTRESOURCE(IDB_PASTGR));

  Tb->InsertButton(7,
     MAKEINTRESOURCE(IDB_UNDOUP),
     MAKEINTRESOURCE(IDB_UNDODOWN), MAKEINTRESOURCE(IDB_UNDOGR));

  Tb->InsertButton(9,
     MAKEINTRESOURCE(IDB_EXITUP),
     MAKEINTRESOURCE(IDB_EXITDOWN), MAKEINTRESOURCE(IDB_EXITGR));

  Tb->InsertButton(10,
     MAKEINTRESOURCE(IDB_HELPUP),
     MAKEINTRESOURCE(IDB_HELPDOWN), MAKEINTRESOURCE(IDB_HELPGR));

  // Загружаем таблицу акселераторов
  haccel = LoadAccelerators(hInstance, "APP_ACCELERATORS");

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    if(!haccel || !TranslateAccelerator(hwnd, haccel, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }
  return msg.wParam;
}

// ======================================================
// Функция InitApp
// Выполняет регистрацию класса окна
// ======================================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации класса окна

  // Записываем во все поля структуры нулевые значения
  memset(&wc, 0, sizeof(wc));

  wc.lpszMenuName  = NULL;
  wc.style         = 0;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(hInstance, "APPICON");
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszClassName = (LPSTR)szClassName;

  // Регистрация класса
  aWndClass = RegisterClass(&wc);
  return (aWndClass != 0);
}

// ======================================================
// Новая функция окна для редактора текста
// ======================================================

LRESULT CALLBACK _export
EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Если в окне редактора текста пользователь нажал
  // правую клавишу мыши, выводим в позиции курсора мыши
  // плавающее меню
  if(msg == WM_RBUTTONDOWN)
  {
    HMENU hmenuPopup;
    POINT pt;

    // Перобразуем координаты курсора мыши в экранные
    pt = MAKEPOINT(lParam);
    ClientToScreen(hwnd, &pt);

    // Создаем пустое временное меню
    hmenuPopup = CreatePopupMenu();

    // Заполняем временное меню
    AppendMenu(hmenuPopup, MF_BYCOMMAND | MF_ENABLED,
         CM_FILENEW, "&New");
    AppendMenu(hmenuPopup, MF_BYCOMMAND | MF_ENABLED,
         CM_FILEOPEN, "&Open");
    AppendMenu(hmenuPopup, MF_BYCOMMAND | MF_ENABLED,
         CM_FILESAVE, "&Save");
    AppendMenu(hmenuPopup, MF_SEPARATOR, 0, 0);
    AppendMenu(hmenuPopup, MF_BYCOMMAND | MF_ENABLED,
         CM_FILEEXIT, "E&xit");

    // Выводим плавающее меню в позиции курсора мыши
    TrackPopupMenu(hmenuPopup,
      TPM_CENTERALIGN | TPM_LEFTBUTTON,
      pt.x, pt.y, 0, hwndMain, NULL);

    // Удаляем временное меню
    DestroyMenu(hmenuPopup);
  }
  // Вызываем старую функцию окна редактора текста
  return CallWindowProc(lpfnEditOldWndProc,
     hwnd, msg, wParam, lParam);
}

// ======================================================
// Функция главного окна приложения WndProc
// ======================================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HFONT hfont;

  switch (msg)
  {
    case WM_CREATE:
    {
      // Создаем редактор текста
      hEdit = CreateWindow("edit", NULL,
	 WS_CHILD | WS_VISIBLE | WS_BORDER |
         WS_HSCROLL | WS_VSCROLL |
	 ES_LEFT | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
	 ES_MULTILINE,
	 0, 30, 100, 100,
	 hwnd, (HMENU) ID_EDIT, hInst, NULL);

      // Задаем для редактора текста шрифт с
      // переменной шириной символов
      hfont = GetStockFont(ANSI_VAR_FONT);
      SendMessage(hEdit, WM_SETFONT, (WPARAM)hfont,
        (LPARAM)MAKELONG((WORD)TRUE, 0));

      // Создаем переходник для новой функции окна редактора текста
      lpfnEditWndProc =
         (WNDPROC)MakeProcInstance((FARPROC)EditWndProc, hInst);
       
      // Определяем адрес старой функции окна редактора текста
      lpfnEditOldWndProc = (WNDPROC)GetWindowLong(hEdit, GWL_WNDPROC);

      // Подключаем к редактору текста новую функцию окна
      SetWindowLong(hEdit, GWL_WNDPROC, (LONG)lpfnEditWndProc);

      // Устанавливаем максимальную длину
      // редактируемого текста, равную 32000 байт
      SendMessage(hEdit, EM_LIMITTEXT, 32000, 0L);

      // Сбрасываем флаг обновления текста и флаг
      // запрета редактирования
      bNeedSave = FALSE;
      bReadOnly = FALSE;

      // Так как редактируемый файл не открывался и не сохранялся,
      // в переменную пути к нему записываем пустую строку
      lstrcpy(szCurrentFileName, "");

      // Устанавливаем заголовок окна приложения
      SetWindowText(hwnd, "SmartPad - [UNTITLED]");

      // Определяем идентификатор системного меню
      hmenuSystemMenu = GetSystemMenu(hwnd, FALSE);

      // Добавляем в системное меню разделительную линию
      // и строку "About"
      AppendMenu(hmenuSystemMenu, MF_SEPARATOR, 0, 0);
      AppendMenu(hmenuSystemMenu, MF_BYCOMMAND | MF_ENABLED,
         CM_SYSABOUT, "&About...");

      // Блокируем в системном меню строку "Close"
      EnableMenuItem(hmenuSystemMenu, SC_CLOSE,
        MF_BYCOMMAND | MF_GRAYED);

      return 0;
    }

    case WM_SIZE:
    {
      // Устанавливаем новую ширину дочернего окна
      // орагна управления TOOLBAR
      Tb->SetWidth(LOWORD(lParam));

      // Устанавливаем размер органа управления
      // (текстового редактора) в соотвестствии
      // с размерами главного окна приложения
      MoveWindow(hEdit, 0, 26, LOWORD(lParam),
	HIWORD(lParam) - 26, TRUE);

      return 0;
    }

    // Когда главное окно приложения получает
    // фокус ввода, отдаем фокус редактору текста
    case WM_SETFOCUS:
    {
      SetFocus(hEdit);
      return 0;
    }

    // Это сообщение приходит от системного меню
    case WM_SYSCOMMAND:
    {
      // Необходимо замаскировать четыре младших бита
      // параметра wParam
      if((wParam & 0xfff0) == CM_SYSABOUT)
      {
        // Переходник для функции диалоговой панели
        lpfnDlgProc = (DLGPROC)MakeProcInstance((FARPROC)DlgProc, hInst);

        // Создаем модальную диалоговую панель
        DialogBox(hInst, "ABOUT", hwnd, lpfnDlgProc);
        return 0;
      }

      // Блокируем строку "Close". Эта строка не является
      // обязательной, так как мы уже заблокировали эту
      // строку функцией EnableMenuItem
      else if((wParam & 0xfff0) == SC_CLOSE)
        return 0;
      break;
    }

    // Сообщение от меню и орагна управления TOOLBAR
    case WM_COMMAND:
    {
       switch(wParam)
       {
         // Обработка извещений текстового редактора
         case ID_EDIT:
         {
           // Ошибка
           if(HIWORD(lParam) == EN_ERRSPACE)
	   {
	     MessageBox(hwnd, "Мало памяти",
	       szWindowTitle, MB_OK);
	   }

	   // Произошло изменение в редактируемом
           // тексте
	   else if(HIWORD(lParam) == EN_UPDATE)
	   {
             // Устанавливаем флаг обновления текста
             bNeedSave = TRUE;
           }
           return 0;
         }

         // Эти строки меню пока заблокированы, так как
         // соответствующие функции не реализованы
         case CM_HELPUSING_HELP:
         case CM_HELPPROCEDURES:
         case CM_HELPCOMMANDS:
         case CM_HELPKEYBOARD:
         case CM_HELPINDEX:
         case CM_FILEPRINTER_SETUP:
         case CM_FILEPAGE_SETUP:
         case CM_FILEPRINT:
         {
	   MessageBox(hwnd, "В текущей версии "
                "редактора SmartPad данная функция не реализована",
                NULL, MB_OK);
           return 0;
         }

         // На запрос подсказки выводим диалоговую панель
         // с информацией о программе
         case TB_HELP:
         case CM_HELPABOUT:
         {
           // Переходник для функции диалоговой панели
           lpfnDlgProc = (DLGPROC)MakeProcInstance((FARPROC)DlgProc, hInst);

           // Создаем модальную диалоговую панель
           DialogBox(hInst, "ABOUT", hwnd, lpfnDlgProc);

           // Ликвидируем переходник
           FreeProcInstance((FARPROC) lpfnDlgProc);

           return 0;
         }

         // Переключение режима запрета редактирования
         case CM_EDITSETREADONLY:
         {
           // Если режим запрета редактирования выключен,
           // включаем его 
           if(!bReadOnly)
           {
             // Запрещаем редактирование
             SendMessage(hEdit, EM_SETREADONLY, TRUE, 0L);

             // Отмечаем соответствующую строку в меню
             CheckMenuItem(hmenuAppMenu, CM_EDITSETREADONLY,
               MF_BYCOMMAND | MF_CHECKED);

             // Устанавливаем флаг запрета редактирования
             bReadOnly = TRUE;
           }
           // Если режим запрета редактирования включен,
           // выключаем его 
           else
           {
             SendMessage(hEdit, EM_SETREADONLY, FALSE, 0L);
             CheckMenuItem(hmenuAppMenu, CM_EDITSETREADONLY,
               MF_BYCOMMAND | MF_UNCHECKED);
             bReadOnly = FALSE;
           }

           // Устанавливаем фокус ввода на редактор текста
           SetFocus(hEdit);
           return 0;
         }

         case CM_EDITPASTE:
         case TB_PAST:
         {
           SendMessage(hEdit, WM_PASTE, 0, 0L);
           SetFocus(hEdit);
           return 0;
         }

         case CM_EDITCOPY:
         case TB_COPY:
         {
           SendMessage(hEdit, WM_COPY, 0, 0L);
           SetFocus(hEdit);
           return 0;
         }

         case CM_EDITCUT:
         case TB_CUT:
         {
           SendMessage(hEdit, WM_CUT, 0, 0L);
           SetFocus(hEdit);
           return 0;
         }

         case CM_EDITCLEAR:
         {
           SendMessage(hEdit, WM_CLEAR, 0, 0L);
           SetFocus(hEdit);
           return 0;
         }

         case CM_EDITSELALL:
         {
           SendMessage(hEdit, EM_SETSEL, 0, MAKELPARAM(0, -1));
           SetFocus(hEdit);
           return 0;
         }

         case CM_EDITUNDO:
         case TB_UNDO:
         {
           SendMessage(hEdit, EM_UNDO, 0, 0L);
           SetFocus(hEdit);
           return 0;
         }

         // Завершаем работу приложения
         case TB_EXIT:
         case CM_FILEEXIT:
         {
           // Проверяем флаг обновления
           if(bNeedSave)
           {
             // Если в тексте были изменения,
             // спрашиваем у пользователя, надо ли
             // созранять текст в файле
	     if(IDYES == MessageBox(hwnd,
	         "Файл был изменен. Желаете сохранить?",
	          szWindowTitle, MB_YESNO | MB_ICONQUESTION))
             {
               // Если файл ни разу не сохранялся,
               // спрашиваем путь и имя нового файла
               if(szCurrentFileName[0] == '\0')
               {
                 SaveFileAs(hwnd);

                 // Изменяем заголовок главного окна приложения
                 // в соответствии с именем и путем к файлу 
                 wsprintf(szTempBuffer, "SmartPad - [%s]",
                    (LPSTR)szCurrentFileName);
                 SetWindowText(hwnd, szTempBuffer);
               }

               // Если файл уже сохранялся, записываем его
               // на прежнее место
               else
                 SaveFile(hwnd);
               }
             }

           // Завершаем работу приложения
           DestroyWindow(hwnd);
           return 0;
         }

         case CM_FILENEW:
         case TB_NEW:
         {
           // Проверяем флаг обновления
           if(bNeedSave)
           {
	     if(IDYES == MessageBox(hwnd,
	         "Файл был изменен. Желаете сохранить?",
	          szWindowTitle, MB_YESNO | MB_ICONQUESTION))
             {
               if(szCurrentFileName[0] == '\0')
               {
                 SaveFileAs(hwnd);
                 wsprintf(szTempBuffer, "SmartPad - [%s]",
                   (LPSTR)szCurrentFileName);
                 SetWindowText(hwnd, szTempBuffer);
               }
               else
                 SaveFile(hwnd);
             }
           }

           // Сбрасываем содержимое текстового редактора
	   SetWindowText(hEdit, "\0");

           bNeedSave = FALSE;

           lstrcpy(szCurrentFileName, "");
           SetWindowText(hwnd, "SmartPad - [UNTITLED]");

           SetFocus(hEdit);
           return 0;
         }

         case CM_FILEOPEN:
         case TB_OPEN:
         {
           // Проверяем флаг обновления
           if(bNeedSave)
           {
	     if(IDYES == MessageBox(hwnd,
	         "Файл был изменен. Желаете сохранить?",
	          szWindowTitle, MB_YESNO | MB_ICONQUESTION))
             SaveFile(hwnd);
           }


           if(!SelectFile(hwnd))
           {
             lstrcpy(szCurrentFileName, "");
             SetWindowText(hwnd, "SmartPad - [UNTITLED]");
           }
           else
           {
             wsprintf(szTempBuffer, "SmartPad - [%s]",
               (LPSTR)szCurrentFileName);
             SetWindowText(hwnd, szTempBuffer);
           }

           return 0;
         }

         case CM_FILESAVEAS:
         {
           if(SaveFileAs(hwnd))
           {
             wsprintf(szTempBuffer, "SmartPad - [%s]",
               (LPSTR)szCurrentFileName);
             SetWindowText(hwnd, szTempBuffer);
           }
           else
           {
             lstrcpy(szCurrentFileName, "");
             SetWindowText(hwnd, "SmartPad - [UNTITLED]");
           }
           return 0;
         }

         case CM_FILESAVE:
         case TB_SAVE:
         {
           if(szCurrentFileName[0] == '\0')
           {
             if(SaveFileAs(hwnd))
             {
               wsprintf(szTempBuffer, "SmartPad - [%s]",
                 (LPSTR)szCurrentFileName);
               SetWindowText(hwnd, szTempBuffer);
             }
             else
             {
               lstrcpy(szCurrentFileName, "");
               SetWindowText(hwnd, "SmartPad - [UNTITLED]");
             }
           }
           else
             SaveFile(hwnd);
           return 0;
         }

         default:
           break;
       }
       break;
    }

    // Это сообщение приходит при завершении работы
    // операционной системы Windows. Если мы не сохранили
    // редактируемый текст, спрашиваем у пользователя,
    // надо ли это делать
    case WM_QUERYENDSESSION:
    {
      // Проверяем флаг обновления
      if(bNeedSave)
      {
        if(IDYES == MessageBox(hwnd,
	    "Файл был изменен. Желаете сохранить?",
	     szWindowTitle, MB_YESNO | MB_ICONQUESTION))
        {
           if(szCurrentFileName[0] == '\0')
           {
              SaveFileAs(hwnd);
              wsprintf(szTempBuffer, "SmartPad - [%s]",
                (LPSTR)szCurrentFileName);
              SetWindowText(hwnd, szTempBuffer);
           }
           else
              SaveFile(hwnd);
        }
      }

      // Разрешаем операционной системе Windows
      // завершить свою работу
      return 1L;
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// ======================================================
// Функция OpenFile
// Сохранение файла
// ======================================================

HFILE OpenFile(void)
{
  // Структура для выбора файла
  OPENFILENAME ofn;

  // Буфер для записи пути к выбранному файлу
  char szFile[256];

  // Буфер для записи имени выбранного файла
  char szFileTitle[256];

  // Фильтр расширений имени файлов
  char szFilter[256] =
	 "Text Files\0*.txt;*.doc\0Any Files\0*.*\0";

  // Идентификатор открываемого файла
  HFILE hf;

  // Инициализация имени выбираемого файла
  // не нужна, поэтому создаем пустую строку
  szFile[0] = '\0';

  // Записываем нулевые значения во все поля
  // структуры, которая будет использована для
  // выбора файла
  memset(&ofn, 0, sizeof(OPENFILENAME));

  // Инициализируем нужные нам поля

  ofn.lStructSize       = sizeof(OPENFILENAME);
  ofn.hwndOwner         = NULL;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = szFile;
  ofn.nMaxFile          = sizeof(szFile);
  ofn.lpstrFileTitle    = szFileTitle;
  ofn.nMaxFileTitle     = sizeof(szFileTitle);
  ofn.lpstrInitialDir   = NULL;
  ofn.Flags =   OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST
				  | OFN_HIDEREADONLY;

  // Выбираем входной файл
  if (GetOpenFileName(&ofn)) {

    // Открываем выбранный файл
    hf = _lopen(ofn.lpstrFile, OF_READ);

    // Сохраняем путь к открытому файлу
    lstrcpy(szCurrentFileName, ofn.lpstrFile);

    // Возвращаем идентификатор файла
    return hf;
  }
  // При отказе от выбора возвращаем
  // нулевое значение
  else return 0;
}

// ======================================================
// Функция OpenSaveFile
// Выбор файла для редактирования
// ======================================================

HFILE OpenSaveFile(void)
{
  OPENFILENAME ofn;

  char szFile[256];
  char szFileTitle[256];
  char szFilter[256] =
	 "Text Files\0*.txt\0Any Files\0*.*\0";

  HFILE hf;

  szFile[0] = '\0';

  memset(&ofn, 0, sizeof(OPENFILENAME));

  ofn.lStructSize       = sizeof(OPENFILENAME);
  ofn.hwndOwner         = NULL;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = szFile;
  ofn.nMaxFile          = sizeof(szFile);
  ofn.lpstrFileTitle    = szFileTitle;
  ofn.nMaxFileTitle     = sizeof(szFileTitle);
  ofn.lpstrInitialDir   = NULL;
  ofn.Flags             = OFN_HIDEREADONLY;

  // Выбираем выходной файл
  if (GetSaveFileName(&ofn)) {

    // При необходимости создаем файл
    hf = _lcreat(ofn.lpstrFile, 0);

    // Сохраняем путь к файлу
    lstrcpy(szCurrentFileName, ofn.lpstrFile);

    return hf;
  }
  else
    return 0;
}

// ======================================================
// Функция SaveFileAs
// Сохранение текста в новом файле
// ======================================================
int SaveFileAs(HWND hwnd)
{
  WORD wSize;
  HANDLE hTxtBuf;
  NPSTR  npTextBuffer;

  // Открываем выходной файл
  hfDstFile = OpenSaveFile();
  if(!hfDstFile) return 0;

  // Определяем размер текста
  wSize = GetWindowTextLength(hEdit);

  // Получаем идентификатор блока памяти,
  // в котором находится редактируемый текст
  hTxtBuf = (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);

  // Фиксируем блок памяти и получаем указатель
  // на него
  npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

  // Записываем содержимое блока памяти в файл
  if(wSize != _lwrite(hfDstFile, npTextBuffer, wSize))
  {
    // При ошибке закрываем файл и выдаем сообщение
    _lclose(hfDstFile);
    MessageBox(hwnd, "Ошибка при записи файла",
       szWindowTitle, MB_OK);
    return 0;
  }

  // Закрываем файл
  _lclose(hfDstFile);

  // Расфиксируем блок памяти
  LocalUnlock(hTxtBuf);

  // Так как файл был только что сохранен,
  // сбрасываем флаг обновления 
  bNeedSave = FALSE;
  SetFocus(hEdit);

  return 1;
}

// ======================================================
// Функция SaveFile
// Сохранение текста в старом файле
// ======================================================
int SaveFile(HWND hwnd)
{
  WORD wSize;
  HANDLE hTxtBuf;
  NPSTR  npTextBuffer;


  // Открываем выходной файл
  hfDstFile = _lopen(szCurrentFileName, OF_WRITE);
  if(!hfDstFile) return 0;

  // Определяем размер текста
  wSize = GetWindowTextLength(hEdit);

  // Получаем идентификатор блока памяти,
  // в котором находится редактируемый текст
  hTxtBuf = (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);

  // Фиксируем блок памяти и получаем указатель
  // на него
  npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

  // Записываем содержимое блока памяти в файл
  if(wSize != _lwrite(hfDstFile, npTextBuffer, wSize))
  {
    // При ошибке закрываем файл и выдаем сообщение
    _lclose(hfDstFile);
    MessageBox(hwnd, "Ошибка при записи файла",
       szWindowTitle, MB_OK);
    return 0;
  }

  // Закрываем файл
  _lclose(hfDstFile);

  // Расфиксируем блок памяти
  LocalUnlock(hTxtBuf);

  // Так как файл был только что сохранен,
  // сбрасываем флаг обновления 
  bNeedSave = FALSE;
  SetFocus(hEdit);

  return 1;
}

// ======================================================
// Функция SelectFile
// Загрузка текста из файла для редактирования
// ======================================================

int SelectFile(HWND hwnd)
{
  LPSTR lpTextBuffer;
  DWORD dwFileSize, dwCurrentPos;

  // Открываем входной файл.
  hfSrcFile = OpenFile();
  if(!hfSrcFile) return 0;

  // Определяем размер файла
  dwCurrentPos = _llseek(hfSrcFile, 0L, 1);
  dwFileSize   = _llseek(hfSrcFile, 0L, 2);
  _llseek(hfSrcFile, dwCurrentPos, 0);

  // Размер файла не должен превосходить 32000 байт
  if(dwFileSize >= 32000)
  {
     _lclose(hfSrcFile);
     MessageBox(hwnd, "Размер файла больше 32000 байт",
        szWindowTitle, MB_OK);
     return 0;
  }

  // Заказываем память для загрузки файла
  lpTextBuffer = (LPSTR)malloc(32000);
  if(lpTextBuffer == NULL)
     return 0;

  // Загружаем текст из файла в буфер
  _lread(hfSrcFile, lpTextBuffer, dwFileSize);

  // Закрываем буфер двоичным нулем
  lpTextBuffer[(WORD)dwFileSize] = '\0';

  // Закрываем файл
  _lclose(hfSrcFile);

  // Переносим содержимое буфера в
  // текстовый редактор
  SetWindowText(hEdit, lpTextBuffer);

  // Освобождаем буфер
  free((void *)lpTextBuffer);

  // сбрасываем флаг обновления
  bNeedSave = FALSE;
  SetFocus(hEdit);
  return 1;
}

// ======================================================
// Функция DldProc
// ======================================================
#pragma argsused

BOOL CALLBACK _export
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    // Инициализация диалоговой панели
    case WM_INITDIALOG:
    {
      return TRUE;
    }

    case WM_COMMAND:
    {
      switch(wParam)
      {
        // Сообщение от кнопки "OK"
        case IDOK:

        // Отмена диалоговой панели.
        // Это сообщение приходит, когда пользователь
        // нажимает на клавишу <Esc>
        case IDCANCEL:
        {
          // Устанавливаем флаг завершения диалога
          EndDialog(hdlg, 0);
          return TRUE;
        }
      }
    }
  }
  return FALSE;
}
