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