1 /*
2  * PROJECT:    ReactOS Notepad
3  * LICENSE:    LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:    Providing a Windows-compatible simple text editor for ReactOS
5  * COPYRIGHT:  Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
6  *             Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
7  *             Copyright 2002 Andriy Palamarchuk
8  *             Copyright 2020-2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
9  */
10 
11 #include "notepad.h"
12 
13 #include <strsafe.h>
14 #include <assert.h>
15 
AlertPrintError(VOID)16 static VOID AlertPrintError(VOID)
17 {
18     TCHAR szUntitled[MAX_STRING_LEN];
19 
20     LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, _countof(szUntitled));
21 
22     DIALOG_StringMsgBox(Globals.hMainWnd, STRING_PRINTERROR,
23                         Globals.szFileName[0] ? Globals.szFileName : szUntitled,
24                         MB_ICONEXCLAMATION | MB_OK);
25 }
26 
27 static RECT
GetPrintingRect(IN HDC hdc,IN LPCRECT pMargins)28 GetPrintingRect(IN HDC hdc, IN LPCRECT pMargins)
29 {
30     INT iLogPixelsX = GetDeviceCaps(hdc, LOGPIXELSX);
31     INT iLogPixelsY = GetDeviceCaps(hdc, LOGPIXELSY);
32     INT iHorzRes = GetDeviceCaps(hdc, HORZRES); /* in pixels */
33     INT iVertRes = GetDeviceCaps(hdc, VERTRES); /* in pixels */
34     RECT rcPrintRect, rcPhysical;
35 
36 #define CONVERT_X(x) MulDiv((x), iLogPixelsX, 2540) /* 100th millimeters to pixels */
37 #define CONVERT_Y(y) MulDiv((y), iLogPixelsY, 2540) /* 100th millimeters to pixels */
38     SetRect(&rcPrintRect,
39             CONVERT_X(pMargins->left), CONVERT_Y(pMargins->top),
40             iHorzRes - CONVERT_X(pMargins->right),
41             iVertRes - CONVERT_Y(pMargins->bottom));
42 
43     rcPhysical.left = GetDeviceCaps(hdc, PHYSICALOFFSETX);
44     rcPhysical.right = rcPhysical.left + GetDeviceCaps(hdc, PHYSICALWIDTH);
45     rcPhysical.top = GetDeviceCaps(hdc, PHYSICALOFFSETY);
46     rcPhysical.bottom = rcPhysical.top + GetDeviceCaps(hdc, PHYSICALHEIGHT);
47 
48     /* Adjust the margin */
49     rcPrintRect.left = max(rcPrintRect.left, rcPhysical.left);
50     rcPrintRect.top = max(rcPrintRect.top, rcPhysical.top);
51     rcPrintRect.right = min(rcPrintRect.right, rcPhysical.right);
52     rcPrintRect.bottom = min(rcPrintRect.bottom, rcPhysical.bottom);
53 
54     return rcPrintRect;
55 }
56 
GetSelectionTextLength(HWND hWnd)57 static INT GetSelectionTextLength(HWND hWnd)
58 {
59     DWORD dwStart = 0, dwEnd = 0;
60     SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
61     return dwEnd - dwStart;
62 }
63 
GetSelectionText(HWND hWnd,LPTSTR lpString,INT nMaxCount)64 static INT GetSelectionText(HWND hWnd, LPTSTR lpString, INT nMaxCount)
65 {
66     DWORD dwStart = 0, dwEnd = 0;
67     INT cchText = GetWindowTextLength(hWnd);
68     LPTSTR pszText;
69     HLOCAL hLocal;
70     HRESULT hr;
71 
72     SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
73     if (!lpString || dwStart == dwEnd || cchText == 0)
74         return 0;
75 
76     hLocal = (HLOCAL)SendMessage(hWnd, EM_GETHANDLE, 0, 0);
77     pszText = (LPTSTR)LocalLock(hLocal);
78     if (!pszText)
79         return 0;
80 
81     hr = StringCchCopyN(lpString, nMaxCount, pszText + dwStart, dwEnd - dwStart);
82     LocalUnlock(hLocal);
83 
84     switch (hr)
85     {
86         case S_OK:
87             return dwEnd - dwStart;
88 
89         case STRSAFE_E_INSUFFICIENT_BUFFER:
90             return nMaxCount - 1;
91 
92         default:
93             return 0;
94     }
95 }
96 
97 typedef struct
98 {
99     PRINTDLG printer;
100     HWND hwndDlg;
101     INT status;
102     INT currentPage;
103     RECT printRect;
104     SYSTEMTIME stNow;
105     HFONT hHeaderFont;
106     HFONT hBodyFont;
107     LPTSTR pszText;
108     DWORD ich;
109     DWORD cchText;
110     INT cyHeader;
111     INT cySpacing;
112     INT cyFooter;
113 } PRINT_DATA, *PPRINT_DATA;
114 
115 /* Convert the points into pixels */
116 #define X_POINTS_TO_PIXELS(hDC, points) MulDiv((points), GetDeviceCaps((hDC), LOGPIXELSX), 72)
117 #define Y_POINTS_TO_PIXELS(hDC, points) MulDiv((points), GetDeviceCaps((hDC), LOGPIXELSY), 72)
118 
119 /*
120  * See also:
121  * https://support.microsoft.com/en-us/windows/help-in-notepad-4d68c388-2ff2-0e7f-b706-35fb2ab88a8c
122  */
123 static VOID
DrawHeaderOrFooter(HDC hDC,LPRECT pRect,LPCTSTR pszFormat,INT nPageNo,const SYSTEMTIME * pstNow)124 DrawHeaderOrFooter(HDC hDC, LPRECT pRect, LPCTSTR pszFormat, INT nPageNo, const SYSTEMTIME *pstNow)
125 {
126     TCHAR szText[256], szField[128];
127     const TCHAR *pchFormat;
128     UINT uAlign = DT_CENTER, uFlags = DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX;
129     HGDIOBJ hOldPen, hOldBrush;
130 
131     /* Draw a rectangle */
132     hOldPen = SelectObject(hDC, GetStockObject(BLACK_PEN));
133     hOldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH));
134     Rectangle(hDC, pRect->left, pRect->top, pRect->right, pRect->bottom);
135     SelectObject(hDC, hOldBrush);
136     SelectObject(hDC, hOldPen);
137 
138     InflateRect(pRect, -X_POINTS_TO_PIXELS(hDC, 3), 0); /* Shrink 3pt */
139 
140     szText[0] = 0;
141 
142     for (pchFormat = pszFormat; *pchFormat; ++pchFormat)
143     {
144         if (*pchFormat != _T('&'))
145         {
146             StringCchCatN(szText, _countof(szText), pchFormat, 1);
147             continue;
148         }
149 
150         ++pchFormat;
151         if (*pchFormat == 0)
152             break;
153 
154         switch (_totupper(*pchFormat)) /* Make it uppercase */
155         {
156             case _T('&'): /* Found double ampersand */
157                 StringCchCat(szText, _countof(szText), TEXT("&"));
158                 break;
159 
160             case _T('L'): /* Left */
161                 DrawText(hDC, szText, -1, pRect, uAlign | uFlags);
162                 szText[0] = 0;
163                 uAlign = DT_LEFT;
164                 break;
165 
166             case _T('C'): /* Center */
167                 DrawText(hDC, szText, -1, pRect, uAlign | uFlags);
168                 szText[0] = 0;
169                 uAlign = DT_CENTER;
170                 break;
171 
172             case _T('R'): /* Right */
173                 DrawText(hDC, szText, -1, pRect, uAlign | uFlags);
174                 szText[0] = 0;
175                 uAlign = DT_RIGHT;
176                 break;
177 
178             case _T('D'): /* Date */
179                 GetDateFormat(LOCALE_USER_DEFAULT, 0, pstNow, NULL,
180                               szField, (INT)_countof(szField));
181                 StringCchCat(szText, _countof(szText), szField);
182                 break;
183 
184             case _T('T'): /* Time */
185                 GetTimeFormat(LOCALE_USER_DEFAULT, 0, pstNow, NULL,
186                               szField, (INT)_countof(szField));
187                 StringCchCat(szText, _countof(szText), szField);
188                 break;
189 
190             case _T('F'): /* Filename */
191                 StringCchCat(szText, _countof(szText), Globals.szFileTitle);
192                 break;
193 
194             case _T('P'): /* Page number */
195                 StringCchPrintf(szField, _countof(szField), TEXT("%u"), nPageNo);
196                 StringCchCat(szText, _countof(szText), szField);
197                 break;
198 
199             default: /* Otherwise */
200                 szField[0] = _T('&');
201                 szField[1] = *pchFormat;
202                 szField[2] = 0;
203                 StringCchCat(szText, _countof(szText), szField);
204                 break;
205         }
206     }
207 
208     DrawText(hDC, szText, -1, pRect, uAlign | uFlags);
209 }
210 
DoPrintBody(PPRINT_DATA pData,DWORD PageCount,BOOL bSkipPage)211 static BOOL DoPrintBody(PPRINT_DATA pData, DWORD PageCount, BOOL bSkipPage)
212 {
213     LPPRINTDLG pPrinter = &pData->printer;
214     RECT printRect = pData->printRect;
215     INT xLeft = printRect.left, yTop = printRect.top + pData->cyHeader + pData->cySpacing;
216     INT xStart, tabWidth;
217     DWORD ichStart;
218     SIZE charMetrics;
219     TEXTMETRIC tmText;
220 
221     /* Calculate a tab width */
222 #define TAB_STOP 8
223     GetTextMetrics(pPrinter->hDC, &tmText);
224     tabWidth = TAB_STOP * tmText.tmAveCharWidth;
225 
226 #define DO_FLUSH() do { \
227     if (ichStart < pData->ich && !bSkipPage) { \
228         TextOut(pPrinter->hDC, xStart, yTop, &pData->pszText[ichStart], pData->ich - ichStart); \
229     } \
230     ichStart = pData->ich; \
231     xStart = xLeft; \
232     if (pData->status == STRING_PRINTCANCELING) return FALSE; \
233 } while (0)
234 
235     /* The drawing-body loop */
236     for (ichStart = pData->ich, xStart = xLeft; pData->ich < pData->cchText; )
237     {
238         TCHAR ch = pData->pszText[pData->ich];
239 
240         if (ch == _T('\r'))
241         {
242             DO_FLUSH();
243 
244             pData->ich++; /* Next char */
245             ichStart = pData->ich;
246             continue;
247         }
248 
249         if (ch == _T('\n'))
250         {
251             DO_FLUSH();
252 
253             /* Next line */
254             yTop += tmText.tmHeight;
255             xLeft = xStart = printRect.left;
256         }
257         else
258         {
259             if (ch == _T('\t'))
260             {
261                 INT nStepWidth = tabWidth - ((xLeft - printRect.left) % tabWidth);
262 
263                 DO_FLUSH();
264 
265                 /* Go to the next tab stop */
266                 xLeft += nStepWidth;
267                 xStart = xLeft;
268             }
269             else /* Normal char */
270             {
271                 GetTextExtentPoint32(pPrinter->hDC, &ch, 1, &charMetrics);
272                 xLeft += charMetrics.cx;
273             }
274 
275             /* Insert a line break if the next position reached the right edge */
276             if (xLeft + charMetrics.cx >= printRect.right)
277             {
278                 if (ch != _T('\t'))
279                     DO_FLUSH();
280 
281                 /* Next line */
282                 yTop += tmText.tmHeight;
283                 xLeft = xStart = printRect.left;
284             }
285         }
286 
287         pData->ich++; /* Next char */
288         if (ch == _T('\t') || ch == _T('\n'))
289             ichStart = pData->ich;
290 
291         if (yTop + tmText.tmHeight >= printRect.bottom - pData->cyFooter)
292             break; /* The next line reached the body bottom */
293     }
294 
295     DO_FLUSH();
296     return TRUE;
297 }
298 
DoPrintPage(PPRINT_DATA pData,DWORD PageCount)299 static BOOL DoPrintPage(PPRINT_DATA pData, DWORD PageCount)
300 {
301     LPPRINTDLG pPrinter = &pData->printer;
302     BOOL bSkipPage, ret;
303     HFONT hOldFont;
304 
305     /* Should we skip this page? */
306     bSkipPage = !(pPrinter->Flags & PD_SELECTION) &&
307                 (pPrinter->Flags & PD_PAGENUMS) &&
308                 !(pPrinter->nFromPage <= PageCount && PageCount <= pPrinter->nToPage);
309 
310     /* The prologue of a page */
311     if (!bSkipPage)
312     {
313         if (StartPage(pPrinter->hDC) <= 0)
314         {
315             pData->status = STRING_PRINTFAILED;
316             return FALSE;
317         }
318 
319         if (pData->cyHeader > 0)
320         {
321             /* Draw the page header */
322             RECT rc = pData->printRect;
323             rc.bottom = rc.top + pData->cyHeader;
324 
325             hOldFont = SelectObject(pPrinter->hDC, pData->hHeaderFont);
326             DrawHeaderOrFooter(pPrinter->hDC, &rc, Globals.szHeader, PageCount, &pData->stNow);
327             SelectObject(pPrinter->hDC, hOldFont); /* De-select the font */
328         }
329     }
330 
331     hOldFont = SelectObject(pPrinter->hDC, pData->hBodyFont);
332     ret = DoPrintBody(pData, PageCount, bSkipPage);
333     SelectObject(pPrinter->hDC, hOldFont);
334     if (!ret)
335         return FALSE; /* Canceled */
336 
337     /* The epilogue of a page */
338     if (!bSkipPage)
339     {
340         if (pData->cyFooter > 0)
341         {
342             /* Draw the page footer */
343             RECT rc = pData->printRect;
344             rc.top = rc.bottom - pData->cyFooter;
345 
346             hOldFont = SelectObject(pPrinter->hDC, pData->hHeaderFont);
347             DrawHeaderOrFooter(pPrinter->hDC, &rc, Globals.szFooter, PageCount, &pData->stNow);
348             SelectObject(pPrinter->hDC, hOldFont);
349         }
350 
351         if (EndPage(pPrinter->hDC) <= 0)
352         {
353             pData->status = STRING_PRINTFAILED;
354             return FALSE;
355         }
356     }
357 
358     return TRUE;
359 }
360 
361 #define BODY_FONT_SIZE      10 /* 10pt */
362 #define HEADER_FONT_SIZE    9  /* 9pt */
363 #define SPACING_HEIGHT      4  /* 4pt */
364 #define PRINTING_MESSAGE (WM_USER + 100)
365 
DoCreatePrintFonts(LPPRINTDLG pPrinter,PPRINT_DATA pPrintData)366 static BOOL DoCreatePrintFonts(LPPRINTDLG pPrinter, PPRINT_DATA pPrintData)
367 {
368     LOGFONT lfBody, lfHeader;
369 
370     /* Create the main text font for printing */
371     lfBody = Globals.lfFont;
372     lfBody.lfHeight = -Y_POINTS_TO_PIXELS(pPrinter->hDC, BODY_FONT_SIZE);
373     pPrintData->hBodyFont = CreateFontIndirect(&lfBody);
374     if (pPrintData->hBodyFont == NULL)
375         return FALSE;
376 
377     /* Create the header/footer font */
378     lfHeader = Globals.lfFont;
379     lfHeader.lfHeight = -Y_POINTS_TO_PIXELS(pPrinter->hDC, HEADER_FONT_SIZE);
380     lfHeader.lfWeight = FW_BOLD;
381     pPrintData->hHeaderFont = CreateFontIndirect(&lfHeader);
382     if (pPrintData->hHeaderFont == NULL)
383         return FALSE;
384 
385     return TRUE;
386 }
387 
DoPrintDocument(PPRINT_DATA printData)388 static BOOL DoPrintDocument(PPRINT_DATA printData)
389 {
390     DOCINFO docInfo;
391     LPPRINTDLG pPrinter = &printData->printer;
392     DWORD CopyCount, PageCount;
393     TEXTMETRIC tmHeader;
394     BOOL ret = FALSE;
395     HFONT hOldFont;
396 
397     GetLocalTime(&printData->stNow);
398 
399     printData->printRect = GetPrintingRect(pPrinter->hDC, &Globals.lMargins);
400 
401     if (!DoCreatePrintFonts(pPrinter, printData))
402     {
403         printData->status = STRING_PRINTFAILED;
404         goto Quit;
405     }
406 
407     if (pPrinter->Flags & PD_SELECTION)
408         printData->cchText = GetSelectionTextLength(Globals.hEdit);
409     else
410         printData->cchText = GetWindowTextLength(Globals.hEdit);
411 
412     /* Allocate a buffer for the text */
413     printData->pszText = HeapAlloc(GetProcessHeap(), 0, (printData->cchText + 1) * sizeof(TCHAR));
414     if (!printData->pszText)
415     {
416         printData->status = STRING_PRINTFAILED;
417         goto Quit;
418     }
419 
420     if (pPrinter->Flags & PD_SELECTION)
421         GetSelectionText(Globals.hEdit, printData->pszText, printData->cchText + 1);
422     else
423         GetWindowText(Globals.hEdit, printData->pszText, printData->cchText + 1);
424 
425     /* Start a document */
426     ZeroMemory(&docInfo, sizeof(docInfo));
427     docInfo.cbSize = sizeof(DOCINFO);
428     docInfo.lpszDocName = Globals.szFileTitle;
429     if (StartDoc(pPrinter->hDC, &docInfo) <= 0)
430     {
431         printData->status = STRING_PRINTFAILED;
432         goto Quit;
433     }
434 
435     /* Calculate the header and footer heights */
436     hOldFont = SelectObject(pPrinter->hDC, printData->hHeaderFont);
437     GetTextMetrics(pPrinter->hDC, &tmHeader);
438     printData->cyHeader = printData->cyFooter = 2 * tmHeader.tmHeight;
439     printData->cySpacing = Y_POINTS_TO_PIXELS(pPrinter->hDC, SPACING_HEIGHT);
440     SelectObject(pPrinter->hDC, hOldFont); /* De-select the font */
441     if (!Globals.szHeader[0])
442         printData->cyHeader = printData->cySpacing = 0;
443     if (!Globals.szFooter[0])
444         printData->cyFooter = 0;
445 
446     /* The printing-copies loop */
447     for (CopyCount = 1; CopyCount <= pPrinter->nCopies; ++CopyCount)
448     {
449         /* The printing-pages loop */
450         for (PageCount = 1, printData->ich = 0; printData->ich < printData->cchText; ++PageCount)
451         {
452             printData->currentPage = PageCount;
453             PostMessage(printData->hwndDlg, PRINTING_MESSAGE, 0, 0);
454 
455             if (!DoPrintPage(printData, PageCount))
456             {
457                 AbortDoc(pPrinter->hDC); /* Cancel printing */
458                 goto Quit;
459             }
460         }
461     }
462 
463     if (EndDoc(pPrinter->hDC) <= 0)
464     {
465         printData->status = STRING_PRINTFAILED;
466         goto Quit;
467     }
468 
469     ret = TRUE;
470     printData->status = STRING_PRINTCOMPLETE;
471 
472 Quit:
473     DeleteObject(printData->hHeaderFont);
474     DeleteObject(printData->hBodyFont);
475     if (printData->pszText)
476         HeapFree(GetProcessHeap(), 0, printData->pszText);
477     if (printData->status == STRING_PRINTCANCELING)
478         printData->status = STRING_PRINTCANCELED;
479     PostMessage(printData->hwndDlg, PRINTING_MESSAGE, 0, 0);
480     return ret;
481 }
482 
PrintThreadFunc(LPVOID arg)483 static DWORD WINAPI PrintThreadFunc(LPVOID arg)
484 {
485     PPRINT_DATA pData = arg;
486     pData->currentPage = 1;
487     pData->status = STRING_NOWPRINTING;
488     PostMessage(pData->hwndDlg, PRINTING_MESSAGE, 0, 0);
489     return DoPrintDocument(pData);
490 }
491 
492 static INT_PTR CALLBACK
DIALOG_Printing_DialogProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)493 DIALOG_Printing_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
494 {
495     TCHAR szText[MAX_STRING_LEN];
496     static TCHAR s_szPage[64];
497     static PPRINT_DATA s_pData = NULL;
498     static HANDLE s_hThread = NULL;
499 
500     switch (uMsg)
501     {
502         case WM_INITDIALOG:
503             s_pData = (PPRINT_DATA)lParam;
504             s_pData->hwndDlg = hwnd;
505             SetDlgItemText(hwnd, IDC_PRINTING_FILENAME, Globals.szFileTitle);
506             GetDlgItemText(hwnd, IDC_PRINTING_PAGE, s_szPage, _countof(s_szPage));
507             SetDlgItemText(hwnd, IDC_PRINTING_PAGE, NULL);
508 
509             s_hThread = CreateThread(NULL, 0, PrintThreadFunc, s_pData, 0, NULL);
510             if (!s_hThread)
511             {
512                 s_pData->status = STRING_PRINTFAILED;
513                 EndDialog(hwnd, IDABORT);
514             }
515             return TRUE;
516 
517         case PRINTING_MESSAGE:
518             switch (s_pData->status)
519             {
520                 case STRING_NOWPRINTING:
521                 case STRING_PRINTCANCELING:
522                     StringCchPrintf(szText, _countof(szText), s_szPage, s_pData->currentPage);
523                     SetDlgItemText(hwnd, IDC_PRINTING_PAGE, szText);
524 
525                     LoadString(Globals.hInstance, s_pData->status, szText, _countof(szText));
526                     SetDlgItemText(hwnd, IDC_PRINTING_STATUS, szText);
527                     break;
528 
529                 case STRING_PRINTCOMPLETE:
530                 case STRING_PRINTCANCELED:
531                 case STRING_PRINTFAILED:
532                     LoadString(Globals.hInstance, s_pData->status, szText, _countof(szText));
533                     SetDlgItemText(hwnd, IDC_PRINTING_STATUS, szText);
534 
535                     if (s_pData->status == STRING_PRINTCOMPLETE)
536                         EndDialog(hwnd, IDOK);
537                     else if (s_pData->status == STRING_PRINTFAILED)
538                         EndDialog(hwnd, IDABORT);
539                     else
540                         EndDialog(hwnd, IDCANCEL);
541                     break;
542             }
543             break;
544 
545         case WM_COMMAND:
546             if (LOWORD(wParam) == IDCANCEL && s_pData->status == STRING_NOWPRINTING)
547             {
548                 EnableWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
549                 s_pData->status = STRING_PRINTCANCELING;
550                 PostMessage(hwnd, PRINTING_MESSAGE, 0, 0);
551             }
552             break;
553 
554         case WM_DESTROY:
555             if (s_hThread)
556                 CloseHandle(s_hThread);
557             DeleteDC(s_pData->printer.hDC);
558             s_pData = LocalFree(s_pData);
559             break;
560     }
561 
562     return 0;
563 }
564 
DIALOG_FilePrint(VOID)565 VOID DIALOG_FilePrint(VOID)
566 {
567     BOOL ret;
568     LPPRINTDLG printer;
569     PPRINT_DATA printData = LocalAlloc(LPTR, sizeof(PRINT_DATA));
570     if (!printData)
571     {
572         ShowLastError();
573         return;
574     }
575 
576     printer = &printData->printer;
577     printer->lStructSize = sizeof(PRINTDLG);
578     printer->hwndOwner = Globals.hMainWnd;
579     printer->Flags = PD_RETURNDC | PD_SELECTION;
580 
581     /* Disable the selection radio button if there is no text selected */
582     if (!GetSelectionTextLength(Globals.hEdit))
583         printer->Flags |= PD_NOSELECTION;
584 
585     printer->nFromPage = 1;
586     printer->nToPage = MAXWORD;
587     printer->nMinPage = 1;
588     printer->nMaxPage = MAXWORD;
589 
590     printer->hDevMode = Globals.hDevMode;
591     printer->hDevNames = Globals.hDevNames;
592 
593     ret = PrintDlg(printer);
594     /* NOTE: Even if PrintDlg returns FALSE, hDevMode and hDevNames may have changed. */
595     Globals.hDevMode = printer->hDevMode;
596     Globals.hDevNames = printer->hDevNames;
597 
598     if (!ret)
599     {
600         LocalFree(printData);
601         return; /* The user canceled printing */
602     }
603     assert(printer->hDC != NULL);
604 
605     /* Ensure that each logical unit maps to one pixel */
606     SetMapMode(printer->hDC, MM_TEXT);
607 
608     if (DialogBoxParam(Globals.hInstance,
609                        MAKEINTRESOURCE(DIALOG_PRINTING),
610                        Globals.hMainWnd,
611                        DIALOG_Printing_DialogProc,
612                        (LPARAM)printer) == IDABORT)
613     {
614         AlertPrintError();
615     }
616 }
617 
618 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
619  *           DIALOG_PAGESETUP_Hook
620  */
DIALOG_PAGESETUP_Hook(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)621 static UINT_PTR CALLBACK DIALOG_PAGESETUP_Hook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
622 {
623     switch (uMsg)
624     {
625         case WM_INITDIALOG:
626             /* fetch last user input prior to display dialog */
627             SetDlgItemText(hDlg, 0x141, Globals.szHeader);
628             SetDlgItemText(hDlg, 0x143, Globals.szFooter);
629             break;
630 
631         case WM_COMMAND:
632         {
633             if (HIWORD(wParam) == BN_CLICKED)
634             {
635                 switch (LOWORD(wParam))
636                 {
637                 case IDOK:
638                     /* save user input and close dialog */
639                     GetDlgItemText(hDlg, 0x141, Globals.szHeader, _countof(Globals.szHeader));
640                     GetDlgItemText(hDlg, 0x143, Globals.szFooter, _countof(Globals.szFooter));
641                     return FALSE;
642 
643                 case IDCANCEL:
644                     /* discard user input and close dialog */
645                     return FALSE;
646 
647                 case IDHELP:
648                     {
649                         /* FIXME: Bring this to work */
650                         static const TCHAR sorry[] = _T("Sorry, no help available");
651                         static const TCHAR help[] = _T("Help");
652                         MessageBox(Globals.hMainWnd, sorry, help, MB_ICONEXCLAMATION);
653                         return TRUE;
654                     }
655 
656                 default:
657                     break;
658                 }
659             }
660             break;
661         }
662     }
663 
664     return FALSE;
665 }
666 
667 /***********************************************************************
668  *           DIALOG_FilePageSetup
669  */
DIALOG_FilePageSetup(VOID)670 VOID DIALOG_FilePageSetup(VOID)
671 {
672     PAGESETUPDLG page;
673 
674     ZeroMemory(&page, sizeof(page));
675     page.lStructSize = sizeof(page);
676     page.hwndOwner = Globals.hMainWnd;
677     page.Flags = PSD_ENABLEPAGESETUPTEMPLATE | PSD_ENABLEPAGESETUPHOOK | PSD_MARGINS;
678     page.hInstance = Globals.hInstance;
679     page.rtMargin = Globals.lMargins;
680     page.hDevMode = Globals.hDevMode;
681     page.hDevNames = Globals.hDevNames;
682     page.lpPageSetupTemplateName = MAKEINTRESOURCE(DIALOG_PAGESETUP);
683     page.lpfnPageSetupHook = DIALOG_PAGESETUP_Hook;
684 
685     PageSetupDlg(&page);
686 
687     /* NOTE: Even if PageSetupDlg returns FALSE, the following members may have changed */
688     Globals.hDevMode = page.hDevMode;
689     Globals.hDevNames = page.hDevNames;
690     Globals.lMargins = page.rtMargin;
691 }
692