/*  A sample program from the book
   "Programming Windows 95" by Charles Petzold and Paul Yao. */

/*---------------------------------------
   POPPAD.C -- Popup Editor
               (c) Charles Petzold, 1996
  ---------------------------------------*/

#include <windows.h>
#include <commdlg.h>
#include <stdlib.h>
#include "poppad.h"

#define EDITID   1
#define UNTITLED "(untitled)"

LRESULT CALLBACK WndProc      (HWND, UINT, WPARAM, LPARAM) ;
BOOL    CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;

          // Functions in POPFILE.C

void PopFileInitialize (HWND) ;
BOOL PopFileOpenDlg    (HWND, PSTR, PSTR) ;
BOOL PopFileSaveDlg    (HWND, PSTR, PSTR) ;
BOOL PopFileRead       (HWND, PSTR) ;
BOOL PopFileWrite      (HWND, PSTR) ;

          // Functions in POPFIND.C

HWND PopFindFindDlg     (HWND) ;
HWND PopFindReplaceDlg  (HWND) ;
BOOL PopFindFindText    (HWND, int *, LPFINDREPLACE) ;
BOOL PopFindReplaceText (HWND, int *, LPFINDREPLACE) ;
BOOL PopFindNextText    (HWND, int *) ;
BOOL PopFindValidFind   (void) ;

          // Functions in POPFONT.C

void PopFontInitialize   (HWND) ;
BOOL PopFontChooseFont   (HWND) ;
void PopFontSetFont      (HWND) ;
void PopFontDeinitialize (void) ;

          // Functions in POPPRNT.C

BOOL PopPrntPrintFile (HINSTANCE, HWND, HWND, PSTR) ;

          // Global variables

static char szAppName[] = "PopPad" ;
static HWND hDlgModeless ;
HMENU		hMenu,hMenuPopup;
HGLOBAL hgbl1,hgbl2;

int  iReturn;

struct
     {
      BYTE   fVirt; 
      WORD   key; 
      WORD   cmd;     
     }
     accel[] =
     {
       FCONTROL, 'N', IDM_NEW,
       FCONTROL, 'O', IDM_OPEN,
       FCONTROL, 'S', IDM_SAVE,
       FCONTROL, 'P', IDM_PRINT,
	   FCONTROL, 'Z', IDM_UNDO,
	   FALT | FVIRTKEY, VK_BACK, IDM_UNDO,
       FCONTROL, 'X', IDM_CUT,
	   FSHIFT | FVIRTKEY, VK_DELETE, IDM_CUT,
       FCONTROL, 'C', IDM_COPY,
	   FCONTROL | FVIRTKEY, VK_INSERT, IDM_COPY,
       FCONTROL, 'V', IDM_PASTE,
	   FSHIFT | FVIRTKEY, VK_INSERT, IDM_PASTE,
	   FVIRTKEY, VK_DELETE, IDM_CLEAR,
       FCONTROL, 'F', IDM_FIND,
	   FVIRTKEY, VK_F3, IDM_NEXT,
       FCONTROL, 'R', IDM_REPLACE,
	   FVIRTKEY, VK_F1, IDM_HELP
     } ;

