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