mssip32: Stubs for DllRegisterServer() and DllUnregisterServer().
[wine] / programs / notepad / dialog.c
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  *  Copyright 2007 Rolf Kalbermatter
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <windows.h>
27 #include <commdlg.h>
28 #include <shlwapi.h>
29 #include <winternl.h>
30
31 #include "main.h"
32 #include "dialog.h"
33
34 #define SPACES_IN_TAB 8
35 #define PRINT_LEN_MAX 500
36
37 static const WCHAR helpfileW[] = { 'n','o','t','e','p','a','d','.','h','l','p',0 };
38
39 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
40
41 /* Swap bytes of WCHAR buffer (big-endian <-> little-endian). */
42 static inline void byteswap_wide_string(LPWSTR str, UINT num)
43 {
44     UINT i;
45     for (i = 0; i < num; i++) str[i] = RtlUshortByteSwap(str[i]);
46 }
47
48 static void load_encoding_name(ENCODING enc, WCHAR* buffer, int length)
49 {
50     switch (enc)
51     {
52         case ENCODING_UTF16LE:
53             LoadStringW(Globals.hInstance, STRING_UNICODE_LE, buffer, length);
54             break;
55
56         case ENCODING_UTF16BE:
57             LoadStringW(Globals.hInstance, STRING_UNICODE_BE, buffer, length);
58             break;
59
60         default:
61         {
62             CPINFOEXW cpi;
63             GetCPInfoExW((enc==ENCODING_UTF8) ? CP_UTF8 : CP_ACP, 0, &cpi);
64             lstrcpynW(buffer, cpi.CodePageName, length);
65             break;
66         }
67     }
68 }
69
70 VOID ShowLastError(void)
71 {
72     DWORD error = GetLastError();
73     if (error != NO_ERROR)
74     {
75         LPWSTR lpMsgBuf;
76         WCHAR szTitle[MAX_STRING_LEN];
77
78         LoadStringW(Globals.hInstance, STRING_ERROR, szTitle, ARRAY_SIZE(szTitle));
79         FormatMessageW(
80             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
81             NULL, error, 0, (LPWSTR)&lpMsgBuf, 0, NULL);
82         MessageBoxW(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR);
83         LocalFree(lpMsgBuf);
84     }
85 }
86
87 /**
88  * Sets the caption of the main window according to Globals.szFileTitle:
89  *    Untitled - Notepad        if no file is open
90  *    filename - Notepad        if a file is given
91  */
92 void UpdateWindowCaption(void)
93 {
94   WCHAR szCaption[MAX_STRING_LEN];
95   WCHAR szNotepad[MAX_STRING_LEN];
96   static const WCHAR hyphenW[] = { ' ','-',' ',0 };
97
98   if (Globals.szFileTitle[0] != '\0')
99       lstrcpyW(szCaption, Globals.szFileTitle);
100   else
101       LoadStringW(Globals.hInstance, STRING_UNTITLED, szCaption, ARRAY_SIZE(szCaption));
102
103   LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
104   lstrcatW(szCaption, hyphenW);
105   lstrcatW(szCaption, szNotepad);
106
107   SetWindowTextW(Globals.hMainWnd, szCaption);
108 }
109
110 int DIALOG_StringMsgBox(HWND hParent, int formatId, LPCWSTR szString, DWORD dwFlags)
111 {
112    WCHAR szMessage[MAX_STRING_LEN];
113    WCHAR szResource[MAX_STRING_LEN];
114
115    /* Load and format szMessage */
116    LoadStringW(Globals.hInstance, formatId, szResource, ARRAY_SIZE(szResource));
117    wnsprintfW(szMessage, ARRAY_SIZE(szMessage), szResource, szString);
118
119    /* Load szCaption */
120    if ((dwFlags & MB_ICONMASK) == MB_ICONEXCLAMATION)
121      LoadStringW(Globals.hInstance, STRING_ERROR,  szResource, ARRAY_SIZE(szResource));
122    else
123      LoadStringW(Globals.hInstance, STRING_NOTEPAD,  szResource, ARRAY_SIZE(szResource));
124
125    /* Display Modal Dialog */
126    if (hParent == NULL)
127      hParent = Globals.hMainWnd;
128    return MessageBoxW(hParent, szMessage, szResource, dwFlags);
129 }
130
131 static void AlertFileNotFound(LPCWSTR szFileName)
132 {
133    DIALOG_StringMsgBox(NULL, STRING_NOTFOUND, szFileName, MB_ICONEXCLAMATION|MB_OK);
134 }
135
136 static int AlertFileNotSaved(LPCWSTR szFileName)
137 {
138    WCHAR szUntitled[MAX_STRING_LEN];
139
140    LoadStringW(Globals.hInstance, STRING_UNTITLED, szUntitled, ARRAY_SIZE(szUntitled));
141    return DIALOG_StringMsgBox(NULL, STRING_NOTSAVED, szFileName[0] ? szFileName : szUntitled,
142      MB_ICONQUESTION|MB_YESNOCANCEL);
143 }
144
145 static int AlertUnicodeCharactersLost(LPCWSTR szFileName)
146 {
147     WCHAR szMsgFormat[MAX_STRING_LEN];
148     WCHAR szEnc[MAX_STRING_LEN];
149     WCHAR szMsg[ARRAY_SIZE(szMsgFormat) + MAX_PATH + ARRAY_SIZE(szEnc)];
150     WCHAR szCaption[MAX_STRING_LEN];
151
152     LoadStringW(Globals.hInstance, STRING_LOSS_OF_UNICODE_CHARACTERS,
153                 szMsgFormat, ARRAY_SIZE(szMsgFormat));
154     load_encoding_name(ENCODING_ANSI, szEnc, ARRAY_SIZE(szEnc));
155     wnsprintfW(szMsg, ARRAY_SIZE(szMsg), szMsgFormat, szFileName, szEnc);
156     LoadStringW(Globals.hInstance, STRING_NOTEPAD, szCaption,
157                 ARRAY_SIZE(szCaption));
158     return MessageBoxW(Globals.hMainWnd, szMsg, szCaption,
159                        MB_OKCANCEL|MB_ICONEXCLAMATION);
160 }
161
162 /**
163  * Returns:
164  *   TRUE  - if file exists
165  *   FALSE - if file does not exist
166  */
167 BOOL FileExists(LPCWSTR szFilename)
168 {
169    WIN32_FIND_DATAW entry;
170    HANDLE hFile;
171
172    hFile = FindFirstFileW(szFilename, &entry);
173    FindClose(hFile);
174
175    return (hFile != INVALID_HANDLE_VALUE);
176 }
177
178 static inline BOOL is_conversion_to_ansi_lossy(LPCWSTR textW, int lenW)
179 {
180     BOOL ret = FALSE;
181     WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, textW, lenW, NULL, 0,
182                         NULL, &ret);
183     return ret;
184 }
185
186 typedef enum
187 {
188     SAVED_OK,
189     SAVE_FAILED,
190     SHOW_SAVEAS_DIALOG
191 } SAVE_STATUS;
192
193 /* szFileName is the filename to save under; enc is the encoding to use.
194  *
195  * If the function succeeds, it returns SAVED_OK.
196  * If the function fails, it returns SAVE_FAILED.
197  * If Unicode data could be lost due to conversion to a non-Unicode character
198  * set, a warning is displayed. The user can continue (and the function carries
199  * on), or cancel (and the function returns SHOW_SAVEAS_DIALOG).
200  */
201 static SAVE_STATUS DoSaveFile(LPCWSTR szFileName, ENCODING enc)
202 {
203     int lenW;
204     WCHAR* textW;
205     HANDLE hFile;
206     DWORD dwNumWrite;
207     PVOID pBytes;
208     DWORD size;
209
210     /* lenW includes the byte-order mark, but not the \0. */
211     lenW = GetWindowTextLengthW(Globals.hEdit) + 1;
212     textW = HeapAlloc(GetProcessHeap(), 0, (lenW+1) * sizeof(WCHAR));
213     if (!textW)
214     {
215         ShowLastError();
216         return SAVE_FAILED;
217     }
218     textW[0] = (WCHAR) 0xfeff;
219     lenW = GetWindowTextW(Globals.hEdit, textW+1, lenW) + 1;
220
221     switch (enc)
222     {
223     case ENCODING_UTF16BE:
224         byteswap_wide_string(textW, lenW);
225         /* fall through */
226
227     case ENCODING_UTF16LE:
228         size = lenW * sizeof(WCHAR);
229         pBytes = textW;
230         break;
231
232     case ENCODING_UTF8:
233         size = WideCharToMultiByte(CP_UTF8, 0, textW, lenW, NULL, 0, NULL, NULL);
234         pBytes = HeapAlloc(GetProcessHeap(), 0, size);
235         if (!pBytes)
236         {
237             ShowLastError();
238             HeapFree(GetProcessHeap(), 0, textW);
239             return SAVE_FAILED;
240         }
241         WideCharToMultiByte(CP_UTF8, 0, textW, lenW, pBytes, size, NULL, NULL);
242         HeapFree(GetProcessHeap(), 0, textW);
243         break;
244
245     default:
246         if (is_conversion_to_ansi_lossy(textW+1, lenW-1)
247             && AlertUnicodeCharactersLost(szFileName) == IDCANCEL)
248         {
249             HeapFree(GetProcessHeap(), 0, textW);
250             return SHOW_SAVEAS_DIALOG;
251         }
252
253         size = WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, NULL, 0, NULL, NULL);
254         pBytes = HeapAlloc(GetProcessHeap(), 0, size);
255         if (!pBytes)
256         {
257             ShowLastError();
258             HeapFree(GetProcessHeap(), 0, textW);
259             return SAVE_FAILED;
260         }
261         WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, pBytes, size, NULL, NULL);
262         HeapFree(GetProcessHeap(), 0, textW);
263         break;
264     }
265
266     hFile = CreateFileW(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
267                        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
268     if(hFile == INVALID_HANDLE_VALUE)
269     {
270         ShowLastError();
271         HeapFree(GetProcessHeap(), 0, pBytes);
272         return SAVE_FAILED;
273     }
274     if (!WriteFile(hFile, pBytes, size, &dwNumWrite, NULL))
275     {
276         ShowLastError();
277         CloseHandle(hFile);
278         HeapFree(GetProcessHeap(), 0, pBytes);
279         return SAVE_FAILED;
280     }
281     SetEndOfFile(hFile);
282     CloseHandle(hFile);
283     HeapFree(GetProcessHeap(), 0, pBytes);
284
285     SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
286     return SAVED_OK;
287 }
288
289 /**
290  * Returns:
291  *   TRUE  - User agreed to close (both save/don't save)
292  *   FALSE - User cancelled close by selecting "Cancel"
293  */
294 BOOL DoCloseFile(void)
295 {
296     int nResult;
297     static const WCHAR empty_strW[] = { 0 };
298
299     if (SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0))
300     {
301         /* prompt user to save changes */
302         nResult = AlertFileNotSaved(Globals.szFileName);
303         switch (nResult) {
304             case IDYES:     return DIALOG_FileSave();
305
306             case IDNO:      break;
307
308             case IDCANCEL:  return(FALSE);
309
310             default:        return(FALSE);
311         } /* switch */
312     } /* if */
313
314     SetFileNameAndEncoding(empty_strW, ENCODING_ANSI);
315
316     UpdateWindowCaption();
317     return(TRUE);
318 }
319
320 static inline ENCODING detect_encoding_of_buffer(const void* buffer, int size)
321 {
322     static const char bom_utf8[] = { 0xef, 0xbb, 0xbf };
323     if (size >= sizeof(bom_utf8) && !memcmp(buffer, bom_utf8, sizeof(bom_utf8)))
324         return ENCODING_UTF8;
325     else
326     {
327         int flags = IS_TEXT_UNICODE_SIGNATURE |
328                     IS_TEXT_UNICODE_REVERSE_SIGNATURE |
329                     IS_TEXT_UNICODE_ODD_LENGTH;
330         IsTextUnicode(buffer, size, &flags);
331         if (flags & IS_TEXT_UNICODE_SIGNATURE)
332             return ENCODING_UTF16LE;
333         else if (flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
334             return ENCODING_UTF16BE;
335         else
336             return ENCODING_ANSI;
337     }
338 }
339
340 void DoOpenFile(LPCWSTR szFileName, ENCODING enc)
341 {
342     static const WCHAR dotlog[] = { '.','L','O','G',0 };
343     HANDLE hFile;
344     LPSTR pTemp;
345     DWORD size;
346     DWORD dwNumRead;
347     int lenW;
348     WCHAR* textW;
349     int i;
350     WCHAR log[5];
351
352     /* Close any files and prompt to save changes */
353     if (!DoCloseFile())
354         return;
355
356     hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
357                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
358     if(hFile == INVALID_HANDLE_VALUE)
359     {
360         AlertFileNotFound(szFileName);
361         return;
362     }
363
364     size = GetFileSize(hFile, NULL);
365     if (size == INVALID_FILE_SIZE)
366     {
367         CloseHandle(hFile);
368         ShowLastError();
369         return;
370     }
371
372     /* Extra memory for (WCHAR)'\0'-termination. */
373     pTemp = HeapAlloc(GetProcessHeap(), 0, size+2);
374     if (!pTemp)
375     {
376         CloseHandle(hFile);
377         ShowLastError();
378         return;
379     }
380
381     if (!ReadFile(hFile, pTemp, size, &dwNumRead, NULL))
382     {
383         CloseHandle(hFile);
384         HeapFree(GetProcessHeap(), 0, pTemp);
385         ShowLastError();
386         return;
387     }
388
389     CloseHandle(hFile);
390
391     size = dwNumRead;
392
393     if (enc == ENCODING_AUTO)
394         enc = detect_encoding_of_buffer(pTemp, size);
395     else if (size >= 2 && (enc==ENCODING_UTF16LE || enc==ENCODING_UTF16BE))
396     {
397         /* If UTF-16 (BE or LE) is selected, and there is a UTF-16 BOM,
398          * override the selection (like native Notepad).
399          */
400         if ((BYTE)pTemp[0] == 0xff && (BYTE)pTemp[1] == 0xfe)
401             enc = ENCODING_UTF16LE;
402         else if ((BYTE)pTemp[0] == 0xfe && (BYTE)pTemp[1] == 0xff)
403             enc = ENCODING_UTF16BE;
404     }
405
406     switch (enc)
407     {
408     case ENCODING_UTF16BE:
409         byteswap_wide_string((WCHAR*) pTemp, size/sizeof(WCHAR));
410         /* Forget whether the file is BE or LE, like native Notepad. */
411         enc = ENCODING_UTF16LE;
412
413         /* fall through */
414
415     case ENCODING_UTF16LE:
416         textW = (LPWSTR)pTemp;
417         lenW  = size/sizeof(WCHAR);
418         break;
419
420     default:
421         {
422             int cp = (enc==ENCODING_UTF8) ? CP_UTF8 : CP_ACP;
423             lenW = MultiByteToWideChar(cp, 0, pTemp, size, NULL, 0);
424             textW = HeapAlloc(GetProcessHeap(), 0, (lenW+1) * sizeof(WCHAR));
425             if (!textW)
426             {
427                 ShowLastError();
428                 HeapFree(GetProcessHeap(), 0, pTemp);
429                 return;
430             }
431             MultiByteToWideChar(cp, 0, pTemp, size, textW, lenW);
432             HeapFree(GetProcessHeap(), 0, pTemp);
433             break;
434         }
435     }
436
437     /* Replace '\0's with spaces. Other than creating a custom control that
438      * can deal with '\0' characters, it's the best that can be done.
439      */
440     for (i = 0; i < lenW; i++)
441         if (textW[i] == '\0')
442             textW[i] = ' ';
443     textW[lenW] = '\0';
444
445     if (lenW >= 1 && textW[0] == 0xfeff)
446         SetWindowTextW(Globals.hEdit, textW+1);
447     else
448         SetWindowTextW(Globals.hEdit, textW);
449
450     HeapFree(GetProcessHeap(), 0, textW);
451
452     SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
453     SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
454     SetFocus(Globals.hEdit);
455     
456     /*  If the file starts with .LOG, add a time/date at the end and set cursor after */
457     if (GetWindowTextW(Globals.hEdit, log, ARRAY_SIZE(log)) && !lstrcmpW(log, dotlog))
458     {
459         static const WCHAR lfW[] = { '\r','\n',0 };
460         SendMessageW(Globals.hEdit, EM_SETSEL, GetWindowTextLengthW(Globals.hEdit), -1);
461         SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
462         DIALOG_EditTimeDate();
463         SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
464     }
465
466     SetFileNameAndEncoding(szFileName, enc);
467     UpdateWindowCaption();
468 }
469
470 VOID DIALOG_FileNew(VOID)
471 {
472     static const WCHAR empty_strW[] = { 0 };
473
474     /* Close any files and prompt to save changes */
475     if (DoCloseFile()) {
476         SetWindowTextW(Globals.hEdit, empty_strW);
477         SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
478         SetFocus(Globals.hEdit);
479     }
480 }
481
482 /* Used to detect encoding of files selected in Open dialog.
483  * Returns ENCODING_AUTO if file can't be read, etc.
484  */
485 static ENCODING detect_encoding_of_file(LPCWSTR szFileName)
486 {
487     DWORD size;
488     HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
489                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
490     if (hFile == INVALID_HANDLE_VALUE)
491         return ENCODING_AUTO;
492     size = GetFileSize(hFile, NULL);
493     if (size == INVALID_FILE_SIZE)
494     {
495         CloseHandle(hFile);
496         return ENCODING_AUTO;
497     }
498     else
499     {
500         DWORD dwNumRead;
501         BYTE buffer[MAX_STRING_LEN];
502         if (!ReadFile(hFile, buffer, min(size, sizeof(buffer)), &dwNumRead, NULL))
503         {
504             CloseHandle(hFile);
505             return ENCODING_AUTO;
506         }
507         CloseHandle(hFile);
508         return detect_encoding_of_buffer(buffer, dwNumRead);
509     }
510 }
511
512 static UINT_PTR CALLBACK OfnHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
513 {
514     static HWND hEncCombo;
515
516     switch (uMsg)
517     {
518     case WM_INITDIALOG:
519         {
520             ENCODING enc;
521             hEncCombo = GetDlgItem(hdlg, IDC_OFN_ENCCOMBO);
522             for (enc = MIN_ENCODING; enc <= MAX_ENCODING; enc++)
523             {
524                 WCHAR szEnc[MAX_STRING_LEN];
525                 load_encoding_name(enc, szEnc, ARRAY_SIZE(szEnc));
526                 SendMessageW(hEncCombo, CB_ADDSTRING, 0, (LPARAM)szEnc);
527             }
528             SendMessageW(hEncCombo, CB_SETCURSEL, (WPARAM)Globals.encOfnCombo, 0);
529         }
530         break;
531
532     case WM_COMMAND:
533         if (LOWORD(wParam) == IDC_OFN_ENCCOMBO &&
534             HIWORD(wParam) == CBN_SELCHANGE)
535         {
536             int index = SendMessageW(hEncCombo, CB_GETCURSEL, 0, 0);
537             Globals.encOfnCombo = index==CB_ERR ? ENCODING_ANSI : (ENCODING)index;
538         }
539
540         break;
541
542     case WM_NOTIFY:
543         switch (((OFNOTIFYW*)lParam)->hdr.code)
544         {
545             case CDN_SELCHANGE:
546                 if (Globals.bOfnIsOpenDialog)
547                 {
548                     /* Check the start of the selected file for a BOM. */
549                     ENCODING enc;
550                     WCHAR szFileName[MAX_PATH];
551                     SendMessageW(GetParent(hdlg), CDM_GETFILEPATH,
552                                  ARRAY_SIZE(szFileName), (LPARAM)szFileName);
553                     enc = detect_encoding_of_file(szFileName);
554                     if (enc != ENCODING_AUTO)
555                     {
556                         Globals.encOfnCombo = enc;
557                         SendMessageW(hEncCombo, CB_SETCURSEL, (WPARAM)enc, 0);
558                     }
559                 }
560                 break;
561
562             default:
563                 break;
564         }
565         break;
566
567     default:
568         break;
569     }
570     return 0;
571 }
572
573 VOID DIALOG_FileOpen(VOID)
574 {
575     OPENFILENAMEW openfilename;
576     WCHAR szPath[MAX_PATH];
577     WCHAR szDir[MAX_PATH];
578     static const WCHAR szDefaultExt[] = { 't','x','t',0 };
579     static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
580
581     ZeroMemory(&openfilename, sizeof(openfilename));
582
583     GetCurrentDirectoryW(ARRAY_SIZE(szDir), szDir);
584     lstrcpyW(szPath, txt_files);
585
586     openfilename.lStructSize       = sizeof(openfilename);
587     openfilename.hwndOwner         = Globals.hMainWnd;
588     openfilename.hInstance         = Globals.hInstance;
589     openfilename.lpstrFilter       = Globals.szFilter;
590     openfilename.lpstrFile         = szPath;
591     openfilename.nMaxFile          = ARRAY_SIZE(szPath);
592     openfilename.lpstrInitialDir   = szDir;
593     openfilename.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER |
594                          OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
595                          OFN_HIDEREADONLY | OFN_ENABLESIZING;
596     openfilename.lpfnHook          = OfnHookProc;
597     openfilename.lpTemplateName    = MAKEINTRESOURCEW(IDD_OFN_TEMPLATE);
598     openfilename.lpstrDefExt       = szDefaultExt;
599
600     Globals.encOfnCombo = ENCODING_ANSI;
601     Globals.bOfnIsOpenDialog = TRUE;
602
603     if (GetOpenFileNameW(&openfilename))
604         DoOpenFile(openfilename.lpstrFile, Globals.encOfnCombo);
605 }
606
607 /* Return FALSE to cancel close */
608 BOOL DIALOG_FileSave(VOID)
609 {
610     if (Globals.szFileName[0] == '\0')
611         return DIALOG_FileSaveAs();
612     else
613     {
614         switch (DoSaveFile(Globals.szFileName, Globals.encFile))
615         {
616             case SAVED_OK:           return TRUE;
617             case SHOW_SAVEAS_DIALOG: return DIALOG_FileSaveAs();
618             default:                 return FALSE;
619         }
620     }
621 }
622
623 BOOL DIALOG_FileSaveAs(VOID)
624 {
625     OPENFILENAMEW saveas;
626     WCHAR szPath[MAX_PATH];
627     WCHAR szDir[MAX_PATH];
628     static const WCHAR szDefaultExt[] = { 't','x','t',0 };
629     static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
630
631     ZeroMemory(&saveas, sizeof(saveas));
632
633     GetCurrentDirectoryW(ARRAY_SIZE(szDir), szDir);
634     lstrcpyW(szPath, txt_files);
635
636     saveas.lStructSize       = sizeof(OPENFILENAMEW);
637     saveas.hwndOwner         = Globals.hMainWnd;
638     saveas.hInstance         = Globals.hInstance;
639     saveas.lpstrFilter       = Globals.szFilter;
640     saveas.lpstrFile         = szPath;
641     saveas.nMaxFile          = ARRAY_SIZE(szPath);
642     saveas.lpstrInitialDir   = szDir;
643     saveas.Flags          = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER |
644                             OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
645                             OFN_HIDEREADONLY | OFN_ENABLESIZING;
646     saveas.lpfnHook          = OfnHookProc;
647     saveas.lpTemplateName    = MAKEINTRESOURCEW(IDD_OFN_TEMPLATE);
648     saveas.lpstrDefExt       = szDefaultExt;
649
650     /* Preset encoding to what file was opened/saved last with. */
651     Globals.encOfnCombo = Globals.encFile;
652     Globals.bOfnIsOpenDialog = FALSE;
653
654 retry:
655     if (!GetSaveFileNameW(&saveas))
656         return FALSE;
657
658     switch (DoSaveFile(szPath, Globals.encOfnCombo))
659     {
660         case SAVED_OK:
661             SetFileNameAndEncoding(szPath, Globals.encOfnCombo);
662             UpdateWindowCaption();
663             return TRUE;
664
665         case SHOW_SAVEAS_DIALOG:
666             goto retry;
667
668         default:
669             return FALSE;
670     }
671 }
672
673 typedef struct {
674     LPWSTR mptr;
675     LPWSTR mend;
676     LPWSTR lptr;
677     DWORD len;
678 } TEXTINFO, *LPTEXTINFO;
679
680 static int notepad_print_header(HDC hdc, RECT *rc, BOOL dopage, BOOL header, int page, LPWSTR text)
681 {
682     SIZE szMetric;
683
684     if (*text)
685     {
686         /* Write the header or footer */
687         GetTextExtentPoint32W(hdc, text, lstrlenW(text), &szMetric);
688         if (dopage)
689             ExtTextOutW(hdc, (rc->left + rc->right - szMetric.cx) / 2,
690                         header ? rc->top : rc->bottom - szMetric.cy,
691                         ETO_CLIPPED, rc, text, lstrlenW(text), NULL);
692         return 1;
693     }
694     return 0;
695 }
696
697 static BOOL notepad_print_page(HDC hdc, RECT *rc, BOOL dopage, int page, LPTEXTINFO tInfo)
698 {
699     int b, y;
700     TEXTMETRICW tm;
701     SIZE szMetrics;
702
703     if (dopage)
704     {
705         if (StartPage(hdc) <= 0)
706         {
707             static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 };
708             static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 };
709             MessageBoxW(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION);
710             return FALSE;
711         }
712     }
713
714     GetTextMetricsW(hdc, &tm);
715     y = rc->top + notepad_print_header(hdc, rc, dopage, TRUE, page, Globals.szFileName) * tm.tmHeight;
716     b = rc->bottom - 2 * notepad_print_header(hdc, rc, FALSE, FALSE, page, Globals.szFooter) * tm.tmHeight;
717
718     do {
719         INT m, n;
720
721         if (!tInfo->len)
722         {
723             /* find the end of the line */
724             while (tInfo->mptr < tInfo->mend && *tInfo->mptr != '\n' && *tInfo->mptr != '\r')
725             {
726                 if (*tInfo->mptr == '\t')
727                 {
728                     /* replace tabs with spaces */
729                     for (m = 0; m < SPACES_IN_TAB; m++)
730                     {
731                         if (tInfo->len < PRINT_LEN_MAX)
732                             tInfo->lptr[tInfo->len++] = ' ';
733                         else if (Globals.bWrapLongLines)
734                             break;
735                     }
736                 }
737                 else if (tInfo->len < PRINT_LEN_MAX)
738                     tInfo->lptr[tInfo->len++] = *tInfo->mptr;
739
740                 if (tInfo->len >= PRINT_LEN_MAX && Globals.bWrapLongLines)
741                      break;
742
743                 tInfo->mptr++;
744             }
745         }
746
747         /* Find out how much we should print if line wrapping is enabled */
748         if (Globals.bWrapLongLines)
749         {
750             GetTextExtentExPointW(hdc, tInfo->lptr, tInfo->len, rc->right - rc->left, &n, NULL, &szMetrics);
751             if (n < tInfo->len && tInfo->lptr[n] != ' ')
752             {
753                 m = n;
754                 /* Don't wrap words unless it's a single word over the entire line */
755                 while (m  && tInfo->lptr[m] != ' ') m--;
756                 if (m > 0) n = m + 1;
757             }
758         }
759         else
760             n = tInfo->len;
761
762         if (dopage)
763             ExtTextOutW(hdc, rc->left, y, ETO_CLIPPED, rc, tInfo->lptr, n, NULL);
764
765         tInfo->len -= n;
766
767         if (tInfo->len)
768         {
769             memcpy(tInfo->lptr, tInfo->lptr + n, tInfo->len * sizeof(WCHAR));
770             y += tm.tmHeight + tm.tmExternalLeading;
771         }
772         else
773         {
774             /* find the next line */
775             while (tInfo->mptr < tInfo->mend && y < b && (*tInfo->mptr == '\n' || *tInfo->mptr == '\r'))
776             {
777                 if (*tInfo->mptr == '\n')
778                     y += tm.tmHeight + tm.tmExternalLeading;
779                 tInfo->mptr++;
780             }
781         }
782     } while (tInfo->mptr < tInfo->mend && y < b);
783
784     notepad_print_header(hdc, rc, dopage, FALSE, page, Globals.szFooter);
785     if (dopage)
786     {
787         EndPage(hdc);
788     }
789     return TRUE;
790 }
791
792 VOID DIALOG_FilePrint(VOID)
793 {
794     DOCINFOW di;
795     PRINTDLGW printer;
796     int page, dopage, copy;
797     LOGFONTW lfFont;
798     HFONT hTextFont, old_font = 0;
799     DWORD size;
800     BOOL ret = FALSE;
801     RECT rc;
802     LPWSTR pTemp;
803     TEXTINFO tInfo;
804     WCHAR cTemp[PRINT_LEN_MAX];
805
806     /* Get Current Settings */
807     ZeroMemory(&printer, sizeof(printer));
808     printer.lStructSize           = sizeof(printer);
809     printer.hwndOwner             = Globals.hMainWnd;
810     printer.hDevMode              = Globals.hDevMode;
811     printer.hDevNames             = Globals.hDevNames;
812     printer.hInstance             = Globals.hInstance;
813
814     /* Set some default flags */
815     printer.Flags                 = PD_RETURNDC | PD_NOSELECTION;
816     printer.nFromPage             = 0;
817     printer.nMinPage              = 1;
818     /* we really need to calculate number of pages to set nMaxPage and nToPage */
819     printer.nToPage               = 0;
820     printer.nMaxPage              = -1;
821     /* Let commdlg manage copy settings */
822     printer.nCopies               = (WORD)PD_USEDEVMODECOPIES;
823
824     if (!PrintDlgW(&printer)) return;
825
826     Globals.hDevMode = printer.hDevMode;
827     Globals.hDevNames = printer.hDevNames;
828
829     SetMapMode(printer.hDC, MM_TEXT);
830
831     /* initialize DOCINFO */
832     di.cbSize = sizeof(DOCINFOW);
833     di.lpszDocName = Globals.szFileTitle;
834     di.lpszOutput = NULL;
835     di.lpszDatatype = NULL;
836     di.fwType = 0; 
837
838     /* Get the file text */
839     size = GetWindowTextLengthW(Globals.hEdit) + 1;
840     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
841     if (!pTemp)
842     {
843        DeleteDC(printer.hDC);
844        ShowLastError();
845        return;
846     }
847     size = GetWindowTextW(Globals.hEdit, pTemp, size);
848
849     if (StartDocW(printer.hDC, &di) > 0)
850     {
851         /* Get the page margins in pixels. */
852         rc.top =    MulDiv(Globals.iMarginTop, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540) -
853                     GetDeviceCaps(printer.hDC, PHYSICALOFFSETY);
854         rc.bottom = GetDeviceCaps(printer.hDC, PHYSICALHEIGHT) -
855                     MulDiv(Globals.iMarginBottom, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540);
856         rc.left =   MulDiv(Globals.iMarginLeft, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540) -
857                     GetDeviceCaps(printer.hDC, PHYSICALOFFSETX);
858         rc.right =  GetDeviceCaps(printer.hDC, PHYSICALWIDTH) -
859                     MulDiv(Globals.iMarginRight, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540);
860
861         /* Create a font for the printer resolution */
862         lfFont = Globals.lfFont;
863         lfFont.lfHeight = MulDiv(lfFont.lfHeight, GetDeviceCaps(printer.hDC, LOGPIXELSY), get_dpi());
864         /* Make the font a bit lighter */
865         lfFont.lfWeight -= 100;
866         hTextFont = CreateFontIndirectW(&lfFont);
867         old_font = SelectObject(printer.hDC, hTextFont);
868
869         for (copy = 1; copy <= printer.nCopies; copy++)
870         {
871             page = 1;
872
873             tInfo.mptr = pTemp;
874             tInfo.mend = pTemp + size;
875             tInfo.lptr = cTemp;
876             tInfo.len = 0;
877
878             do {
879                 if (printer.Flags & PD_PAGENUMS)
880                 {
881                     /* a specific range of pages is selected, so
882                      * skip pages that are not to be printed
883                      */
884                     if (page > printer.nToPage)
885                         break;
886                     else if (page >= printer.nFromPage)
887                         dopage = 1;
888                     else
889                         dopage = 0;
890                 }
891                 else
892                     dopage = 1;
893
894                 ret = notepad_print_page(printer.hDC, &rc, dopage, page, &tInfo);
895                 page++;
896             } while (ret && tInfo.mptr < tInfo.mend);
897
898             if (!ret) break;
899         }
900         EndDoc(printer.hDC);
901         SelectObject(printer.hDC, old_font);
902         DeleteObject(hTextFont);
903     }
904     DeleteDC(printer.hDC);
905     HeapFree(GetProcessHeap(), 0, pTemp);
906 }
907
908 VOID DIALOG_FilePrinterSetup(VOID)
909 {
910     PRINTDLGW printer;
911
912     ZeroMemory(&printer, sizeof(printer));
913     printer.lStructSize         = sizeof(printer);
914     printer.hwndOwner           = Globals.hMainWnd;
915     printer.hDevMode            = Globals.hDevMode;
916     printer.hDevNames           = Globals.hDevNames;
917     printer.hInstance           = Globals.hInstance;
918     printer.Flags               = PD_PRINTSETUP;
919     printer.nCopies             = 1;
920
921     PrintDlgW(&printer);
922
923     Globals.hDevMode = printer.hDevMode;
924     Globals.hDevNames = printer.hDevNames;
925 }
926
927 VOID DIALOG_FileExit(VOID)
928 {
929     PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0l);
930 }
931
932 VOID DIALOG_EditUndo(VOID)
933 {
934     SendMessageW(Globals.hEdit, EM_UNDO, 0, 0);
935 }
936
937 VOID DIALOG_EditCut(VOID)
938 {
939     SendMessageW(Globals.hEdit, WM_CUT, 0, 0);
940 }
941
942 VOID DIALOG_EditCopy(VOID)
943 {
944     SendMessageW(Globals.hEdit, WM_COPY, 0, 0);
945 }
946
947 VOID DIALOG_EditPaste(VOID)
948 {
949     SendMessageW(Globals.hEdit, WM_PASTE, 0, 0);
950 }
951
952 VOID DIALOG_EditDelete(VOID)
953 {
954     SendMessageW(Globals.hEdit, WM_CLEAR, 0, 0);
955 }
956
957 VOID DIALOG_EditSelectAll(VOID)
958 {
959     SendMessageW(Globals.hEdit, EM_SETSEL, 0, -1);
960 }
961
962 VOID DIALOG_EditTimeDate(VOID)
963 {
964     SYSTEMTIME   st;
965     WCHAR        szDate[MAX_STRING_LEN];
966     static const WCHAR spaceW[] = { ' ',0 };
967
968     GetLocalTime(&st);
969
970     GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, szDate, MAX_STRING_LEN);
971     SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
972
973     SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)spaceW);
974
975     GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
976     SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
977 }
978
979 VOID DIALOG_EditWrap(VOID)
980 {
981     BOOL modify = FALSE;
982     static const WCHAR editW[] = { 'e','d','i','t',0 };
983     DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |
984                     ES_AUTOVSCROLL | ES_MULTILINE;
985     RECT rc;
986     DWORD size;
987     LPWSTR pTemp;
988
989     size = GetWindowTextLengthW(Globals.hEdit) + 1;
990     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
991     if (!pTemp)
992     {
993         ShowLastError();
994         return;
995     }
996     GetWindowTextW(Globals.hEdit, pTemp, size);
997     modify = SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0);
998     DestroyWindow(Globals.hEdit);
999     GetClientRect(Globals.hMainWnd, &rc);
1000     if( Globals.bWrapLongLines ) dwStyle |= WS_HSCROLL | ES_AUTOHSCROLL;
1001     Globals.hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, editW, NULL, dwStyle,
1002                          0, 0, rc.right, rc.bottom, Globals.hMainWnd,
1003                          NULL, Globals.hInstance, NULL);
1004     SendMessageW(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
1005     SetWindowTextW(Globals.hEdit, pTemp);
1006     SendMessageW(Globals.hEdit, EM_SETMODIFY, modify, 0);
1007     SetFocus(Globals.hEdit);
1008     HeapFree(GetProcessHeap(), 0, pTemp);
1009     
1010     Globals.bWrapLongLines = !Globals.bWrapLongLines;
1011     CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_WRAP,
1012         MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_CHECKED : MF_UNCHECKED));
1013 }
1014
1015 VOID DIALOG_SelectFont(VOID)
1016 {
1017     CHOOSEFONTW cf;
1018     LOGFONTW lf=Globals.lfFont;
1019
1020     ZeroMemory( &cf, sizeof(cf) );
1021     cf.lStructSize=sizeof(cf);
1022     cf.hwndOwner=Globals.hMainWnd;
1023     cf.lpLogFont=&lf;
1024     cf.Flags=CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
1025
1026     if( ChooseFontW(&cf) )
1027     {
1028         HFONT currfont=Globals.hFont;
1029
1030         Globals.hFont=CreateFontIndirectW( &lf );
1031         Globals.lfFont=lf;
1032         SendMessageW( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, TRUE );
1033         if( currfont!=NULL )
1034             DeleteObject( currfont );
1035     }
1036 }
1037
1038 VOID DIALOG_Search(VOID)
1039 {
1040         /* Allow only one search/replace dialog to open */
1041         if(Globals.hFindReplaceDlg != NULL)
1042         {
1043             SetActiveWindow(Globals.hFindReplaceDlg);
1044             return;
1045         }
1046
1047         ZeroMemory(&Globals.find, sizeof(Globals.find));
1048         Globals.find.lStructSize      = sizeof(Globals.find);
1049         Globals.find.hwndOwner        = Globals.hMainWnd;
1050         Globals.find.hInstance        = Globals.hInstance;
1051         Globals.find.lpstrFindWhat    = Globals.szFindText;
1052         Globals.find.wFindWhatLen     = ARRAY_SIZE(Globals.szFindText);
1053         Globals.find.Flags            = FR_DOWN|FR_HIDEWHOLEWORD;
1054
1055         /* We only need to create the modal FindReplace dialog which will */
1056         /* notify us of incoming events using hMainWnd Window Messages    */
1057
1058         Globals.hFindReplaceDlg = FindTextW(&Globals.find);
1059         assert(Globals.hFindReplaceDlg !=0);
1060 }
1061
1062 VOID DIALOG_SearchNext(VOID)
1063 {
1064     if (Globals.lastFind.lpstrFindWhat == NULL)
1065         DIALOG_Search();
1066     else                /* use the last find data */
1067         NOTEPAD_DoFind(&Globals.lastFind);
1068 }
1069
1070 VOID DIALOG_Replace(VOID)
1071 {
1072         /* Allow only one search/replace dialog to open */
1073         if(Globals.hFindReplaceDlg != NULL)
1074         {
1075             SetActiveWindow(Globals.hFindReplaceDlg);
1076             return;
1077         }
1078
1079         ZeroMemory(&Globals.find, sizeof(Globals.find));
1080         Globals.find.lStructSize      = sizeof(Globals.find);
1081         Globals.find.hwndOwner        = Globals.hMainWnd;
1082         Globals.find.hInstance        = Globals.hInstance;
1083         Globals.find.lpstrFindWhat    = Globals.szFindText;
1084         Globals.find.wFindWhatLen     = ARRAY_SIZE(Globals.szFindText);
1085         Globals.find.lpstrReplaceWith = Globals.szReplaceText;
1086         Globals.find.wReplaceWithLen  = ARRAY_SIZE(Globals.szReplaceText);
1087         Globals.find.Flags            = FR_DOWN|FR_HIDEWHOLEWORD;
1088
1089         /* We only need to create the modal FindReplace dialog which will */
1090         /* notify us of incoming events using hMainWnd Window Messages    */
1091
1092         Globals.hFindReplaceDlg = ReplaceTextW(&Globals.find);
1093         assert(Globals.hFindReplaceDlg !=0);
1094 }
1095
1096 VOID DIALOG_HelpContents(VOID)
1097 {
1098     WinHelpW(Globals.hMainWnd, helpfileW, HELP_INDEX, 0);
1099 }
1100
1101 VOID DIALOG_HelpSearch(VOID)
1102 {
1103         /* Search Help */
1104 }
1105
1106 VOID DIALOG_HelpHelp(VOID)
1107 {
1108     WinHelpW(Globals.hMainWnd, helpfileW, HELP_HELPONHELP, 0);
1109 }
1110
1111 VOID DIALOG_HelpAboutNotepad(VOID)
1112 {
1113     static const WCHAR notepadW[] = { 'W','i','n','e',' ','N','o','t','e','p','a','d',0 };
1114     WCHAR szNotepad[MAX_STRING_LEN];
1115     HICON icon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_NOTEPAD),
1116                             IMAGE_ICON, 48, 48, LR_SHARED);
1117
1118     LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
1119     ShellAboutW(Globals.hMainWnd, szNotepad, notepadW, icon);
1120 }
1121
1122
1123 /***********************************************************************
1124  *
1125  *           DIALOG_FilePageSetup
1126  */
1127 VOID DIALOG_FilePageSetup(void)
1128 {
1129     DialogBoxW(Globals.hInstance, MAKEINTRESOURCEW(DIALOG_PAGESETUP),
1130                Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
1131 }
1132
1133
1134 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1135  *
1136  *           DIALOG_PAGESETUP_DlgProc
1137  */
1138
1139 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1140 {
1141
1142    switch (msg)
1143     {
1144     case WM_COMMAND:
1145       switch (wParam)
1146         {
1147         case IDOK:
1148           /* save user input and close dialog */
1149           GetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader, ARRAY_SIZE(Globals.szHeader));
1150           GetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter, ARRAY_SIZE(Globals.szFooter));
1151
1152           Globals.iMarginTop = GetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, NULL, FALSE) * 100;
1153           Globals.iMarginBottom = GetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, NULL, FALSE) * 100;
1154           Globals.iMarginLeft = GetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, NULL, FALSE) * 100;
1155           Globals.iMarginRight = GetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, NULL, FALSE) * 100;
1156           EndDialog(hDlg, IDOK);
1157           return TRUE;
1158
1159         case IDCANCEL:
1160           /* discard user input and close dialog */
1161           EndDialog(hDlg, IDCANCEL);
1162           return TRUE;
1163
1164         case IDHELP:
1165         {
1166           /* FIXME: Bring this to work */
1167           static const WCHAR sorryW[] = { 'S','o','r','r','y',',',' ','n','o',' ','h','e','l','p',' ','a','v','a','i','l','a','b','l','e',0 };
1168           static const WCHAR helpW[] = { 'H','e','l','p',0 };
1169           MessageBoxW(Globals.hMainWnd, sorryW, helpW, MB_ICONEXCLAMATION);
1170           return TRUE;
1171         }
1172
1173         default:
1174             break;
1175         }
1176       break;
1177
1178     case WM_INITDIALOG:
1179        /* fetch last user input prior to display dialog */
1180        SetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader);
1181        SetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter);
1182        SetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, Globals.iMarginTop / 100, FALSE);
1183        SetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, Globals.iMarginBottom / 100, FALSE);
1184        SetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, Globals.iMarginLeft / 100, FALSE);
1185        SetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, Globals.iMarginRight / 100, FALSE);
1186        break;
1187     }
1188
1189   return FALSE;
1190 }