#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "resource.h"
#include "afxres.h"
#include "psheet.h"

// Структура, в которой хранятся параметры
typedef struct 
{
  int  nBold;
  int  nItalic;
  int  nUnderline;
  int  nUseTabs;
  char szKeyWord[80];
} OPTIONS;

OPTIONS opt;

// Массив описаний страниц блокнота
PROPSHEETPAGE   psheetPage[3];

// Заголовок блокнота
PROPSHEETHEADER psheetHeader;

// Идентификаторы страниц блокнота
HPROPSHEETPAGE hPage[3];

HINSTANCE hInst;
char szAppName[]  = "PropSheetApp";
char szAppTitle[] = "Property Sheet Demo";

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------
int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;
  
  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
    if(IsIconic(hWnd))
	  ShowWindow(hWnd, SW_RESTORE);
	SetForegroundWindow(hWnd);
    return FALSE;
  }

  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICONSM), IMAGE_ICON, 16, 16, 0);
  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU);
  wc.lpszClassName = szAppName;
  if(!RegisterClassEx(&wc))
    if(!RegisterClass((LPWNDCLASS)&wc.style))
	  return FALSE;
    
  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW,
   	 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно и запускаем цикл обработки сообщений
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hWnd, WM_CREATE,     WndProc_OnCreate);
    HANDLE_MSG(hWnd, WM_DESTROY,    WndProc_OnDestroy);
    HANDLE_MSG(hWnd, WM_COMMAND,    WndProc_OnCommand);

	default:
      return(DefWindowProc(hWnd, msg, wParam, lParam));
  }
}

// -----------------------------------------------------
// Функция WndProc_OnCreate
// -----------------------------------------------------
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
  // Инициализируем библиотеку стандартных органов управления
  InitCommonControls();

  // Инициализируем параметры
  opt.nBold =
  opt.nItalic =
  opt.nUnderline =
  opt.nUseTabs = 0;
  strcpy(opt.szKeyWord, "Undef");

  return TRUE;
}

// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
  PostQuitMessage(0);
  return 0L;
}

// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  switch (id)
  {
	case ID_FILE_EXIT:  
	  PostQuitMessage(0); // завершаем работу приложения
	  return 0L;
	  break;
	  
  	case ID_HELP_ABOUT:
      MessageBox(hWnd, 
        "Property Sheet Demo Application, v.1.0\n"
        "(C) Alexandr Frolov, 1995\n"
        "Email: frolov@glas.apc.org",
        szAppTitle, MB_OK | MB_ICONINFORMATION);
	  return 0L;
	  break;

	case ID_FILE_OPTIONS:  
    {
      // Инициализируем страницы блокнота  
      psheetPage[0].dwSize = sizeof(PROPSHEETPAGE);
      psheetPage[0].hInstance = hInst;
      psheetPage[0].pszIcon = MAKEINTRESOURCE(IDI_EFFECTS);
      psheetPage[0].dwFlags = PSP_USETITLE | PSP_USEICONID;
      psheetPage[0].pszTemplate = 
        MAKEINTRESOURCE(IDD_DIALOG1);
      psheetPage[0].pfnDlgProc = DlgProc1;
      psheetPage[0].pszTitle = "Set Effects";
      psheetPage[0].lParam = 0;

      // Добавляем страницу в блокнот, сохраняя ее
      // идентификатор в массиве hPage
      hPage[0] = CreatePropertySheetPage(&psheetPage[0]);

      psheetPage[1].dwSize = sizeof(PROPSHEETPAGE);
      psheetPage[1].hInstance = hInst;
      psheetPage[1].pszIcon = MAKEINTRESOURCE(IDI_TAB);
      psheetPage[1].dwFlags = PSP_USETITLE | PSP_USEICONID;
      psheetPage[1].pszTemplate = 
        MAKEINTRESOURCE(IDD_DIALOG2);
      psheetPage[1].pfnDlgProc = DlgProc2;
      psheetPage[1].pszTitle = "Using Tabs";
      psheetPage[1].lParam = 0;
      hPage[1] = CreatePropertySheetPage(&psheetPage[1]);

      psheetPage[2].dwSize = sizeof(PROPSHEETPAGE);
      psheetPage[2].hInstance = hInst;
      psheetPage[2].pszIcon = MAKEINTRESOURCE(IDI_KEYWORD);
      psheetPage[2].dwFlags = PSP_USETITLE | PSP_USEICONID;
      psheetPage[2].pszTemplate = 
        MAKEINTRESOURCE(IDD_DIALOG3);
      psheetPage[2].pfnDlgProc = DlgProc3;
      psheetPage[2].pszTitle = "Keyword";
      psheetPage[2].lParam = 0;
      hPage[2] = CreatePropertySheetPage(&psheetPage[2]);

      // Инициализируем заголовок блокнота
      psheetHeader.dwSize = sizeof(PROPSHEETHEADER);
      psheetHeader.hInstance = hInst;
      psheetHeader.pszIcon = MAKEINTRESOURCE(IDI_APPICONSM);
      psheetHeader.dwFlags = PSH_USEICONID;
      psheetHeader.hwndParent = hWnd;
      psheetHeader.pszCaption = "Property Sheet Sample";
      psheetHeader.nPages = 
        sizeof(psheetPage) / sizeof(PROPSHEETPAGE);
      psheetHeader.phpage = (HPROPSHEETPAGE FAR *)&hPage[0];
      
      // Создаем и отображаем блокнот
      PropertySheet(&psheetHeader);

      return 0L;
	  break;
    }

  	default:
	  break;
  }
  return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, 
    codeNotify, DefWindowProc);
}

