1 /*
2  * PROJECT:     ReactOS Font Viewer
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Main source file
5  * COPYRIGHT:   Copyright 2007 Timo Kreuzer <timo.kreuzer@reactos.org>
6  *              Copyright 2016-2017 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7  */
8 
9 #include "precomp.h"
10 
11 #include <winnls.h>
12 #include <shellapi.h>
13 #include <windowsx.h>
14 #include <winreg.h>
15 
16 #include "fontview.h"
17 #include "resource.h"
18 
19 HINSTANCE g_hInstance;
20 INT g_FontIndex = 0;
21 INT g_NumFonts = 0;
22 LOGFONTW g_LogFonts[64];
23 LPCWSTR g_fileName = L"";
24 WCHAR g_FontTitle[1024] = L"";
25 BOOL g_FontPrint = FALSE;
26 BOOL g_DisableInstall = FALSE;
27 
28 static const WCHAR g_szFontViewClassName[] = L"FontViewWClass";
29 
30 /* GetFontResourceInfoW is undocumented */
31 BOOL WINAPI GetFontResourceInfoW(LPCWSTR lpFileName, DWORD *pdwBufSize, void* lpBuffer, DWORD dwType);
32 
33 DWORD
FormatString(DWORD dwFlags,HINSTANCE hInstance,DWORD dwStringId,DWORD dwLanguageId,LPWSTR lpBuffer,DWORD nSize,va_list * Arguments)34 FormatString(
35     DWORD dwFlags,
36     HINSTANCE hInstance,
37     DWORD dwStringId,
38     DWORD dwLanguageId,
39     LPWSTR lpBuffer,
40     DWORD nSize,
41     va_list* Arguments
42 )
43 {
44     DWORD dwRet;
45     int len;
46     WCHAR Buffer[1000];
47 
48     len = LoadStringW(hInstance, dwStringId, (LPWSTR)Buffer, 1000);
49 
50     if (len)
51     {
52         dwFlags |= FORMAT_MESSAGE_FROM_STRING;
53         dwFlags &= ~(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM);
54         dwRet = FormatMessageW(dwFlags, Buffer, 0, dwLanguageId, lpBuffer, nSize, Arguments);
55         return dwRet;
56     }
57     return 0;
58 }
59 
60 static void
FormatMsgBox(_In_ HWND hParent,_In_ DWORD dwMessageId,_In_ DWORD dwCaptionId,_In_ UINT uType,_In_ va_list args)61 FormatMsgBox(
62     _In_ HWND hParent,
63     _In_ DWORD dwMessageId,
64     _In_ DWORD dwCaptionId,
65     _In_ UINT uType,
66     _In_ va_list args)
67 {
68     HLOCAL hMemCaption = NULL;
69     HLOCAL hMemText = NULL;
70 
71     FormatString(FORMAT_MESSAGE_ALLOCATE_BUFFER,
72                   NULL, dwMessageId, 0, (LPWSTR)&hMemText, 0, &args);
73     FormatString(FORMAT_MESSAGE_ALLOCATE_BUFFER,
74                   NULL, dwCaptionId, 0, (LPWSTR)&hMemCaption, 0, NULL);
75 
76     MessageBoxW(hParent, hMemText, hMemCaption, uType);
77     LocalFree(hMemCaption);
78     LocalFree(hMemText);
79 }
80 
81 static void
ErrorMsgBox(HWND hParent,DWORD dwMessageId,...)82 ErrorMsgBox(
83     HWND hParent,
84     DWORD dwMessageId,
85     ...)
86 {
87     va_list args;
88 
89     va_start(args, dwMessageId);
90     FormatMsgBox(hParent, dwMessageId, IDS_ERROR, MB_ICONERROR, args);
91     va_end(args);
92 }
93 
94 static void
SuccessMsgBox(HWND hParent,DWORD dwMessageId,...)95 SuccessMsgBox(
96     HWND hParent,
97     DWORD dwMessageId,
98     ...)
99 {
100     va_list args;
101 
102     va_start(args, dwMessageId);
103     FormatMsgBox(hParent, dwMessageId, IDS_SUCCESS, MB_ICONINFORMATION, args);
104     va_end(args);
105 }
106 
107 int WINAPI
wWinMain(HINSTANCE hThisInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow)108 wWinMain(HINSTANCE hThisInstance,
109          HINSTANCE hPrevInstance,
110          LPWSTR lpCmdLine,
111          int nCmdShow)
112 {
113     int argc;
114     INT i;
115     WCHAR** argv;
116     DWORD dwSize;
117     HWND hMainWnd;
118     MSG msg;
119     WNDCLASSEXW wincl;
120     LPCWSTR fileName;
121 
122     switch (GetUserDefaultUILanguage())
123     {
124     case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
125       SetProcessDefaultLayout(LAYOUT_RTL);
126       break;
127 
128     default:
129       break;
130     }
131 
132     g_hInstance = hThisInstance;
133 
134     /* Get unicode command line */
135     argv = CommandLineToArgvW(GetCommandLineW(), &argc);
136     if (argc < 2)
137     {
138 #if 0
139         WCHAR szFileName[MAX_PATH] = L"";
140         OPENFILENAMEW fontOpen;
141         WCHAR filter[MAX_PATH*2] = {0}, dialogTitle[MAX_PATH];
142 
143         LoadStringW(NULL, IDS_OPEN, dialogTitle, ARRAYSIZE(dialogTitle));
144         LoadStringW(NULL, IDS_FILTER_LIST, filter, ARRAYSIZE(filter) - 1);
145 
146         /* Clears out any values of fontOpen before we use it */
147         ZeroMemory(&fontOpen, sizeof(fontOpen));
148 
149         /* Sets up the open dialog box */
150         fontOpen.lStructSize = sizeof(fontOpen);
151         fontOpen.hwndOwner = NULL;
152         fontOpen.lpstrFilter = filter;
153         fontOpen.lpstrFile = szFileName;
154         fontOpen.lpstrTitle = dialogTitle;
155         fontOpen.nMaxFile = MAX_PATH;
156         fontOpen.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
157         fontOpen.lpstrDefExt = L"ttf";
158 
159         /* Opens up the Open File dialog box in order to chose a font file. */
160         if(GetOpenFileNameW(&fontOpen))
161         {
162             fileName = fontOpen.lpstrFile;
163             g_fileName = fileName;
164         } else {
165             /* If the user decides to close out of the open dialog effectively
166             exiting the program altogether */
167             return 0;
168         }
169 #endif
170     }
171     else
172     {
173         /* Try to add the font resource from command line */
174         for (i = 1; i < argc; ++i)
175         {
176             // Treat the last argument as filename
177             if (i + 1 == argc)
178             {
179                 fileName = argv[i];
180             }
181             else if (argv[i][0] == '/' || argv[i][0] == '-')
182             {
183                 switch (argv[i][1])
184                 {
185                 case 'p':
186                 case 'P':
187                     g_FontPrint = TRUE;
188                     break;
189                 case 'd':
190                 case 'D':
191                     g_DisableInstall = TRUE;
192                     break;
193                 default:
194                     fileName = argv[i];
195                     break;
196                 }
197             }
198             else
199             {
200                 fileName = argv[i];
201             }
202         }
203         g_fileName = fileName;
204     }
205 
206     if (!AddFontResourceW(g_fileName))
207     {
208         ErrorMsgBox(0, IDS_ERROR_NOFONT, g_fileName);
209         return -1;
210     }
211 
212     /* Get the font name */
213     dwSize = sizeof(g_LogFonts);
214     ZeroMemory(g_LogFonts, sizeof(g_LogFonts));
215     if (!GetFontResourceInfoW(fileName, &dwSize, g_LogFonts, 2))
216     {
217         ErrorMsgBox(0, IDS_ERROR_NOFONT, fileName);
218         return -1;
219     }
220     g_NumFonts = 0;
221     for (i = 0; i < ARRAYSIZE(g_LogFonts); ++i)
222     {
223         if (g_LogFonts[i].lfFaceName[0] == 0)
224             break;
225 
226         ++g_NumFonts;
227     }
228     if (g_NumFonts == 0)
229     {
230         ErrorMsgBox(0, IDS_ERROR_NOFONT, fileName);
231         return -1;
232     }
233 
234     /* get font title */
235     dwSize = sizeof(g_FontTitle);
236     ZeroMemory(g_FontTitle, sizeof(g_FontTitle));
237     GetFontResourceInfoW(fileName, &dwSize, g_FontTitle, 1);
238 
239     if (!Display_InitClass(hThisInstance))
240     {
241         ErrorMsgBox(0, IDS_ERROR_NOCLASS);
242         return -1;
243     }
244 
245     /* The main window class */
246     wincl.cbSize = sizeof (WNDCLASSEXW);
247     wincl.style = CS_DBLCLKS;
248     wincl.lpfnWndProc = MainWndProc;
249     wincl.cbClsExtra = 0;
250     wincl.cbWndExtra = 0;
251     wincl.hInstance = hThisInstance;
252     wincl.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_TT));
253     wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
254     wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
255     wincl.lpszMenuName = NULL;
256     wincl.lpszClassName = g_szFontViewClassName;
257     wincl.hIconSm = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_TT));
258 
259     /* Register the window class, and if it fails quit the program */
260     if (!RegisterClassExW (&wincl))
261     {
262         ErrorMsgBox(0, IDS_ERROR_NOCLASS);
263         return 0;
264     }
265 
266     /* The class is registered, let's create the main window */
267     hMainWnd = CreateWindowExW(
268                 0,                      /* Extended possibilities for variation */
269                 g_szFontViewClassName,  /* Classname */
270                 g_FontTitle,            /* Title Text */
271                 WS_OVERLAPPEDWINDOW,    /* default window */
272                 CW_USEDEFAULT,          /* Windows decides the position */
273                 CW_USEDEFAULT,          /* where the window ends up on the screen */
274                 544,                    /* The programs width */
275                 375,                    /* and height in pixels */
276                 HWND_DESKTOP,           /* The window is a child-window to desktop */
277                 NULL,                   /* No menu */
278                 hThisInstance,          /* Program Instance handler */
279                 NULL                    /* No Window Creation data */
280             );
281     ShowWindow(hMainWnd, nCmdShow);
282 
283     /* Main message loop */
284     while (GetMessage (&msg, NULL, 0, 0))
285     {
286         if (IsDialogMessage(hMainWnd, &msg))
287             continue;
288         TranslateMessage(&msg);
289         DispatchMessage(&msg);
290     }
291 
292     RemoveFontResourceW(argv[1]);
293 
294     return (int)msg.wParam;
295 }
296 
297 static LRESULT
MainWnd_OnCreate(HWND hwnd)298 MainWnd_OnCreate(HWND hwnd)
299 {
300     WCHAR szQuit[MAX_BUTTONNAME];
301     WCHAR szPrint[MAX_BUTTONNAME];
302     WCHAR szString[MAX_STRING];
303     WCHAR szPrevious[MAX_STRING];
304     WCHAR szNext[MAX_STRING];
305     HWND hDisplay, hButtonInstall, hButtonPrint, hButtonPrev, hButtonNext;
306 
307     /* create the display window */
308     hDisplay = CreateWindowExW(
309                 0,                        /* Extended style */
310                 g_szFontDisplayClassName, /* Classname */
311                 L"",                      /* Title text */
312                 WS_CHILD | WS_VSCROLL,    /* Window style */
313                 0,                        /* X-pos */
314                 HEADER_SIZE,              /* Y-Pos */
315                 550,                      /* Width */
316                 370-HEADER_SIZE,          /* Height */
317                 hwnd,                     /* Parent */
318                 (HMENU)IDC_DISPLAY,       /* Identifier */
319                 g_hInstance,              /* Program Instance handler */
320                 NULL                      /* Window Creation data */
321             );
322 
323     LoadStringW(g_hInstance, IDS_STRING, szString, MAX_STRING);
324     SendMessage(hDisplay, FVM_SETSTRING, 0, (LPARAM)szString);
325 
326     /* Create the install button */
327     LoadStringW(g_hInstance, IDS_INSTALL, szQuit, MAX_BUTTONNAME);
328     hButtonInstall = CreateWindowExW(
329                 0,                      /* Extended style */
330                 L"button",              /* Classname */
331                 szQuit,                 /* Title text */
332                 WS_CHILD | WS_VISIBLE,  /* Window style */
333                 BUTTON_POS_X,           /* X-pos */
334                 BUTTON_POS_Y,           /* Y-Pos */
335                 BUTTON_WIDTH,           /* Width */
336                 BUTTON_HEIGHT,          /* Height */
337                 hwnd,                   /* Parent */
338                 (HMENU)IDC_INSTALL,     /* Identifier */
339                 g_hInstance,            /* Program Instance handler */
340                 NULL                    /* Window Creation data */
341             );
342     SendMessage(hButtonInstall, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE);
343     EnableWindow(hButtonInstall, !g_DisableInstall);
344 
345     /* Create the print button */
346     LoadStringW(g_hInstance, IDS_PRINT, szPrint, MAX_BUTTONNAME);
347     hButtonPrint = CreateWindowExW(
348                 0,                      /* Extended style */
349                 L"button",              /* Classname */
350                 szPrint,                /* Title text */
351                 WS_CHILD | WS_VISIBLE,  /* Window style */
352                 450,                    /* X-pos */
353                 BUTTON_POS_Y,           /* Y-Pos */
354                 BUTTON_WIDTH,           /* Width */
355                 BUTTON_HEIGHT,          /* Height */
356                 hwnd,                   /* Parent */
357                 (HMENU)IDC_PRINT,       /* Identifier */
358                 g_hInstance,            /* Program Instance handler */
359                 NULL                    /* Window Creation data */
360             );
361     SendMessage(hButtonPrint, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE);
362 
363     /* Create the previous button */
364     LoadStringW(g_hInstance, IDS_PREVIOUS, szPrevious, MAX_BUTTONNAME);
365     hButtonPrev = CreateWindowExW(
366                 0,                      /* Extended style */
367                 L"button",              /* Classname */
368                 szPrevious,             /* Title text */
369                 WS_CHILD | WS_VISIBLE,  /* Window style */
370                 450,                    /* X-pos */
371                 BUTTON_POS_Y,           /* Y-Pos */
372                 BUTTON_WIDTH,           /* Width */
373                 BUTTON_HEIGHT,          /* Height */
374                 hwnd,                   /* Parent */
375                 (HMENU)IDC_PREV,        /* Identifier */
376                 g_hInstance,            /* Program Instance handler */
377                 NULL                    /* Window Creation data */
378             );
379     SendMessage(hButtonPrev, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE);
380 
381     /* Create the next button */
382     LoadStringW(g_hInstance, IDS_NEXT, szNext, MAX_BUTTONNAME);
383     hButtonNext = CreateWindowExW(
384                 0,                      /* Extended style */
385                 L"button",              /* Classname */
386                 szNext,                 /* Title text */
387                 WS_CHILD | WS_VISIBLE,  /* Window style */
388                 450,                    /* X-pos */
389                 BUTTON_POS_Y,           /* Y-Pos */
390                 BUTTON_WIDTH,           /* Width */
391                 BUTTON_HEIGHT,          /* Height */
392                 hwnd,                   /* Parent */
393                 (HMENU)IDC_NEXT,        /* Identifier */
394                 g_hInstance,            /* Program Instance handler */
395                 NULL                    /* Window Creation data */
396             );
397     SendMessage(hButtonNext, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE);
398 
399     EnableWindow(hButtonPrev, FALSE);
400     if (g_NumFonts <= 1)
401         EnableWindow(hButtonNext, FALSE);
402 
403     /* Init the display window with the font name */
404     g_FontIndex = 0;
405     SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_LogFonts[g_FontIndex]);
406     ShowWindow(hDisplay, SW_SHOWNORMAL);
407 
408     if (g_FontPrint)
409         PostMessage(hwnd, WM_COMMAND, IDC_PRINT, 0);
410 
411     return 0;
412 }
413 
414 static LRESULT
MainWnd_OnSize(HWND hwnd)415 MainWnd_OnSize(HWND hwnd)
416 {
417     RECT rc;
418     HWND hInstall, hPrint, hPrev, hNext, hDisplay;
419     HDWP hDWP;
420 
421     GetClientRect(hwnd, &rc);
422 
423     hDWP = BeginDeferWindowPos(5);
424 
425     hInstall = GetDlgItem(hwnd, IDC_INSTALL);
426     if (hDWP)
427         hDWP = DeferWindowPos(hDWP, hInstall, NULL, BUTTON_POS_X, BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
428 
429     hPrint = GetDlgItem(hwnd, IDC_PRINT);
430     if (hDWP)
431         hDWP = DeferWindowPos(hDWP, hPrint, NULL, BUTTON_POS_X + BUTTON_WIDTH + BUTTON_PADDING, BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
432 
433     hPrev = GetDlgItem(hwnd, IDC_PREV);
434     if (hDWP)
435         hDWP = DeferWindowPos(hDWP, hPrev, NULL, rc.right - (BUTTON_WIDTH * 2 + BUTTON_PADDING + BUTTON_POS_X), BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
436 
437     hNext = GetDlgItem(hwnd, IDC_NEXT);
438     if (hDWP)
439         hDWP = DeferWindowPos(hDWP, hNext, NULL, rc.right - (BUTTON_WIDTH + BUTTON_POS_X), BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
440 
441     hDisplay = GetDlgItem(hwnd, IDC_DISPLAY);
442     if (hDWP)
443         hDWP = DeferWindowPos(hDWP, hDisplay, NULL, 0, HEADER_SIZE, rc.right, rc.bottom - HEADER_SIZE, SWP_NOZORDER);
444 
445     EndDeferWindowPos(hDWP);
446 
447     InvalidateRect(hwnd, NULL, TRUE);
448 
449     return 0;
450 }
451 
452 static LRESULT
MainWnd_OnPaint(HWND hwnd)453 MainWnd_OnPaint(HWND hwnd)
454 {
455     HDC hDC;
456     PAINTSTRUCT ps;
457     RECT rc;
458 
459     hDC = BeginPaint(hwnd, &ps);
460     GetClientRect(hwnd, &rc);
461     rc.top = HEADER_SIZE - 2;
462     rc.bottom = HEADER_SIZE;
463     FillRect(hDC, &rc, GetStockObject(GRAY_BRUSH));
464     EndPaint(hwnd, &ps);
465     return 0;
466 }
467 
468 static LRESULT
MainWnd_OnInstall(HWND hwnd)469 MainWnd_OnInstall(HWND hwnd)
470 {
471     WCHAR szFullName[64];
472 
473     WCHAR szSrcPath[MAX_PATH];
474     WCHAR szDestPath[MAX_PATH];
475     PWSTR pszFileName;
476     LONG res;
477     HKEY hKey;
478 
479     SendDlgItemMessage(hwnd, IDC_DISPLAY, FVM_GETFULLNAME, 64, (LPARAM)szFullName);
480 
481     /* First, we have to find out if the font still exists */
482     if (GetFileAttributes(g_fileName) == INVALID_FILE_ATTRIBUTES)
483     {
484         /* Fail, if the source file does not exist */
485         ErrorMsgBox(0, IDS_ERROR_NOFONT, g_fileName);
486         return -1;
487     }
488 
489     /* Build the full destination file name */
490     GetFullPathNameW(g_fileName, MAX_PATH, szSrcPath, &pszFileName);
491 
492     GetWindowsDirectoryW(szDestPath, MAX_PATH);
493     wcscat(szDestPath, L"\\Fonts\\");
494     wcscat(szDestPath, pszFileName);
495 
496     /* Check if the file already exists */
497     if (GetFileAttributesW(szDestPath) != INVALID_FILE_ATTRIBUTES)
498     {
499         ErrorMsgBox(hwnd, IDS_ERROR_ISINSTALLED);
500         return 0;
501     }
502 
503     /* Copy the font file */
504     if (!CopyFileW(g_fileName, szDestPath, TRUE))
505     {
506         ErrorMsgBox(hwnd, IDS_ERROR_FONTCPY);
507         return -1;
508     }
509 
510     /* Open the fonts key */
511     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
512                         L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
513                         0,
514                         KEY_ALL_ACCESS,
515                         &hKey);
516     if (res != ERROR_SUCCESS)
517     {
518         ErrorMsgBox(hwnd, IDS_ERROR_OPENKEY);
519         return -1;
520     }
521 
522     /* Register the font */
523     res = RegSetValueExW(hKey,
524                          szFullName,
525                          0,
526                          REG_SZ,
527                          (LPBYTE)pszFileName,
528                          (DWORD)(wcslen(pszFileName) + 1) * sizeof(WCHAR));
529     if (res != ERROR_SUCCESS)
530     {
531         ErrorMsgBox(hwnd, IDS_ERROR_REGISTER);
532         RegCloseKey(hKey);
533         return -1;
534     }
535 
536     /* Close the fonts key */
537     RegCloseKey(hKey);
538 
539     /* Broadcast WM_FONTCHANGE message */
540     SendMessageW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
541 
542     /* if all of this goes correctly, message the user about success */
543     SuccessMsgBox(hwnd, IDS_COMPLETED);
544 
545     return 0;
546 }
547 
548 static LRESULT
MainWnd_OnPrev(HWND hwnd)549 MainWnd_OnPrev(HWND hwnd)
550 {
551     HWND hDisplay;
552     if (g_FontIndex > 0)
553     {
554         --g_FontIndex;
555         EnableWindow(GetDlgItem(hwnd, IDC_NEXT), TRUE);
556         if (g_FontIndex == 0)
557             EnableWindow(GetDlgItem(hwnd, IDC_PREV), FALSE);
558 
559         hDisplay = GetDlgItem(hwnd, IDC_DISPLAY);
560         SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_LogFonts[g_FontIndex]);
561         InvalidateRect(hDisplay, NULL, TRUE);
562     }
563     return 0;
564 }
565 
566 static LRESULT
MainWnd_OnNext(HWND hwnd)567 MainWnd_OnNext(HWND hwnd)
568 {
569     HWND hDisplay;
570     if (g_FontIndex + 1 < g_NumFonts)
571     {
572         ++g_FontIndex;
573         EnableWindow(GetDlgItem(hwnd, IDC_PREV), TRUE);
574         if (g_FontIndex == g_NumFonts - 1)
575             EnableWindow(GetDlgItem(hwnd, IDC_NEXT), FALSE);
576 
577         hDisplay = GetDlgItem(hwnd, IDC_DISPLAY);
578         SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_LogFonts[g_FontIndex]);
579         InvalidateRect(hDisplay, NULL, TRUE);
580     }
581     return 0;
582 }
583 
584 LRESULT CALLBACK
MainWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)585 MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
586 {
587     switch (message)
588     {
589         case WM_CREATE:
590             return MainWnd_OnCreate(hwnd);
591 
592         case WM_PAINT:
593             return MainWnd_OnPaint(hwnd);
594 
595         case WM_SIZE:
596             return MainWnd_OnSize(hwnd);
597 
598         case WM_COMMAND:
599             switch(LOWORD(wParam))
600             {
601                 case IDC_INSTALL:
602                     return MainWnd_OnInstall(hwnd);
603 
604                 case IDC_PRINT:
605                     return Display_OnPrint(hwnd);
606 
607                 case IDC_PREV:
608                     return MainWnd_OnPrev(hwnd);
609 
610                 case IDC_NEXT:
611                     return MainWnd_OnNext(hwnd);
612             }
613             break;
614 
615         case WM_DESTROY:
616             PostQuitMessage (0);    /* send a WM_QUIT to the message queue */
617             break;
618 
619         default:                    /* for messages that we don't deal with */
620             return DefWindowProcW(hwnd, message, wParam, lParam);
621     }
622 
623     return 0;
624 }
625