LPWORD lpwAlign ( LPWORD lpIn)
{
         ULONG ul;

         ul = (ULONG) lpIn;
         ul +=3;
         ul >>=2;
         ul <<=2;
         return (LPWORD) ul;
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
     {
     MSG         msg ;
     HWND        hwnd ;
     HACCEL      hAccel ;
     WNDCLASSEX  wndclass ;
	 LPACCEL lpaccl = accel ;

       LPDLGTEMPLATE lpdt;
       LPDLGITEMTEMPLATE lpdit;
       LPWORD lpw;
       LPWSTR lpwsz;

       hgbl1 = GlobalAlloc(GMEM_ZEROINIT, 1024);
       if (!hgbl1)
           return -1;

       lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl1);

       // Define a dialog box.

	   lpdt->style = WS_POPUP | WS_DLGFRAME;
       lpdt->cdit = 4;  // number of controls
       lpdt->x  = 20;  lpdt->y  = 20;
       lpdt->cx = 160; lpdt->cy = 80;

       lpw = (LPWORD) (lpdt + 1);
       *lpw++ = 0;   // no menu
       *lpw++ = 0;   // predefined dialog box class (by default)

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"About Box");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);

       //-----------------------
       // Define a static text control.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->x  = 0; lpdit->y  = 12;
       lpdit->cx = 160; lpdit->cy = 8;
       lpdit->id = -1;		    // text identifier
       lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER;

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0082;                         // static class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"PopPad");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       //-----------------------
       // Define a static text control.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->x  = 0; lpdit->y  = 36;
       lpdit->cx = 160; lpdit->cy = 8;
       lpdit->id = -1;		    // text identifier
       lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER;

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0082;                         // static class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"Popup Editor for Microsoft Windows");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       //-----------------------
       // Define a static text control.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->x  = 0; lpdit->y  = 48;
       lpdit->cx = 160; lpdit->cy = 8;
       lpdit->id = -1;		    // text identifier
       lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER;

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0082;                         // static class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"Copyright (c) Charles Petzold , 1996");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       //-----------------------
       // Define an OK button.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
       lpdit->x  = 64; lpdit->y  = 60;
       lpdit->cx = 32; lpdit->cy = 14;
       lpdit->id = IDOK;  // OK button identifier

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0080;    // button class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"OK");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       GlobalUnlock(hgbl1);

       hgbl2 = GlobalAlloc(GMEM_ZEROINIT, 1024);
       if (!hgbl2)
           return -1;

       lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl2);

       // Define a dialog box.

	   lpdt->style = WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE ;
       lpdt->cdit = 4;  // number of controls
       lpdt->x  = 20;  lpdt->y  = 20;
       lpdt->cx = 100; lpdt->cy = 76;

       lpw = (LPWORD) (lpdt + 1);
       *lpw++ = 0;   // no menu
       *lpw++ = 0;   // predefined dialog box class (by default)

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"PopPad");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);

       //-----------------------
       // Define a static text control.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->x  = 0; lpdit->y  = 10;
       lpdit->cx = 100; lpdit->cy = 8;
       lpdit->id = -1;		    // text identifier
       lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER;

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0082;                         // static class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"Sending");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       //-----------------------
       // Define a static text control.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->x  = 0; lpdit->y  = 20;
       lpdit->cx = 100; lpdit->cy = 8;
       lpdit->id = IDD_FNAME;		    // text identifier
       lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER;

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0082;                         // static class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       //-----------------------
       // Define a static text control.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->x  = 0; lpdit->y  = 30;
       lpdit->cx = 100; lpdit->cy = 8;
       lpdit->id = -1;		    // text identifier
       lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER;

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0082;                         // static class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"to print spooler.");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       //-----------------------
       // Define an OK button.
       //-----------------------
       lpw = lpwAlign (lpw);

       lpdit = (LPDLGITEMTEMPLATE) lpw;
       lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
       lpdit->x  = 34; lpdit->y  = 50;
       lpdit->cx = 32; lpdit->cy = 14;
       lpdit->id = IDCANCEL;  // OK button identifier

       lpw = (LPWORD) (lpdit + 1);
       *lpw++ = 0xFFFF;
       *lpw++ = 0x0080;    // button class

       lpwsz = (LPWSTR) lpw;
       lstrcpyW(lpwsz, L"Cancel");
       lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
       *lpw++ = 0;              // no creation data

       GlobalUnlock(hgbl2);

     wndclass.cbSize        = sizeof (wndclass) ;
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
//     wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;
     wndclass.hIcon         = LoadImage (NULL, "poppad.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = szAppName ;
     wndclass.lpszClassName = szAppName ;
//     wndclass.hIconSm       = LoadIcon (hInstance, szAppName) ;
	 wndclass.hIconSm       = LoadImage (NULL, "poppad.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE) ;

     RegisterClassEx (&wndclass) ;

	 hMenu = CreateMenu ();

	 hMenuPopup = CreateMenu ();
	 AppendMenu (hMenuPopup, MF_STRING, IDM_NEW,    "&New\tCtrl+N");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_OPEN,   "&Open...\tCtrl+O");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_SAVE,   "&Save\tCtrl+S");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_SAVEAS, "Save &As...");
	 AppendMenu (hMenuPopup, MF_SEPARATOR, 0,       NULL);
	 AppendMenu (hMenuPopup, MF_STRING, IDM_PRINT, "&Print...\tCtrl+P");
	 AppendMenu (hMenuPopup, MF_SEPARATOR, 0,       NULL);
	 AppendMenu (hMenuPopup, MF_STRING, IDM_EXIT,   "E&xit");

	 AppendMenu (hMenu, MF_POPUP, (UINT) hMenuPopup, "&File");

	 hMenuPopup = CreateMenu ();
	 AppendMenu (hMenuPopup, MF_STRING, IDM_UNDO,  "&Undo\tCtrl+Z");
	 AppendMenu (hMenuPopup, MF_SEPARATOR, 0,      NULL);
	 AppendMenu (hMenuPopup, MF_STRING, IDM_CUT,   "Cu&t\tCtrl+X");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_COPY,  "&Copy\tCtrl+C");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_PASTE, "&Paste\tCtrl+V");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_CLEAR,   "De&lete\tDel");
	 AppendMenu (hMenuPopup, MF_SEPARATOR, 0,      NULL);
	 AppendMenu (hMenuPopup, MF_STRING, IDM_SELALL,   "&Select All");

	 AppendMenu (hMenu, MF_POPUP, (UINT) hMenuPopup, "&Edit");

	 hMenuPopup = CreateMenu ();
	 AppendMenu (hMenuPopup, MF_STRING, IDM_FIND,   "&Find...\tCtrl+F");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_NEXT, "Find &Next\tF3");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_REPLACE,  "R&eplace...\tCtrl+R");

	 AppendMenu (hMenu, MF_POPUP, (UINT) hMenuPopup, "&Search");

	 hMenuPopup = CreateMenu ();
	 AppendMenu (hMenuPopup, MF_STRING, IDM_FONT,  "&Font...");

	 AppendMenu (hMenu, MF_POPUP, (UINT) hMenuPopup, "F&ormat");

	 hMenuPopup = CreateMenu ();
	 AppendMenu (hMenuPopup, MF_STRING, IDM_HELP,  "&Help");
	 AppendMenu (hMenuPopup, MF_STRING, IDM_ABOUT, "&About PopPad...");

	 AppendMenu (hMenu, MF_POPUP, (UINT) hMenuPopup, "&Help");

     hwnd = CreateWindow (szAppName, NULL,
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, hMenu, hInstance, szCmdLine) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ; 

     //hAccel = LoadAccelerators (hInstance, szAppName) ;
	 hAccel = CreateAcceleratorTable(lpaccl, 17);

     while (GetMessage (&msg, NULL, 0, 0))
          {
          if (hDlgModeless == NULL || !IsDialogMessage (hDlgModeless, &msg))
               {
               if (!TranslateAccelerator (hwnd, hAccel, &msg))
                    {
                    TranslateMessage (&msg) ;
                    DispatchMessage (&msg) ;
                    }
               }
          }
	 GlobalFree(hgbl1);
	 GlobalFree(hgbl2);
     return msg.wParam ;
     }

