fe0bf8aa304a9d3325183de5f5cbe68affce56fe
[reactos.git] / base / applications / fontview / fontview.c
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 /* if all of this goes correctly, message the user about success */
519 MessageBoxW(hwnd, L"Font Installation Completed.", L"Success", MB_OK);
520
521 return 0;
522 }
523
524 static LRESULT
525 MainWnd_OnPrev(HWND hwnd)
526 {
527 HWND hDisplay;
528 if (g_FontIndex > 0)
529 {
530 --g_FontIndex;
531 EnableWindow(GetDlgItem(hwnd, IDC_NEXT), TRUE);
532 if (g_FontIndex == 0)
533 EnableWindow(GetDlgItem(hwnd, IDC_PREV), FALSE);
534
535 hDisplay = GetDlgItem(hwnd, IDC_DISPLAY);
536 SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_LogFonts[g_FontIndex]);
537 InvalidateRect(hDisplay, NULL, TRUE);
538 }
539 return 0;
540 }
541
542 static LRESULT
543 MainWnd_OnNext(HWND hwnd)
544 {
545 HWND hDisplay;
546 if (g_FontIndex + 1 < g_NumFonts)
547 {
548 ++g_FontIndex;
549 EnableWindow(GetDlgItem(hwnd, IDC_PREV), TRUE);
550 if (g_FontIndex == g_NumFonts - 1)
551 EnableWindow(GetDlgItem(hwnd, IDC_NEXT), 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 LRESULT CALLBACK
561 MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
562 {
563 switch (message)
564 {
565 case WM_CREATE:
566 return MainWnd_OnCreate(hwnd);
567
568 case WM_PAINT:
569 return MainWnd_OnPaint(hwnd);
570
571 case WM_SIZE:
572 return MainWnd_OnSize(hwnd);
573
574 case WM_COMMAND:
575 switch(LOWORD(wParam))
576 {
577 case IDC_INSTALL:
578 return MainWnd_OnInstall(hwnd);
579
580 case IDC_PRINT:
581 return Display_OnPrint(hwnd);
582
583 case IDC_PREV:
584 return MainWnd_OnPrev(hwnd);
585
586 case IDC_NEXT:
587 return MainWnd_OnNext(hwnd);
588 }
589 break;
590
591 case WM_DESTROY:
592 PostQuitMessage (0); /* send a WM_QUIT to the message queue */
593 break;
594
595 default: /* for messages that we don't deal with */
596 return DefWindowProcW(hwnd, message, wParam, lParam);
597 }
598
599 return 0;
600 }
601
602 /* EOF */