// -----------------------------------------------------
// Функция DlgProc1
// для первой страницы блокнота
// -----------------------------------------------------
BOOL APIENTRY
DlgProc1(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc1_OnInitDialog);
    HANDLE_MSG(hdlg, WM_COMMAND,    DlgProc1_OnCommand);
    HANDLE_MSG(hdlg, WM_NOTIFY,     DlgProc1_OnNotify);
	default:
      break;
  }
  return FALSE;
}

// -----------------------------------------------------
// Функция DlgProc1_OnInitDialog
// Вызывается при инициализации первой страницы блокнота
// -----------------------------------------------------
BOOL DlgProc1_OnInitDialog(HWND hdlg, 
  HWND hwndFocus, LPARAM lParam)
{
  // Устанавливаем переключатели в соответствии
  // со значениями параметров, записанных в 
  // структуре opt
  SendMessage(GetDlgItem(hdlg, IDC_BOLD), 
    BM_SETCHECK, opt.nBold, 0L);

  SendMessage(GetDlgItem(hdlg, IDC_ITALIC), 
    BM_SETCHECK, opt.nItalic, 0L);

  SendMessage(GetDlgItem(hdlg, IDC_UNDERLINE), 
    BM_SETCHECK, opt.nUnderline, 0L);

  return TRUE;
}

// -----------------------------------------------------
// Функция DlgProc1_OnNotify
// Обрабатывает извещение от первой страницы блокнота
// -----------------------------------------------------
LRESULT 
DlgProc1_OnNotify(HWND hdlg, int idFrom, NMHDR* pnmhdr)
{
  switch(pnmhdr->code)
  {
    // Когда пользователь нажимает кнопку OK, получаем
    // состояние переключателей, расположенных в первой
    // странице блокнота, и сохраняем это состояние в
    // соответствующих полях структуры opt
    case PSN_APPLY:
	{
      opt.nBold = (int)SendMessage(
        GetDlgItem(hdlg, IDC_BOLD), 
        BM_GETCHECK, 0L, 0L);

      opt.nItalic = (int)SendMessage(
        GetDlgItem(hdlg, IDC_ITALIC), 
        BM_GETCHECK, 0L, 0L);

      opt.nUnderline = (int)SendMessage(
        GetDlgItem(hdlg, IDC_UNDERLINE), 
        BM_GETCHECK, 0L, 0L);
      break;
    }

    default:
      break;
  }
  return FALSE;
}

// -----------------------------------------------------
// Функция DlgProc1_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void DlgProc1_OnCommand(HWND hdlg, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  // Разблокируем кнопку "Apply"
  PropSheet_Changed(GetParent(hdlg), hdlg);

  return NULL;
}

// -----------------------------------------------------
// Функция DlgProc2
// для второй страницы блокнота
// -----------------------------------------------------
BOOL APIENTRY
DlgProc2(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc2_OnInitDialog);
    HANDLE_MSG(hdlg, WM_NOTIFY,     DlgProc2_OnNotify);
    default:
      break;
  }
  return FALSE;
}