void DoCaption (HWND hwnd, char *szTitleName)
     {
     char szCaption[64 + _MAX_FNAME + _MAX_EXT] ;
     sprintf (szCaption, "%s - %s", szAppName,
               szTitleName[0] ? szTitleName : UNTITLED) ;

     SetWindowText (hwnd, szCaption) ;
     }

void OkMessage (HWND hwnd, char *szMessage, char *szTitleName)
     {
     char szBuffer[64 + _MAX_FNAME + _MAX_EXT] ;
     sprintf (szBuffer, szMessage, szTitleName[0] ? szTitleName : UNTITLED) ;

     MessageBox (hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION) ;
     }

short AskAboutSave (HWND hwnd, char *szTitleName)
     {
     char szBuffer[64 + _MAX_FNAME + _MAX_EXT] ;

     sprintf (szBuffer, "Save current changes in %s?",
               szTitleName[0] ? szTitleName : UNTITLED) ;

     iReturn = MessageBox (hwnd, szBuffer, szAppName,
                           MB_YESNOCANCEL | MB_ICONQUESTION) ;

     if (iReturn == IDYES)
          if (!SendMessage (hwnd, WM_COMMAND, IDM_SAVE, 0L))
               iReturn = IDCANCEL ;

     return iReturn ;
     }

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
     {
     static BOOL      bNeedSave = FALSE ;
     static char      szFileName[_MAX_PATH] ;
     static char      szTitleName[_MAX_FNAME + _MAX_EXT] ;
     static HINSTANCE hInst ;
     static HWND      hwndEdit ;
     static int       iOffset ;
     static UINT      iMsgFindReplace ;
     int              iSelBeg, iSelEnd, iEnable ;
     LPFINDREPLACE    pfr ;

     switch (iMsg)
          {
          case WM_CREATE :
               hInst = ((LPCREATESTRUCT) lParam) -> hInstance ;

                         // Create the edit control child window

               hwndEdit = CreateWindow ("edit", NULL,
                         WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
                              WS_BORDER | ES_LEFT | ES_MULTILINE |
                              ES_NOHIDESEL | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
                         0, 0, 0, 0,
                         hwnd, (HMENU) EDITID, hInst, NULL) ;

               SendMessage (hwndEdit, EM_LIMITTEXT, 32000, 0L) ;

                         // Initialize common dialog box stuff

               PopFileInitialize (hwnd) ;
               PopFontInitialize (hwndEdit) ;

               iMsgFindReplace = RegisterWindowMessage (FINDMSGSTRING) ;

                         // Process command line

               lstrcpy (szFileName, (PSTR)
                        (((LPCREATESTRUCT) lParam)->lpCreateParams)) ;

               if (strlen (szFileName) > 0)
                    {
                    GetFileTitle (szFileName, szTitleName,
                                  sizeof (szTitleName)) ;

                    if (!PopFileRead (hwndEdit, szFileName))
                         OkMessage (hwnd, "File %s cannot be read!",
                                          szTitleName) ;
                    }

               DoCaption (hwnd, szTitleName) ;
               return 0 ;

          case WM_SETFOCUS :
               SetFocus (hwndEdit) ;
               return 0 ;

          case WM_SIZE : 
               MoveWindow (hwndEdit, 0, 0, LOWORD (lParam),
                                           HIWORD (lParam), TRUE) ;
               return 0 ;

          case WM_INITMENUPOPUP :
               switch (lParam)
                    {
                    case 1 :        // Edit menu

                              // Enable Undo if edit control can do it

                         EnableMenuItem ((HMENU) wParam, IDM_UNDO,
                              SendMessage (hwndEdit, EM_CANUNDO, 0, 0L) ?
                                   MF_ENABLED : MF_GRAYED) ;

                              // Enable Paste if text is in the clipboard

                         EnableMenuItem ((HMENU) wParam, IDM_PASTE,
                              IsClipboardFormatAvailable (CF_TEXT) ?
                                   MF_ENABLED : MF_GRAYED) ;

                              // Enable Cut, Copy, and Del if text is selected

                         SendMessage (hwndEdit, EM_GETSEL, (WPARAM) &iSelBeg,
                                                           (LPARAM) &iSelEnd) ;

                         iEnable = iSelBeg != iSelEnd ? MF_ENABLED : MF_GRAYED ;

                         EnableMenuItem ((HMENU) wParam, IDM_CUT,   iEnable) ;
                         EnableMenuItem ((HMENU) wParam, IDM_COPY,  iEnable) ;
                         EnableMenuItem ((HMENU) wParam, IDM_CLEAR, iEnable) ;
                         break ;

                    case 2 :        // Search menu

                              // Enable Find, Next, and Replace if modeless
                              //   dialogs are not already active

                         iEnable = hDlgModeless == NULL ?
                                        MF_ENABLED : MF_GRAYED ;

                         EnableMenuItem ((HMENU) wParam, IDM_FIND,    iEnable) ;
                         EnableMenuItem ((HMENU) wParam, IDM_NEXT,    iEnable) ;
                         EnableMenuItem ((HMENU) wParam, IDM_REPLACE, iEnable) ;
                         break ;
                    }
               return 0 ;

          case WM_COMMAND :
                              // Messages from edit control

               if (lParam && LOWORD (wParam) == EDITID)
                    {
                    switch (HIWORD (wParam))
                         {
                         case EN_UPDATE :
                              bNeedSave = TRUE ;
                              return 0 ;

                         case EN_ERRSPACE :
                         case EN_MAXTEXT :
                              MessageBox (hwnd, "Edit control out of space.",
                                        szAppName, MB_OK | MB_ICONSTOP) ;
                              return 0 ;
                         }
                    break ;
                    }

               switch (LOWORD (wParam))
                    {
                              // Messages from File menu

                    case IDM_NEW :
                         if (bNeedSave && IDCANCEL ==
                                   AskAboutSave (hwnd, szTitleName))
                              return 0 ;

                         SetWindowText (hwndEdit, "\0") ;
                         szFileName[0]  = '\0' ;
                         szTitleName[0] = '\0' ;
                         DoCaption (hwnd, szTitleName) ;
                         bNeedSave = FALSE ;
                         return 0 ;

                    case IDM_OPEN :
                         if (bNeedSave && IDCANCEL ==
                                   AskAboutSave (hwnd, szTitleName))
                              return 0 ;

                         if (PopFileOpenDlg (hwnd, szFileName, szTitleName)!=0)
                              {
							  
                              if (!PopFileRead (hwndEdit, szFileName))
                                   {
                                   OkMessage (hwnd, "Could not read file %s!",
                                                    szTitleName) ;
                                   szFileName[0]  = '\0' ;
                                   szTitleName[0] = '\0' ;
                                   }
                              }

                         DoCaption (hwnd, szTitleName) ;
                         bNeedSave = FALSE ;
                         return 0 ;

                    case IDM_SAVE :
                         if (szFileName[0])
                              {
                              if (PopFileWrite (hwndEdit, szFileName))
                                   {
                                   bNeedSave = FALSE ;
                                   return 1 ;
                                   }
                              else
                                   OkMessage (hwnd, "Could not write file %s",
                                                    szTitleName) ;
                              return 0 ;
                              }
                                                  // fall through
                    case IDM_SAVEAS :
                         if (PopFileSaveDlg (hwnd, szFileName, szTitleName))
                              {
                              DoCaption (hwnd, szTitleName) ;

                              if (PopFileWrite (hwndEdit, szFileName))
                                   {
                                   bNeedSave = FALSE ;
                                   return 1 ;
                                   }
                              else
                                   OkMessage (hwnd, "Could not write file %s",
                                                    szTitleName) ;
                              }
                         return 0 ;

                    case IDM_PRINT :
                         if (!PopPrntPrintFile (hInst, hwnd, hwndEdit,
                                                szTitleName))
                              OkMessage (hwnd, "Could not print file %s",
                                         szTitleName) ;
                         return 0 ;

                    case IDM_EXIT :
                         SendMessage (hwnd, WM_CLOSE, 0, 0) ;
                         return 0 ;

                              // Messages from Edit menu

                    case IDM_UNDO :
                         SendMessage (hwndEdit, WM_UNDO, 0, 0) ;
                         return 0 ;

                    case IDM_CUT :
                         SendMessage (hwndEdit, WM_CUT, 0, 0) ;
                         return 0 ;

                    case IDM_COPY :
                         SendMessage (hwndEdit, WM_COPY, 0, 0) ;
                         return 0 ;

                    case IDM_PASTE :
                         SendMessage (hwndEdit, WM_PASTE, 0, 0) ;
                         return 0 ;

                    case IDM_CLEAR :
                         SendMessage (hwndEdit, WM_CLEAR, 0, 0) ;
                         return 0 ;

                    case IDM_SELALL :
                         SendMessage (hwndEdit, EM_SETSEL, 0, -1) ;
                         return 0 ;

                              // Messages from Search menu

                    case IDM_FIND :
                         SendMessage (hwndEdit, EM_GETSEL, NULL,
                                                           (LPARAM) &iOffset) ;

                         hDlgModeless = PopFindFindDlg (hwnd) ;
                         return 0 ;

                    case IDM_NEXT :
                         SendMessage (hwndEdit, EM_GETSEL, NULL,
                                                           (LPARAM) &iOffset) ;

                         if (PopFindValidFind ())
                              PopFindNextText (hwndEdit, &iOffset) ;
                         else
                              hDlgModeless = PopFindFindDlg (hwnd) ;

                         return 0 ;

                    case IDM_REPLACE :
                         SendMessage (hwndEdit, EM_GETSEL, NULL,
                                                           (LPARAM) &iOffset) ;

                         hDlgModeless = PopFindReplaceDlg (hwnd) ;
                         return 0 ;

                    case IDM_FONT :
                         if (PopFontChooseFont (hwnd))
                              PopFontSetFont (hwndEdit) ;

                         return 0 ;

                              // Messages from Help menu

                    case IDM_HELP :
                         OkMessage (hwnd, "Help not yet implemented!", "\0") ;
                         return 0 ;

                    case IDM_ABOUT :
						 DialogBoxIndirect(hInst, (LPDLGTEMPLATE) hgbl1,
                               hwnd, (DLGPROC) AboutDlgProc);
                         return 0 ;
                    }
               break ;

          case WM_CLOSE :
               if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName))
                    DestroyWindow (hwnd) ;

               return 0 ;

          case WM_QUERYENDSESSION :
               if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName))
                    return 1 ;

               return 0 ;

          case WM_DESTROY :
               PopFontDeinitialize () ;
               PostQuitMessage (0) ;
               return 0 ;

          default:
                         // Process "Find-Replace" iMsgs

               if (iMsg == iMsgFindReplace)
                    {
                    pfr = (LPFINDREPLACE) lParam ;

                    if (pfr->Flags & FR_DIALOGTERM)
                         hDlgModeless = NULL ;

                    if (pfr->Flags & FR_FINDNEXT)
                       if (!PopFindFindText (hwndEdit, &iOffset, pfr))
                              OkMessage (hwnd, "Text not found!", "\0") ;

                    if (pfr->Flags & FR_REPLACE ||
                        pfr->Flags & FR_REPLACEALL)
                         if (!PopFindReplaceText (hwndEdit, &iOffset, pfr))
                              OkMessage (hwnd, "Text not found!", "\0") ;

                    if (pfr->Flags & FR_REPLACEALL)
                         while (PopFindReplaceText (hwndEdit, &iOffset, pfr)) ;

                    return 0 ;
                    }
               break ;
          }
     return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
     }

BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
     {
     switch (iMsg)
          {
          case WM_INITDIALOG :
               return TRUE ;

          case WM_COMMAND :
               switch (LOWORD (wParam))
                    {
                    case IDOK :
                         EndDialog (hDlg, 0) ;
                         return TRUE ;
                    }
               break ;
          }
     return FALSE ;
     }

#pragma importf "popfile.c"
#pragma importf "popfind.c"
#pragma importf "popfont.c"
#pragma importf "popprnt.c"
/*------------------------------------------
   POPFILE.C -- Popup Editor File Functions
  ------------------------------------------*/

#include <windows.h>
#include <commdlg.h>
#include <stdlib.h>
#include <stdio.h>

static OPENFILENAME ofn ;

void PopFileInitialize (HWND hwnd)
     {
     //static char szFilter[] = "Text Files (*.TXT)\0*.txt\0" \
     //                         "ASCII Files (*.ASC)\0*.asc\0" \
     //                         "All Files (*.*)\0*.*\0\0" ;

     static char szFilter[256], chReplace;
     UINT i,cbString;

     strcpy(szFilter,
		 "Text Files (*.TXT)|*.txt|"
		 "ASCII Files (*.ASC)|*.asc|"
         "All files (*.*)|*.*||");

         cbString = strlen(szFilter);
         chReplace = szFilter[cbString-1];
         for (i=0; szFilter[i]; i++)
            if (szFilter[i] == chReplace) szFilter[i] = '\0';
 

     ofn.lStructSize       = sizeof (OPENFILENAME) ;
     ofn.hwndOwner         = hwnd ;
     ofn.hInstance         = NULL ;
     ofn.lpstrFilter       = szFilter ;
     ofn.lpstrCustomFilter = NULL ;
     ofn.nMaxCustFilter    = 0 ;
     ofn.nFilterIndex      = 0 ;
     ofn.lpstrFile         = NULL ;          // Set in Open and Close functions
     ofn.nMaxFile          = _MAX_PATH ;
     ofn.lpstrFileTitle    = NULL ;          // Set in Open and Close functions
     ofn.nMaxFileTitle     = _MAX_FNAME + _MAX_EXT ;
     ofn.lpstrInitialDir   = NULL ;
     ofn.lpstrTitle        = NULL ;
     ofn.Flags             = 0 ;             // Set in Open and Close functions
     ofn.nFileOffset       = 0 ;
     ofn.nFileExtension    = 0 ;
     ofn.lpstrDefExt       = "txt" ;
     ofn.lCustData         = 0L ;
     ofn.lpfnHook          = NULL ;
     ofn.lpTemplateName    = NULL ;
     }

