xref: /reactos/base/applications/notepad/dialog.c (revision d8c6ef5e)
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_FileOpen(VOID)
419 {
420     OPENFILENAME openfilename;
421     TCHAR szPath[MAX_PATH];
422 
423     ZeroMemory(&openfilename, sizeof(openfilename));
424 
425     if (Globals.szFileName[0] == 0)
426         _tcscpy(szPath, txt_files);
427     else
428         _tcscpy(szPath, Globals.szFileName);
429 
430     openfilename.lStructSize = sizeof(openfilename);
431     openfilename.hwndOwner = Globals.hMainWnd;
432     openfilename.hInstance = Globals.hInstance;
433     openfilename.lpstrFilter = Globals.szFilter;
434     openfilename.lpstrFile = szPath;
435     openfilename.nMaxFile = ARRAY_SIZE(szPath);
436     openfilename.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
437     openfilename.lpstrDefExt = szDefaultExt;
438 
439     if (GetOpenFileName(&openfilename)) {
440         if (FileExists(openfilename.lpstrFile))
441             DoOpenFile(openfilename.lpstrFile);
442         else
443             AlertFileNotFound(openfilename.lpstrFile);
444     }
445 }
446 
447 BOOL DIALOG_FileSave(VOID)
448 {
449     if (Globals.szFileName[0] == 0)
450     {
451         return DIALOG_FileSaveAs();
452     }
453     else if (DoSaveFile())
454     {
455         UpdateWindowCaption(TRUE);
456         return TRUE;
457     }
458     return FALSE;
459 }
460 
461 static UINT_PTR
462 CALLBACK
463 DIALOG_FileSaveAs_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
464 {
465     TCHAR szText[128];
466     HWND hCombo;
467 
468     UNREFERENCED_PARAMETER(wParam);
469 
470     switch(msg)
471     {
472         case WM_INITDIALOG:
473             hCombo = GetDlgItem(hDlg, ID_ENCODING);
474 
475             LoadString(Globals.hInstance, STRING_ANSI, szText, ARRAY_SIZE(szText));
476             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
477 
478             LoadString(Globals.hInstance, STRING_UNICODE, szText, ARRAY_SIZE(szText));
479             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
480 
481             LoadString(Globals.hInstance, STRING_UNICODE_BE, szText, ARRAY_SIZE(szText));
482             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
483 
484             LoadString(Globals.hInstance, STRING_UTF8, szText, ARRAY_SIZE(szText));
485             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
486 
487             SendMessage(hCombo, CB_SETCURSEL, Globals.encFile, 0);
488 
489             hCombo = GetDlgItem(hDlg, ID_EOLN);
490 
491             LoadString(Globals.hInstance, STRING_CRLF, szText, ARRAY_SIZE(szText));
492             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
493 
494             LoadString(Globals.hInstance, STRING_LF, szText, ARRAY_SIZE(szText));
495             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
496 
497             LoadString(Globals.hInstance, STRING_CR, szText, ARRAY_SIZE(szText));
498             SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
499 
500             SendMessage(hCombo, CB_SETCURSEL, Globals.iEoln, 0);
501             break;
502 
503         case WM_NOTIFY:
504             if (((NMHDR *) lParam)->code == CDN_FILEOK)
505             {
506                 hCombo = GetDlgItem(hDlg, ID_ENCODING);
507                 if (hCombo)
508                     Globals.encFile = (ENCODING) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
509 
510                 hCombo = GetDlgItem(hDlg, ID_EOLN);
511                 if (hCombo)
512                     Globals.iEoln = (int) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
513             }
514             break;
515     }
516     return 0;
517 }
518 
519 BOOL DIALOG_FileSaveAs(VOID)
520 {
521     OPENFILENAME saveas;
522     TCHAR szPath[MAX_PATH];
523 
524     ZeroMemory(&saveas, sizeof(saveas));
525 
526     if (Globals.szFileName[0] == 0)
527         _tcscpy(szPath, txt_files);
528     else
529         _tcscpy(szPath, Globals.szFileName);
530 
531     saveas.lStructSize = sizeof(OPENFILENAME);
532     saveas.hwndOwner = Globals.hMainWnd;
533     saveas.hInstance = Globals.hInstance;
534     saveas.lpstrFilter = Globals.szFilter;
535     saveas.lpstrFile = szPath;
536     saveas.nMaxFile = ARRAY_SIZE(szPath);
537     saveas.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
538                    OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
539     saveas.lpstrDefExt = szDefaultExt;
540     saveas.lpTemplateName = MAKEINTRESOURCE(DIALOG_ENCODING);
541     saveas.lpfnHook = DIALOG_FileSaveAs_Hook;
542 
543     if (GetSaveFileName(&saveas))
544     {
545         /* HACK: Because in ROS, Save-As boxes don't check the validity
546          * of file names and thus, here, szPath can be invalid !! We only
547          * see its validity when we call DoSaveFile()... */
548         SetFileName(szPath);
549         if (DoSaveFile())
550         {
551             UpdateWindowCaption(TRUE);
552             return TRUE;
553         }
554         else
555         {
556             SetFileName(_T(""));
557             return FALSE;
558         }
559     }
560     else
561     {
562         return FALSE;
563     }
564 }
565 
566 VOID DIALOG_FilePrint(VOID)
567 {
568     DOCINFO di;
569     TEXTMETRIC tm;
570     PRINTDLG printer;
571     SIZE szMetric;
572     int border;
573     int xLeft, yTop, pagecount, dopage, copycount;
574     unsigned int i;
575     LOGFONT hdrFont;
576     HFONT font, old_font=0;
577     DWORD size;
578     LPTSTR pTemp;
579     static const TCHAR times_new_roman[] = _T("Times New Roman");
580     RECT rcPrintRect;
581 
582     /* Get a small font and print some header info on each page */
583     ZeroMemory(&hdrFont, sizeof(hdrFont));
584     hdrFont.lfHeight = 100;
585     hdrFont.lfWeight = FW_BOLD;
586     hdrFont.lfCharSet = ANSI_CHARSET;
587     hdrFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
588     hdrFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
589     hdrFont.lfQuality = PROOF_QUALITY;
590     hdrFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
591     _tcscpy(hdrFont.lfFaceName, times_new_roman);
592 
593     font = CreateFontIndirect(&hdrFont);
594 
595     /* Get Current Settings */
596     ZeroMemory(&printer, sizeof(printer));
597     printer.lStructSize = sizeof(printer);
598     printer.hwndOwner = Globals.hMainWnd;
599     printer.hInstance = Globals.hInstance;
600 
601     /* Set some default flags */
602     printer.Flags = PD_RETURNDC | PD_SELECTION;
603 
604     /* Disable the selection radio button if there is no text selected */
605     if (!GetSelectionTextLength(Globals.hEdit))
606     {
607         printer.Flags = printer.Flags | PD_NOSELECTION;
608     }
609 
610     printer.nFromPage = 0;
611     printer.nMinPage = 1;
612     /* we really need to calculate number of pages to set nMaxPage and nToPage */
613     printer.nToPage = (WORD)-1;
614     printer.nMaxPage = (WORD)-1;
615 
616     /* Let commdlg manage copy settings */
617     printer.nCopies = (WORD)PD_USEDEVMODECOPIES;
618 
619     printer.hDevMode = Globals.hDevMode;
620     printer.hDevNames = Globals.hDevNames;
621 
622     if (!PrintDlg(&printer))
623     {
624         DeleteObject(font);
625         return;
626     }
627 
628     Globals.hDevMode = printer.hDevMode;
629     Globals.hDevNames = printer.hDevNames;
630 
631     assert(printer.hDC != 0);
632 
633     /* initialize DOCINFO */
634     di.cbSize = sizeof(DOCINFO);
635     di.lpszDocName = Globals.szFileTitle;
636     di.lpszOutput = NULL;
637     di.lpszDatatype = NULL;
638     di.fwType = 0;
639 
640     if (StartDoc(printer.hDC, &di) <= 0)
641     {
642         DeleteObject(font);
643         return;
644     }
645 
646 
647     /* Get the file text */
648     if (printer.Flags & PD_SELECTION)
649     {
650         size = GetSelectionTextLength(Globals.hEdit) + 1;
651     }
652     else
653     {
654         size = GetWindowTextLength(Globals.hEdit) + 1;
655     }
656 
657     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(TCHAR));
658     if (!pTemp)
659     {
660         EndDoc(printer.hDC);
661         DeleteObject(font);
662         ShowLastError();
663         return;
664     }
665 
666     if (printer.Flags & PD_SELECTION)
667     {
668         size = GetSelectionText(Globals.hEdit, pTemp, size);
669     }
670     else
671     {
672         size = GetWindowText(Globals.hEdit, pTemp, size);
673     }
674 
675     /* Get the current printing area */
676     rcPrintRect = GetPrintingRect(printer.hDC, Globals.lMargins);
677 
678     /* Ensure that each logical unit maps to one pixel */
679     SetMapMode(printer.hDC, MM_TEXT);
680 
681     /* Needed to get the correct height of a text line */
682     GetTextMetrics(printer.hDC, &tm);
683 
684     border = 15;
685     for (copycount=1; copycount <= printer.nCopies; copycount++) {
686         i = 0;
687         pagecount = 1;
688         do {
689             /* Don't start a page if none of the conditions below are true */
690             dopage = 0;
691 
692             /* The user wants to print the current selection */
693             if (printer.Flags & PD_SELECTION)
694             {
695                 dopage = 1;
696             }
697 
698             /* The user wants to print the entire document */
699             if (!(printer.Flags & PD_PAGENUMS) && !(printer.Flags & PD_SELECTION))
700             {
701                 dopage = 1;
702             }
703 
704             /* The user wants to print a specified range of pages */
705             if ((pagecount >= printer.nFromPage && pagecount <= printer.nToPage))
706             {
707                 dopage = 1;
708             }
709 
710             old_font = SelectObject(printer.hDC, font);
711 
712             if (dopage) {
713                 if (StartPage(printer.hDC) <= 0) {
714                     SelectObject(printer.hDC, old_font);
715                     EndDoc(printer.hDC);
716                     DeleteDC(printer.hDC);
717                     HeapFree(GetProcessHeap(), 0, pTemp);
718                     DeleteObject(font);
719                     AlertPrintError();
720                     return;
721                 }
722 
723                 SetViewportOrgEx(printer.hDC, rcPrintRect.left, rcPrintRect.top, NULL);
724 
725                 /* Write a rectangle and header at the top of each page */
726                 Rectangle(printer.hDC, border, border, rcPrintRect.right - border, border + tm.tmHeight * 2);
727                 /* I don't know what's up with this TextOut command. This comes out
728                 kind of mangled.
729                 */
730                 TextOut(printer.hDC,
731                         border * 2,
732                         border + tm.tmHeight / 2,
733                         Globals.szFileTitle,
734                         lstrlen(Globals.szFileTitle));
735             }
736 
737             /* The starting point for the main text */
738             xLeft = 0;
739             yTop = border + tm.tmHeight * 4;
740 
741             SelectObject(printer.hDC, old_font);
742 
743             /* Since outputting strings is giving me problems, output the main
744              * text one character at a time. */
745             do {
746                 if (pTemp[i] == '\n') {
747                     xLeft = 0;
748                     yTop += tm.tmHeight;
749                 }
750                 else if (pTemp[i] != '\r') {
751                     if (dopage)
752                         TextOut(printer.hDC, xLeft, yTop, &pTemp[i], 1);
753 
754                     /* We need to get the width for each individual char, since a proportional font may be used */
755                     GetTextExtentPoint32(printer.hDC, &pTemp[i], 1, &szMetric);
756                     xLeft += szMetric.cx;
757 
758                     /* Insert a line break if the current line does not fit into the printing area */
759                     if (xLeft > rcPrintRect.right)
760                     {
761                         xLeft = 0;
762                         yTop = yTop + tm.tmHeight;
763                     }
764                 }
765             } while (i++ < size && yTop < rcPrintRect.bottom);
766 
767             if (dopage)
768                 EndPage(printer.hDC);
769             pagecount++;
770         } while (i < size);
771     }
772 
773     if (old_font != 0)
774         SelectObject(printer.hDC, old_font);
775     EndDoc(printer.hDC);
776     DeleteDC(printer.hDC);
777     HeapFree(GetProcessHeap(), 0, pTemp);
778     DeleteObject(font);
779 }
780 
781 VOID DIALOG_FileExit(VOID)
782 {
783     PostMessage(Globals.hMainWnd, WM_CLOSE, 0, 0l);
784 }
785 
786 VOID DIALOG_EditUndo(VOID)
787 {
788     SendMessage(Globals.hEdit, EM_UNDO, 0, 0);
789 }
790 
791 VOID DIALOG_EditCut(VOID)
792 {
793     SendMessage(Globals.hEdit, WM_CUT, 0, 0);
794 }
795 
796 VOID DIALOG_EditCopy(VOID)
797 {
798     SendMessage(Globals.hEdit, WM_COPY, 0, 0);
799 }
800 
801 VOID DIALOG_EditPaste(VOID)
802 {
803     SendMessage(Globals.hEdit, WM_PASTE, 0, 0);
804 }
805 
806 VOID DIALOG_EditDelete(VOID)
807 {
808     SendMessage(Globals.hEdit, WM_CLEAR, 0, 0);
809 }
810 
811 VOID DIALOG_EditSelectAll(VOID)
812 {
813     SendMessage(Globals.hEdit, EM_SETSEL, 0, (LPARAM)-1);
814 }
815 
816 VOID DIALOG_EditTimeDate(VOID)
817 {
818     SYSTEMTIME st;
819     TCHAR szDate[MAX_STRING_LEN];
820     TCHAR szText[MAX_STRING_LEN * 2 + 2];
821 
822     GetLocalTime(&st);
823 
824     GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
825     _tcscpy(szText, szDate);
826     _tcscat(szText, _T(" "));
827     GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, MAX_STRING_LEN);
828     _tcscat(szText, szDate);
829     SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szText);
830 }
831 
832 VOID DoCreateStatusBar(VOID)
833 {
834     RECT rc;
835     RECT rcstatus;
836     BOOL bStatusBarVisible;
837 
838     /* Check if status bar object already exists. */
839     if (Globals.hStatusBar == NULL)
840     {
841         /* Try to create the status bar */
842         Globals.hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_EX_STATICEDGE,
843                                                 NULL,
844                                                 Globals.hMainWnd,
845                                                 CMD_STATUSBAR_WND_ID);
846 
847         if (Globals.hStatusBar == NULL)
848         {
849             ShowLastError();
850             return;
851         }
852 
853         /* Load the string for formatting column/row text output */
854         LoadString(Globals.hInstance, STRING_LINE_COLUMN, Globals.szStatusBarLineCol, MAX_PATH - 1);
855 
856         /* Set the status bar for single-text output */
857         SendMessage(Globals.hStatusBar, SB_SIMPLE, (WPARAM)TRUE, (LPARAM)0);
858     }
859 
860     /* Set status bar visiblity according to the settings. */
861     if ((Globals.bWrapLongLines != FALSE) || (Globals.bShowStatusBar == FALSE))
862     {
863         bStatusBarVisible = FALSE;
864         ShowWindow(Globals.hStatusBar, SW_HIDE);
865     }
866     else
867     {
868         bStatusBarVisible = TRUE;
869         ShowWindow(Globals.hStatusBar, SW_SHOW);
870         SendMessage(Globals.hStatusBar, WM_SIZE, 0, 0);
871     }
872 
873     /* Set check state in show status bar item. */
874     if (bStatusBarVisible)
875     {
876         CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_CHECKED);
877     }
878     else
879     {
880         CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_UNCHECKED);
881     }
882 
883     /* Update menu mar with the previous changes */
884     DrawMenuBar(Globals.hMainWnd);
885 
886     /* Sefety test is edit control exists */
887     if (Globals.hEdit != NULL)
888     {
889         /* Retrieve the sizes of the controls */
890         GetClientRect(Globals.hMainWnd, &rc);
891         GetClientRect(Globals.hStatusBar, &rcstatus);
892 
893         /* If status bar is currently visible, update dimensions of edit control */
894         if (bStatusBarVisible)
895             rc.bottom -= (rcstatus.bottom - rcstatus.top);
896 
897         /* Resize edit control to right size. */
898         MoveWindow(Globals.hEdit,
899                    rc.left,
900                    rc.top,
901                    rc.right - rc.left,
902                    rc.bottom - rc.top,
903                    TRUE);
904     }
905 
906     /* Update content with current row/column text */
907     DIALOG_StatusBarUpdateCaretPos();
908 }
909 
910 VOID DoCreateEditWindow(VOID)
911 {
912     DWORD dwStyle;
913     int iSize;
914     LPTSTR pTemp = NULL;
915     BOOL bModified = FALSE;
916 
917     iSize = 0;
918 
919     /* If the edit control already exists, try to save its content */
920     if (Globals.hEdit != NULL)
921     {
922         /* number of chars currently written into the editor. */
923         iSize = GetWindowTextLength(Globals.hEdit);
924         if (iSize)
925         {
926             /* Allocates temporary buffer. */
927             pTemp = HeapAlloc(GetProcessHeap(), 0, (iSize + 1) * sizeof(TCHAR));
928             if (!pTemp)
929             {
930                 ShowLastError();
931                 return;
932             }
933 
934             /* Recover the text into the control. */
935             GetWindowText(Globals.hEdit, pTemp, iSize + 1);
936 
937             if (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0))
938                 bModified = TRUE;
939         }
940 
941         /* Restore original window procedure */
942         SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)Globals.EditProc);
943 
944         /* Destroy the edit control */
945         DestroyWindow(Globals.hEdit);
946     }
947 
948     /* Update wrap status into the main menu and recover style flags */
949     if (Globals.bWrapLongLines)
950     {
951         dwStyle = EDIT_STYLE_WRAP;
952         EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
953     } else {
954         dwStyle = EDIT_STYLE;
955         EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_ENABLED);
956     }
957 
958     /* Update previous changes */
959     DrawMenuBar(Globals.hMainWnd);
960 
961     /* Create the new edit control */
962     Globals.hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
963                                    EDIT_CLASS,
964                                    NULL,
965                                    dwStyle,
966                                    CW_USEDEFAULT,
967                                    CW_USEDEFAULT,
968                                    CW_USEDEFAULT,
969                                    CW_USEDEFAULT,
970                                    Globals.hMainWnd,
971                                    NULL,
972                                    Globals.hInstance,
973                                    NULL);
974 
975     if (Globals.hEdit == NULL)
976     {
977         if (pTemp)
978         {
979             HeapFree(GetProcessHeap(), 0, pTemp);
980         }
981 
982         ShowLastError();
983         return;
984     }
985 
986     SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
987     SendMessage(Globals.hEdit, EM_LIMITTEXT, 0, 0);
988 
989     /* If some text was previously saved, restore it. */
990     if (iSize != 0)
991     {
992         SetWindowText(Globals.hEdit, pTemp);
993         HeapFree(GetProcessHeap(), 0, pTemp);
994 
995         if (bModified)
996             SendMessage(Globals.hEdit, EM_SETMODIFY, TRUE, 0);
997     }
998 
999     /* Sub-class a new window callback for row/column detection. */
1000     Globals.EditProc = (WNDPROC)SetWindowLongPtr(Globals.hEdit,
1001                                                  GWLP_WNDPROC,
1002                                                  (LONG_PTR)EDIT_WndProc);
1003 
1004     /* Create/update status bar */
1005     DoCreateStatusBar();
1006 
1007     /* Finally shows new edit control and set focus into it. */
1008     ShowWindow(Globals.hEdit, SW_SHOW);
1009     SetFocus(Globals.hEdit);
1010 }
1011 
1012 VOID DIALOG_EditWrap(VOID)
1013 {
1014     Globals.bWrapLongLines = !Globals.bWrapLongLines;
1015 
1016     if (Globals.bWrapLongLines)
1017     {
1018         EnableMenuItem(Globals.hMenu, CMD_GOTO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1019     }
1020     else
1021     {
1022         EnableMenuItem(Globals.hMenu, CMD_GOTO, MF_BYCOMMAND | MF_ENABLED);
1023     }
1024 
1025     DoCreateEditWindow();
1026 }
1027 
1028 VOID DIALOG_SelectFont(VOID)
1029 {
1030     CHOOSEFONT cf;
1031     LOGFONT lf = Globals.lfFont;
1032 
1033     ZeroMemory( &cf, sizeof(cf) );
1034     cf.lStructSize = sizeof(cf);
1035     cf.hwndOwner = Globals.hMainWnd;
1036     cf.lpLogFont = &lf;
1037     cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_NOVERTFONTS;
1038 
1039     if (ChooseFont(&cf))
1040     {
1041         HFONT currfont = Globals.hFont;
1042 
1043         Globals.hFont = CreateFontIndirect(&lf);
1044         Globals.lfFont = lf;
1045         SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)TRUE);
1046         if (currfont != NULL)
1047             DeleteObject(currfont);
1048     }
1049 }
1050 
1051 typedef HWND (WINAPI *FINDPROC)(LPFINDREPLACE lpfr);
1052 
1053 static VOID DIALOG_SearchDialog(FINDPROC pfnProc)
1054 {
1055     if (Globals.hFindReplaceDlg != NULL)
1056     {
1057         SetFocus(Globals.hFindReplaceDlg);
1058         return;
1059     }
1060 
1061     ZeroMemory(&Globals.find, sizeof(Globals.find));
1062     Globals.find.lStructSize = sizeof(Globals.find);
1063     Globals.find.hwndOwner = Globals.hMainWnd;
1064     Globals.find.hInstance = Globals.hInstance;
1065     Globals.find.lpstrFindWhat = Globals.szFindText;
1066     Globals.find.wFindWhatLen = ARRAY_SIZE(Globals.szFindText);
1067     Globals.find.lpstrReplaceWith = Globals.szReplaceText;
1068     Globals.find.wReplaceWithLen = ARRAY_SIZE(Globals.szReplaceText);
1069     Globals.find.Flags = FR_DOWN;
1070 
1071     /* We only need to create the modal FindReplace dialog which will */
1072     /* notify us of incoming events using hMainWnd Window Messages    */
1073 
1074     Globals.hFindReplaceDlg = pfnProc(&Globals.find);
1075     assert(Globals.hFindReplaceDlg != NULL);
1076 }
1077 
1078 VOID DIALOG_Search(VOID)
1079 {
1080     DIALOG_SearchDialog(FindText);
1081 }
1082 
1083 VOID DIALOG_SearchNext(VOID)
1084 {
1085     if (Globals.find.lpstrFindWhat != NULL)
1086         NOTEPAD_FindNext(&Globals.find, FALSE, TRUE);
1087     else
1088         DIALOG_Search();
1089 }
1090 
1091 VOID DIALOG_Replace(VOID)
1092 {
1093     DIALOG_SearchDialog(ReplaceText);
1094 }
1095 
1096 static INT_PTR
1097 CALLBACK
1098 DIALOG_GoTo_DialogProc(HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
1099 {
1100     BOOL bResult = FALSE;
1101     HWND hTextBox;
1102     TCHAR szText[32];
1103 
1104     switch(uMsg) {
1105     case WM_INITDIALOG:
1106         hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
1107         _sntprintf(szText, ARRAY_SIZE(szText), _T("%Id"), lParam);
1108         SetWindowText(hTextBox, szText);
1109         break;
1110     case WM_COMMAND:
1111         if (HIWORD(wParam) == BN_CLICKED)
1112         {
1113             if (LOWORD(wParam) == IDOK)
1114             {
1115                 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
1116                 GetWindowText(hTextBox, szText, ARRAY_SIZE(szText));
1117                 EndDialog(hwndDialog, _ttoi(szText));
1118                 bResult = TRUE;
1119             }
1120             else if (LOWORD(wParam) == IDCANCEL)
1121             {
1122                 EndDialog(hwndDialog, 0);
1123                 bResult = TRUE;
1124             }
1125         }
1126         break;
1127     }
1128 
1129     return bResult;
1130 }
1131 
1132 VOID DIALOG_GoTo(VOID)
1133 {
1134     INT_PTR nLine;
1135     LPTSTR pszText;
1136     int nLength, i;
1137     DWORD dwStart, dwEnd;
1138 
1139     nLength = GetWindowTextLength(Globals.hEdit);
1140     pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(*pszText));
1141     if (!pszText)
1142         return;
1143 
1144     /* Retrieve current text */
1145     GetWindowText(Globals.hEdit, pszText, nLength + 1);
1146     SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwStart, (LPARAM) &dwEnd);
1147 
1148     nLine = 1;
1149     for (i = 0; (i < (int) dwStart) && pszText[i]; i++)
1150     {
1151         if (pszText[i] == '\n')
1152             nLine++;
1153     }
1154 
1155     nLine = DialogBoxParam(Globals.hInstance,
1156                            MAKEINTRESOURCE(DIALOG_GOTO),
1157                            Globals.hMainWnd,
1158                            DIALOG_GoTo_DialogProc,
1159                            nLine);
1160 
1161     if (nLine >= 1)
1162     {
1163         for (i = 0; pszText[i] && (nLine > 1) && (i < nLength - 1); i++)
1164         {
1165             if (pszText[i] == '\n')
1166                 nLine--;
1167         }
1168         SendMessage(Globals.hEdit, EM_SETSEL, i, i);
1169         SendMessage(Globals.hEdit, EM_SCROLLCARET, 0, 0);
1170     }
1171     HeapFree(GetProcessHeap(), 0, pszText);
1172 }
1173 
1174 VOID DIALOG_StatusBarUpdateCaretPos(VOID)
1175 {
1176     int line, col;
1177     TCHAR buff[MAX_PATH];
1178     DWORD dwStart, dwSize;
1179 
1180     SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwSize);
1181     line = SendMessage(Globals.hEdit, EM_LINEFROMCHAR, (WPARAM)dwStart, 0);
1182     col = dwStart - SendMessage(Globals.hEdit, EM_LINEINDEX, (WPARAM)line, 0);
1183 
1184     _stprintf(buff, Globals.szStatusBarLineCol, line + 1, col + 1);
1185     SendMessage(Globals.hStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)buff);
1186 }
1187 
1188 VOID DIALOG_ViewStatusBar(VOID)
1189 {
1190     Globals.bShowStatusBar = !Globals.bShowStatusBar;
1191 
1192     DoCreateStatusBar();
1193 }
1194 
1195 VOID DIALOG_HelpContents(VOID)
1196 {
1197     WinHelp(Globals.hMainWnd, helpfile, HELP_INDEX, 0);
1198 }
1199 
1200 VOID DIALOG_HelpAboutNotepad(VOID)
1201 {
1202     TCHAR szNotepad[MAX_STRING_LEN];
1203     TCHAR szNotepadAuthors[MAX_STRING_LEN];
1204 
1205     HICON notepadIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_NPICON));
1206 
1207     LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
1208     LoadString(Globals.hInstance, STRING_NOTEPAD_AUTHORS, szNotepadAuthors, ARRAY_SIZE(szNotepadAuthors));
1209 
1210     ShellAbout(Globals.hMainWnd, szNotepad, szNotepadAuthors, notepadIcon);
1211     DeleteObject(notepadIcon);
1212 }
1213 
1214 /***********************************************************************
1215  *
1216  *           DIALOG_FilePageSetup
1217  */
1218 VOID DIALOG_FilePageSetup(void)
1219 {
1220     PAGESETUPDLG page;
1221 
1222     ZeroMemory(&page, sizeof(page));
1223     page.lStructSize = sizeof(page);
1224     page.hwndOwner = Globals.hMainWnd;
1225     page.Flags = PSD_ENABLEPAGESETUPTEMPLATE | PSD_ENABLEPAGESETUPHOOK | PSD_MARGINS;
1226     page.hInstance = Globals.hInstance;
1227     page.rtMargin = Globals.lMargins;
1228     page.hDevMode = Globals.hDevMode;
1229     page.hDevNames = Globals.hDevNames;
1230     page.lpPageSetupTemplateName = MAKEINTRESOURCE(DIALOG_PAGESETUP);
1231     page.lpfnPageSetupHook = DIALOG_PAGESETUP_Hook;
1232 
1233     PageSetupDlg(&page);
1234 
1235     Globals.hDevMode = page.hDevMode;
1236     Globals.hDevNames = page.hDevNames;
1237     Globals.lMargins = page.rtMargin;
1238 }
1239 
1240 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1241  *
1242  *           DIALOG_PAGESETUP_Hook
1243  */
1244 
1245 static UINT_PTR CALLBACK DIALOG_PAGESETUP_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1246 {
1247     switch (msg)
1248     {
1249     case WM_COMMAND:
1250         if (HIWORD(wParam) == BN_CLICKED)
1251         {
1252             switch (LOWORD(wParam))
1253             {
1254             case IDOK:
1255                 /* save user input and close dialog */
1256                 GetDlgItemText(hDlg, 0x141, Globals.szHeader, ARRAY_SIZE(Globals.szHeader));
1257                 GetDlgItemText(hDlg, 0x143, Globals.szFooter, ARRAY_SIZE(Globals.szFooter));
1258                 return FALSE;
1259 
1260             case IDCANCEL:
1261                 /* discard user input and close dialog */
1262                 return FALSE;
1263 
1264             case IDHELP:
1265                 {
1266                     /* FIXME: Bring this to work */
1267                     static const TCHAR sorry[] = _T("Sorry, no help available");
1268                     static const TCHAR help[] = _T("Help");
1269                     MessageBox(Globals.hMainWnd, sorry, help, MB_ICONEXCLAMATION);
1270                     return TRUE;
1271                 }
1272 
1273             default:
1274                 break;
1275             }
1276         }
1277         break;
1278 
1279     case WM_INITDIALOG:
1280         /* fetch last user input prior to display dialog */
1281         SetDlgItemText(hDlg, 0x141, Globals.szHeader);
1282         SetDlgItemText(hDlg, 0x143, Globals.szFooter);
1283         break;
1284     }
1285 
1286     return FALSE;
1287 }
1288