[FONTEXT] Initial implementation of CFontExt::DoGetFontTitle (#3127)
[reactos.git] / dll / shellext / fontext / CFontExt.cpp
1 /*
2 * PROJECT: ReactOS Font Shell Extension
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: CFontExt implementation
5 * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org)
6 * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7 */
8
9 #include "precomp.h"
10 #include "undocgdi.h" // for GetFontResourceInfoW
11
12 WINE_DEFAULT_DEBUG_CHANNEL(fontext);
13
14
15 struct FolderViewColumns
16 {
17 int iResource;
18 DWORD dwDefaultState;
19 int cxChar;
20 int fmt;
21 };
22
23 static FolderViewColumns g_ColumnDefs[] =
24 {
25 { IDS_COL_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 25, LVCFMT_LEFT },
26 { IDS_COL_FILENAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 20, LVCFMT_LEFT },
27 { IDS_COL_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT },
28 { IDS_COL_MODIFIED, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, 15, LVCFMT_LEFT },
29 { IDS_COL_ATTR, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 12, LVCFMT_RIGHT },
30 };
31
32
33
34 // Should fix our headers..
35 EXTERN_C HRESULT WINAPI SHCreateFileExtractIconW(LPCWSTR pszPath, DWORD dwFileAttributes, REFIID riid, void **ppv);
36
37
38 // Helper functions to translate a guid to a readable name
39 bool GetInterfaceName(const WCHAR* InterfaceString, WCHAR* buf, size_t size)
40 {
41 WCHAR LocalBuf[100];
42 DWORD dwType = 0, dwDataSize = size * sizeof(WCHAR);
43
44 if (!SUCCEEDED(StringCchPrintfW(LocalBuf, _countof(LocalBuf), L"Interface\\%s", InterfaceString)))
45 return false;
46
47 return RegGetValueW(HKEY_CLASSES_ROOT, LocalBuf, NULL, RRF_RT_REG_SZ, &dwType, buf, &dwDataSize) == ERROR_SUCCESS;
48 }
49
50 WCHAR* g2s(REFCLSID iid)
51 {
52 static WCHAR buf[2][300];
53 static int idx = 0;
54
55 idx ^= 1;
56
57 LPOLESTR tmp;
58 HRESULT hr = ProgIDFromCLSID(iid, &tmp);
59 if (SUCCEEDED(hr))
60 {
61 wcscpy(buf[idx], tmp);
62 CoTaskMemFree(tmp);
63 return buf[idx];
64 }
65 StringFromGUID2(iid, buf[idx], _countof(buf[idx]));
66 if (GetInterfaceName(buf[idx], buf[idx], _countof(buf[idx])))
67 {
68 return buf[idx];
69 }
70 StringFromGUID2(iid, buf[idx], _countof(buf[idx]));
71
72 return buf[idx];
73 }
74
75
76 CFontExt::CFontExt()
77 {
78 InterlockedIncrement(&g_ModuleRefCnt);
79 }
80
81 CFontExt::~CFontExt()
82 {
83 InterlockedDecrement(&g_ModuleRefCnt);
84 }
85
86 // *** IShellFolder2 methods ***
87 STDMETHODIMP CFontExt::GetDefaultSearchGUID(GUID *lpguid)
88 {
89 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
90 return E_NOTIMPL;
91 }
92
93 STDMETHODIMP CFontExt::EnumSearches(IEnumExtraSearch **ppenum)
94 {
95 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
96 return E_NOTIMPL;
97 }
98
99 STDMETHODIMP CFontExt::GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
100 {
101 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
102 return E_NOTIMPL;
103 }
104
105 STDMETHODIMP CFontExt::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags)
106 {
107 if (!pcsFlags || iColumn >= _countof(g_ColumnDefs))
108 return E_INVALIDARG;
109
110 *pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
111 return S_OK;
112 }
113
114 STDMETHODIMP CFontExt::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
115 {
116 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
117 return E_NOTIMPL;
118 }
119
120 STDMETHODIMP CFontExt::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
121 {
122 if (iColumn >= _countof(g_ColumnDefs))
123 return E_FAIL;
124
125 psd->cxChar = g_ColumnDefs[iColumn].cxChar;
126 psd->fmt = g_ColumnDefs[iColumn].fmt;
127
128 // No item requested, so return the column name
129 if (pidl == NULL)
130 {
131 return SHSetStrRet(&psd->str, _AtlBaseModule.GetResourceInstance(), g_ColumnDefs[iColumn].iResource);
132 }
133
134 // Validate that this pidl is the last one
135 PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl);
136 if (curpidl->mkid.cb != 0)
137 {
138 ERR("ERROR, unhandled PIDL!\n");
139 return E_FAIL;
140 }
141
142 // Name, ReactOS specific?
143 if (iColumn == 0)
144 return GetDisplayNameOf(pidl, 0, &psd->str);
145
146 const FontPidlEntry* fontEntry = _FontFromIL(pidl);
147 if (!fontEntry)
148 {
149 ERR("ERROR, not a font PIDL!\n");
150 return E_FAIL;
151 }
152
153 // If we got here, we are in details view!
154 // Let's see if we got info about this file that we can re-use
155 if (m_LastDetailsFontName != fontEntry->Name)
156 {
157 CStringW File = g_FontCache->Filename(fontEntry, true);
158 HANDLE hFile = FindFirstFileW(File, &m_LastDetailsFileData);
159 if (hFile == INVALID_HANDLE_VALUE)
160 {
161 m_LastDetailsFontName.Empty();
162 ERR("Unable to query info about %S\n", File.GetString());
163 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
164 }
165 FindClose(hFile);
166 m_LastDetailsFontName = fontEntry->Name;
167 }
168
169 // Most code borrowed from CFSFolder::GetDetailsOf
170 FILETIME lft;
171 SYSTEMTIME time;
172 int ret;
173 LARGE_INTEGER FileSize;
174 CStringA AttrLetters;
175 switch (iColumn)
176 {
177 case 1: // Filename
178 return SHSetStrRet(&psd->str, m_LastDetailsFileData.cFileName);
179 case 2: // Size
180 psd->str.uType = STRRET_CSTR;
181 FileSize.HighPart = m_LastDetailsFileData.nFileSizeHigh;
182 FileSize.LowPart = m_LastDetailsFileData.nFileSizeLow;
183 StrFormatKBSizeA(FileSize.QuadPart, psd->str.cStr, MAX_PATH);
184 return S_OK;
185 case 3: // Modified
186 FileTimeToLocalFileTime(&m_LastDetailsFileData.ftLastWriteTime, &lft);
187 FileTimeToSystemTime (&lft, &time);
188 psd->str.uType = STRRET_CSTR;
189 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, psd->str.cStr, MAX_PATH);
190 if (ret < 1)
191 {
192 ERR("GetDateFormatA failed\n");
193 return E_FAIL;
194 }
195 psd->str.cStr[ret-1] = ' ';
196 GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &psd->str.cStr[ret], MAX_PATH - ret);
197 return S_OK;
198 case 4: // Attributes
199 AttrLetters.LoadString(IDS_COL_ATTR_LETTERS);
200 if (AttrLetters.GetLength() != 5)
201 {
202 ERR("IDS_COL_ATTR_LETTERS does not contain 5 letters!\n");
203 return E_FAIL;
204 }
205 psd->str.uType = STRRET_CSTR;
206 ret = 0;
207 if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
208 psd->str.cStr[ret++] = AttrLetters[0];
209 if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
210 psd->str.cStr[ret++] = AttrLetters[1];
211 if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
212 psd->str.cStr[ret++] = AttrLetters[2];
213 if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
214 psd->str.cStr[ret++] = AttrLetters[3];
215 if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)
216 psd->str.cStr[ret++] = AttrLetters[4];
217 psd->str.cStr[ret] = '\0';
218 return S_OK;
219 default:
220 break;
221 }
222
223 UNIMPLEMENTED;
224 return E_NOTIMPL;
225 }
226
227 STDMETHODIMP CFontExt::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
228 {
229 //ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
230 return E_NOTIMPL;
231 }
232
233 // *** IShellFolder2 methods ***
234 STDMETHODIMP CFontExt::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
235 {
236 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
237 return E_NOTIMPL;
238 }
239
240 STDMETHODIMP CFontExt::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
241 {
242 return _CEnumFonts_CreateInstance(this, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
243 }
244
245 STDMETHODIMP CFontExt::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
246 {
247 ERR("%s(riid=%S) UNIMPLEMENTED\n", __FUNCTION__, g2s(riid));
248 return E_NOTIMPL;
249 }
250
251 STDMETHODIMP CFontExt::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
252 {
253 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
254 return E_NOTIMPL;
255 }
256
257 STDMETHODIMP CFontExt::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
258 {
259 const FontPidlEntry* fontEntry1 = _FontFromIL(pidl1);
260 const FontPidlEntry* fontEntry2 = _FontFromIL(pidl2);
261
262 if (!fontEntry1 || !fontEntry2)
263 return E_INVALIDARG;
264
265 int result = (int)fontEntry1->Index - (int)fontEntry2->Index;
266
267 return MAKE_COMPARE_HRESULT(result);
268 }
269
270 STDMETHODIMP CFontExt::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
271 {
272 HRESULT hr = E_NOINTERFACE;
273
274 *ppvOut = NULL;
275
276 if (IsEqualIID(riid, IID_IDropTarget))
277 {
278 ERR("IDropTarget not implemented\n");
279 *ppvOut = static_cast<IDropTarget *>(this);
280 AddRef();
281 hr = S_OK;
282 }
283 else if (IsEqualIID(riid, IID_IContextMenu))
284 {
285 ERR("IContextMenu not implemented\n");
286 hr = E_NOTIMPL;
287 }
288 else if (IsEqualIID(riid, IID_IShellView))
289 {
290 // Just create a default shell folder view, and register ourself as folder
291 SFV_CREATE sfv = { sizeof(SFV_CREATE) };
292 sfv.pshf = this;
293 hr = SHCreateShellFolderView(&sfv, (IShellView**)ppvOut);
294 }
295
296 return hr;
297 }
298
299 STDMETHODIMP CFontExt::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
300 {
301 if (!rgfInOut || !cidl || !apidl)
302 return E_INVALIDARG;
303
304 DWORD rgf = 0;
305 while (cidl > 0 && *apidl)
306 {
307 const FontPidlEntry* fontEntry = _FontFromIL(*apidl);
308 if (fontEntry)
309 {
310 // We don't support delete yet
311 rgf |= (/*SFGAO_CANDELETE |*/ SFGAO_HASPROPSHEET | SFGAO_CANCOPY | SFGAO_FILESYSTEM);
312 }
313 else
314 {
315 rgf = 0;
316 break;
317 }
318
319 apidl++;
320 cidl--;
321 }
322
323 *rgfInOut = rgf;
324 return S_OK;
325 }
326
327
328 STDMETHODIMP CFontExt::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
329 {
330 if (riid == IID_IContextMenu ||
331 riid == IID_IContextMenu2 ||
332 riid == IID_IContextMenu3)
333 {
334 return _CFontMenu_CreateInstance(hwndOwner, cidl, apidl, this, riid, ppvOut);
335 }
336 else if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
337 {
338 if (cidl == 1)
339 {
340 const FontPidlEntry* fontEntry = _FontFromIL(*apidl);
341 if (fontEntry)
342 {
343 DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL;
344 CStringW File = g_FontCache->Filename(fontEntry);
345 // Just create a default icon extractor based on the filename
346 // We might want to create a preview with the font to get really fancy one day.
347 return SHCreateFileExtractIconW(File, dwAttributes, riid, ppvOut);
348 }
349 }
350 else
351 {
352 ERR("IID_IExtractIcon with cidl != 1 UNIMPLEMENTED\n");
353 }
354 }
355 else if (riid == IID_IDataObject)
356 {
357 if (cidl >= 1)
358 {
359 return _CDataObject_CreateInstance(m_Folder, cidl, apidl, riid, ppvOut);
360 }
361 else
362 {
363 ERR("IID_IDataObject with cidl == 0 UNIMPLEMENTED\n");
364 }
365 }
366
367 //ERR("%s(riid=%S) UNIMPLEMENTED\n", __FUNCTION__, g2s(riid));
368 return E_NOTIMPL;
369 }
370
371 STDMETHODIMP CFontExt::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
372 {
373 if (!pidl)
374 return E_NOTIMPL;
375
376 // Validate that this pidl is the last one
377 PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl);
378 if (curpidl->mkid.cb != 0)
379 {
380 ERR("ERROR, unhandled PIDL!\n");
381 return E_FAIL;
382 }
383
384 const FontPidlEntry* fontEntry = _FontFromIL(pidl);
385 if (!fontEntry)
386 return E_FAIL;
387
388 return SHSetStrRet(strRet, fontEntry->Name);
389 }
390
391 STDMETHODIMP CFontExt::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
392 {
393 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
394 return E_NOTIMPL;
395 }
396
397 // *** IPersistFolder2 methods ***
398 STDMETHODIMP CFontExt::GetCurFolder(LPITEMIDLIST *ppidl)
399 {
400 if (ppidl && m_Folder)
401 {
402 *ppidl = ILClone(m_Folder);
403 return S_OK;
404 }
405
406 return E_POINTER;
407 }
408
409
410 // *** IPersistFolder methods ***
411 STDMETHODIMP CFontExt::Initialize(LPCITEMIDLIST pidl)
412 {
413 WCHAR PidlPath[MAX_PATH + 1] = {0}, FontsDir[MAX_PATH + 1];
414 if (!SHGetPathFromIDListW(pidl, PidlPath))
415 {
416 ERR("Unable to extract path from pidl\n");
417 return E_FAIL;
418 }
419
420 HRESULT hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, FontsDir);
421 if (FAILED_UNEXPECTEDLY(hr))
422 {
423 ERR("Unable to get fonts path (0x%x)\n", hr);
424 return hr;
425 }
426
427 if (_wcsicmp(PidlPath, FontsDir))
428 {
429 ERR("CFontExt View initializing on unexpected folder: '%S'\n", PidlPath);
430 return E_FAIL;
431 }
432
433 m_Folder.Attach(ILClone(pidl));
434 StringCchCatW(FontsDir, _countof(FontsDir), L"\\");
435 g_FontCache->SetFontDir(FontsDir);
436
437 return S_OK;
438 }
439
440
441 // *** IPersist methods ***
442 STDMETHODIMP CFontExt::GetClassID(CLSID *lpClassId)
443 {
444 *lpClassId = CLSID_CFontExt;
445 return S_OK;
446 }
447
448 // *** IDropTarget methods ***
449 STDMETHODIMP CFontExt::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
450 {
451 *pdwEffect = DROPEFFECT_NONE;
452
453 CComHeapPtr<CIDA> cida;
454 HRESULT hr = _GetCidlFromDataObject(pDataObj, &cida);
455 if (FAILED_UNEXPECTEDLY(hr))
456 return hr;
457
458 *pdwEffect = DROPEFFECT_COPY;
459 return S_OK;
460 }
461
462 STDMETHODIMP CFontExt::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
463 {
464 return S_OK;
465 }
466
467 STDMETHODIMP CFontExt::DragLeave()
468 {
469 return S_OK;
470 }
471
472 STDMETHODIMP CFontExt::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
473 {
474 *pdwEffect = DROPEFFECT_NONE;
475
476 CComHeapPtr<CIDA> cida;
477 HRESULT hr = _GetCidlFromDataObject(pDataObj, &cida);
478 if (FAILED_UNEXPECTEDLY(hr))
479 return hr;
480
481 PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(cida);
482 if (!pidlParent)
483 {
484 ERR("pidlParent is NULL\n");
485 return E_FAIL;
486 }
487
488 BOOL bOK = TRUE;
489 CAtlArray<CStringW> FontPaths;
490 for (UINT n = 0; n < cida->cidl; ++n)
491 {
492 PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(cida, n);
493 if (!pidlRelative)
494 continue;
495
496 PIDLIST_ABSOLUTE pidl = ILCombine(pidlParent, pidlRelative);
497 if (!pidl)
498 {
499 ERR("ILCombine failed\n");
500 bOK = FALSE;
501 break;
502 }
503
504 WCHAR szPath[MAX_PATH];
505 BOOL ret = SHGetPathFromIDListW(pidl, szPath);
506 ILFree(pidl);
507
508 if (!ret)
509 {
510 ERR("SHGetPathFromIDListW failed\n");
511 bOK = FALSE;
512 break;
513 }
514
515 if (PathIsDirectoryW(szPath))
516 {
517 ERR("PathIsDirectory\n");
518 bOK = FALSE;
519 break;
520 }
521
522 LPCWSTR pchDotExt = PathFindExtensionW(szPath);
523 if (!IsFontDotExt(pchDotExt))
524 {
525 ERR("'%S' is not supported\n", pchDotExt);
526 bOK = FALSE;
527 break;
528 }
529
530 FontPaths.Add(szPath);
531 }
532
533 if (!bOK)
534 return E_FAIL;
535
536 CRegKey keyFonts;
537 if (keyFonts.Open(FONT_HIVE, FONT_KEY, KEY_WRITE) != ERROR_SUCCESS)
538 {
539 ERR("keyFonts.Open failed\n");
540 return E_FAIL;
541 }
542
543 for (size_t iItem = 0; iItem < FontPaths.GetCount(); ++iItem)
544 {
545 HRESULT hr = DoInstallFontFile(FontPaths[iItem], g_FontCache->FontPath(), keyFonts.m_hKey);
546 if (FAILED_UNEXPECTEDLY(hr))
547 {
548 bOK = FALSE;
549 break;
550 }
551 }
552
553 // TODO: update g_FontCache
554
555 SendMessageW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
556
557 // TODO: Show message
558
559 return bOK ? S_OK : E_FAIL;
560 }
561
562 HRESULT CFontExt::DoInstallFontFile(LPCWSTR pszFontPath, LPCWSTR pszFontsDir, HKEY hkeyFonts)
563 {
564 WCHAR szDestFile[MAX_PATH];
565 LPCWSTR pszFileTitle = PathFindFileName(pszFontPath);
566
567 CStringW strFontName;
568 if (!DoGetFontTitle(pszFontPath, strFontName))
569 return E_FAIL;
570
571 RemoveFontResourceW(pszFileTitle);
572
573 StringCchCopyW(szDestFile, sizeof(szDestFile), pszFontsDir);
574 PathAppendW(szDestFile, pszFileTitle);
575 if (!CopyFileW(pszFontPath, szDestFile, FALSE))
576 {
577 ERR("CopyFileW('%S', '%S') failed\n", pszFontPath, szDestFile);
578 return E_FAIL;
579 }
580
581 if (!AddFontResourceW(szDestFile))
582 {
583 ERR("AddFontResourceW('%S') failed\n", pszFileTitle);
584 DeleteFileW(szDestFile);
585 return E_FAIL;
586 }
587
588 DWORD cbData = (wcslen(pszFileTitle) + 1) * sizeof(WCHAR);
589 LONG nError = RegSetValueExW(hkeyFonts, strFontName, 0, REG_SZ,
590 (const BYTE *)pszFileTitle, cbData);
591 if (nError)
592 {
593 ERR("RegSetValueExW failed with %ld\n", nError);
594 RemoveFontResourceW(pszFileTitle);
595 DeleteFileW(szDestFile);
596 return E_FAIL;
597 }
598
599 return S_OK;
600 }
601
602 HRESULT
603 CFontExt::DoGetFontTitle(IN LPCWSTR pszFontPath, OUT CStringW& strFontName)
604 {
605 DWORD cbInfo = 0;
606 BOOL ret = GetFontResourceInfoW(pszFontPath, &cbInfo, NULL, 1);
607 if (!ret || !cbInfo)
608 {
609 ERR("GetFontResourceInfoW failed\n");
610 return E_FAIL;
611 }
612
613 LPWSTR pszBuffer = strFontName.GetBuffer(cbInfo / sizeof(WCHAR));
614 ret = GetFontResourceInfoW(pszFontPath, &cbInfo, pszBuffer, 1);
615 strFontName.ReleaseBuffer();
616 if (ret)
617 {
618 TRACE("pszFontName: %S\n", (LPCWSTR)strFontName);
619 return S_OK;
620 }
621
622 ERR("GetFontResourceInfoW failed\n");
623 return E_FAIL;
624 }