BOOL PopFileOpenDlg (HWND hwnd, PSTR pstrFileName, PSTR pstrTitleName)
     {

     ofn.hwndOwner         = hwnd ;
     ofn.lpstrFile         = pstrFileName ;
     ofn.lpstrFileTitle    = pstrTitleName ;
     ofn.Flags             = OFN_HIDEREADONLY | OFN_CREATEPROMPT ;

     return GetOpenFileName (&ofn) ;
     }

BOOL PopFileSaveDlg (HWND hwnd, PSTR pstrFileName, PSTR pstrTitleName)
     {

     ofn.hwndOwner         = hwnd ;
     ofn.lpstrFile         = pstrFileName ;
     ofn.lpstrFileTitle    = pstrTitleName ;
     ofn.Flags             = OFN_OVERWRITEPROMPT ;

     return GetSaveFileName (&ofn) ;
     }

static long PopFileLength (FILE *file)
     {
     int iCurrentPos, iFileLength ;

     iCurrentPos = ftell (file) ;

     fseek (file, 0, SEEK_END) ;

     iFileLength = ftell (file) ;

     fseek (file, iCurrentPos, SEEK_SET) ;

     return iFileLength ;
     }

BOOL PopFileRead (HWND hwndEdit, PSTR pstrFileName)
     {
     FILE  *file ;
     int    iLength ;
     PSTR   pstrBuffer ;

     //printf("pstrFileName = %s\n", pstrFileName);
     if (NULL == (file = fopen (pstrFileName, "rb")))
          return FALSE ;

     iLength = PopFileLength (file) ;

     if (NULL == (pstrBuffer = (PSTR) malloc (iLength)))
          {
          fclose (file) ;
          return FALSE ;
          }

     fread (pstrBuffer, 1, iLength, file) ;
     fclose (file) ;
     pstrBuffer[iLength] = '\0' ;

     SetWindowText (hwndEdit, pstrBuffer) ;
     free (pstrBuffer) ;

     return TRUE ;
     }

