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