// -----------------------------------------------------
// Функция DlgProc2_OnInitDialog
// Вызывается при инициализации второй страницы блокнота
// -----------------------------------------------------
BOOL DlgProc2_OnInitDialog(HWND hdlg, 
  HWND hwndFocus, LPARAM lParam)
{
  SendMessage(GetDlgItem(hdlg, IDC_USETABS), 
    BM_SETCHECK, opt.nUseTabs, 0L);

  SendMessage(GetDlgItem(hdlg, IDC_DONTUSETABS), 
    BM_SETCHECK, (opt.nUseTabs) ? 0 : 1, 0L);

  return TRUE;
}

// -----------------------------------------------------
// Функция DlgProc2_OnNotify
// Обрабатывает извещение от второй страницы блокнота
// -----------------------------------------------------
LRESULT 
DlgProc2_OnNotify(HWND hdlg, int idFrom, NMHDR* pnmhdr)
{
  switch(pnmhdr->code)
  {
    case PSN_SETACTIVE:
	{
      // Разблокируем кнопку "Apply", когда страница
      // блокнота становится активной
      PropSheet_Changed(GetParent(hdlg), hdlg);
      break;
    }

    case PSN_KILLACTIVE:
	{
      // Блокируем кнопку "Apply", когда страница
      // блокнота становится неактивной
      PropSheet_UnChanged(GetParent(hdlg), hdlg);
      break;
    }

    case PSN_APPLY:
	{
      opt.nUseTabs = (int)SendMessage(
        GetDlgItem(hdlg, IDC_USETABS), 
        BM_GETCHECK, 0L, 0L);
      break;
    }
    default:
      break;
  }
  return FALSE;
}

// -----------------------------------------------------
// Функция DlgProc3
// для третьей страницы блокнота
// -----------------------------------------------------
BOOL APIENTRY
DlgProc3(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc3_OnInitDialog);
    HANDLE_MSG(hdlg, WM_NOTIFY,     DlgProc3_OnNotify);
    HANDLE_MSG(hdlg, WM_COMMAND,    DlgProc3_OnCommand);
    default:
      break;
  }
  return FALSE;
}

// -----------------------------------------------------
// Функция DlgProc3_OnInitDialog
// Вызывается при инициализации третьей страницы блокнота
// -----------------------------------------------------
BOOL DlgProc3_OnInitDialog(HWND hdlg, 
  HWND hwndFocus, LPARAM lParam)
{
  SetWindowText(GetDlgItem(hdlg, IDC_EDITKEYWORD), 
    opt.szKeyWord);

  return TRUE;
}

// -----------------------------------------------------
// Функция DlgProc3_OnNotify
// Обрабатывает извещение от третьей страницы блокнота
// -----------------------------------------------------
LRESULT 
DlgProc3_OnNotify(HWND hdlg, int idFrom, NMHDR* pnmhdr)
{
  switch(pnmhdr->code)
  {
    // Выполняем проверку длины ключевого слова,
    // которое не должно быть длиннее 8 символов
    case PSN_KILLACTIVE:
	{
      char szTempBuf[80];

      // Получаем новое ключевое слово во временный буфер
      GetWindowText(GetDlgItem(hdlg, IDC_EDITKEYWORD), 
        szTempBuf, 80);

      // Проверяем его длину
      if(lstrlen(szTempBuf) > 8)
      {
        // Если длина больше 8 символов, выводим
        // предупреждающее сообщение
        MessageBox(NULL, "Too long keyword, "
          "must be shorter than 8 characters", 
          szAppName,  MB_OK | MB_ICONEXCLAMATION);

        // Отменяем закрытие страницы блокнота
        SetWindowLong(hdlg, DWL_MSGRESULT, TRUE);

        // Отменяем обновление параметров
        return TRUE;
      }
      else
      {
        // Если длина сообщения правильная, разрешаем
        // закрытие страницы блокнота и
        // обновление параметров
        SetWindowLong(hdlg, DWL_MSGRESULT, FALSE);
        return FALSE;
      }

      break;
    }

    case PSN_APPLY:
	{
      GetWindowText(GetDlgItem(hdlg, IDC_EDITKEYWORD), 
        opt.szKeyWord, 80);
      break;
    }

    default:
      break;
  }
  return FALSE;
}

// -----------------------------------------------------
// Функция DlgProc3_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void DlgProc3_OnCommand(HWND hdlg, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  // Сообщение от редактора текста
  if(id == IDC_EDITKEYWORD)
  {
    // Если пользователь изменил ключевое слово в окне
    // редактирования, разблокируем кнопку "Apply"
    if(codeNotify == EN_CHANGE)
    {
      PropSheet_Changed(GetParent(hdlg), hdlg);
    }
  }
  return FALSE;
}