BOOL PopFileWrite (HWND hwndEdit, PSTR pstrFileName)
     {
     FILE  *file ;
     int    iLength ;
     PSTR   pstrBuffer ;

     if (NULL == (file = fopen (pstrFileName, "wb")))
          return FALSE ;

     iLength = GetWindowTextLength (hwndEdit) ;

     if (NULL == (pstrBuffer = (PSTR) malloc (iLength + 1)))
          {
          fclose (file) ;
          return FALSE ;
          }

     GetWindowText (hwndEdit, pstrBuffer, iLength + 1) ;

     if (iLength != (int) fwrite (pstrBuffer, 1, iLength, file))
          {
          fclose (file) ;
          free (pstrBuffer) ;
          return FALSE ;
          }

     fclose (file) ;
     free (pstrBuffer) ;

     return TRUE ;
     }
/*--------------------------------------------------------
   POPFIND.C -- Popup Editor Search and Replace Functions
  --------------------------------------------------------*/

#include <windows.h>
#include <commdlg.h>
#include <string.h>

#define MAX_STRING_LEN   256

static char szFindText [MAX_STRING_LEN] ;
static char szReplText [MAX_STRING_LEN] ;

HWND PopFindFindDlg (HWND hwnd)
     {
     static FINDREPLACE fr ;       // must be static for modeless dialog!!!

     fr.lStructSize      = sizeof (FINDREPLACE) ;
     fr.hwndOwner        = hwnd ;
     fr.hInstance        = NULL ;
     fr.Flags            = FR_HIDEUPDOWN | FR_HIDEMATCHCASE | FR_HIDEWHOLEWORD ;
     fr.lpstrFindWhat    = szFindText ;
     fr.lpstrReplaceWith = NULL ;
     fr.wFindWhatLen     = sizeof (szFindText) ;
     fr.wReplaceWithLen  = 0 ;
     fr.lCustData        = 0 ;
     fr.lpfnHook         = NULL ;
     fr.lpTemplateName   = NULL ;

     return FindText (&fr) ;
     }

HWND PopFindReplaceDlg (HWND hwnd)
     {
     static FINDREPLACE fr ;       // must be static for modeless dialog!!!

     fr.lStructSize      = sizeof (FINDREPLACE) ;
     fr.hwndOwner        = hwnd ;
     fr.hInstance        = NULL ;
     fr.Flags            = FR_HIDEUPDOWN | FR_HIDEMATCHCASE | FR_HIDEWHOLEWORD ;
     fr.lpstrFindWhat    = szFindText ;
     fr.lpstrReplaceWith = szReplText ;
     fr.wFindWhatLen     = sizeof (szFindText) ;
     fr.wReplaceWithLen  = sizeof (szReplText) ;
     fr.lCustData        = 0 ;
     fr.lpfnHook         = NULL ;
     fr.lpTemplateName   = NULL ;

     return ReplaceText (&fr) ;
     }

