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