Leaked source code of windows server 2003
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.

1480 lines
40 KiB

  1. /****************************Module*Header******************************\
  2. * Module Name: FONTINST.C
  3. *
  4. * Module Descripton:
  5. * Unidrv's built in font installer. Generously borrowed from Rasdd's
  6. * font installer code.
  7. *
  8. * Warnings:
  9. *
  10. * Issues:
  11. *
  12. * Created: 22 October 1997
  13. * Author: Srinivasan Chandrasekar [srinivac]
  14. *
  15. * Copyright (c) 1996, 1997 Microsoft Corporation
  16. \***********************************************************************/
  17. #include "precomp.h"
  18. //
  19. // Global constants
  20. //
  21. static const DWORD FontInstallerHelpIDs[]=
  22. {
  23. IDD_ADD, IDH_SOFT_FONT_ADD_BTN,
  24. IDD_DELFONT, IDH_SOFT_FONT_DELETE_BTN,
  25. IDD_FONTDIR, IDH_SOFT_FONT_DIRECTORY,
  26. IDD_NEWFONTS, IDH_SOFT_FONT_NEW_LIST,
  27. IDD_CURFONTS, IDH_SOFT_FONT_INSTALLED_LIST,
  28. IDD_OPEN, IDH_SOFT_FONT_OPEN_BTN,
  29. TID_FONTDIR, IDH_SOFT_FONT_DIRECTORY,
  30. TID_NEWFONTS, IDH_SOFT_FONT_NEW_LIST,
  31. TID_CURFONTS, IDH_SOFT_FONT_INSTALLED_LIST,
  32. 0, 0
  33. };
  34. //
  35. // External functions
  36. //
  37. BOOL bSFontToFIData(FI_DATA *, HANDLE, BYTE *, DWORD);
  38. //
  39. // Structure used to remember state
  40. //
  41. typedef struct tagSFINFO
  42. {
  43. HANDLE hModule; // Module handle of calling program
  44. HANDLE hPrinter; // Printer handle passed by caller
  45. HANDLE hHeap; // Handle to heap that we allocate memory from
  46. DWORD dwFlags; // Miscellaneous flags
  47. DWORD cMaxFontNum; // Maximum ID of of fonts already in the file
  48. DWORD cFonts; // Number of fonts added from font file
  49. DWORD cCartridgeFonts; // Number of cartridge fonts in file
  50. PFNTDAT pFNTDATHead; // Head of linked list of FNTDATs
  51. PFNTDAT pFNTDATTail; // The last of them
  52. } SFINFO, *PSFINFO;
  53. //
  54. // Internal functions
  55. //
  56. void vFontInit(HWND, PSFINFO);
  57. void vAddFont(HWND, PSFINFO);
  58. void vDelFont(HWND, PSFINFO);
  59. void vDelSel(HWND, int);
  60. void vFontClean(PSFINFO);
  61. BOOL bNewFontDir(HWND, PSFINFO);
  62. BOOL bIsFileFont(PSFINFO, FI_DATA *, PWSTR);
  63. BOOL bFontUpdate(HWND, PSFINFO);
  64. BOOL InMultiSzSet(PWSTR, PWSTR);
  65. /******************************************************************************
  66. *
  67. * FontInstProc
  68. *
  69. * Function:
  70. * Entry point for font installer dialog code.
  71. *
  72. * Arguments:
  73. * hWnd - Handle to window
  74. * usMsg - Message code
  75. * wParam - wParam
  76. * lParam - lParam
  77. *
  78. * Returns:
  79. * TRUE on success, FALSE otherwise
  80. *
  81. ******************************************************************************/
  82. INT_PTR CALLBACK
  83. FontInstProc(
  84. HWND hWnd, // The window of interest
  85. UINT usMsg, // Message code
  86. WPARAM wParam, // Depends on above, but message subcode
  87. LPARAM lParam // Miscellaneous usage
  88. )
  89. {
  90. POEMFONTINSTPARAM pfip;
  91. PSFINFO pSFInfo;
  92. switch( usMsg )
  93. {
  94. case WM_INITDIALOG:
  95. //
  96. // Get the passed in parameter and set SFINFO as the window data
  97. //
  98. pfip = (POEMFONTINSTPARAM)lParam;
  99. if (!(pSFInfo = HEAPALLOC(pfip->hHeap, sizeof(SFINFO))))
  100. return FALSE;
  101. memset(pSFInfo, 0, sizeof(SFINFO));
  102. pSFInfo->hModule = pfip->hModule;
  103. pSFInfo->hPrinter = pfip->hPrinter;
  104. pSFInfo->hHeap = pfip->hHeap;
  105. pSFInfo->dwFlags = pfip->dwFlags;
  106. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pSFInfo);
  107. //
  108. // Get list of installed fonts and show them
  109. //
  110. vFontInit(hWnd, pSFInfo);
  111. return TRUE;
  112. case WM_COMMAND:
  113. pSFInfo = (PSFINFO)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  114. switch (LOWORD(wParam))
  115. {
  116. case IDD_OPEN: // User selects Open button
  117. return bNewFontDir(hWnd, pSFInfo);
  118. case IDD_NEWFONTS: // New font list
  119. if( HIWORD( wParam ) != CBN_SELCHANGE )
  120. return FALSE;
  121. break;
  122. case IDD_CURFONTS: // Existing font activity
  123. if (HIWORD (wParam) != CBN_SELCHANGE)
  124. return FALSE;
  125. break;
  126. case IDD_DELFONT: // Delete the selected fonts
  127. vDelFont(hWnd, pSFInfo);
  128. return TRUE;
  129. case IDD_ADD: // Add the selected fonts
  130. vAddFont(hWnd, pSFInfo);
  131. return TRUE;
  132. case IDOK:
  133. //
  134. // Save the updated information
  135. //
  136. if (pSFInfo->dwFlags & FG_CANCHANGE)
  137. bFontUpdate(hWnd, pSFInfo);
  138. //
  139. // Fall thru
  140. //
  141. case IDCANCEL:
  142. EndDialog(hWnd, LOWORD(wParam) == IDOK ? TRUE : FALSE);
  143. return TRUE;
  144. default:
  145. return FALSE;
  146. }
  147. break;
  148. case WM_HELP:
  149. case WM_CONTEXTMENU:
  150. {
  151. PDRIVER_INFO_3 pDriverInfo3;
  152. pSFInfo = (PSFINFO)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  153. if (!pSFInfo ||
  154. !(pDriverInfo3 = MyGetPrinterDriver(pSFInfo->hPrinter, NULL, 3)))
  155. {
  156. return FALSE;
  157. }
  158. if (usMsg == WM_HELP)
  159. {
  160. WinHelp(((LPHELPINFO) lParam)->hItemHandle,
  161. pDriverInfo3->pHelpFile,
  162. HELP_WM_HELP,
  163. (ULONG_PTR)FontInstallerHelpIDs);
  164. }
  165. else
  166. {
  167. WinHelp((HWND) wParam,
  168. pDriverInfo3->pHelpFile,
  169. HELP_CONTEXTMENU,
  170. (ULONG_PTR)FontInstallerHelpIDs);
  171. }
  172. }
  173. break;
  174. case WM_DESTROY:
  175. pSFInfo = (PSFINFO)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  176. vFontClean(pSFInfo); // Free what we consumed
  177. //
  178. // Free the SFINFO structure
  179. //
  180. HeapFree(pSFInfo->hHeap, 0, pSFInfo);
  181. return TRUE;
  182. default:
  183. return FALSE; // didn't process the message
  184. }
  185. return FALSE;
  186. }
  187. /******************************************************************************
  188. *
  189. * BInstallSoftFont
  190. *
  191. * Function:
  192. * This function installs a softfont for the given printer
  193. *
  194. * Arguments:
  195. * hPrinter - Handle of printer to install fonts for
  196. * hHeap - Handle of heap to use to allocate memory
  197. * pInBuf - Pointer to PCL data buffer
  198. * dwSize - Size of buffer
  199. *
  200. * Returns:
  201. * TRUE on success, FALSE otherwise
  202. *
  203. ******************************************************************************/
  204. BOOL APIENTRY
  205. BInstallSoftFont(
  206. HANDLE hPrinter,
  207. HANDLE hHeap,
  208. PBYTE pInBuf,
  209. DWORD dwSize
  210. )
  211. {
  212. FNTDAT FntDat;
  213. HANDLE hOldFile = NULL;
  214. HANDLE hFontFile = NULL;
  215. DWORD cFonts = 0, i;
  216. BOOL bRc = FALSE;
  217. //
  218. // Parse the given PCL font
  219. //
  220. if (!bSFontToFIData(&FntDat.fid, hHeap, pInBuf, dwSize))
  221. return FALSE;
  222. FntDat.pVarData = pInBuf;
  223. FntDat.dwSize = dwSize;
  224. //
  225. // Open exisiting font file
  226. //
  227. if (hOldFile = FIOpenFontFile(hPrinter, hHeap))
  228. {
  229. cFonts = FIGetNumFonts(hOldFile);
  230. }
  231. //
  232. // Create a new font file
  233. //
  234. hFontFile = FICreateFontFile(hPrinter, hHeap, cFonts+1);
  235. if (!hFontFile)
  236. {
  237. WARNING(("Error creating a new font file\n"));
  238. goto EndInstallSoftFont;
  239. }
  240. //
  241. // Seek past header and font directory in new file
  242. //
  243. FIAlignedSeek(hFontFile, sizeof(UFF_FILEHEADER) + (cFonts + 1) * sizeof(UFF_FONTDIRECTORY));
  244. for (i=0; i<cFonts; i++)
  245. {
  246. if (!FICopyFontRecord(hFontFile, hOldFile, i, i))
  247. {
  248. WARNING(("Error copying font record %d\n", i));
  249. goto EndInstallSoftFont;
  250. }
  251. }
  252. //
  253. // Add new font record
  254. //
  255. if (!FIAddFontRecord(hFontFile, cFonts, &FntDat))
  256. {
  257. WARNING(("Error adding new font record\n"));
  258. goto EndInstallSoftFont;
  259. }
  260. //
  261. // Write out the font header and directory
  262. //
  263. if (!FIWriteFileHeader(hFontFile) ||
  264. !FIWriteFontDirectory(hFontFile))
  265. {
  266. WARNING(("Error writing font file header/directory of font file\n"))
  267. goto EndInstallSoftFont;
  268. }
  269. bRc = TRUE;
  270. EndInstallSoftFont:
  271. (VOID)FIUpdateFontFile(hOldFile, hFontFile, bRc);
  272. return bRc;
  273. }
  274. /******************************************************************************
  275. *
  276. * BUpdateExternalFonts
  277. *
  278. * Function:
  279. * This function is called by the driver UI to update the font installer
  280. * file if one or more cartridges are added or removed by the user.
  281. *
  282. * Arguments:
  283. * hPrinter - Handle of printer
  284. * hHeap - Handle of heap to use to allocate memory
  285. * pwstrCartridges - Pointer to MULTI_SZ string of cartridges currently
  286. * installed on the printer
  287. *
  288. * Returns:
  289. * TRUE on success, FALSE otherwise
  290. *
  291. ******************************************************************************/
  292. BOOL APIENTRY
  293. BUpdateExternalFonts(
  294. HANDLE hPrinter,
  295. HANDLE hHeap,
  296. PWSTR pwstrCartridges
  297. )
  298. {
  299. HANDLE hOldFile = NULL;
  300. HANDLE hFontFile = NULL;
  301. HANDLE hCartFile = NULL;
  302. DWORD cFonts = 0;
  303. DWORD cCartFonts = 0;
  304. DWORD cNewFonts = 0;
  305. DWORD i, j;
  306. PWSTR pwstrName;
  307. BOOL bRc = FALSE;
  308. //
  309. // Open exisiting font file
  310. //
  311. if ((hOldFile = FIOpenFontFile(hPrinter, hHeap)) == NULL)
  312. {
  313. WARNING(("Error opening font file\n"));
  314. return FALSE;
  315. }
  316. cFonts = FIGetNumFonts(hOldFile);
  317. //
  318. // Find out number of non cartridge fonts
  319. //
  320. for (i=0; i<cFonts; i++)
  321. {
  322. if (FIGetFontCartridgeName(hOldFile, i) == NULL)
  323. cNewFonts++;
  324. }
  325. //
  326. // Open font cartridge file
  327. //
  328. if ((hCartFile = FIOpenCartridgeFile(hPrinter, hHeap)) == NULL &&
  329. pwstrCartridges != NULL)
  330. {
  331. WARNING(("Error opening cartridge file\n"));
  332. goto EndUpdateExternalFonts;
  333. }
  334. if (hCartFile)
  335. {
  336. //
  337. // Find number of fonts belonging to these cartridges
  338. //
  339. cCartFonts = FIGetNumFonts(hCartFile);
  340. for (i=0; i<cCartFonts; i++)
  341. {
  342. pwstrName = FIGetFontCartridgeName(hCartFile, i);
  343. ASSERT(pwstrName != NULL);
  344. if (InMultiSzSet(pwstrCartridges, pwstrName))
  345. cNewFonts++;
  346. }
  347. }
  348. //
  349. // Create a new font file
  350. //
  351. hFontFile = FICreateFontFile(hPrinter, hHeap, cNewFonts);
  352. if (!hFontFile)
  353. {
  354. WARNING(("Error creating a new font file\n"));
  355. goto EndUpdateExternalFonts;
  356. }
  357. //
  358. // Seek past header and font directory in new file
  359. //
  360. FIAlignedSeek(hFontFile, sizeof(UFF_FILEHEADER) + cNewFonts * sizeof(UFF_FONTDIRECTORY));
  361. //
  362. // Copy over all fonts from old font file that don't belong to any
  363. // cartridges
  364. //
  365. for (i=0, j=0; i<cFonts; i++)
  366. {
  367. if (FIGetFontCartridgeName(hOldFile, i) != NULL)
  368. continue;
  369. if (!FICopyFontRecord(hFontFile, hOldFile, j, i))
  370. {
  371. WARNING(("Error copying font record %d\n", i));
  372. goto EndUpdateExternalFonts;
  373. }
  374. j++;
  375. }
  376. //
  377. // NOTE: Do not change j - we continue to use it below
  378. //
  379. //
  380. // Copy over cartridge fonts that are curently selected
  381. //
  382. for (i=0; i<cCartFonts; i++)
  383. {
  384. pwstrName = FIGetFontCartridgeName(hCartFile, i);
  385. if (!InMultiSzSet(pwstrCartridges, pwstrName))
  386. continue;
  387. if (!FICopyFontRecord(hFontFile, hCartFile, j, i))
  388. {
  389. WARNING(("Error copying font record %d\n", i));
  390. goto EndUpdateExternalFonts;
  391. }
  392. j++;
  393. }
  394. //
  395. // Write out the font header and directory
  396. //
  397. if (!FIWriteFileHeader(hFontFile) ||
  398. !FIWriteFontDirectory(hFontFile))
  399. {
  400. WARNING(("Error writing font file header/directory of font file\n"))
  401. goto EndUpdateExternalFonts;
  402. }
  403. bRc = TRUE;
  404. EndUpdateExternalFonts:
  405. (VOID)FIUpdateFontFile(hOldFile, hFontFile, bRc);
  406. (VOID)FICloseFontFile(hCartFile);
  407. return bRc;
  408. }
  409. /******************************************************************************
  410. *
  411. * BGetFontCartridgeFile
  412. *
  413. * Function:
  414. * This function is called by the driver UI to copy the font cartridge
  415. * file from the server to the client
  416. *
  417. * Arguments:
  418. * hPrinter - Handle of printer
  419. * hHeap - Handle of heap to use to allocate memory
  420. *
  421. * Returns:
  422. * TRUE on success, FALSE otherwise
  423. *
  424. ******************************************************************************/
  425. BOOL
  426. BGetFontCartridgeFile(
  427. HANDLE hPrinter,
  428. HANDLE hHeap
  429. )
  430. {
  431. CACHEDFILE CachedFile;
  432. PPRINTER_INFO_2 ppi2 = NULL;
  433. DWORD dwSize = 0;
  434. BOOL bRc = FALSE;
  435. GetPrinterW(hPrinter, 2, NULL, 0, &dwSize);
  436. if ((dwSize == 0) ||
  437. !(ppi2 = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize)) ||
  438. !(GetPrinterW(hPrinter, 2, (PBYTE)ppi2, dwSize, &dwSize)))
  439. {
  440. goto EndGetFCF;
  441. }
  442. if (!(ppi2->Attributes & PRINTER_ATTRIBUTE_LOCAL))
  443. {
  444. if (! _BPrepareToCopyCachedFile(hPrinter, &CachedFile, REGVAL_CARTRIDGEFILENAME) ||
  445. ! _BCopyCachedFile(NULL, &CachedFile))
  446. bRc = FALSE;
  447. else
  448. bRc = TRUE;
  449. _VDisposeCachedFileInfo(&CachedFile);
  450. goto EndGetFCF;
  451. }
  452. bRc = TRUE;
  453. EndGetFCF:
  454. if (ppi2)
  455. HeapFree(hHeap, 0, ppi2);
  456. return bRc;
  457. }
  458. /******************************************************************************
  459. * Internal helper functions
  460. ******************************************************************************/
  461. /******************************************************************************
  462. *
  463. * vFontInit
  464. *
  465. * Function:
  466. * Called to initialise the dialog before it is displayed to the
  467. * user. Requires making decisions about buttons based on any
  468. * existing fonts.
  469. *
  470. * Arguments:
  471. * hWnd - Handle to window
  472. * pSFInfo - Pointer to structure that holds state information
  473. *
  474. * Returns:
  475. * Nothing
  476. *
  477. ******************************************************************************/
  478. void
  479. vFontInit(
  480. HWND hWnd,
  481. PSFINFO pSFInfo
  482. )
  483. {
  484. HANDLE hFontFile; // Handle to font file
  485. INT iNum = 0; // Number of entries
  486. INT i; // Loop parameter
  487. DWORD cFonts = 0; // Number of fonts
  488. //
  489. // If there is a font file associated with this printer, open it and
  490. // read the fonts
  491. //
  492. if (hFontFile = FIOpenFontFile(pSFInfo->hPrinter, pSFInfo->hHeap))
  493. {
  494. iNum = FIGetNumFonts(hFontFile);
  495. }
  496. for (i=0; i<iNum; i++)
  497. {
  498. LONG_PTR iFont;
  499. PWSTR pwstr; // Font display name
  500. //
  501. // We do not display fonts that belong to font cartridges
  502. //
  503. pwstr = FIGetFontCartridgeName(hFontFile, i);
  504. if (pwstr)
  505. {
  506. pSFInfo->cCartridgeFonts++;
  507. continue;
  508. }
  509. pwstr = FIGetFontName(hFontFile, i);
  510. if (!pwstr)
  511. continue; // Should not happen!
  512. //
  513. // Add font name to list of installed fonts
  514. //
  515. iFont = SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_ADDSTRING, 0, (LPARAM)pwstr);
  516. //
  517. // Set the font number
  518. //
  519. SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_SETITEMDATA, iFont, (LPARAM)i);
  520. cFonts++; // Increment number of fonts
  521. }
  522. pSFInfo->cMaxFontNum = (DWORD)i; // For separating new/old
  523. if (cFonts > 0)
  524. {
  525. //
  526. // There are existing fonts, so we can enable the DELETE button
  527. //
  528. pSFInfo->cFonts = cFonts; // Number of fonts added
  529. EnableWindow(GetDlgItem(hWnd, IDD_DELFONT), TRUE);
  530. }
  531. if (hFontFile)
  532. {
  533. FICloseFontFile(hFontFile);
  534. }
  535. if (pSFInfo->dwFlags & FG_CANCHANGE)
  536. {
  537. //
  538. // User has access to change stuff, so place a default directory
  539. //
  540. SetDlgItemText(hWnd, IDD_FONTDIR, L"A:\\");
  541. }
  542. else
  543. {
  544. //
  545. // No permission to change things, so disable most of the dialog
  546. //
  547. EnableWindow( GetDlgItem( hWnd, IDD_FONTDIR ), FALSE );
  548. EnableWindow( GetDlgItem( hWnd, TID_FONTDIR ), FALSE );
  549. EnableWindow( GetDlgItem( hWnd, IDD_OPEN ), FALSE );
  550. EnableWindow( GetDlgItem( hWnd, IDD_ADD ), FALSE );
  551. EnableWindow( GetDlgItem( hWnd, IDD_DELFONT ), FALSE );
  552. EnableWindow( GetDlgItem( hWnd, IDD_NEWFONTS ), FALSE );
  553. EnableWindow( GetDlgItem( hWnd, TID_NEWFONTS ), FALSE );
  554. }
  555. return;
  556. }
  557. /******************************************************************************
  558. *
  559. * bNewFontDir
  560. *
  561. * Function:
  562. * Processes a new font directory. This means opening the
  563. * directory and passing the file names to the screening function.
  564. *
  565. * Arguments:
  566. * hWnd - Handle to window
  567. * pSFInfo - Pointer to structure that holds state information
  568. *
  569. * Returns:
  570. * TRUE on success, FALSE otherwise
  571. *
  572. ******************************************************************************/
  573. BOOL
  574. bNewFontDir(
  575. HWND hWnd,
  576. PSFINFO pSFInfo
  577. )
  578. {
  579. WIN32_FIND_DATA ffd; // Data about the file we find
  580. UINT iErrMode; // For manipulating error msgs
  581. INT cOKFiles; // Count the number of font files found
  582. HANDLE hDir; // FindFirstFile ... scanning
  583. HCURSOR hCursor; // Switch to wait symbol while reading
  584. INT cDN; // Length of directory name
  585. // (count of chars, excluding terminating null char)
  586. WCHAR wchDirNm[MAX_PATH];// Font directory + file name
  587. //
  588. // GetDlgItemText's 4th parameter is the max number of characters, not bytes.
  589. //
  590. cDN = GetDlgItemTextW(hWnd, IDD_FONTDIR, wchDirNm, sizeof(wchDirNm) / sizeof(WCHAR));
  591. //
  592. // Check to see if the name will be too long: the 5 below is the
  593. // number of additional characters to add to the directory name:
  594. // namely, L"\\*.*".
  595. //
  596. if (cDN >= (CCHOF(wchDirNm) - 5))
  597. {
  598. IDisplayErrorMessageBox(hWnd,
  599. MB_OK | MB_ICONERROR,
  600. IDS_FONTINST_FONTINSTALLER,
  601. IDS_FONTINST_DIRECTORYTOOLONG);
  602. return FALSE;
  603. }
  604. if (cDN > 0)
  605. {
  606. if (wchDirNm[cDN - 1] != (WCHAR)'\\' )
  607. {
  608. StringCchCatW(wchDirNm, CCHOF(wchDirNm), L"\\");
  609. cDN++; // One more now!
  610. }
  611. StringCchCatW(wchDirNm, CCHOF(wchDirNm), L"*.*");
  612. //
  613. // Save error mode, and enable file open error box.
  614. //
  615. iErrMode = SetErrorMode(0);
  616. SetErrorMode(iErrMode & ~SEM_NOOPENFILEERRORBOX);
  617. hDir = FindFirstFile(wchDirNm, &ffd);
  618. SetErrorMode(iErrMode); // Restore old mode
  619. cOKFiles = 0;
  620. if (hDir == INVALID_HANDLE_VALUE)
  621. {
  622. //
  623. // Put up a dialog box to tell the user "no such directory".
  624. //
  625. if (GetLastError() == ERROR_PATH_NOT_FOUND)
  626. {
  627. IDisplayErrorMessageBox(hWnd,
  628. MB_OK | MB_ICONERROR,
  629. IDS_FONTINST_FONTINSTALLER,
  630. IDS_FONTINST_INVALIDDIR);
  631. }
  632. return FALSE;
  633. }
  634. //
  635. // Switch to the hourglass cursor while reading, since the data
  636. // is probably coming from a SLOW floppy. Also stop redrawing,
  637. // since the list box looks ugly during this time.
  638. //
  639. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  640. SendMessage(hWnd, WM_SETREDRAW, FALSE, 0L);
  641. do
  642. {
  643. //
  644. // Generate a file name which is passed to a function to determine
  645. // whether this file is understood by us. This function returns
  646. // FALSE if it does not understand the file; otherwise it returns
  647. // TRUE, and also a string to display. We display the string,
  648. // and remember the file name for future use.
  649. //
  650. LONG_PTR iFont; // List Box index
  651. FI_DATA FD; // Filled in by bIsFileFont
  652. PFNTDAT pFNTDAT; // For remembering it all
  653. StringCchCopyW(&wchDirNm[cDN],
  654. CCHOF(wchDirNm) - cDN,
  655. ffd.cFileName);
  656. if (bIsFileFont(pSFInfo, &FD, wchDirNm))
  657. {
  658. //
  659. // Part of the data returned is a descriptive string
  660. // for the font. We need to display this to the user.
  661. // We also allocate a structure we use to keep track of
  662. // all the data we have. This includes the file name
  663. // that we have!
  664. //
  665. pFNTDAT = (PFNTDAT)HEAPALLOC(pSFInfo->hHeap, sizeof(FNTDAT));
  666. if (pFNTDAT == NULL)
  667. {
  668. break;
  669. }
  670. if (pSFInfo->pFNTDATHead == NULL)
  671. {
  672. //
  673. // Starting a chain, so remember the first.
  674. // AND also enable the Add button in the dialog,
  675. // now that we have something to add.
  676. //
  677. pSFInfo->pFNTDATHead = pFNTDAT;
  678. EnableWindow(GetDlgItem(hWnd, IDD_ADD), TRUE);
  679. }
  680. if (pSFInfo->pFNTDATTail)
  681. pSFInfo->pFNTDATTail->pNext = pFNTDAT;
  682. pSFInfo->pFNTDATTail = pFNTDAT;
  683. pFNTDAT->pNext = 0;
  684. pFNTDAT->pVarData = NULL;
  685. pFNTDAT->dwSize = 0;
  686. pFNTDAT->fid = FD;
  687. wcsncpy(pFNTDAT->wchFileName, wchDirNm, cDN);
  688. StringCchCatW(pFNTDAT->wchFileName,
  689. CCHOF(pFNTDAT->wchFileName),
  690. ffd.cFileName);
  691. //
  692. // Display this message, and tag it with the address
  693. // of the data area we just allocated.
  694. //
  695. iFont = SendDlgItemMessage(hWnd,
  696. IDD_NEWFONTS,
  697. LB_ADDSTRING,
  698. 0,
  699. (LPARAM)FD.dsIdentStr.pvData);
  700. SendDlgItemMessage(hWnd,
  701. IDD_NEWFONTS,
  702. LB_SETITEMDATA,
  703. iFont,
  704. (LPARAM)pFNTDAT);
  705. ++cOKFiles; // One more to the list
  706. }
  707. } while (FindNextFile(hDir, &ffd));
  708. //
  709. // Now can redraw the box & return to the previous cursor
  710. //
  711. SendMessage(hWnd, WM_SETREDRAW, TRUE, 0L);
  712. InvalidateRect(hWnd, NULL, TRUE);
  713. SetCursor(hCursor);
  714. //
  715. // Finished with the directory now, so close it up
  716. //
  717. FindClose(hDir);
  718. if (cOKFiles == 0)
  719. {
  720. //
  721. // Didn't find any files, so tell the user
  722. //
  723. IDisplayErrorMessageBox(hWnd,
  724. MB_OK | MB_ICONERROR,
  725. IDS_FONTINST_FONTINSTALLER,
  726. IDS_FONTINST_NOFONTFOUND);
  727. }
  728. }
  729. else
  730. {
  731. //
  732. // Empty font directory name!
  733. //
  734. IDisplayErrorMessageBox(hWnd,
  735. MB_OK | MB_ICONERROR,
  736. IDS_FONTINST_FONTINSTALLER,
  737. IDS_FONTINST_NODIRNAME);
  738. }
  739. return TRUE;
  740. }
  741. /******************************************************************************
  742. *
  743. * vAddFont
  744. *
  745. * Function:
  746. * Called to move the new selected fonts to the font list
  747. *
  748. * Arguments:
  749. * hWnd - Handle to window
  750. * pSFInfo - Pointer to structure that holds state information
  751. *
  752. * Returns:
  753. * Nothing
  754. *
  755. ******************************************************************************/
  756. void
  757. vAddFont(
  758. HWND hWnd,
  759. PSFINFO pSFInfo
  760. )
  761. {
  762. LONG_PTR cSel; // Number of entries selected
  763. LONG_PTR *piSel; // List of selected fonts
  764. INT iI; // Loop index
  765. //
  766. // Find the selected items in the new font box and move them to the
  767. // Installed box. Also set up the linked list of stuff to pass
  768. // to the common font installer code should the user decide to
  769. // update the list.
  770. //
  771. cSel = SendDlgItemMessage(hWnd, IDD_NEWFONTS, LB_GETSELCOUNT, 0, 0);
  772. piSel = (LONG_PTR *)HEAPALLOC(pSFInfo->hHeap, (DWORD)(cSel * sizeof(INT)));
  773. if (piSel == NULL )
  774. {
  775. IDisplayErrorMessageBox(hWnd,
  776. MB_OK | MB_ICONERROR,
  777. IDS_FONTINST_FONTINSTALLER,
  778. IDS_FONTINST_OUTOFMEMORY);
  779. return;
  780. }
  781. //
  782. // Disable updates to reduce screen flicker
  783. //
  784. SendMessage(hWnd, WM_SETREDRAW, FALSE, 0L);
  785. SendDlgItemMessage(hWnd, IDD_NEWFONTS, LB_GETSELITEMS, cSel, (LPARAM)piSel);
  786. for (iI=0; iI<cSel; ++iI)
  787. {
  788. LONG_PTR iFont; // Index in list box
  789. FNTDAT *pFontData; // Significant font info
  790. pFontData = (FNTDAT *)SendDlgItemMessage(hWnd,
  791. IDD_NEWFONTS,
  792. LB_GETITEMDATA,
  793. piSel[iI],
  794. 0L);
  795. if ((LONG_PTR)pFontData == LB_ERR )
  796. continue; // SHOULD NOT HAPPEN
  797. iFont = SendDlgItemMessage(hWnd,
  798. IDD_CURFONTS,
  799. LB_ADDSTRING,
  800. 0,
  801. (LPARAM)pFontData->fid.dsIdentStr.pvData);
  802. SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_SETITEMDATA, iFont, (LPARAM)pFontData);
  803. }
  804. if (iI > 0)
  805. EnableWindow(GetDlgItem(hWnd, IDD_DELFONT), TRUE);
  806. //
  807. // Can now delete the selected items: we no longer need them
  808. //
  809. vDelSel(hWnd, IDD_NEWFONTS);
  810. //
  811. // Re enable updates
  812. //
  813. SendMessage(hWnd, WM_SETREDRAW, TRUE, 0L);
  814. InvalidateRect(hWnd, NULL, TRUE);
  815. HeapFree(pSFInfo->hHeap, 0, (LPSTR)piSel);
  816. return;
  817. }
  818. /******************************************************************************
  819. *
  820. * vDelFont
  821. *
  822. * Function:
  823. * Called when the Delete button is clicked. We discover which
  824. * items in the Installed fonts list box are selected, and mark these
  825. * for deletion. We do NOT delete them, simply remove them from
  826. * display and mark for deletion later.
  827. *
  828. * Arguments:
  829. * hWnd - Handle to window
  830. * pSFInfo - Pointer to structure that holds state information
  831. *
  832. * Returns:
  833. * Nothing
  834. *
  835. ******************************************************************************/
  836. void
  837. vDelFont(
  838. HWND hWnd,
  839. PSFINFO pSFInfo
  840. )
  841. {
  842. INT iI; // Loop index
  843. LONG_PTR cSel; // Number of selected items
  844. LONG_PTR *piSel; // From heap, contains selected items list
  845. //
  846. // Obtain the list of selected items in the Installed list box.
  847. // Then place any existing fonts into the to delete list, and
  848. // move any new fonts back into the New fonts list.
  849. //
  850. cSel = SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_GETSELCOUNT, 0, 0);
  851. piSel = (LONG_PTR *)HEAPALLOC(pSFInfo->hHeap, (DWORD)(cSel * sizeof(INT)));
  852. if (piSel == NULL)
  853. {
  854. IDisplayErrorMessageBox(hWnd,
  855. MB_OK | MB_ICONERROR,
  856. IDS_FONTINST_FONTINSTALLER,
  857. IDS_FONTINST_OUTOFMEMORY);
  858. return;
  859. }
  860. //
  861. // Disable updates to reduce screen flicker
  862. //
  863. SendMessage(hWnd, WM_SETREDRAW, FALSE, 0L);
  864. SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_GETSELITEMS, cSel, (LPARAM)piSel);
  865. for (iI=0; iI<cSel; ++iI)
  866. {
  867. LONG_PTR iVal;
  868. iVal = SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_GETITEMDATA, piSel[iI], 0);
  869. if (iVal == LB_ERR)
  870. continue; // SHOULD NOT HAPPEN
  871. if (iVal >= (LONG_PTR)pSFInfo->cMaxFontNum)
  872. {
  873. //
  874. // We are deleting a font that we just installed, so add it back
  875. // into the new fonts, so that it remains visible.
  876. //
  877. LONG_PTR iFont; // New list box index
  878. WCHAR awch[256]; // ???
  879. if (SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_GETTEXT,
  880. piSel[iI], (LPARAM)awch) != LB_ERR)
  881. {
  882. //
  883. // Have the text and value, so back into the new list
  884. //
  885. iFont = SendDlgItemMessage(hWnd, IDD_NEWFONTS, LB_ADDSTRING, 0, (LPARAM)awch);
  886. SendDlgItemMessage(hWnd, IDD_NEWFONTS, LB_SETITEMDATA, iFont, (LPARAM)iVal);
  887. }
  888. }
  889. }
  890. //
  891. // Now delete them from the list
  892. //
  893. vDelSel(hWnd, IDD_CURFONTS);
  894. //
  895. // Disable the delete button if there are no fonts.
  896. //
  897. if (SendDlgItemMessage( hWnd, IDD_CURFONTS, LB_GETCOUNT, 0, 0L) == 0)
  898. EnableWindow(GetDlgItem(hWnd, IDD_DELFONT), FALSE);
  899. //
  900. /// Re-enable updates
  901. //
  902. SendMessage(hWnd, WM_SETREDRAW, TRUE, 0L);
  903. InvalidateRect(hWnd, NULL, TRUE);
  904. HeapFree(pSFInfo->hHeap, 0, (LPSTR)piSel);
  905. return;
  906. }
  907. /******************************************************************************
  908. *
  909. * vDelSel
  910. *
  911. * Function:
  912. * Delete all selected items in the specified list box.
  913. *
  914. * Arguments:
  915. * hWnd - Handle to window
  916. * iBox - Identifies the list box
  917. *
  918. * Returns:
  919. * Nothing
  920. *
  921. ******************************************************************************/
  922. void
  923. vDelSel(
  924. HWND hWnd,
  925. INT iBox
  926. )
  927. {
  928. INT iSel;
  929. //
  930. // Find how many items are selected, then retrieve their index
  931. // one at a time until they are all deleted. This is needed because
  932. // otherwise we delete the wrong ones! This is because the data is
  933. // presented to us as an array of indices, and these are wrong when
  934. // we start deleting them.
  935. //
  936. while (SendDlgItemMessage(hWnd, iBox, LB_GETSELITEMS, 1, (LPARAM)&iSel) > 0)
  937. SendDlgItemMessage(hWnd, iBox, LB_DELETESTRING, iSel, 0L);
  938. return;
  939. }
  940. /******************************************************************************
  941. *
  942. * vFontClean
  943. *
  944. * Function:
  945. * Clean up all the dangling bits & pieces we have left around.
  946. *
  947. * Arguments:
  948. * pSFInfo - Pointer to structure that holds state information
  949. *
  950. * Returns:
  951. * Nothing
  952. *
  953. ******************************************************************************/
  954. void
  955. vFontClean(
  956. PSFINFO pSFInfo
  957. )
  958. {
  959. //
  960. // Look at the storage addresses we allocate. If non zero,
  961. // free them up and set to NULL to prevent a second freeing.
  962. //
  963. if (pSFInfo->pFNTDATHead)
  964. {
  965. //
  966. // The details of each new font we found. These form a linked
  967. // list, so we need to traverse the chain and free every entry.
  968. //
  969. FNTDAT *pFD0, *pFD1;
  970. for (pFD0 = pSFInfo->pFNTDATHead; pFD0; pFD0 = pFD1)
  971. {
  972. pFD1 = pFD0->pNext; // Next one, perhaps
  973. HeapFree(pSFInfo->hHeap, 0, (LPSTR)pFD0);
  974. }
  975. pSFInfo->pFNTDATHead = NULL;
  976. pSFInfo->pFNTDATTail = NULL;
  977. }
  978. return;
  979. }
  980. /******************************************************************************
  981. *
  982. * bIsFileFont
  983. *
  984. * Function:
  985. * Called with a file name and returns TRUE if this file is a font
  986. * format we understand. Also returns a FONT_DATA structure.
  987. *
  988. * Arguments:
  989. * pSFInfo - Pointer to structure that holds state information
  990. * pFIDat - Information about the font to fill if successful
  991. * pwstr - Name of file to check
  992. *
  993. * Returns:
  994. * TRUE on success, FALSE otherwise
  995. *
  996. ******************************************************************************/
  997. BOOL
  998. bIsFileFont(
  999. PSFINFO pSFInfo,
  1000. FI_DATA *pFIDat,
  1001. PWSTR pwstr
  1002. )
  1003. {
  1004. HANDLE hFile;
  1005. BYTE *pbFile;
  1006. DWORD dwSize;
  1007. BOOL bRet;
  1008. hFile = CreateFile(pwstr,
  1009. GENERIC_READ,
  1010. FILE_SHARE_READ,
  1011. NULL,
  1012. OPEN_EXISTING,
  1013. FILE_ATTRIBUTE_NORMAL | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
  1014. NULL);
  1015. if (hFile == INVALID_HANDLE_VALUE)
  1016. {
  1017. return FALSE;
  1018. }
  1019. if (!MapFileIntoMemory(pwstr, &pbFile, NULL))
  1020. {
  1021. CloseHandle(hFile);
  1022. return FALSE;
  1023. }
  1024. //
  1025. // Want to find out how big the file is, so now seek to the
  1026. // end, and see what address comes back! There appears to be
  1027. // no other way to do this.
  1028. //
  1029. dwSize = SetFilePointer(hFile, 0L, NULL, FILE_END);
  1030. bRet = bSFontToFIData(pFIDat, pSFInfo->hHeap, pbFile, dwSize);
  1031. UnmapFileFromMemory((HFILEMAP)pbFile);
  1032. CloseHandle(hFile);
  1033. return bRet;
  1034. }
  1035. /******************************************************************************
  1036. *
  1037. * bFontUpdate
  1038. *
  1039. * Function:
  1040. * Update the font installer common file. Called when the user
  1041. * has clicked on the OK button.
  1042. *
  1043. * Arguments:
  1044. * hWnd - Handle to window
  1045. * pSFInfo - Pointer to structure that holds state information
  1046. *
  1047. * Returns:
  1048. * TRUE on success, FALSE otherwise
  1049. *
  1050. ******************************************************************************/
  1051. BOOL
  1052. bFontUpdate(
  1053. HWND hWnd,
  1054. PSFINFO pSFInfo
  1055. )
  1056. {
  1057. HANDLE hOldFile = NULL; // Handle to old font file
  1058. HANDLE hFontFile = NULL; // Handle to new font file
  1059. DWORD cFonts; // Final number of fonts selected
  1060. DWORD dwIndex; // Index into current font file
  1061. LRESULT lrOldIndex; // Index into old font file
  1062. DWORD i; // Loop index
  1063. BOOL bRc = FALSE; // Return code
  1064. //
  1065. // Initialize some variables
  1066. //
  1067. hOldFile = hFontFile = NULL;
  1068. //
  1069. // Get number of fonts that have finally been added
  1070. //
  1071. cFonts = (DWORD)SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_GETCOUNT, 0, 0);
  1072. //
  1073. // If no fonts have been added or deleted, we can skip doing anything.
  1074. // Check for this case
  1075. //
  1076. if (cFonts == pSFInfo->cFonts)
  1077. {
  1078. BOOL bNoChange = TRUE;
  1079. for (i=0; i<cFonts; i++)
  1080. {
  1081. lrOldIndex = SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_GETITEMDATA, i, 0);
  1082. if (lrOldIndex >= (LONG)(pSFInfo->cMaxFontNum))
  1083. {
  1084. bNoChange = FALSE;
  1085. break;
  1086. }
  1087. }
  1088. if (bNoChange)
  1089. {
  1090. return TRUE;
  1091. }
  1092. }
  1093. //
  1094. // Open existing font file
  1095. //
  1096. hOldFile = FIOpenFontFile(pSFInfo->hPrinter, pSFInfo->hHeap);
  1097. if (!hOldFile && pSFInfo->cMaxFontNum > 0)
  1098. {
  1099. WARNING(("Unable to open existing font file\n"));
  1100. goto EndFontUpdate;
  1101. }
  1102. //
  1103. // Create a new font file
  1104. //
  1105. hFontFile = FICreateFontFile(pSFInfo->hPrinter, pSFInfo->hHeap, cFonts+pSFInfo->cCartridgeFonts);
  1106. if (!hFontFile)
  1107. {
  1108. WARNING(("Error creating new font file\n"));
  1109. goto EndFontUpdate;
  1110. }
  1111. //
  1112. // Seek past header and font directory in new file
  1113. //
  1114. FIAlignedSeek(hFontFile, sizeof(UFF_FILEHEADER) + (cFonts+pSFInfo->cCartridgeFonts) * sizeof(UFF_FONTDIRECTORY));
  1115. for (dwIndex=0; dwIndex<cFonts; dwIndex++)
  1116. {
  1117. lrOldIndex = SendDlgItemMessage(hWnd, IDD_CURFONTS, LB_GETITEMDATA, dwIndex, 0);
  1118. if (lrOldIndex < (LONG)(pSFInfo->cMaxFontNum))
  1119. {
  1120. //
  1121. // This is an old font from existing font file
  1122. //
  1123. if (!FICopyFontRecord(hFontFile, hOldFile, dwIndex, (DWORD)lrOldIndex))
  1124. {
  1125. WARNING(("Error copying font record\n"));
  1126. goto EndFontUpdate;
  1127. }
  1128. }
  1129. else
  1130. {
  1131. //
  1132. // This is a font being newly added
  1133. //
  1134. if (!FIAddFontRecord(hFontFile, dwIndex, (PFNTDAT)lrOldIndex))
  1135. {
  1136. WARNING(("Error creating new font record\n"));
  1137. goto EndFontUpdate;
  1138. }
  1139. }
  1140. }
  1141. //
  1142. // NOTE: Do not change dwIndex - we continue to use it below
  1143. //
  1144. if (pSFInfo->cCartridgeFonts > 0)
  1145. {
  1146. //
  1147. // Copy cartridge fonts to new font file
  1148. //
  1149. cFonts = FIGetNumFonts(hOldFile);
  1150. for (i=0; i<cFonts; i++)
  1151. {
  1152. PWSTR pwstr = FIGetFontCartridgeName(hOldFile, i);
  1153. if (pwstr)
  1154. {
  1155. if (!FICopyFontRecord(hFontFile, hOldFile, dwIndex, i))
  1156. {
  1157. WARNING(("Error copyinf font record\n"));
  1158. goto EndFontUpdate;
  1159. }
  1160. dwIndex++;
  1161. }
  1162. }
  1163. }
  1164. //
  1165. // Write out the font header and directory
  1166. //
  1167. if (!FIWriteFileHeader(hFontFile) ||
  1168. !FIWriteFontDirectory(hFontFile))
  1169. {
  1170. WARNING(("Error writing font header/directory of font file\n"))
  1171. goto EndFontUpdate;
  1172. }
  1173. bRc = TRUE;
  1174. EndFontUpdate:
  1175. (VOID)FIUpdateFontFile(hOldFile, hFontFile, bRc);
  1176. return bRc;
  1177. }
  1178. BOOL
  1179. InMultiSzSet(
  1180. PWSTR pwstrMultiSz,
  1181. PWSTR pwstr
  1182. )
  1183. {
  1184. while (*pwstrMultiSz)
  1185. {
  1186. if (wcscmp(pwstrMultiSz, pwstr) == 0)
  1187. {
  1188. return TRUE;
  1189. }
  1190. pwstrMultiSz += wcslen(pwstrMultiSz) + 1;
  1191. }
  1192. return FALSE;
  1193. }