BOOL PopFindFindText (HWND hwndEdit, int *piSearchOffset, LPFINDREPLACE pfr)
     {
     int   iLength, iPos ;
     PSTR  pstrDoc, pstrPos ;

               // Read in the edit document

     iLength = GetWindowTextLength (hwndEdit) ;

     if (NULL == (pstrDoc = (PSTR) malloc (iLength + 1)))
          return FALSE ;

     GetWindowText (hwndEdit, pstrDoc, iLength + 1) ;

               // Search the document for the find string

     pstrPos = strstr (pstrDoc + *piSearchOffset, pfr->lpstrFindWhat) ;

               // Return an error code if the string cannot be found

     if (pstrPos == NULL)
	{
          free (pstrDoc) ;
          return FALSE ;
	}

               // Find the position in the document and the new start offset

     iPos = pstrPos - pstrDoc ;
     *piSearchOffset = iPos + strlen (pfr->lpstrFindWhat) ;

               // Select the found text

     SendMessage (hwndEdit, EM_SETSEL, iPos, *piSearchOffset) ;
     SendMessage (hwndEdit, EM_SCROLLCARET, 0, 0) ;
     free (pstrDoc) ;
     return TRUE ;
     }

BOOL PopFindNextText (HWND hwndEdit, int *piSearchOffset)
     {
     FINDREPLACE fr ;

     fr.lpstrFindWhat = szFindText ;

     return PopFindFindText (hwndEdit, piSearchOffset, &fr) ;
     }

BOOL PopFindReplaceText (HWND hwndEdit, int *piSearchOffset, LPFINDREPLACE pfr)
     {
               // Find the text

     if (!PopFindFindText (hwndEdit, piSearchOffset, pfr))
          return FALSE ;

               // Replace it

     SendMessage (hwndEdit, EM_REPLACESEL, 0, (LPARAM) pfr->lpstrReplaceWith) ;

     return TRUE ;
     }

BOOL PopFindValidFind (void)
     {
     return *szFindText != '\0' ;
     }
/*------------------------------------------
   POPFONT.C -- Popup Editor Font Functions
  ------------------------------------------*/

#include <windows.h>
#include <commdlg.h>

static LOGFONT logfont ;
static HFONT   hFont ;

BOOL PopFontChooseFont (HWND hwnd)
     {
     CHOOSEFONT cf ;

     cf.lStructSize      = sizeof (CHOOSEFONT) ;
     cf.hwndOwner        = hwnd ;
     cf.hDC              = NULL ;
     cf.lpLogFont        = &logfont ;
     cf.iPointSize       = 0 ;
     cf.Flags            = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS
                                                  | CF_EFFECTS ;
     cf.rgbColors        = 0L ;
     cf.lCustData        = 0L ;
     cf.lpfnHook         = NULL ;
     cf.lpTemplateName   = NULL ;
     cf.hInstance        = NULL ;
     cf.lpszStyle        = NULL ;
     cf.nFontType        = 0 ;               // Returned from ChooseFont
     cf.nSizeMin         = 0 ;
     cf.nSizeMax         = 0 ;

     return ChooseFont (&cf) ;
     }

void PopFontInitialize (HWND hwndEdit)
     {
     GetObject (GetStockObject (SYSTEM_FONT), sizeof (LOGFONT),
                                              (PSTR) &logfont) ;
     hFont = CreateFontIndirect (&logfont) ;
     SendMessage (hwndEdit, WM_SETFONT, (WPARAM) hFont, 0) ;
     }

void PopFontSetFont (HWND hwndEdit)
     {
     HFONT hFontNew ;
     RECT  rect ;

     hFontNew = CreateFontIndirect (&logfont) ;
     SendMessage (hwndEdit, WM_SETFONT, (WPARAM) hFontNew, 0) ;
     DeleteObject (hFont) ;
     hFont = hFontNew ;
     GetClientRect (hwndEdit, &rect) ;
     InvalidateRect (hwndEdit, &rect, TRUE) ;
     }

void PopFontDeinitialize (void)
     {
     DeleteObject (hFont) ;
     }
/*----------------------------------------------
   POPPRNT.C -- Popup Editor Printing Functions
  ----------------------------------------------*/

#include <windows.h>
#include <commdlg.h>
#include <string.h>
#include <stdio.h>
#include "poppad.h"

BOOL bUserAbort ;
HWND hDlgPrint ;

BOOL CALLBACK PrintDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
     {
     switch (msg)
          {
          case WM_INITDIALOG :
               EnableMenuItem (GetSystemMenu (hDlg, FALSE), SC_CLOSE,
                                                            MF_GRAYED) ;
               return TRUE ;

          case WM_COMMAND :
               bUserAbort = TRUE ;
               EnableWindow (GetParent (hDlg), TRUE) ;
               DestroyWindow (hDlg) ;
               hDlgPrint = 0 ;
               return TRUE ;
          }
     return FALSE ;
     }          

