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.

657 lines
19 KiB

  1. #include "pch.hxx"
  2. #include "shlwapi.h"
  3. #include "fontcash.h"
  4. #include "strconst.h"
  5. #include "inetreg.h"
  6. #include "oleutil.h"
  7. #include "msoedbg.h"
  8. #include <wingdi.h>
  9. #include "demand.h"
  10. HRESULT CreateFontCacheEntry(FONTCACHEENTRY **ppNewEntry)
  11. {
  12. HRESULT hr = S_OK;
  13. FONTCACHEENTRY* pNew;
  14. if (!MemAlloc((LPVOID *)&pNew, sizeof(FONTCACHEENTRY)))
  15. hr = E_OUTOFMEMORY;
  16. else
  17. {
  18. pNew->uiCodePage = 0;
  19. pNew->szFaceName[0] = TCHAR(0);
  20. for (int i = 0; i < FNT_SYS_LAST; i++)
  21. pNew->rgFonts[i] = 0;
  22. }
  23. *ppNewEntry = pNew;
  24. return S_OK;
  25. }
  26. void FreeFontsInEntry(FONTCACHEENTRY *pEntry)
  27. {
  28. for (int i = 0; i < FNT_SYS_LAST; i++)
  29. if (pEntry->rgFonts[i])
  30. {
  31. DeleteObject(pEntry->rgFonts[i]);
  32. pEntry->rgFonts[i] = 0;
  33. }
  34. }
  35. HRESULT FreeFontCacheEntry(FONTCACHEENTRY *pEntry)
  36. {
  37. Assert(pEntry);
  38. FreeFontsInEntry(pEntry);
  39. MemFree(pEntry);
  40. return S_OK;
  41. }
  42. // =================================================================================
  43. // Font Cache Implementation
  44. // =================================================================================
  45. CFontCache::CFontCache(IUnknown *pUnkOuter) : CPrivateUnknown(pUnkOuter),
  46. m_pAdviseRegistry(NULL), m_pFontEntries(NULL),
  47. m_pSysCacheEntry(NULL), m_bISO_2022_JP_ESC_SIO_Control(false),
  48. m_uiSystemCodePage(0)
  49. {
  50. InitializeCriticalSection(&m_rFontCritSect);
  51. InitializeCriticalSection(&m_rAdviseCritSect);
  52. }
  53. //***************************************************
  54. CFontCache::~CFontCache()
  55. {
  56. if (m_pAdviseRegistry)
  57. m_pAdviseRegistry->Release();
  58. if (m_pFontEntries)
  59. m_pFontEntries->Release();
  60. if (m_pSysCacheEntry)
  61. FreeFontCacheEntry(m_pSysCacheEntry);
  62. DeleteCriticalSection(&m_rFontCritSect);
  63. DeleteCriticalSection(&m_rAdviseCritSect);
  64. }
  65. //***************************************************
  66. HRESULT CFontCache::InitSysFontEntry()
  67. {
  68. // Locals
  69. NONCLIENTMETRICS ncm;
  70. CHARSETINFO rCharsetInfo={0};
  71. UINT nACP;
  72. HRESULT hr = S_OK;
  73. LOGFONT rSysLogFonts;
  74. Assert(m_pSysCacheEntry);
  75. // Get system ansi code page
  76. nACP = GetACP();
  77. m_pSysCacheEntry->uiCodePage = nACP;
  78. m_uiSystemCodePage = nACP;
  79. // Get the charset for the current ANSI code page
  80. TranslateCharsetInfo((DWORD *)IntToPtr(MAKELONG(nACP, 0)), &rCharsetInfo, TCI_SRCCODEPAGE);
  81. // Get icon font metrics
  82. if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &rSysLogFonts, 0))
  83. {
  84. StrCpyN(m_pSysCacheEntry->szFaceName, rSysLogFonts.lfFaceName, ARRAYSIZE(m_pSysCacheEntry->szFaceName));
  85. // Reset lfCharset depending on the current ansi code page
  86. rSysLogFonts.lfCharSet = (BYTE) rCharsetInfo.ciCharset;
  87. //$HACK - This code is necessary to work around a bug in Windows.
  88. // If the icon font has never been changed from the default,
  89. // SystemParametersInfo returns the wrong height. We need
  90. // to select the font into a DC and get the textmetrics to
  91. // determine the correct height. (EricAn)
  92. HFONT hFont;
  93. if (hFont = CreateFontIndirect(&rSysLogFonts))
  94. {
  95. HDC hdc;
  96. if (hdc = GetDC(NULL))
  97. {
  98. TEXTMETRIC tm;
  99. HFONT hFontOld = SelectFont(hdc, hFont);
  100. GetTextMetrics(hdc, &tm);
  101. rSysLogFonts.lfHeight = -(tm.tmHeight - tm.tmInternalLeading);
  102. SelectFont(hdc, hFontOld);
  103. ReleaseDC(NULL, hdc);
  104. }
  105. DeleteObject(hFont);
  106. }
  107. if (m_pSysCacheEntry->rgFonts[FNT_SYS_ICON] == 0)
  108. m_pSysCacheEntry->rgFonts[FNT_SYS_ICON] = CreateFontIndirect(&rSysLogFonts);
  109. // Bold Icon Font
  110. if (m_pSysCacheEntry->rgFonts[FNT_SYS_ICON_BOLD] == 0)
  111. {
  112. LONG lOldWeight = rSysLogFonts.lfWeight;
  113. rSysLogFonts.lfWeight = (rSysLogFonts.lfWeight < 700) ? 700 : 1000;
  114. m_pSysCacheEntry->rgFonts[FNT_SYS_ICON_BOLD] = CreateFontIndirect(&rSysLogFonts);
  115. rSysLogFonts.lfWeight = lOldWeight;
  116. }
  117. if (m_pSysCacheEntry->rgFonts[FNT_SYS_ICON_STRIKEOUT] == 0)
  118. {
  119. rSysLogFonts.lfStrikeOut = TRUE;
  120. m_pSysCacheEntry->rgFonts[FNT_SYS_ICON_STRIKEOUT] = CreateFontIndirect(&rSysLogFonts);
  121. }
  122. }
  123. else
  124. {
  125. AssertSz (FALSE, "SystemParametersInfo (SPI_GETICONTITLELOGFONT) - Failed ---.");
  126. hr = E_FAIL;
  127. goto Exit;
  128. }
  129. if (m_pSysCacheEntry->rgFonts[FNT_SYS_MENU] == 0)
  130. {
  131. #ifndef WIN16 // WIN16FF - SPI_GETNONCLIENTMETRICS
  132. // Prepare to get icon metrics
  133. ncm.cbSize = sizeof(ncm);
  134. // Get system menu font
  135. if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
  136. {
  137. CopyMemory((LPBYTE)&rSysLogFonts, (LPBYTE)&ncm.lfMenuFont, sizeof(LOGFONT));
  138. m_pSysCacheEntry->rgFonts[FNT_SYS_MENU] = CreateFontIndirect(&rSysLogFonts);
  139. }
  140. else
  141. {
  142. AssertSz (FALSE, "SystemParametersInfo (SPI_GETNONCLIENTMETRICS) - Failed ---.");
  143. hr = E_FAIL;
  144. goto Exit;
  145. }
  146. #else
  147. m_pSysCacheEntry->rgFonts[FNT_SYS_MENU] = m_pSysCacheEntry->rgFonts[FNT_SYS_ICON];
  148. #endif
  149. }
  150. Exit:
  151. return hr;
  152. }
  153. //***************************************************
  154. HRESULT CFontCache::GetSysFont(FNTSYSTYPE fntType, HFONT *phFont)
  155. {
  156. // check params
  157. Assert(fntType < FNT_SYS_LAST);
  158. Assert(m_pSysCacheEntry);
  159. EnterCriticalSection(&m_rFontCritSect);
  160. // System Font
  161. if (m_pSysCacheEntry->rgFonts[fntType] == NULL)
  162. // This call might fail, but we can return NULL fonts, so is OK
  163. (void)InitSysFontEntry();
  164. // Done
  165. *phFont = m_pSysCacheEntry->rgFonts[fntType];
  166. LeaveCriticalSection(&m_rFontCritSect);
  167. return ((*phFont) ? S_OK : E_FAIL);
  168. }
  169. //***************************************************
  170. HRESULT CFontCache::FreeResources()
  171. {
  172. m_pFontEntries->ClearList();
  173. FreeFontsInEntry(m_pSysCacheEntry);
  174. return S_OK;
  175. }
  176. //***************************************************
  177. HRESULT CFontCache::InitResources()
  178. {
  179. DWORD dummyCookie = 0;
  180. #ifdef DEBUG
  181. DWORD cCount;
  182. m_pFontEntries->GetCount(&cCount);
  183. Assert(cCount == 0);
  184. #endif
  185. HRESULT hr = InitSysFontEntry();
  186. return hr;
  187. }
  188. //***************************************************
  189. void CFontCache::SendPostChangeNotifications()
  190. {
  191. DWORD cookie = 0;
  192. IFontCacheNotify* pCurr;
  193. IUnknown* pTempCurr;
  194. while(SUCCEEDED(m_pAdviseRegistry->GetNext(LD_FORWARD, &pTempCurr, &cookie)))
  195. {
  196. if (pTempCurr->QueryInterface(IID_IFontCacheNotify, (LPVOID *)&pCurr)==S_OK)
  197. {
  198. pCurr->OnPostFontChange();
  199. pCurr->Release();
  200. }
  201. pTempCurr->Release();
  202. }
  203. }
  204. //***************************************************
  205. void CFontCache::SendPreChangeNotifications()
  206. {
  207. DWORD cookie = 0;
  208. IFontCacheNotify* pCurr;
  209. IUnknown* pTempCurr;
  210. while(SUCCEEDED(m_pAdviseRegistry->GetNext(LD_FORWARD, &pTempCurr, &cookie)))
  211. {
  212. if (pTempCurr->QueryInterface(IID_IFontCacheNotify, (LPVOID *)&pCurr)==S_OK)
  213. {
  214. pCurr->OnPreFontChange();
  215. pCurr->Release();
  216. }
  217. pTempCurr->Release();
  218. }
  219. }
  220. //************************************
  221. // IFontCache interface implementation
  222. //************************************
  223. HRESULT CFontCache::Init(HKEY hkey, LPCSTR pszIntlKey, DWORD dwFlags)
  224. {
  225. HRESULT hr;
  226. DWORD dummyCookie, dw, cb;
  227. HKEY hTopkey;
  228. if (m_pSysCacheEntry)
  229. return E_UNEXPECTED;
  230. EnterCriticalSection(&m_rFontCritSect);
  231. EnterCriticalSection(&m_rAdviseCritSect);
  232. hr = IUnknownList_CreateInstance(&m_pAdviseRegistry);
  233. if (FAILED(hr))
  234. goto Exit;
  235. hr = m_pAdviseRegistry->Init(NULL, 0, 0);
  236. if (FAILED(hr))
  237. goto Exit;
  238. hr = IVoidPtrList_CreateInstance(&m_pFontEntries);
  239. if (FAILED(hr))
  240. goto Exit;
  241. hr = m_pFontEntries->Init(NULL, 0, (IVPL_FREEITEMFUNCTYPE)(&FreeFontCacheEntry), 0);
  242. if (FAILED(hr))
  243. goto Exit;
  244. hr = CreateFontCacheEntry(&m_pSysCacheEntry);
  245. if (FAILED(hr))
  246. goto Exit;
  247. hr = InitResources();
  248. if (FAILED(hr))
  249. goto Exit;
  250. m_hkey = hkey;
  251. StrCpyN(m_szIntlKeyPath, pszIntlKey, ARRAYSIZE(m_szIntlKeyPath));
  252. if (RegOpenKeyEx(m_hkey, m_szIntlKeyPath, NULL, KEY_READ, &hTopkey) == ERROR_SUCCESS)
  253. {
  254. cb = sizeof(dw);
  255. if (RegQueryValueEx(hTopkey, c_szISO2022JPControl, NULL, NULL, (LPBYTE)&dw, &cb) == ERROR_SUCCESS)
  256. m_bISO_2022_JP_ESC_SIO_Control = (BOOL) dw;
  257. else
  258. m_bISO_2022_JP_ESC_SIO_Control = false;
  259. RegCloseKey(hTopkey);
  260. }
  261. else
  262. m_bISO_2022_JP_ESC_SIO_Control = false;
  263. Exit:
  264. LeaveCriticalSection(&m_rAdviseCritSect);
  265. LeaveCriticalSection(&m_rFontCritSect);
  266. return hr;
  267. }
  268. //***************************************************
  269. HRESULT CFontCache::GetFont(FNTSYSTYPE fntType, HCHARSET hCharset, HFONT *phFont)
  270. {
  271. INETCSETINFO CsetInfo;
  272. UINT uiCodePage = 0;
  273. FONTCACHEENTRY *pCurrEntry = NULL;
  274. DWORD cookie = 0;
  275. // check params
  276. Assert(fntType < FNT_SYS_LAST);
  277. Assert(m_pSysCacheEntry);
  278. if (hCharset == NULL)
  279. return GetSysFont(fntType, phFont);
  280. *phFont = 0;
  281. /* get CodePage from HCHARSET */
  282. MimeOleGetCharsetInfo(hCharset,&CsetInfo);
  283. uiCodePage = (CP_JAUTODETECT == CsetInfo.cpiWindows) ? 932 : CsetInfo.cpiWindows;
  284. if ( uiCodePage == CP_KAUTODETECT )
  285. uiCodePage = 949 ;
  286. // Don't want to duplicate the system codepage in the list.
  287. if (m_pSysCacheEntry && (uiCodePage == m_uiSystemCodePage))
  288. return GetSysFont(fntType, phFont);
  289. EnterCriticalSection(&m_rFontCritSect);
  290. // Check to see if code page is in cache
  291. while (SUCCEEDED(m_pFontEntries->GetNext(LD_FORWARD, (LPVOID *)&pCurrEntry, &cookie)))
  292. if (pCurrEntry->uiCodePage == uiCodePage)
  293. break;
  294. // If code page not in cache, add it
  295. if (NULL == pCurrEntry)
  296. {
  297. if (FAILED(CreateFontCacheEntry(&pCurrEntry)))
  298. goto ErrorExit;
  299. if (FAILED(m_pFontEntries->AddItem(pCurrEntry, &cookie)))
  300. goto ErrorExit;
  301. pCurrEntry->uiCodePage = uiCodePage;
  302. }
  303. // See if desired font is available for code page. If not, create code page
  304. if (0 == pCurrEntry->rgFonts[fntType])
  305. {
  306. // Locals
  307. LOGFONT lf;
  308. TCHAR szFaceName[LF_FACESIZE] = { TCHAR(0) } ;
  309. BYTE bGDICharset;
  310. // Get logfont for charset
  311. if (0 == GetObject(m_pSysCacheEntry->rgFonts[fntType], sizeof (LOGFONT), &lf))
  312. goto ErrorExit;
  313. if (FAILED(SetGDIAndFaceNameInLF(uiCodePage, CsetInfo.cpiWindows, &lf)))
  314. goto ErrorExit;
  315. // Create the font
  316. if ((CP_UNICODE == uiCodePage) || IsValidCodePage(uiCodePage))
  317. pCurrEntry->rgFonts[fntType] = CreateFontIndirect(&lf);
  318. else
  319. goto ErrorExit;
  320. }
  321. *phFont = pCurrEntry->rgFonts[fntType];
  322. LeaveCriticalSection(&m_rFontCritSect);
  323. return S_OK;
  324. ErrorExit:
  325. LeaveCriticalSection(&m_rFontCritSect);
  326. return GetSysFont(fntType, phFont);
  327. }
  328. //***************************************************
  329. HRESULT CFontCache::OnOptionChange()
  330. {
  331. HRESULT hr;
  332. EnterCriticalSection(&m_rAdviseCritSect);
  333. SendPreChangeNotifications();
  334. EnterCriticalSection(&m_rFontCritSect);
  335. FreeResources();
  336. // Even if this fails, still need to send notifications
  337. InitResources();
  338. LeaveCriticalSection(&m_rFontCritSect);
  339. SendPostChangeNotifications();
  340. LeaveCriticalSection(&m_rAdviseCritSect);
  341. return S_OK;
  342. }
  343. //***************************************************
  344. HRESULT CFontCache::GetJP_ISOControl(BOOL *pfUseSIO)
  345. {
  346. // 0 means use ESC, 1 means use SIO
  347. *pfUseSIO = m_bISO_2022_JP_ESC_SIO_Control;
  348. return S_OK;
  349. }
  350. //******************************************
  351. // IConnectionPoint interface implementation
  352. //
  353. // The only functions we care about right now
  354. // are the Advise and Unadvise functions. The
  355. // others return E_NOTIMPL
  356. //******************************************
  357. HRESULT CFontCache::Advise(IUnknown *pUnkSink, DWORD *pdwCookie)
  358. {
  359. EnterCriticalSection(&m_rAdviseCritSect);
  360. HRESULT hr = m_pAdviseRegistry->AddItem(pUnkSink, pdwCookie);
  361. LeaveCriticalSection(&m_rAdviseCritSect);
  362. return hr;
  363. }
  364. //***************************************************
  365. HRESULT CFontCache::Unadvise(DWORD dwCookie)
  366. {
  367. EnterCriticalSection(&m_rAdviseCritSect);
  368. HRESULT hr = m_pAdviseRegistry->RemoveItem(dwCookie);
  369. LeaveCriticalSection(&m_rAdviseCritSect);
  370. return hr;
  371. }
  372. //***************************************************
  373. HRESULT CFontCache::GetConnectionInterface(IID *pIID)
  374. {
  375. return E_NOTIMPL;
  376. }
  377. //***************************************************
  378. HRESULT CFontCache::GetConnectionPointContainer(IConnectionPointContainer **ppCPC)
  379. {
  380. *ppCPC = NULL;
  381. return E_NOTIMPL;
  382. }
  383. //***************************************************
  384. HRESULT CFontCache::EnumConnections(IEnumConnections **ppEnum)
  385. {
  386. *ppEnum = NULL;
  387. return E_NOTIMPL;
  388. }
  389. //***************************************************
  390. HRESULT CFontCache::PrivateQueryInterface(REFIID riid, LPVOID *lplpObj)
  391. {
  392. TraceCall("CFontCache::PrivateQueryInterface");
  393. if(!lplpObj)
  394. return E_INVALIDARG;
  395. *lplpObj = NULL;
  396. if (IsEqualIID(riid, IID_IFontCache))
  397. *lplpObj = (LPVOID)(IFontCache *)this;
  398. else if (IsEqualIID(riid, IID_IConnectionPoint))
  399. *lplpObj = (LPVOID)(IConnectionPoint *)this;
  400. else
  401. {
  402. *lplpObj = NULL;
  403. return E_NOINTERFACE;
  404. }
  405. AddRef();
  406. return NOERROR;
  407. }
  408. //***************************************************
  409. // szFaceName is assumed to be from LOGFONT->lfFaceName
  410. HRESULT CFontCache::SetFaceNameFromReg(UINT uiCodePage, LPTSTR szFaceName, DWORD cchFaceName)
  411. {
  412. HKEY hkey, hTopkey;
  413. DWORD cb, dw, i = 0;
  414. TCHAR szName[LF_FACESIZE];
  415. szFaceName[0] = TCHAR(0);
  416. if (RegOpenKeyEx(m_hkey, m_szIntlKeyPath, NULL, KEY_READ, &hTopkey) == ERROR_SUCCESS)
  417. {
  418. cb = sizeof(szName);
  419. while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hTopkey, i++, szName, &cb, 0, NULL, NULL, NULL))
  420. {
  421. UINT uiTempCodePage = StrToInt(szName);
  422. if (uiTempCodePage == uiCodePage)
  423. {
  424. if (RegOpenKeyEx(hTopkey, szName, NULL, KEY_READ, &hkey) == ERROR_SUCCESS)
  425. {
  426. cb = sizeof(TCHAR)*cchFaceName;
  427. RegQueryValueEx(hkey, REGSTR_VAL_PROP_FONT, NULL, NULL, (LPBYTE)szFaceName, &cb);
  428. RegCloseKey(hkey);
  429. break;
  430. }
  431. }
  432. cb = sizeof(szName);
  433. }
  434. RegCloseKey(hTopkey);
  435. }
  436. if (TCHAR(0) == szFaceName[0])
  437. return E_FAIL;
  438. return S_OK;
  439. }
  440. // =================================================================================
  441. // EnumFontFamExProc
  442. // =================================================================================
  443. INT CALLBACK EnumFontFamExProc (ENUMLOGFONTEX *lpelfe,
  444. NEWTEXTMETRICEX *lpntme,
  445. INT FontType,
  446. LPARAM lParam)
  447. {
  448. // Check Param
  449. Assert (lpelfe && lpntme && lParam);
  450. // NOTE: Assuming size of buffer is LF_FACESIZE. If it changes below, change
  451. // here also.
  452. StrCpyN((LPTSTR)lParam, lpelfe->elfLogFont.lfFaceName, LF_FACESIZE);
  453. // End the enumeration by return 0
  454. return 0;
  455. }
  456. //***************************************************
  457. // szFaceName is assumed to be from LOGFONT->lfFaceName
  458. HRESULT CFontCache::SetFaceNameFromGDI(BYTE bGDICharSet, LPTSTR szFaceName, DWORD cchFaceName)
  459. {
  460. HDC hdc;
  461. LOGFONT rSysLogFont;
  462. // I know these charsets support Arial
  463. if (bGDICharSet == ANSI_CHARSET || bGDICharSet == EASTEUROPE_CHARSET ||
  464. bGDICharSet == RUSSIAN_CHARSET || bGDICharSet == BALTIC_CHARSET ||
  465. bGDICharSet == GREEK_CHARSET || bGDICharSet == TURKISH_CHARSET)
  466. {
  467. StrCpyN(szFaceName, TEXT("Arial"), cchFaceName);
  468. goto Exit;
  469. }
  470. if (0 == GetObject(m_pSysCacheEntry->rgFonts[FNT_SYS_ICON], sizeof (LOGFONT), &rSysLogFont))
  471. {
  472. StrCpyN(szFaceName, rSysLogFont.lfFaceName, cchFaceName);
  473. if (TCHAR(0) != szFaceName[0])
  474. goto Exit;
  475. }
  476. // Get an hdc from the hwnd
  477. hdc = GetDC (NULL);
  478. TCHAR szName[LF_FACESIZE]; // Note: If we change size, change callback above.
  479. // EnumFontFamilies
  480. EnumFontFamiliesEx(hdc, &rSysLogFont, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)szName, 0);
  481. StrCpyN(szFaceName, szName, cchFaceName);
  482. // Done
  483. ReleaseDC (NULL, hdc);
  484. Exit:
  485. return (0 != *szFaceName) ? S_OK : E_FAIL;
  486. }
  487. //***************************************************
  488. // szFaceName is assumed to be from LOGFONT->lfFaceName
  489. HRESULT CFontCache::SetFaceNameFromCPID(UINT cpID, LPTSTR szFaceName, DWORD cchFaceName)
  490. {
  491. CODEPAGEINFO CodePageInfo ;
  492. /* get CodePageInfo from HCHARSET */
  493. MimeOleGetCodePageInfo(cpID,&CodePageInfo);
  494. if ( CodePageInfo.szVariableFont[0] != '\0' )
  495. StrCpyN(szFaceName, CodePageInfo.szVariableFont, cchFaceName);
  496. else
  497. StrCpyN(szFaceName, CodePageInfo.szFixedFont, cchFaceName);
  498. if (szFaceName[0] == '\0')
  499. return E_FAIL;
  500. return S_OK;
  501. }
  502. //***************************************************
  503. HRESULT CFontCache::SetGDIAndFaceNameInLF(UINT uiCodePage, CODEPAGEID cpID, LOGFONT *lpLF)
  504. {
  505. HRESULT hr = S_OK;
  506. BOOL fDoLastChance = false;
  507. CHARSETINFO rCharsetInfo;
  508. if (FAILED(SetFaceNameFromReg(uiCodePage, lpLF->lfFaceName, ARRAYSIZE(lpLF->lfFaceName))))
  509. if (FAILED(SetFaceNameFromCPID(cpID, lpLF->lfFaceName, ARRAYSIZE(lpLF->lfFaceName))))
  510. fDoLastChance = true;
  511. if ( TranslateCharsetInfo((LPDWORD) IntToPtr(uiCodePage), &rCharsetInfo, TCI_SRCCODEPAGE))
  512. lpLF->lfCharSet = (BYTE) rCharsetInfo.ciCharset;
  513. else
  514. lpLF->lfCharSet = DEFAULT_CHARSET;
  515. if (fDoLastChance)
  516. hr = SetFaceNameFromGDI(lpLF->lfCharSet, lpLF->lfFaceName, ARRAYSIZE(lpLF->lfFaceName));
  517. return hr;
  518. }
  519. //***************************************************
  520. HRESULT CFontCache::CreateInstance(IUnknown* pUnkOuter, IUnknown** ppUnknown)
  521. {
  522. // Invalid Arg
  523. Assert(ppUnknown);
  524. // Initialize
  525. *ppUnknown = NULL;
  526. // Create me
  527. CFontCache *pNew = new CFontCache(pUnkOuter);
  528. if (NULL == pNew)
  529. return (E_OUTOFMEMORY);
  530. // Cast to unknown
  531. *ppUnknown = (IFontCache*)pNew;
  532. // Done
  533. return S_OK;
  534. }