Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

673 lines
22 KiB

  1. /****************************************************************************
  2. Freecell.c
  3. June 91, JimH initial code
  4. Oct 91, JimH port to Win32
  5. Main source module for Windows Free Cell.
  6. Contains WinMain, initialization routines, and MainWndProc.
  7. Design notes:
  8. Note that although this program uses some of the mapping macros,
  9. this version of the code is 32 bit only! See Wep2 sources for
  10. 16 bit sources.
  11. The current layout of the cards is kept in the array card[MAXCOL][MAXPOS].
  12. In this scheme, column 0 is actually the top row. In this "column", pos
  13. 0 to 3 are the free cells, and 4 to 7 are the home cells. The other
  14. columns numbered 1 to 8 are the stacked card columns.
  15. See PaintMainWindow() for some details on changing the display for EGA.
  16. A previous version of Free Cell used a timer for multi-card moves.
  17. WM_FAKETIMER messages are now sent manually to accomplish the same thing.
  18. ****************************************************************************/
  19. #include "freecell.h"
  20. #include "freecons.h"
  21. #include <shellapi.h>
  22. #include <regstr.h>
  23. #include <htmlhelp.h> // for HtmlHelp()
  24. #include <commctrl.h> // for fusion classes.
  25. /* Registry strings -- do not translate */
  26. CONST TCHAR pszRegPath[] = REGSTR_PATH_WINDOWSAPPLETS TEXT("\\FreeCell");
  27. CONST TCHAR pszWon[] = TEXT("won");
  28. CONST TCHAR pszLost[] = TEXT("lost");
  29. CONST TCHAR pszWins[] = TEXT("wins");
  30. CONST TCHAR pszLosses[] = TEXT("losses");
  31. CONST TCHAR pszStreak[] = TEXT("streak");
  32. CONST TCHAR pszSType[] = TEXT("stype");
  33. CONST TCHAR pszMessages[] = TEXT("messages");
  34. CONST TCHAR pszQuick[] = TEXT("quick");
  35. CONST TCHAR pszDblClick[] = TEXT("dblclick");
  36. CONST TCHAR pszAlreadyPlayed[] = TEXT("AlreadyPlayed");
  37. #define WTSIZE 50 // window text size in characters
  38. void _setargv() { } // reduces size of C runtimes
  39. void _setenvp() { }
  40. /****************************************************************************
  41. WinMain(HANDLE, HANDLE, LPSTR, int)
  42. ****************************************************************************/
  43. MMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) /* { */
  44. MSG msg; // message
  45. HANDLE hAccel; // LifeMenu accelerators
  46. if (!hPrevInstance) // Other instances of app running?
  47. if (!InitApplication(hInstance)) // Initialize shared things
  48. return FALSE; // Exits if unable to initialize
  49. if (!InitInstance(hInstance, nCmdShow))
  50. return FALSE;
  51. hAccel = LoadAccelerators(hInstance, TEXT("FreeMenu"));
  52. while (GetMessage(&msg, NULL, 0, 0))
  53. {
  54. if (!TranslateAccelerator(hMainWnd, hAccel, &msg))
  55. {
  56. TranslateMessage(&msg); // Translates virtual key codes
  57. DispatchMessage(&msg); // Dispatches message to window
  58. }
  59. }
  60. DEBUGMSG(TEXT("---- Free Cell Terminated ----\n\r"),0);
  61. return (INT) msg.wParam; /* Returns the value from PostQuitMessage */
  62. }
  63. /****************************************************************************
  64. InitApplication(HANDLE hInstance)
  65. ****************************************************************************/
  66. BOOL InitApplication(HANDLE hInstance)
  67. {
  68. WNDCLASS wc;
  69. HDC hIC; // information context
  70. INITCOMMONCONTROLSEX icc; // common control registration.
  71. DEBUGMSG(TEXT("---- Free Cell Initiated ----\n\r"),0);
  72. /* Check if monochrome */
  73. hIC = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
  74. if (GetDeviceCaps(hIC, NUMCOLORS) == 2)
  75. {
  76. bMonochrome = TRUE;
  77. /* BrightPen is not so bright in mono. */
  78. hBrightPen = CreatePen(PS_SOLID, 1, RGB( 0, 0, 0));
  79. hBgndBrush = CreateSolidBrush(RGB(255, 255, 255));
  80. }
  81. else
  82. {
  83. bMonochrome = FALSE;
  84. hBrightPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
  85. hBgndBrush = CreateSolidBrush(RGB(0, 127, 0)); // green background
  86. }
  87. DeleteDC(hIC);
  88. // Create the freecell icon
  89. hIconMain = LoadIcon(hInstance, MAKEINTRESOURCE(ID_ICON_MAIN));
  90. // Register the common controls.
  91. icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  92. icc.dwICC = ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_HOTKEY_CLASS | ICC_LISTVIEW_CLASSES |
  93. ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS | ICC_TAB_CLASSES | ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES;
  94. InitCommonControlsEx(&icc);
  95. wc.style = CS_DBLCLKS; // allow double clicks
  96. wc.lpfnWndProc = MainWndProc;
  97. wc.cbClsExtra = 0;
  98. wc.cbWndExtra = 0;
  99. wc.hInstance = hInstance;
  100. wc.hIcon = hIconMain;
  101. wc.hCursor = NULL;
  102. wc.hbrBackground = hBgndBrush;
  103. wc.lpszMenuName = TEXT("FreeMenu");
  104. wc.lpszClassName = TEXT("FreeWClass");
  105. return RegisterClass(&wc);
  106. }
  107. /****************************************************************************
  108. InitInstance(HANDLE hInstance, int nCmdShow)
  109. ****************************************************************************/
  110. BOOL InitInstance(HANDLE hInstance, INT nCmdShow)
  111. {
  112. HWND hWnd; // Main window handle.
  113. UINT col, pos;
  114. INT nWindowHeight;
  115. UINT wAlreadyPlayed; // have we already updated the registry ?
  116. UINT cTLost, cTWon; // total losses and wins
  117. UINT cTLosses, cTWins; // streaks
  118. UINT wStreak; // current streak amount
  119. UINT wSType; // current streak type
  120. LONG lRegResult; // used to store return code from registry call
  121. if (!hBrightPen || !hBgndBrush)
  122. return FALSE;
  123. /* Initialize some global variables */
  124. for (col = 0; col < MAXCOL; col++) // clear the deck
  125. for (pos = 0; pos < MAXPOS; pos++)
  126. card[col][pos] = EMPTY;
  127. hInst = hInstance;
  128. cWins = 0;
  129. cLosses = 0;
  130. cGames = 0;
  131. cUndo = 0;
  132. gamenumber = 0; // so no cards are drawn in main wnd
  133. oldgamenumber = 0; // this is first game and will count
  134. hMenuFont = 0;
  135. bWonState = FALSE;
  136. bGameInProgress = FALSE;
  137. bCheating = FALSE;
  138. bFastMode = FALSE;
  139. bFlipping = FALSE;
  140. pszIni = TEXT("entpack.ini");
  141. bDblClick = TRUE;
  142. bMessages = FALSE;
  143. /* for VGA or smaller, window will just fit inside screen */
  144. nWindowHeight = min(WINHEIGHT, GetSystemMetrics(SM_CYSCREEN));
  145. /* Create a main window for this application instance. */
  146. LoadString(hInst, IDS_APPNAME, smallbuf, SMALL);
  147. hWnd = CreateWindow(
  148. TEXT("FreeWClass"), // See RegisterClass() call.
  149. smallbuf, // Text for window title bar.
  150. WS_OVERLAPPEDWINDOW, // Window style.
  151. CW_USEDEFAULT, // Default horizontal position.
  152. CW_USEDEFAULT, // Default vertical position.
  153. WINWIDTH, // width.
  154. nWindowHeight, // height.
  155. NULL, // Overlapped windows have no parent.
  156. NULL, // Use the window class menu.
  157. hInstance, // This instance owns this window.
  158. NULL // Pointer not needed.
  159. );
  160. /* If window could not be created, return "failure" */
  161. if (!hWnd)
  162. return FALSE;
  163. hMainWnd = hWnd;
  164. /* Make the window visible; update its client area; and return "success" */
  165. ShowWindow(hWnd, nCmdShow); // Show the window
  166. UpdateWindow(hWnd); // Sends WM_PAINT message
  167. // Do the transfer of stats from the .ini file to the
  168. // registry (for people migrating from NT 4.0 freecell to NT 5.0)
  169. lRegResult = REGOPEN
  170. if (ERROR_SUCCESS == lRegResult)
  171. {
  172. wAlreadyPlayed = GetInt(pszAlreadyPlayed, 0);
  173. // If this is the first time we are playing
  174. // update the registry with the stats from the .ini file.
  175. if (!wAlreadyPlayed)
  176. {
  177. LoadString(hInst, IDS_APPNAME, bigbuf, BIG);
  178. // Read the stats from the .ini file. (if present)
  179. // If we can't read the stats, default value is zero.
  180. cTLost = GetPrivateProfileInt(bigbuf, TEXT("lost"), 0, pszIni);
  181. cTWon = GetPrivateProfileInt(bigbuf, TEXT("won"), 0, pszIni);
  182. cTLosses = GetPrivateProfileInt(bigbuf, TEXT("losses"), 0, pszIni);
  183. cTWins = GetPrivateProfileInt(bigbuf, TEXT("wins"), 0, pszIni);
  184. wStreak = GetPrivateProfileInt(bigbuf, TEXT("streak"), 0, pszIni);
  185. wSType = GetPrivateProfileInt(bigbuf, TEXT("stype"), 0, pszIni);
  186. // Copy the stats from the .ini file to the registry.
  187. SetInt(pszLost, cTLost);
  188. SetInt(pszWon, cTWon);
  189. SetInt(pszLosses, cTLosses);
  190. SetInt(pszWins, cTWins);
  191. SetInt(pszStreak, wStreak);
  192. SetInt(pszSType, wSType);
  193. // Set the already-played flag to 1.
  194. SetInt(pszAlreadyPlayed, 1);
  195. }
  196. REGCLOSE;
  197. }
  198. return TRUE; // Returns the value from PostQuitMessage
  199. }
  200. /****************************************************************************
  201. MainWndProc(HWND, unsigned, UINT, LONG)
  202. ****************************************************************************/
  203. LRESULT APIENTRY MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  204. {
  205. INT i; // generic counter
  206. int nResp; // messagebox response
  207. UINT col, pos;
  208. UINT wCheck; // for checking IDM_MESSAGES menu item
  209. HDC hDC;
  210. POINT FAR *MMInfo; // for GetMinMaxInfo
  211. HBRUSH hOldBrush;
  212. RECT rect;
  213. HMENU hMenu;
  214. static BOOL bEatNextMouseHit = FALSE; // is next hit only for activation?
  215. switch (message) {
  216. case WM_COMMAND:
  217. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  218. case IDM_ABOUT:
  219. LoadString(hInst, IDS_FULLNAME, bigbuf, BIG);
  220. LoadString(hInst, IDS_CREDITS, smallbuf, SMALL);
  221. ShellAbout(hWnd, (LPCTSTR)bigbuf, (LPCTSTR)smallbuf, hIconMain);
  222. break;
  223. case IDM_EXIT:
  224. SendMessage(hWnd, WM_CLOSE, 0, 0);
  225. break;
  226. case IDM_NEWGAME:
  227. lParam = GenerateRandomGameNum();
  228. case IDM_SELECT:
  229. case IDM_RESTART:
  230. if (bGameInProgress)
  231. {
  232. LoadString(hInst, IDS_RESIGN, bigbuf, BIG);
  233. LoadString(hInst, IDS_APPNAME, smallbuf, SMALL);
  234. MessageBeep(MB_ICONQUESTION);
  235. if (IDNO == MessageBox(hWnd, bigbuf, smallbuf,
  236. MB_YESNO | MB_ICONQUESTION))
  237. {
  238. break;
  239. }
  240. UpdateLossCount();
  241. }
  242. if (wParam == IDM_RESTART)
  243. {
  244. if (bGameInProgress)
  245. lParam = gamenumber;
  246. else
  247. lParam = oldgamenumber;
  248. }
  249. else if (wParam == IDM_SELECT)
  250. lParam = 0L;
  251. if (wParam == IDM_NEWGAME)
  252. bSelecting = FALSE;
  253. else if (wParam == IDM_SELECT)
  254. bSelecting = TRUE;
  255. bGameInProgress = FALSE;
  256. wFromCol = EMPTY; // no FROM selected
  257. wMouseMode = FROM; // FROM selected next
  258. moveindex = 0; // no queued moves
  259. for (i = 0; i < 4; i++) // nothing in home cells
  260. {
  261. homesuit[i] = EMPTY;
  262. home[i] = EMPTY;
  263. }
  264. ShuffleDeck(hWnd, lParam);
  265. if (gamenumber == CANCELGAME)
  266. break;
  267. InvalidateRect(hWnd, NULL, TRUE);
  268. wCardCount = 52;
  269. bGameInProgress = TRUE;
  270. hMenu = GetMenu(hWnd);
  271. EnableMenuItem(hMenu, IDM_RESTART, MF_ENABLED);
  272. DisplayCardCount(hWnd);
  273. hDC = GetDC(hWnd);
  274. DrawKing(hDC, RIGHT, FALSE);
  275. bWonState = FALSE;
  276. ReleaseDC(hWnd, hDC);
  277. break;
  278. case IDM_STATS:
  279. DialogBox(hInst, TEXT("Stats"), hWnd, StatsDlg);
  280. break;
  281. case IDM_OPTIONS:
  282. DialogBox(hInst, MAKEINTRESOURCE(DLG_OPTIONS), hWnd, OptionsDlg);
  283. break;
  284. case IDM_HELP:
  285. HtmlHelpA(GetDesktopWindow(), GetHelpFileName(), HH_DISPLAY_TOPIC, 0);
  286. break;
  287. case IDM_HOWTOPLAY:
  288. HtmlHelpA(GetDesktopWindow(), GetHelpFileName(), HH_DISPLAY_INDEX, 0);
  289. break;
  290. case IDM_HELPONHELP:
  291. HtmlHelpA(GetDesktopWindow(), "NTHelp.chm", HH_DISPLAY_TOPIC, 0);
  292. break;
  293. case IDM_UNDO:
  294. Undo(hWnd);
  295. break;
  296. /* Hidden options -- these strings need not be translated */
  297. case IDM_CHEAT:
  298. i = MessageBox(hWnd, TEXT("Choose Abort to Win,\n")
  299. TEXT("Retry to Lose,\nor Ignore to Cancel."),
  300. TEXT("User-Friendly User Interface"),
  301. MB_ABORTRETRYIGNORE | MB_ICONQUESTION);
  302. if (i == IDABORT)
  303. bCheating = CHEAT_WIN;
  304. else if (i == IDRETRY)
  305. bCheating = CHEAT_LOSE;
  306. else
  307. bCheating = FALSE;
  308. break;
  309. default:
  310. return DefWindowProc(hWnd, message, wParam, lParam);
  311. }
  312. break;
  313. case WM_CLOSE:
  314. if (bGameInProgress) // did user quit mid-game?
  315. {
  316. LoadString(hInst, IDS_APPNAME, smallbuf, SMALL);
  317. LoadString(hInst, IDS_RESIGN, bigbuf, BIG);
  318. MessageBeep(MB_ICONQUESTION);
  319. nResp = MessageBox(hWnd, bigbuf, smallbuf,
  320. MB_YESNO | MB_ICONQUESTION);
  321. if (nResp == IDNO)
  322. break;
  323. UpdateLossCount();
  324. }
  325. WriteOptions();
  326. return DefWindowProc(hWnd, message, wParam, lParam);
  327. case WM_CREATE:
  328. WMCreate(hWnd);
  329. break;
  330. case WM_DESTROY:
  331. if (hBgndBrush)
  332. DeleteObject(hBgndBrush);
  333. if (hBrightPen)
  334. DeleteObject(hBrightPen);
  335. if (hBM_Fgnd)
  336. DeleteObject(hBM_Fgnd);
  337. if (hBM_Bgnd1)
  338. DeleteObject(hBM_Bgnd1);
  339. if (hBM_Bgnd2)
  340. DeleteObject(hBM_Bgnd2);
  341. if (hBM_Ghost)
  342. DeleteObject(hBM_Ghost);
  343. if (hMenuFont)
  344. DeleteObject(hMenuFont);
  345. cdtTerm();
  346. PostQuitMessage(0);
  347. break;
  348. case WM_PAINT:
  349. PaintMainWindow(hWnd);
  350. break;
  351. case WM_SIZE:
  352. DrawMenuBar(hWnd); // fixes overlapping score on menu
  353. xOldLoc = 30000; // force cards left to redraw
  354. DisplayCardCount(hWnd); // must update if size changes
  355. break;
  356. /***** NOTE: WM_LBUTTONDBLCLK falls through to WM_LBUTTONDOWN ****/
  357. /* Double clicking works by simulating a move to a free cell. On
  358. the off cycle (that is, when wMouseMode == FROM) the double
  359. click is processed as a single click to cancel the move, and a
  360. second double click message is posted. */
  361. case WM_LBUTTONDBLCLK:
  362. if (moveindex != 0) // no mouse hit while cards moving
  363. break;
  364. if (gamenumber == 0)
  365. break;
  366. if (bFlipping)
  367. break;
  368. if (bDblClick && wFromCol > TOPROW && wFromCol < MAXCOL)
  369. {
  370. if (wMouseMode == TO)
  371. {
  372. Point2Card(LOWORD(lParam), HIWORD(lParam), &col, &pos);
  373. if (col == wFromCol)
  374. if (ProcessDoubleClick(hWnd)) // if card moved ok
  375. break;
  376. }
  377. else
  378. PostMessage(hWnd, message, wParam, lParam);
  379. }
  380. case WM_LBUTTONDOWN:
  381. if (bEatNextMouseHit) // is this only window activation?
  382. {
  383. bEatNextMouseHit = FALSE;
  384. break;
  385. }
  386. bEatNextMouseHit = FALSE;
  387. if (bFlipping) // cards flipping for keyboard players
  388. break;
  389. if (moveindex != 0) // no mouse hit while cards moving
  390. break;
  391. if (gamenumber == 0)
  392. break;
  393. if (wMouseMode == FROM)
  394. SetFromLoc(hWnd, LOWORD(lParam), HIWORD(lParam));
  395. else
  396. ProcessMoveRequest(hWnd, LOWORD(lParam), HIWORD(lParam));
  397. break;
  398. case WM_RBUTTONDOWN:
  399. SetCapture(hWnd);
  400. if (bFlipping)
  401. break;
  402. if (gamenumber != 0)
  403. RevealCard(hWnd, LOWORD(lParam), HIWORD(lParam));
  404. break;
  405. case WM_RBUTTONUP:
  406. ReleaseCapture();
  407. RestoreColumn(hWnd);
  408. break;
  409. case WM_MOUSEACTIVATE: // app is being activated,
  410. if (LOWORD(lParam) == HTCLIENT) // so don't try new cell on
  411. bEatNextMouseHit = TRUE; // clicked location
  412. break;
  413. case WM_MOUSEMOVE:
  414. SetCursorShape(hWnd, LOWORD(lParam), HIWORD(lParam));
  415. break;
  416. case WM_MOVE: // card count erases when moved
  417. DisplayCardCount(hWnd);
  418. return (DefWindowProc(hWnd, message, wParam, lParam));
  419. case WM_GETMINMAXINFO:
  420. if (GetSystemMetrics(SM_CXSCREEN) > 640) // skip if VGA
  421. {
  422. MMInfo = (POINT FAR *) lParam; // see SDK ref
  423. if (MMInfo[4].x > WINWIDTH)
  424. MMInfo[4].x = WINWIDTH; // set max window width to 640
  425. }
  426. else
  427. return DefWindowProc(hWnd, message, wParam, lParam);
  428. break;
  429. case WM_CHAR:
  430. if (!bFlipping)
  431. KeyboardInput(hWnd, (UINT) wParam);
  432. break;
  433. case WM_TIMER: // flash main window
  434. if (wParam == FLASH_TIMER)
  435. Flash(hWnd);
  436. else
  437. Flip(hWnd);
  438. break;
  439. default: // Passes it on if unproccessed
  440. return DefWindowProc(hWnd, message, wParam, lParam);
  441. }
  442. return 0;
  443. }
  444. /****************************************************************************
  445. WMCreate
  446. Handles WM_CREATE message in main window.
  447. ****************************************************************************/
  448. VOID WMCreate(HWND hWnd)
  449. {
  450. BOOL bResult; // result of cards.dll initialization
  451. HDC hDC;
  452. HDC hMemDC;
  453. HBITMAP hOldBitmap;
  454. HBRUSH hOldBrush;
  455. HPEN hOldPen;
  456. /* initialize cards.dll */
  457. bResult = cdtInit(&dxCrd, &dyCrd);
  458. CalcOffsets(hWnd);
  459. hDC = GetDC(hWnd);
  460. hMemDC = CreateCompatibleDC(hDC);
  461. hBM_Fgnd = CreateCompatibleBitmap(hDC, dxCrd, dyCrd);
  462. hBM_Bgnd1 = CreateCompatibleBitmap(hDC, dxCrd, dyCrd);
  463. hBM_Bgnd2 = CreateCompatibleBitmap(hDC, dxCrd, dyCrd);
  464. hBM_Ghost = CreateCompatibleBitmap(hDC, dxCrd, dyCrd);
  465. if (hBM_Ghost) // if memory allocation succeeded
  466. {
  467. hOldBitmap = SelectObject(hMemDC, hBM_Ghost);
  468. hOldBrush = SelectObject(hMemDC, hBgndBrush);
  469. PatBlt(hMemDC, 0, 0, dxCrd, dyCrd, PATCOPY);
  470. hOldPen = SelectObject(hMemDC, GetStockObject(BLACK_PEN));
  471. MoveToEx(hMemDC, 0, dyCrd-2, NULL);
  472. LineTo(hMemDC, 0, 0);
  473. LineTo(hMemDC, dxCrd-1, 0);
  474. SelectObject(hMemDC, hBrightPen);
  475. MoveToEx(hMemDC, dxCrd-1, 1, NULL);
  476. LineTo(hMemDC, dxCrd-1, dyCrd-1);
  477. LineTo(hMemDC, 0, dyCrd-1);
  478. SelectObject(hMemDC, hOldPen);
  479. SelectObject(hMemDC, hOldBitmap);
  480. SelectObject(hMemDC, hOldBrush);
  481. }
  482. DeleteDC(hMemDC);
  483. ReleaseDC(hWnd, hDC);
  484. if (!bResult || !hBM_Fgnd || !hBM_Bgnd1 || !hBM_Bgnd2)
  485. {
  486. LoadString(hInst, IDS_MEMORY, bigbuf, BIG);
  487. LoadString(hInst, IDS_APPNAME, smallbuf, SMALL);
  488. MessageBeep(MB_ICONHAND);
  489. MessageBox(hWnd, bigbuf, smallbuf, MB_OK | MB_ICONHAND);
  490. PostQuitMessage(0);
  491. return;
  492. }
  493. ReadOptions();
  494. CreateMenuFont();
  495. }
  496. /****************************************************************************
  497. CreateMenuFont
  498. Makes a copy of the menu font and puts the handle in hMenuFont
  499. ****************************************************************************/
  500. VOID CreateMenuFont()
  501. {
  502. LOGFONT lf; // description of menu font
  503. NONCLIENTMETRICS ncm;
  504. hMenuFont = 0;
  505. ncm.cbSize = sizeof(ncm);
  506. if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
  507. return;
  508. lf.lfHeight = (int)ncm.lfMenuFont.lfHeight;
  509. lf.lfWidth = (int)ncm.lfMenuFont.lfWidth;
  510. lf.lfEscapement = (int)ncm.lfMenuFont.lfEscapement;
  511. lf.lfOrientation = (int)ncm.lfMenuFont.lfOrientation;
  512. lf.lfWeight = (int)ncm.lfMenuFont.lfWeight;
  513. lf.lfItalic = ncm.lfMenuFont.lfItalic;
  514. lf.lfUnderline = ncm.lfMenuFont.lfUnderline;
  515. lf.lfStrikeOut = ncm.lfMenuFont.lfStrikeOut;
  516. lf.lfCharSet = ncm.lfMenuFont.lfCharSet;
  517. lf.lfOutPrecision = ncm.lfMenuFont.lfOutPrecision;
  518. lf.lfClipPrecision = ncm.lfMenuFont.lfClipPrecision;
  519. lf.lfQuality = ncm.lfMenuFont.lfQuality;
  520. lf.lfPitchAndFamily = ncm.lfMenuFont.lfPitchAndFamily;
  521. lstrcpyn(lf.lfFaceName, ncm.lfMenuFont.lfFaceName, LF_FACESIZE);
  522. hMenuFont = CreateFontIndirect(&lf);
  523. }