BOOL CALLBACK AbortProc (HDC hPrinterDC, int iCode)
     {
     MSG msg ;

     while (!bUserAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
          {
          if (!hDlgPrint || !IsDialogMessage (hDlgPrint, &msg))
               {
               TranslateMessage (&msg) ;
               DispatchMessage (&msg) ;
               }
          }
     return !bUserAbort ;
     }

BOOL PopPrntPrintFile (HINSTANCE hInst, HWND hwnd, HWND hwndEdit, 
                                                   LPSTR szTitleName)
     {
     static DOCINFO  di = { sizeof (DOCINFO), "", NULL } ;
     static PRINTDLG pd ;
     BOOL            bSuccess ;
     LPCTSTR         pstrBuffer ;
     int             yChar, iCharsPerLine, iLinesPerPage, iTotalLines,
                     iTotalPages, iPage, iLine, iLineNum ;
     TEXTMETRIC      tm ;
     WORD            iColCopy, iNoiColCopy ;
     
     pd.lStructSize         = sizeof (PRINTDLG) ;
     pd.hwndOwner           = hwnd ;
     pd.hDevMode            = NULL ;
     pd.hDevNames           = NULL ;
     pd.hDC                 = NULL ;
     pd.Flags               = PD_ALLPAGES | PD_COLLATE | PD_RETURNDC ;
     pd.nFromPage           = 0 ;
     pd.nToPage             = 0 ;
     pd.nMinPage            = 0 ;
     pd.nMaxPage            = 0 ;
     pd.nCopies             = 1 ;
     pd.hInstance           = NULL ;
     pd.lCustData           = 0L ;
     pd.lpfnPrintHook       = NULL ;
     pd.lpfnSetupHook       = NULL ;
     pd.lpPrintTemplateName = NULL ;
     pd.lpSetupTemplateName = NULL ;
     pd.hPrintTemplate      = NULL ;
     pd.hSetupTemplate      = NULL ;

     if (!PrintDlg (&pd))
          return TRUE ;

     iTotalLines = (short) SendMessage (hwndEdit, EM_GETLINECOUNT, 0, 0L) ;

     if (iTotalLines == 0)
          return TRUE ;

     GetTextMetrics (pd.hDC, &tm) ;
     yChar = tm.tmHeight + tm.tmExternalLeading ;

     iCharsPerLine = GetDeviceCaps (pd.hDC, HORZRES) / tm.tmAveCharWidth ;
     iLinesPerPage = GetDeviceCaps (pd.hDC, VERTRES) / yChar ;
     iTotalPages   = (iTotalLines + iLinesPerPage - 1) / iLinesPerPage ;

     pstrBuffer = (LPCTSTR) HeapAlloc (GetProcessHeap (), 
		                               HEAP_NO_SERIALIZE, iCharsPerLine + 1) ;

     EnableWindow (hwnd, FALSE) ;

     bSuccess   = TRUE ;
     bUserAbort = FALSE ;

     //hDlgPrint = CreateDialog (hInst, (LPCTSTR) "PrintDlgBox", hwnd, PrintDlgProc) ;
	 hDlgPrint = CreateDialogIndirect(hInst,
                               (LPDLGTEMPLATE) hgbl2,
                               hwnd,
                               (DLGPROC) PrintDlgProc);

     SetDlgItemText (hDlgPrint, IDD_FNAME, szTitleName) ;

     SetAbortProc (pd.hDC, AbortProc) ;

     GetWindowText (hwnd, (PTSTR) di.lpszDocName, sizeof (PTSTR)) ;

     if (StartDoc (pd.hDC, &di) > 0)
          {
          for (iColCopy = 0 ;
               iColCopy < ((WORD) pd.Flags & PD_COLLATE ? pd.nCopies : 1) ;
               iColCopy++)
               {
               for (iPage = 0 ; iPage < iTotalPages ; iPage++)
                    {
                    for (iNoiColCopy = 0 ;
                         iNoiColCopy < (pd.Flags & PD_COLLATE ? 1 : pd.nCopies) ;
                         iNoiColCopy++)
                         {

                         if (StartPage (pd.hDC) < 0)
                              {
                              bSuccess = FALSE ;
                              break ;
                              }

                         for (iLine = 0 ; iLine < iLinesPerPage ; iLine++)
                              {
                              iLineNum = iLinesPerPage * iPage + iLine ;

                              if (iLineNum > iTotalLines)
                                   break ;

                              *(int *) pstrBuffer = iCharsPerLine ;

                              TextOut (pd.hDC, 0, yChar * iLine, pstrBuffer,
                                   (int) SendMessage (hwndEdit, EM_GETLINE,
                                   (WPARAM) iLineNum, (LPARAM) pstrBuffer)) ;
                              }

                         if (EndPage (pd.hDC) < 0)
                              {
                              bSuccess = FALSE ;
                              break ;
                              }

                         if (bUserAbort)
                              break ;
                         }

                    if (!bSuccess || bUserAbort)
                         break ;
                    }

               if (!bSuccess || bUserAbort)
                    break ;
               }
          }
     else
          bSuccess = FALSE ;

     if (bSuccess)
          EndDoc (pd.hDC) ;

     if (!bUserAbort)
          {
          EnableWindow (hwnd, TRUE) ;
          DestroyWindow (hDlgPrint) ;
          }

     HeapFree (GetProcessHeap (), 0, (LPVOID) pstrBuffer) ;
     DeleteDC (pd.hDC) ;

     return bSuccess && !bUserAbort ;
     }