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