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