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