xref: /reactos/base/applications/notepad/dialog.c (revision 55b93aec)
1 /*
2  *  Notepad (dialog.c)
3  *
4  *  Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
5  *  Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6  *  Copyright 2002 Andriy Palamarchuk
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #include "notepad.h"
24 
25 #include <assert.h>
26 #include <commctrl.h>
27 #include <strsafe.h>
28 
29 LRESULT CALLBACK EDIT_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
30 
31 static const TCHAR helpfile[] = _T("notepad.hlp");
32 static const TCHAR empty_str[] = _T("");
33 static const TCHAR szDefaultExt[] = _T("txt");
34 static const TCHAR txt_files[] = _T("*.txt");
35 
36 static UINT_PTR CALLBACK DIALOG_PAGESETUP_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
37 
38 VOID ShowLastError(VOID)
39 {
40     DWORD error = GetLastError();
41     if (error != NO_ERROR)
42     {
43         LPTSTR lpMsgBuf = NULL;
44         TCHAR szTitle[MAX_STRING_LEN];
45 
46         LoadString(Globals.hInstance, STRING_ERROR, szTitle, ARRAY_SIZE(szTitle));
47 
48         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
49                       NULL,
50                       error,
51                       0,
52                       (LPTSTR) &lpMsgBuf,
53                       0,
54                       NULL);
55 
56         MessageBox(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR);
57         LocalFree(lpMsgBuf);
58     }
59 }
60 
61 /**
62  * Sets the caption of the main window according to Globals.szFileTitle:
63  *    (untitled) - Notepad      if no file is open
64  *    [filename] - Notepad      if a file is given
65  */
66 void UpdateWindowCaption(BOOL clearModifyAlert)
67 {
68     TCHAR szCaption[MAX_STRING_LEN];
69     TCHAR szNotepad[MAX_STRING_LEN];
70     TCHAR szFilename[MAX_STRING_LEN];
71 
72     /* Load the name of the application */
73     LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
74 
75     /* Determine if the file has been saved or if this is a new file */
76     if (Globals.szFileTitle[0] != 0)
77         StringCchCopy(szFilename, ARRAY_SIZE(szFilename), Globals.szFileTitle);
78     else
79         LoadString(Globals.hInstance, STRING_UNTITLED, szFilename, ARRAY_SIZE(szFilename));
80 
81     /* When a file is being opened or created, there is no need to have the edited flag shown
82        when the new or opened file has not been edited yet */
83     if (clearModifyAlert)
84     {
85         StringCbPrintf(szCaption, sizeof(szCaption), _T("%s - %s"),
86                        szFilename, szNotepad);
87     }
88     else
89     {
90         BOOL isModified = (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0) ? TRUE : FALSE);
91 
92         /* Update the caption based upon if the user has modified the contents of the file or not */
93         StringCbPrintf(szCaption, sizeof(szCaption), _T("%s%s - %s"),
94             (isModified ? _T("*") : _T("")), szFilename, szNotepad);
95     }
96 
97     /* Update the window caption */
98     SetWindowText(Globals.hMainWnd, szCaption);
99 }
100 
101 int DIALOG_StringMsgBox(HWND hParent, int formatId, LPCTSTR szString, DWORD dwFlags)
102 {
103     TCHAR szMessage[MAX_STRING_LEN];
104     TCHAR szResource[MAX_STRING_LEN];
105 
106     /* Load and format szMessage */
107     LoadString(Globals.hInstance, formatId, szResource, ARRAY_SIZE(szResource));
108     _sntprintf(szMessage, ARRAY_SIZE(szMessage), szResource, szString);
109 
110     /* Load szCaption */
111     if ((dwFlags & MB_ICONMASK) == MB_ICONEXCLAMATION)
112         LoadString(Globals.hInstance, STRING_ERROR, szResource, ARRAY_SIZE(szResource));
113     else
114         LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, ARRAY_SIZE(szResource));
115 
116     /* Display Modal Dialog */
117     // if (hParent == NULL)
118         // hParent = Globals.hMainWnd;
119     return MessageBox(hParent, szMessage, szResource, dwFlags);
120 }
121 
122 static void AlertFileNotFound(LPCTSTR szFileName)
123 {
124     DIALOG_StringMsgBox(Globals.hMainWnd, STRING_NOTFOUND, szFileName, MB_ICONEXCLAMATION | MB_OK);
125 }
126 
127 static int AlertFileNotSaved(LPCTSTR szFileName)
128 {
129     TCHAR szUntitled[MAX_STRING_LEN];
130 
131     LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, ARRAY_SIZE(szUntitled));
132 
133     return DIALOG_StringMsgBox(Globals.hMainWnd, STRING_NOTSAVED,
134                                szFileName[0] ? szFileName : szUntitled,
135                                MB_ICONQUESTION | MB_YESNOCANCEL);
136 }
137 
138 static void AlertPrintError(void)
139 {
140     TCHAR szUntitled[MAX_STRING_LEN];
141 
142     LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, ARRAY_SIZE(szUntitled));
143 
144     DIALOG_StringMsgBox(Globals.hMainWnd, STRING_PRINTERROR,
145                         Globals.szFileName[0] ? Globals.szFileName : szUntitled,
146                         MB_ICONEXCLAMATION | MB_OK);
147 }
148 
149 /**
150  * Returns:
151  *   TRUE  - if file exists
152  *   FALSE - if file does not exist
153  */
154 BOOL FileExists(LPCTSTR szFilename)
155 {
156     WIN32_FIND_DATA entry;
157     HANDLE hFile;
158 
159     hFile = FindFirstFile(szFilename, &entry);
160     FindClose(hFile);
161 
162     return (hFile != INVALID_HANDLE_VALUE);
163 }
164 
165 BOOL HasFileExtension(LPCTSTR szFilename)
166 {
167     LPCTSTR s;
168 
169     s = _tcsrchr(szFilename, _T('\\'));
170     if (s)
171         szFilename = s;
172     return _tcsrchr(szFilename, _T('.')) != NULL;
173 }
174 
175 int GetSelectionTextLength(HWND hWnd)
176 {
177     DWORD dwStart = 0;
178     DWORD dwEnd = 0;
179 
180     SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
181 
182     return dwEnd - dwStart;
183 }
184 
185 int GetSelectionText(HWND hWnd, LPTSTR lpString, int nMaxCount)
186 {
187     DWORD dwStart = 0;
188     DWORD dwEnd = 0;
189     DWORD dwSize;
190     HRESULT hResult;
191     LPTSTR lpTemp;
192 
193     if (!lpString)
194     {
195         return 0;
196     }
197 
198     SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
199 
200     if (dwStart == dwEnd)
201     {
202         return 0;
203     }
204 
205     dwSize = GetWindowTextLength(hWnd) + 1;
206     lpTemp = HeapAlloc(GetProcessHeap(), 0, dwSize * sizeof(TCHAR));
207     if (!lpTemp)
208     {
209         return 0;
210     }
211 
212     dwSize = GetWindowText(hWnd, lpTemp, dwSize);
213 
214     if (!dwSize)
215     {
216         HeapFree(GetProcessHeap(), 0, lpTemp);
217         return 0;
218     }
219 
220     hResult = StringCchCopyN(lpString, nMaxCount, lpTemp + dwStart, dwEnd - dwStart);
221     HeapFree(GetProcessHeap(), 0, lpTemp);
222 
223     switch (hResult)
224     {
225         case S_OK:
226         {
227             return dwEnd - dwStart;
228         }
229 
230         case STRSAFE_E_INSUFFICIENT_BUFFER:
231         {
232             return nMaxCount - 1;
233         }
234 
235         default:
236         {
237             return 0;
238         }
239     }
240 }
241 
242 static RECT
243 GetPrintingRect(HDC hdc, RECT margins)
244 {
245     int iLogPixelsX, iLogPixelsY;
246     int iHorzRes, iVertRes;
247     int iPhysPageX, iPhysPageY, iPhysPageW, iPhysPageH;
248     RECT rcPrintRect;
249 
250     iPhysPageX = GetDeviceCaps(hdc, PHYSICALOFFSETX);
251     iPhysPageY = GetDeviceCaps(hdc, PHYSICALOFFSETY);
252     iPhysPageW = GetDeviceCaps(hdc, PHYSICALWIDTH);
253     iPhysPageH = GetDeviceCaps(hdc, PHYSICALHEIGHT);
254     iLogPixelsX = GetDeviceCaps(hdc, LOGPIXELSX);
255     iLogPixelsY = GetDeviceCaps(hdc, LOGPIXELSY);
256     iHorzRes = GetDeviceCaps(hdc, HORZRES);
257     iVertRes = GetDeviceCaps(hdc, VERTRES);
258 
259     rcPrintRect.left = (margins.left * iLogPixelsX / 2540) - iPhysPageX;
260     rcPrintRect.top = (margins.top * iLogPixelsY / 2540) - iPhysPageY;
261     rcPrintRect.right = iHorzRes - (((margins.left * iLogPixelsX / 2540) - iPhysPageX) + ((margins.right * iLogPixelsX / 2540) - (iPhysPageW - iPhysPageX - iHorzRes)));
262     rcPrintRect.bottom = iVertRes - (((margins.top * iLogPixelsY / 2540) - iPhysPageY) + ((margins.bottom * iLogPixelsY / 2540) - (iPhysPageH - iPhysPageY - iVertRes)));
263 
264     return rcPrintRect;
265 }
266 
267 static BOOL DoSaveFile(VOID)
268 {
269     BOOL bRet = TRUE;
270     HANDLE hFile;
271     LPTSTR pTemp;
272     DWORD size;
273 
274     hFile = CreateFile(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
275                        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
276     if(hFile == INVALID_HANDLE_VALUE)
277     {
278         ShowLastError();
279         return FALSE;
280     }
281 
282     size = GetWindowTextLength(Globals.hEdit) + 1;
283     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*pTemp));
284     if (!pTemp)
285     {
286         CloseHandle(hFile);
287         ShowLastError();
288         return FALSE;
289     }
290     size = GetWindowText(Globals.hEdit, pTemp, size);
291 
292     if (size)
293     {
294         if (!WriteText(hFile, (LPWSTR)pTemp, size, Globals.encFile, Globals.iEoln))
295         {
296             ShowLastError();
297             bRet = FALSE;
298         }
299         else
300         {
301             SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
302             bRet = TRUE;
303         }
304     }
305 
306     CloseHandle(hFile);
307     HeapFree(GetProcessHeap(), 0, pTemp);
308 
309     if (bRet)
310     {
311         SetFileName(Globals.szFileName);
312     }
313 
314     return bRet;
315 }
316 
317 /**
318  * Returns:
319  *   TRUE  - User agreed to close (both save/don't save)
320  *   FALSE - User cancelled close by selecting "Cancel"
321  */
322 BOOL DoCloseFile(VOID)
323 {
324     int nResult;
325 
326     if (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0))
327     {
328         /* prompt user to save changes */
329         nResult = AlertFileNotSaved(Globals.szFileName);
330         switch (nResult)
331         {
332             case IDYES:
333                 if(!DIALOG_FileSave())
334                     return FALSE;
335                 break;
336 
337             case IDNO:
338                 break;
339 
340             case IDCANCEL:
341                 return FALSE;
342 
343             default:
344                 return FALSE;
345         }
346     }
347 
348     SetFileName(empty_str);
349     UpdateWindowCaption(TRUE);
350 
351     return TRUE;
352 }
353 
354 VOID DoOpenFile(LPCTSTR szFileName)
355 {
356     static const TCHAR dotlog[] = _T(".LOG");
357     HANDLE hFile;
358     LPTSTR pszText = NULL;
359     DWORD dwTextLen;
360     TCHAR log[5];
361 
362     /* Close any files and prompt to save changes */
363     if (!DoCloseFile())
364         return;
365 
366     hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
367                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
368     if (hFile == INVALID_HANDLE_VALUE)
369     {
370         ShowLastError();
371         goto done;
372     }
373 
374     if (!ReadText(hFile, (LPWSTR *)&pszText, &dwTextLen, &Globals.encFile, &Globals.iEoln))
375     {
376         ShowLastError();
377         goto done;
378     }
379     SetWindowText(Globals.hEdit, pszText);
380 
381     SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
382     SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
383     SetFocus(Globals.hEdit);
384 
385     /*  If the file starts with .LOG, add a time/date at the end and set cursor after
386      *  See http://support.microsoft.com/?kbid=260563
387      */
388     if (GetWindowText(Globals.hEdit, log, ARRAY_SIZE(log)) && !_tcscmp(log, dotlog))
389     {
390         static const TCHAR lf[] = _T("\r\n");
391         SendMessage(Globals.hEdit, EM_SETSEL, GetWindowTextLength(Globals.hEdit), -1);
392         SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lf);
393         DIALOG_EditTimeDate();
394         SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lf);
395     }
396 
397     SetFileName(szFileName);
398     UpdateWindowCaption(TRUE);
399     NOTEPAD_EnableSearchMenu();
400 done:
401     if (hFile != INVALID_HANDLE_VALUE)
402         CloseHandle(hFile);
403     if (pszText)
404         HeapFree(GetProcessHeap(), 0, pszText);
405 }
406 
407 VOID DIALOG_FileNew(VOID)
408 {
409     /* Close any files and prompt to save changes */
410     if (DoCloseFile()) {
411         SetWindowText(Globals.hEdit, empty_str);
412         SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
413         SetFocus(Globals.hEdit);
414         NOTEPAD_EnableSearchMenu();
415     }
416 }
417 
418 VOID DIALOG_FileNewWindow(VOID)
419 {
420     TCHAR pszNotepadExe[MAX_PATH];
421     GetModuleFileName(NULL, pszNotepadExe, ARRAYSIZE(pszNotepadExe));
422     ShellExecute(NULL, NULL, pszNotepadExe, NULL, NULL, SW_SHOWNORMAL);
423 }
424 
425 VOID DIALOG_FileOpen(VOID)
426 {
427     OPENFILENAME openfilename;
428     TCHAR szPath[MAX_PATH];
429 
430     ZeroMemory(&openfilename, sizeof(openfilename));
431 
432     if (Globals.szFileName[0] == 0)
433         _tcscpy(szPath, txt_files);
434     else
435         _tcscpy(szPath, Globals.szFileName);
436 
437     openfilename.lStructSize = sizeof(openfilename);
438     openfilename.hwndOwner = Globals.hMainWnd;
439     openfilename.hInstance = Globals.hInstance;
440     openfilename.lpstrFilter = Globals.szFilter;
441     openfilename.lpstrFile = szPath;
442     openfilename.nMaxFile = ARRAY_SIZE(szPath);
443     openfilename.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
444     openfilename.lpstrDefExt = szDefaultExt;
445 
446     if (GetOpenFileName(&openfilename)) {
447         if (FileExists(openfilename.lpstrFile))
448             DoOpenFile(openfilename.lpstrFile);
449         else
450             AlertFileNotFound(openfilename.lpstrFile);
451     }
452 }
453 
454 BOOL DIALOG_FileSave(VOID)
455 {
456     if (Globals.szFileName[0] == 0)
457     {
458         return DIALOG_FileSaveAs();
459     }
460     else if (DoSaveFile())
461     {
462         UpdateWindowCaption(TRUE);
463         return TRUE;
464     }
465     return FALSE;
466 }
467 
468 static UINT_PTR
469 CALLBACK
470 DIALOG_FileSaveAs_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
471 {
472     TCHAR szText[128];
473     HWND hCombo;
474 
475     UNREFERENCED_PARAMETER(wParam);
476 
477     switch(msg)
478     {
479         case WM_INITDIALOG:
480             hCombo = GetDlgItem(hDlg, ID_ENCODING);
481 
482             LoadString(Globals.hInstance, STRING_ANSI, szText, ARRAY_SIZE(szText));
483             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
484 
485             LoadString(Globals.hInstance, STRING_UNICODE, szText, ARRAY_SIZE(szText));
486             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
487 
488             LoadString(Globals.hInstance, STRING_UNICODE_BE, szText, ARRAY_SIZE(szText));
489             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
490 
491             LoadString(Globals.hInstance, STRING_UTF8, szText, ARRAY_SIZE(szText));
492             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
493 
494             SendMessage(hCombo, CB_SETCURSEL, Globals.encFile, 0);
495 
496             hCombo = GetDlgItem(hDlg, ID_EOLN);
497 
498             LoadString(Globals.hInstance, STRING_CRLF, szText, ARRAY_SIZE(szText));
499             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
500 
501             LoadString(Globals.hInstance, STRING_LF, szText, ARRAY_SIZE(szText));
502             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
503 
504             LoadString(Globals.hInstance, STRING_CR, szText, ARRAY_SIZE(szText));
505             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
506 
507             SendMessage(hCombo, CB_SETCURSEL, Globals.iEoln, 0);
508             break;
509 
510         case WM_NOTIFY:
511             if (((NMHDR *) lParam)->code == CDN_FILEOK)
512             {
513                 hCombo = GetDlgItem(hDlg, ID_ENCODING);
514                 if (hCombo)
515                     Globals.encFile = (ENCODING) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
516 
517                 hCombo = GetDlgItem(hDlg, ID_EOLN);
518                 if (hCombo)
519                     Globals.iEoln = (int) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
520             }
521             break;
522     }
523     return 0;
524 }
525 
526 BOOL DIALOG_FileSaveAs(VOID)
527 {
528     OPENFILENAME saveas;
529     TCHAR szPath[MAX_PATH];
530 
531     ZeroMemory(&saveas, sizeof(saveas));
532 
533     if (Globals.szFileName[0] == 0)
534         _tcscpy(szPath, txt_files);
535     else
536         _tcscpy(szPath, Globals.szFileName);
537 
538     saveas.lStructSize = sizeof(OPENFILENAME);
539     saveas.hwndOwner = Globals.hMainWnd;
540     saveas.hInstance = Globals.hInstance;
541     saveas.lpstrFilter = Globals.szFilter;
542     saveas.lpstrFile = szPath;
543     saveas.nMaxFile = ARRAY_SIZE(szPath);
544     saveas.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
545                    OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
546     saveas.lpstrDefExt = szDefaultExt;
547     saveas.lpTemplateName = MAKEINTRESOURCE(DIALOG_ENCODING);
548     saveas.lpfnHook = DIALOG_FileSaveAs_Hook;
549 
550     if (GetSaveFileName(&saveas))
551     {
552         /* HACK: Because in ROS, Save-As boxes don't check the validity
553          * of file names and thus, here, szPath can be invalid !! We only
554          * see its validity when we call DoSaveFile()... */
555         SetFileName(szPath);
556         if (DoSaveFile())
557         {
558             UpdateWindowCaption(TRUE);
559             return TRUE;
560         }
561         else
562         {
563             SetFileName(_T(""));
564             return FALSE;
565         }
566     }
567     else
568     {
569         return FALSE;
570     }
571 }
572 
573 VOID DIALOG_FilePrint(VOID)
574 {
575     DOCINFO di;
576     TEXTMETRIC tm;
577     PRINTDLG printer;
578     SIZE szMetric;
579     int border;
580     int xLeft, yTop, pagecount, dopage, copycount;
581     unsigned int i;
582     LOGFONT hdrFont;
583     HFONT font, old_font=0;
584     DWORD size;
585     LPTSTR pTemp;
586     static const TCHAR times_new_roman[] = _T("Times New Roman");
587     RECT rcPrintRect;
588 
589     /* Get a small font and print some header info on each page */
590     ZeroMemory(&hdrFont, sizeof(hdrFont));
591     hdrFont.lfHeight = 100;
592     hdrFont.lfWeight = FW_BOLD;
593     hdrFont.lfCharSet = ANSI_CHARSET;
594     hdrFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
595     hdrFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
596     hdrFont.lfQuality = PROOF_QUALITY;
597     hdrFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
598     _tcscpy(hdrFont.lfFaceName, times_new_roman);
599 
600     font = CreateFontIndirect(&hdrFont);
601 
602     /* Get Current Settings */
603     ZeroMemory(&printer, sizeof(printer));
604     printer.lStructSize = sizeof(printer);
605     printer.hwndOwner = Globals.hMainWnd;
606     printer.hInstance = Globals.hInstance;
607 
608     /* Set some default flags */
609     printer.Flags = PD_RETURNDC | PD_SELECTION;
610 
611     /* Disable the selection radio button if there is no text selected */
612     if (!GetSelectionTextLength(Globals.hEdit))
613     {
614         printer.Flags = printer.Flags | PD_NOSELECTION;
615     }
616 
617     printer.nFromPage = 0;
618     printer.nMinPage = 1;
619     /* we really need to calculate number of pages to set nMaxPage and nToPage */
620     printer.nToPage = (WORD)-1;
621     printer.nMaxPage = (WORD)-1;
622 
623     /* Let commdlg manage copy settings */
624     printer.nCopies = (WORD)PD_USEDEVMODECOPIES;
625 
626     printer.hDevMode = Globals.hDevMode;
627     printer.hDevNames = Globals.hDevNames;
628 
629     if (!PrintDlg(&printer))
630     {
631         DeleteObject(font);
632         return;
633     }
634 
635     Globals.hDevMode = printer.hDevMode;
636     Globals.hDevNames = printer.hDevNames;
637 
638     assert(printer.hDC != 0);
639 
640     /* initialize DOCINFO */
641     di.cbSize = sizeof(DOCINFO);
642     di.lpszDocName = Globals.szFileTitle;
643     di.lpszOutput = NULL;
644     di.lpszDatatype = NULL;
645     di.fwType = 0;
646 
647     if (StartDoc(printer.hDC, &di) <= 0)
648     {
649         DeleteObject(font);
650         return;
651     }
652 
653 
654     /* Get the file text */
655     if (printer.Flags & PD_SELECTION)
656     {
657         size = GetSelectionTextLength(Globals.hEdit) + 1;
658     }
659     else
660     {
661         size = GetWindowTextLength(Globals.hEdit) + 1;
662     }
663 
664     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(TCHAR));
665     if (!pTemp)
666     {
667         EndDoc(printer.hDC);
668         DeleteObject(font);
669         ShowLastError();
670         return;
671     }
672 
673     if (printer.Flags & PD_SELECTION)
674     {
675         size = GetSelectionText(Globals.hEdit, pTemp, size);
676     }
677     else
678     {
679         size = GetWindowText(Globals.hEdit, pTemp, size);
680     }
681 
682     /* Get the current printing area */
683     rcPrintRect = GetPrintingRect(printer.hDC, Globals.lMargins);
684 
685     /* Ensure that each logical unit maps to one pixel */
686     SetMapMode(printer.hDC, MM_TEXT);
687 
688     /* Needed to get the correct height of a text line */
689     GetTextMetrics(printer.hDC, &tm);
690 
691     border = 15;
692     for (copycount=1; copycount <= printer.nCopies; copycount++) {
693         i = 0;
694         pagecount = 1;
695         do {
696             /* Don't start a page if none of the conditions below are true */
697             dopage = 0;
698 
699             /* The user wants to print the current selection */
700             if (printer.Flags & PD_SELECTION)
701             {
702                 dopage = 1;
703             }
704 
705             /* The user wants to print the entire document */
706             if (!(printer.Flags & PD_PAGENUMS) && !(printer.Flags & PD_SELECTION))
707             {
708                 dopage = 1;
709             }
710 
711             /* The user wants to print a specified range of pages */
712             if ((pagecount >= printer.nFromPage && pagecount <= printer.nToPage))
713             {
714                 dopage = 1;
715             }
716 
717             old_font = SelectObject(printer.hDC, font);
718 
719             if (dopage) {
720                 if (StartPage(printer.hDC) <= 0) {
721                     SelectObject(printer.hDC, old_font);
722                     EndDoc(printer.hDC);
723                     DeleteDC(printer.hDC);
724                     HeapFree(GetProcessHeap(), 0, pTemp);
725                     DeleteObject(font);
726                     AlertPrintError();
727                     return;
728                 }
729 
730                 SetViewportOrgEx(printer.hDC, rcPrintRect.left, rcPrintRect.top, NULL);
731 
732                 /* Write a rectangle and header at the top of each page */
733                 Rectangle(printer.hDC, border, border, rcPrintRect.right - border, border + tm.tmHeight * 2);
734                 /* I don't know what's up with this TextOut command. This comes out
735                 kind of mangled.
736                 */
737                 TextOut(printer.hDC,
738                         border * 2,
739                         border + tm.tmHeight / 2,
740                         Globals.szFileTitle,
741                         lstrlen(Globals.szFileTitle));
742             }
743 
744             /* The starting point for the main text */
745             xLeft = 0;
746             yTop = border + tm.tmHeight * 4;
747 
748             SelectObject(printer.hDC, old_font);
749 
750             /* Since outputting strings is giving me problems, output the main
751              * text one character at a time. */
752             do {
753                 if (pTemp[i] == '\n') {
754                     xLeft = 0;
755                     yTop += tm.tmHeight;
756                 }
757                 else if (pTemp[i] != '\r') {
758                     if (dopage)
759                         TextOut(printer.hDC, xLeft, yTop, &pTemp[i], 1);
760 
761                     /* We need to get the width for each individual char, since a proportional font may be used */
762                     GetTextExtentPoint32(printer.hDC, &pTemp[i], 1, &szMetric);
763                     xLeft += szMetric.cx;
764 
765                     /* Insert a line break if the current line does not fit into the printing area */
766                     if (xLeft > rcPrintRect.right)
767                     {
768                         xLeft = 0;
769                         yTop = yTop + tm.tmHeight;
770                     }
771                 }
772             } while (i++ < size && yTop < rcPrintRect.bottom);
773 
774             if (dopage)
775                 EndPage(printer.hDC);
776             pagecount++;
777         } while (i < size);
778     }
779 
780     if (old_font != 0)
781         SelectObject(printer.hDC, old_font);
782     EndDoc(printer.hDC);
783     DeleteDC(printer.hDC);
784     HeapFree(GetProcessHeap(), 0, pTemp);
785     DeleteObject(font);
786 }
787 
788 VOID DIALOG_FileExit(VOID)
789 {
790     PostMessage(Globals.hMainWnd, WM_CLOSE, 0, 0l);
791 }
792 
793 VOID DIALOG_EditUndo(VOID)
794 {
795     SendMessage(Globals.hEdit, EM_UNDO, 0, 0);
796 }
797 
798 VOID DIALOG_EditCut(VOID)
799 {
800     SendMessage(Globals.hEdit, WM_CUT, 0, 0);
801 }
802 
803 VOID DIALOG_EditCopy(VOID)
804 {
805     SendMessage(Globals.hEdit, WM_COPY, 0, 0);
806 }
807 
808 VOID DIALOG_EditPaste(VOID)
809 {
810     SendMessage(Globals.hEdit, WM_PASTE, 0, 0);
811 }
812 
813 VOID DIALOG_EditDelete(VOID)
814 {
815     SendMessage(Globals.hEdit, WM_CLEAR, 0, 0);
816 }
817 
818 VOID DIALOG_EditSelectAll(VOID)
819 {
820     SendMessage(Globals.hEdit, EM_SETSEL, 0, (LPARAM)-1);
821 }
822 
823 VOID DIALOG_EditTimeDate(VOID)
824 {
825     SYSTEMTIME st;
826     TCHAR szDate[MAX_STRING_LEN];
827     TCHAR szText[MAX_STRING_LEN * 2 + 2];
828 
829     GetLocalTime(&st);
830 
831     GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
832     _tcscpy(szText, szDate);
833     _tcscat(szText, _T(" "));
834     GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, MAX_STRING_LEN);
835     _tcscat(szText, szDate);
836     SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szText);
837 }
838 
839 VOID DoCreateStatusBar(VOID)
840 {
841     RECT rc;
842     RECT rcstatus;
843     BOOL bStatusBarVisible;
844 
845     /* Check if status bar object already exists. */
846     if (Globals.hStatusBar == NULL)
847     {
848         /* Try to create the status bar */
849         Globals.hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_EX_STATICEDGE,
850                                                 NULL,
851                                                 Globals.hMainWnd,
852                                                 CMD_STATUSBAR_WND_ID);
853 
854         if (Globals.hStatusBar == NULL)
855         {
856             ShowLastError();
857             return;
858         }
859 
860         /* Load the string for formatting column/row text output */
861         LoadString(Globals.hInstance, STRING_LINE_COLUMN, Globals.szStatusBarLineCol, MAX_PATH - 1);
862 
863         /* Set the status bar for single-text output */
864         SendMessage(Globals.hStatusBar, SB_SIMPLE, (WPARAM)TRUE, (LPARAM)0);
865     }
866 
867     /* Set status bar visiblity according to the settings. */
868     if ((Globals.bWrapLongLines != FALSE) || (Globals.bShowStatusBar == FALSE))
869     {
870         bStatusBarVisible = FALSE;
871         ShowWindow(Globals.hStatusBar, SW_HIDE);
872     }
873     else
874     {
875         bStatusBarVisible = TRUE;
876         ShowWindow(Globals.hStatusBar, SW_SHOW);
877         SendMessage(Globals.hStatusBar, WM_SIZE, 0, 0);
878     }
879 
880     /* Set check state in show status bar item. */
881     if (bStatusBarVisible)
882     {
883         CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_CHECKED);
884     }
885     else
886     {
887         CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_UNCHECKED);
888     }
889 
890     /* Update menu mar with the previous changes */
891     DrawMenuBar(Globals.hMainWnd);
892 
893     /* Sefety test is edit control exists */
894     if (Globals.hEdit != NULL)
895     {
896         /* Retrieve the sizes of the controls */
897         GetClientRect(Globals.hMainWnd, &rc);
898         GetClientRect(Globals.hStatusBar, &rcstatus);
899 
900         /* If status bar is currently visible, update dimensions of edit control */
901         if (bStatusBarVisible)
902             rc.bottom -= (rcstatus.bottom - rcstatus.top);
903 
904         /* Resize edit control to right size. */
905         MoveWindow(Globals.hEdit,
906                    rc.left,
907                    rc.top,
908                    rc.right - rc.left,
909                    rc.bottom - rc.top,
910                    TRUE);
911     }
912 
913     /* Update content with current row/column text */
914     DIALOG_StatusBarUpdateCaretPos();
915 }
916 
917 VOID DoCreateEditWindow(VOID)
918 {
919     DWORD dwStyle;
920     int iSize;
921     LPTSTR pTemp = NULL;
922     BOOL bModified = FALSE;
923 
924     iSize = 0;
925 
926     /* If the edit control already exists, try to save its content */
927     if (Globals.hEdit != NULL)
928     {
929         /* number of chars currently written into the editor. */
930         iSize = GetWindowTextLength(Globals.hEdit);
931         if (iSize)
932         {
933             /* Allocates temporary buffer. */
934             pTemp = HeapAlloc(GetProcessHeap(), 0, (iSize + 1) * sizeof(TCHAR));
935             if (!pTemp)
936             {
937                 ShowLastError();
938                 return;
939             }
940 
941             /* Recover the text into the control. */
942             GetWindowText(Globals.hEdit, pTemp, iSize + 1);
943 
944             if (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0))
945                 bModified = TRUE;
946         }
947 
948         /* Restore original window procedure */
949         SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)Globals.EditProc);
950 
951         /* Destroy the edit control */
952         DestroyWindow(Globals.hEdit);
953     }
954 
955     /* Update wrap status into the main menu and recover style flags */
956     if (Globals.bWrapLongLines)
957     {
958         dwStyle = EDIT_STYLE_WRAP;
959         EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
960     } else {
961         dwStyle = EDIT_STYLE;
962         EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_ENABLED);
963     }
964 
965     /* Update previous changes */
966     DrawMenuBar(Globals.hMainWnd);
967 
968     /* Create the new edit control */
969     Globals.hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
970                                    EDIT_CLASS,
971                                    NULL,
972                                    dwStyle,
973                                    CW_USEDEFAULT,
974                                    CW_USEDEFAULT,
975                                    CW_USEDEFAULT,
976                                    CW_USEDEFAULT,
977                                    Globals.hMainWnd,
978                                    NULL,
979                                    Globals.hInstance,
980                                    NULL);
981 
982     if (Globals.hEdit == NULL)
983     {
984         if (pTemp)
985         {
986             HeapFree(GetProcessHeap(), 0, pTemp);
987         }
988 
989         ShowLastError();
990         return;
991     }
992 
993     SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
994     SendMessage(Globals.hEdit, EM_LIMITTEXT, 0, 0);
995 
996     /* If some text was previously saved, restore it. */
997     if (iSize != 0)
998     {
999         SetWindowText(Globals.hEdit, pTemp);
1000         HeapFree(GetProcessHeap(), 0, pTemp);
1001 
1002         if (bModified)
1003             SendMessage(Globals.hEdit, EM_SETMODIFY, TRUE, 0);
1004     }
1005 
1006     /* Sub-class a new window callback for row/column detection. */
1007     Globals.EditProc = (WNDPROC)SetWindowLongPtr(Globals.hEdit,
1008                                                  GWLP_WNDPROC,
1009                                                  (LONG_PTR)EDIT_WndProc);
1010 
1011     /* Create/update status bar */
1012     DoCreateStatusBar();
1013 
1014     /* Finally shows new edit control and set focus into it. */
1015     ShowWindow(Globals.hEdit, SW_SHOW);
1016     SetFocus(Globals.hEdit);
1017 }
1018 
1019 VOID DIALOG_EditWrap(VOID)
1020 {
1021     Globals.bWrapLongLines = !Globals.bWrapLongLines;
1022 
1023     if (Globals.bWrapLongLines)
1024     {
1025         EnableMenuItem(Globals.hMenu, CMD_GOTO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1026     }
1027     else
1028     {
1029         EnableMenuItem(Globals.hMenu, CMD_GOTO, MF_BYCOMMAND | MF_ENABLED);
1030     }
1031 
1032     DoCreateEditWindow();
1033 }
1034 
1035 VOID DIALOG_SelectFont(VOID)
1036 {
1037     CHOOSEFONT cf;
1038     LOGFONT lf = Globals.lfFont;
1039 
1040     ZeroMemory( &cf, sizeof(cf) );
1041     cf.lStructSize = sizeof(cf);
1042     cf.hwndOwner = Globals.hMainWnd;
1043     cf.lpLogFont = &lf;
1044     cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_NOVERTFONTS;
1045 
1046     if (ChooseFont(&cf))
1047     {
1048         HFONT currfont = Globals.hFont;
1049 
1050         Globals.hFont = CreateFontIndirect(&lf);
1051         Globals.lfFont = lf;
1052         SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)TRUE);
1053         if (currfont != NULL)
1054             DeleteObject(currfont);
1055     }
1056 }
1057 
1058 typedef HWND (WINAPI *FINDPROC)(LPFINDREPLACE lpfr);
1059 
1060 static VOID DIALOG_SearchDialog(FINDPROC pfnProc)
1061 {
1062     if (Globals.hFindReplaceDlg != NULL)
1063     {
1064         SetFocus(Globals.hFindReplaceDlg);
1065         return;
1066     }
1067 
1068     ZeroMemory(&Globals.find, sizeof(Globals.find));
1069     Globals.find.lStructSize = sizeof(Globals.find);
1070     Globals.find.hwndOwner = Globals.hMainWnd;
1071     Globals.find.hInstance = Globals.hInstance;
1072     Globals.find.lpstrFindWhat = Globals.szFindText;
1073     Globals.find.wFindWhatLen = ARRAY_SIZE(Globals.szFindText);
1074     Globals.find.lpstrReplaceWith = Globals.szReplaceText;
1075     Globals.find.wReplaceWithLen = ARRAY_SIZE(Globals.szReplaceText);
1076     Globals.find.Flags = FR_DOWN;
1077 
1078     /* We only need to create the modal FindReplace dialog which will */
1079     /* notify us of incoming events using hMainWnd Window Messages    */
1080 
1081     Globals.hFindReplaceDlg = pfnProc(&Globals.find);
1082     assert(Globals.hFindReplaceDlg != NULL);
1083 }
1084 
1085 VOID DIALOG_Search(VOID)
1086 {
1087     DIALOG_SearchDialog(FindText);
1088 }
1089 
1090 VOID DIALOG_SearchNext(VOID)
1091 {
1092     if (Globals.find.lpstrFindWhat != NULL)
1093         NOTEPAD_FindNext(&Globals.find, FALSE, TRUE);
1094     else
1095         DIALOG_Search();
1096 }
1097 
1098 VOID DIALOG_Replace(VOID)
1099 {
1100     DIALOG_SearchDialog(ReplaceText);
1101 }
1102 
1103 static INT_PTR
1104 CALLBACK
1105 DIALOG_GoTo_DialogProc(HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
1106 {
1107     BOOL bResult = FALSE;
1108     HWND hTextBox;
1109     TCHAR szText[32];
1110 
1111     switch(uMsg) {
1112     case WM_INITDIALOG:
1113         hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
1114         _sntprintf(szText, ARRAY_SIZE(szText), _T("%Id"), lParam);
1115         SetWindowText(hTextBox, szText);
1116         break;
1117     case WM_COMMAND:
1118         if (HIWORD(wParam) == BN_CLICKED)
1119         {
1120             if (LOWORD(wParam) == IDOK)
1121             {
1122                 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
1123                 GetWindowText(hTextBox, szText, ARRAY_SIZE(szText));
1124                 EndDialog(hwndDialog, _ttoi(szText));
1125                 bResult = TRUE;
1126             }
1127             else if (LOWORD(wParam) == IDCANCEL)
1128             {
1129                 EndDialog(hwndDialog, 0);
1130                 bResult = TRUE;
1131             }
1132         }
1133         break;
1134     }
1135 
1136     return bResult;
1137 }
1138 
1139 VOID DIALOG_GoTo(VOID)
1140 {
1141     INT_PTR nLine;
1142     LPTSTR pszText;
1143     int nLength, i;
1144     DWORD dwStart, dwEnd;
1145 
1146     nLength = GetWindowTextLength(Globals.hEdit);
1147     pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(*pszText));
1148     if (!pszText)
1149         return;
1150 
1151     /* Retrieve current text */
1152     GetWindowText(Globals.hEdit, pszText, nLength + 1);
1153     SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwStart, (LPARAM) &dwEnd);
1154 
1155     nLine = 1;
1156     for (i = 0; (i < (int) dwStart) && pszText[i]; i++)
1157     {
1158         if (pszText[i] == '\n')
1159             nLine++;
1160     }
1161 
1162     nLine = DialogBoxParam(Globals.hInstance,
1163                            MAKEINTRESOURCE(DIALOG_GOTO),
1164                            Globals.hMainWnd,
1165                            DIALOG_GoTo_DialogProc,
1166                            nLine);
1167 
1168     if (nLine >= 1)
1169     {
1170         for (i = 0; pszText[i] && (nLine > 1) && (i < nLength - 1); i++)
1171         {
1172             if (pszText[i] == '\n')
1173                 nLine--;
1174         }
1175         SendMessage(Globals.hEdit, EM_SETSEL, i, i);
1176         SendMessage(Globals.hEdit, EM_SCROLLCARET, 0, 0);
1177     }
1178     HeapFree(GetProcessHeap(), 0, pszText);
1179 }
1180 
1181 VOID DIALOG_StatusBarUpdateCaretPos(VOID)
1182 {
1183     int line, col;
1184     TCHAR buff[MAX_PATH];
1185     DWORD dwStart, dwSize;
1186 
1187     SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwSize);
1188     line = SendMessage(Globals.hEdit, EM_LINEFROMCHAR, (WPARAM)dwStart, 0);
1189     col = dwStart - SendMessage(Globals.hEdit, EM_LINEINDEX, (WPARAM)line, 0);
1190 
1191     _stprintf(buff, Globals.szStatusBarLineCol, line + 1, col + 1);
1192     SendMessage(Globals.hStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)buff);
1193 }
1194 
1195 VOID DIALOG_ViewStatusBar(VOID)
1196 {
1197     Globals.bShowStatusBar = !Globals.bShowStatusBar;
1198 
1199     DoCreateStatusBar();
1200 }
1201 
1202 VOID DIALOG_HelpContents(VOID)
1203 {
1204     WinHelp(Globals.hMainWnd, helpfile, HELP_INDEX, 0);
1205 }
1206 
1207 VOID DIALOG_HelpAboutNotepad(VOID)
1208 {
1209     TCHAR szNotepad[MAX_STRING_LEN];
1210     TCHAR szNotepadAuthors[MAX_STRING_LEN];
1211 
1212     HICON notepadIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_NPICON));
1213 
1214     LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
1215     LoadString(Globals.hInstance, STRING_NOTEPAD_AUTHORS, szNotepadAuthors, ARRAY_SIZE(szNotepadAuthors));
1216 
1217     ShellAbout(Globals.hMainWnd, szNotepad, szNotepadAuthors, notepadIcon);
1218     DeleteObject(notepadIcon);
1219 }
1220 
1221 /***********************************************************************
1222  *
1223  *           DIALOG_FilePageSetup
1224  */
1225 VOID DIALOG_FilePageSetup(void)
1226 {
1227     PAGESETUPDLG page;
1228 
1229     ZeroMemory(&page, sizeof(page));
1230     page.lStructSize = sizeof(page);
1231     page.hwndOwner = Globals.hMainWnd;
1232     page.Flags = PSD_ENABLEPAGESETUPTEMPLATE | PSD_ENABLEPAGESETUPHOOK | PSD_MARGINS;
1233     page.hInstance = Globals.hInstance;
1234     page.rtMargin = Globals.lMargins;
1235     page.hDevMode = Globals.hDevMode;
1236     page.hDevNames = Globals.hDevNames;
1237     page.lpPageSetupTemplateName = MAKEINTRESOURCE(DIALOG_PAGESETUP);
1238     page.lpfnPageSetupHook = DIALOG_PAGESETUP_Hook;
1239 
1240     PageSetupDlg(&page);
1241 
1242     Globals.hDevMode = page.hDevMode;
1243     Globals.hDevNames = page.hDevNames;
1244     Globals.lMargins = page.rtMargin;
1245 }
1246 
1247 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1248  *
1249  *           DIALOG_PAGESETUP_Hook
1250  */
1251 
1252 static UINT_PTR CALLBACK DIALOG_PAGESETUP_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1253 {
1254     switch (msg)
1255     {
1256     case WM_COMMAND:
1257         if (HIWORD(wParam) == BN_CLICKED)
1258         {
1259             switch (LOWORD(wParam))
1260             {
1261             case IDOK:
1262                 /* save user input and close dialog */
1263                 GetDlgItemText(hDlg, 0x141, Globals.szHeader, ARRAY_SIZE(Globals.szHeader));
1264                 GetDlgItemText(hDlg, 0x143, Globals.szFooter, ARRAY_SIZE(Globals.szFooter));
1265                 return FALSE;
1266 
1267             case IDCANCEL:
1268                 /* discard user input and close dialog */
1269                 return FALSE;
1270 
1271             case IDHELP:
1272                 {
1273                     /* FIXME: Bring this to work */
1274                     static const TCHAR sorry[] = _T("Sorry, no help available");
1275                     static const TCHAR help[] = _T("Help");
1276                     MessageBox(Globals.hMainWnd, sorry, help, MB_ICONEXCLAMATION);
1277                     return TRUE;
1278                 }
1279 
1280             default:
1281                 break;
1282             }
1283         }
1284         break;
1285 
1286     case WM_INITDIALOG:
1287         /* fetch last user input prior to display dialog */
1288         SetDlgItemText(hDlg, 0x141, Globals.szHeader);
1289         SetDlgItemText(hDlg, 0x143, Globals.szFooter);
1290         break;
1291     }
1292 
1293     return FALSE;
1294 }
1295