diff --git a/dll/shellext/fontext/CEnumFonts.cpp b/dll/shellext/fontext/CEnumFonts.cpp index 95d67bc117f..093e7cc99dc 100644 --- a/dll/shellext/fontext/CEnumFonts.cpp +++ b/dll/shellext/fontext/CEnumFonts.cpp @@ -47,7 +47,7 @@ public: if (m_Index < g_FontCache->Size()) { CStringW Name = g_FontCache->Name(m_Index); - LPITEMIDLIST item = _ILCreate(Name, m_Index); + LPITEMIDLIST item = _ILCreate(Name); if (!item) { hr = Fetched ? S_FALSE : E_OUTOFMEMORY; diff --git a/dll/shellext/fontext/CFontCache.cpp b/dll/shellext/fontext/CFontCache.cpp index 28413779b54..3e9f63a855e 100644 --- a/dll/shellext/fontext/CFontCache.cpp +++ b/dll/shellext/fontext/CFontCache.cpp @@ -144,12 +144,6 @@ CStringW CFontCache::Name(size_t Index) CFontInfo* CFontCache::Find(const FontPidlEntry* fontEntry) { - if (fontEntry->Index < m_Fonts.GetCount()) - { - if (m_Fonts[fontEntry->Index].Name().CompareNoCase(fontEntry->Name) == 0) - return &m_Fonts[fontEntry->Index]; - } - for (UINT n = 0; n < Size(); ++n) { if (m_Fonts[n].Name().CompareNoCase(fontEntry->Name) == 0) diff --git a/dll/shellext/fontext/CFontExt.cpp b/dll/shellext/fontext/CFontExt.cpp index cf770e21c8e..ccc4d4c0854 100644 --- a/dll/shellext/fontext/CFontExt.cpp +++ b/dll/shellext/fontext/CFontExt.cpp @@ -3,7 +3,7 @@ * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontExt implementation * COPYRIGHT: Copyright 2019-2021 Mark Jansen - * Copyright 2019-2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + * Copyright 2019-2026 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ #include "precomp.h" @@ -259,8 +259,7 @@ STDMETHODIMP CFontExt::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUID DWORD column = lParam & 0x0000FFFF; if (sortMode == SHCIDS_ALLFIELDS) { - UNIMPLEMENTED; - result = (int)fontEntry1->Index - (int)fontEntry2->Index; + result = StrCmpIW(fontEntry1->Name, fontEntry2->Name); } else { @@ -278,11 +277,10 @@ STDMETHODIMP CFontExt::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUID case 0xffff: /* ROS bug? */ case FONTEXT_COL_NAME: - // These items are already ordered by name - result = (int)fontEntry1->Index - (int)fontEntry2->Index; + result = StrCmpIW(fontEntry1->Name, fontEntry2->Name); break; case FONTEXT_COL_FILENAME: - result = _wcsicmp(PathFindFileNameW(info1->File()), PathFindFileNameW(info2->File())); + result = StrCmpIW(PathFindFileNameW(info1->File()), PathFindFileNameW(info2->File())); break; case FONTEXT_COL_SIZE: result = (int)info1->FileSize().HighPart - info2->FileSize().HighPart; @@ -313,7 +311,6 @@ STDMETHODIMP CFontExt::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppv if (IsEqualIID(riid, IID_IDropTarget)) { - ERR("IDropTarget not implemented\n"); *ppvOut = static_cast(this); AddRef(); hr = S_OK; @@ -325,10 +322,14 @@ STDMETHODIMP CFontExt::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppv } else if (IsEqualIID(riid, IID_IShellView)) { - // Just create a default shell folder view, and register ourself as folder - SFV_CREATE sfv = { sizeof(SFV_CREATE) }; - sfv.pshf = this; - hr = SHCreateShellFolderView(&sfv, (IShellView**)ppvOut); + CComPtr sfviewcb; + if (SUCCEEDED(hr = ShellObjectCreator(sfviewcb))) + { + SFV_CREATE create = { sizeof(create), this, NULL, sfviewcb }; + hr = SHCreateShellFolderView(&create, (IShellView**)ppvOut); + if (SUCCEEDED(hr)) + sfviewcb->Initialize(this, (IShellView*)*ppvOut, m_Folder); + } } return hr; @@ -400,6 +401,12 @@ STDMETHODIMP CFontExt::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ ERR("IID_IDataObject with cidl == 0 UNIMPLEMENTED\n"); } } + else if (riid == IID_IDropTarget) + { + *ppvOut = static_cast(this); + AddRef(); + return S_OK; + } //ERR("%s(riid=%S) UNIMPLEMENTED\n", __FUNCTION__, g2s(riid)); return E_NOTIMPL; @@ -469,7 +476,7 @@ STDMETHODIMP CFontExt::Initialize(LPCITEMIDLIST pidl) return hr; } - if (_wcsicmp(PidlPath, FontsDir)) + if (StrCmpIW(PidlPath, FontsDir)) { ERR("CFontExt View initializing on unexpected folder: '%S'\n", PidlPath); return E_FAIL; @@ -492,18 +499,38 @@ STDMETHODIMP CFontExt::GetClassID(CLSID *lpClassId) // *** IDropTarget methods *** STDMETHODIMP CFontExt::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { - *pdwEffect = DROPEFFECT_NONE; + m_bDragAccepted = FALSE; - CDataObjectHIDA cida(pDataObj); - if (FAILED_UNEXPECTEDLY(cida.hr())) - return cida.hr(); + STGMEDIUM stg; + HDROP hDrop = GetDropFromDataObject(stg, pDataObj); + if (!hDrop) + { + *pdwEffect = DROPEFFECT_NONE; + DragLeave(); + return E_FAIL; + } - *pdwEffect = DROPEFFECT_COPY; + m_bDragAccepted = CheckDropFontFiles(hDrop); + ::ReleaseStgMedium(&stg); + + if (!m_bDragAccepted) + { + *pdwEffect = DROPEFFECT_NONE; + return E_FAIL; + } + + *pdwEffect &= DROPEFFECT_COPY; return S_OK; } STDMETHODIMP CFontExt::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { + if (!m_bDragAccepted) + { + *pdwEffect = DROPEFFECT_NONE; + return E_FAIL; + } + *pdwEffect &= DROPEFFECT_COPY; return S_OK; } @@ -512,13 +539,85 @@ STDMETHODIMP CFontExt::DragLeave() return S_OK; } +DWORD WINAPI CFontExt::InstallThreadProc(LPVOID lpParameter) +{ + PINSTALL_FONT_DATA pData = (PINSTALL_FONT_DATA)lpParameter; + ATLASSERT(pData); + pData->hrResult = InstallFontFiles(pData); + if (pData->bCanceled) + pData->hrResult = S_FALSE; + TRACE("hrResult: 0x%08X\n", pData->hrResult); + ::PostMessageW(pData->hwnd, WM_COMMAND, IDOK, 0); + pData->pDataObj->Release(); + return 0; +} + +INT_PTR CALLBACK +CFontExt::InstallDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, PINSTALL_FONT_DATA pData) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + pData->hwnd = hwnd; + ATLASSERT(pData->cSteps >= 0); + SendDlgItemMessageW(hwnd, IDC_INSTALL_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, pData->cSteps)); + if (!SHCreateThread(CFontExt::InstallThreadProc, pData, CTF_COINIT, NULL)) + { + WARN("!SHCreateThread\n"); + pData->pDataObj->Release(); + pData->hrResult = E_ABORT; + EndDialog(hwnd, IDABORT); + } + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + EndDialog(hwnd, IDOK); + break; + case IDCANCEL: + pData->bCanceled = TRUE; + EndDialog(hwnd, IDCANCEL); + break; + case IDCONTINUE: + pData->iStep += 1; + ATLASSERT(pData->iStep <= pData->cSteps); + SendDlgItemMessageW(hwnd, IDC_INSTALL_PROGRESS, PBM_SETPOS, pData->iStep, 0); + break; + } + break; + } + } + return 0; +} + +INT_PTR CALLBACK +CFontExt::InstallDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PINSTALL_FONT_DATA pData = (PINSTALL_FONT_DATA)GetWindowLongPtrW(hwnd, DWLP_USER); + if (uMsg == WM_INITDIALOG) + { + pData = (PINSTALL_FONT_DATA)lParam; + SetWindowLongPtrW(hwnd, DWLP_USER, lParam); + } + + ATLASSERT(pData); + ATLASSERT(pData->pFontExt); + return pData->pFontExt->InstallDlgProc(hwnd, uMsg, wParam, lParam, pData); +} + STDMETHODIMP CFontExt::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { - *pdwEffect = DROPEFFECT_NONE; - + // NOTE: Getting cida in the other thread fails CDataObjectHIDA cida(pDataObj); if (!cida || cida->cidl <= 0) + { + ERR("E_UNEXPECTED\n"); return E_UNEXPECTED; + } PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(cida); if (!pidlParent) @@ -532,28 +631,46 @@ STDMETHODIMP CFontExt::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, { PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(cida, n); if (!pidlRelative) + { + ERR("!pidlRelative\n"); return E_FAIL; - + } apidl.Add(pidlRelative); } - CStringW strMessage; - if (InstallFontFiles(strMessage, pidlParent, cida->cidl, &apidl[0]) != S_OK) + // Show progress dialog + INSTALL_FONT_DATA data; + data.pFontExt = this; + data.pDataObj = pDataObj; + data.pidlParent = pidlParent; + data.apidl = &apidl[0]; + data.cSteps = cida->cidl; + pDataObj->AddRef(); + DialogBoxParamW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDD_INSTALL), + m_hwndView, CFontExt::InstallDialogProc, (LPARAM)&data); + if (data.bCanceled) + return E_ABORT; + + CStringW text, title; + title.LoadStringW(IDS_REACTOS_FONTS_FOLDER); + if (SUCCEEDED(data.hrResult)) { - // TODO: Show message - return E_FAIL; + // Invalidate our cache + g_FontCache->Read(); + + // Notify the system that a font was added + SendMessageW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); + + // Show successful message + text.LoadStringW(IDS_INSTALL_OK); + MessageBoxW(m_hwndView, text, title, MB_ICONINFORMATION); + } + else + { + // Show error message + text.LoadStringW(IDS_INSTALL_FAILED); + MessageBoxW(m_hwndView, text, title, MB_ICONERROR); } - // Invalidate our cache - g_FontCache->Read(); - - // Notify the system that a font was added - SendMessageW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); - - // Notify the shell that the folder contents are changed - SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATHW, g_FontCache->FontPath().GetString(), NULL); - - // TODO: Show message - - return S_OK; + return data.hrResult; } diff --git a/dll/shellext/fontext/CFontExt.hpp b/dll/shellext/fontext/CFontExt.hpp index c95952d8114..c6451ea4b9a 100644 --- a/dll/shellext/fontext/CFontExt.hpp +++ b/dll/shellext/fontext/CFontExt.hpp @@ -3,7 +3,7 @@ * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontExt definition * COPYRIGHT: Copyright 2019,2020 Mark Jansen - * Copyright 2019-2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + * Copyright 2019-2026 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ #pragma once @@ -16,11 +16,21 @@ class CFontExt : public IDropTarget { CComHeapPtr m_Folder; + BOOL m_bDragAccepted = FALSE; + HWND m_hwndView = nullptr; + static INT_PTR CALLBACK InstallDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + INT_PTR CALLBACK InstallDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, PINSTALL_FONT_DATA pData); + static DWORD WINAPI InstallThreadProc(LPVOID lpParameter); public: CFontExt(); ~CFontExt(); + void SetViewWindow(HWND hwndView) + { + m_hwndView = hwndView; + } + // *** IShellFolder2 methods *** STDMETHODIMP GetDefaultSearchGUID(GUID *lpguid) override; STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum) override; diff --git a/dll/shellext/fontext/CFontFolderViewCB.cpp b/dll/shellext/fontext/CFontFolderViewCB.cpp new file mode 100644 index 00000000000..582d91b66b9 --- /dev/null +++ b/dll/shellext/fontext/CFontFolderViewCB.cpp @@ -0,0 +1,111 @@ +/* + * PROJECT: ReactOS Font Shell Extension + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Fonts folder view callback implementation + * COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "precomp.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell_ad); + +void CFontFolderViewCB::Initialize(CFontExt* pFontExt, IShellView *psv, LPCITEMIDLIST pidlParent) +{ + ATLASSERT(pFontExt); + ATLASSERT(psv); + ATLASSERT(pidlParent); + m_pFontExt = pFontExt; + m_pShellView = psv; + m_pidlParent.Attach(ILClone(pidlParent)); + if (!m_pidlParent) + ERR("!m_pidlParent\n"); +} + +HRESULT CFontFolderViewCB::TranslatePidl(LPITEMIDLIST* ppidlNew, LPCITEMIDLIST pidl) +{ + ATLASSERT(ppidlNew); + + *ppidlNew = NULL; + + WCHAR szFontFile[MAX_PATH]; + if (!SHGetPathFromIDListW(pidl, szFontFile)) + return E_FAIL; + + CStringW strFontName; + HRESULT hr = DoGetFontTitle(szFontFile, strFontName); + if (FAILED_UNEXPECTEDLY(hr)) + return E_FAIL; + + LPITEMIDLIST pidlChild = _ILCreate(strFontName); + if (!pidlChild) + { + ERR("!pidlChild\n"); + return E_OUTOFMEMORY; + } + + *ppidlNew = ILCombine(m_pidlParent, pidlChild); + ILFree(pidlChild); + + return *ppidlNew ? S_OK : E_OUTOFMEMORY; +} + +void CFontFolderViewCB::TranslateTwoPIDLs(PIDLIST_ABSOLUTE* pidls) +{ + ATLASSERT(pidls); + + HRESULT hr; + if (pidls[0]) + { + m_pidl0.Free(); + hr = TranslatePidl(&m_pidl0, pidls[0]); + if (!FAILED_UNEXPECTEDLY(hr)) + pidls[0] = m_pidl0; + } + if (pidls[1]) + { + m_pidl1.Free(); + hr = TranslatePidl(&m_pidl1, pidls[1]); + if (!FAILED_UNEXPECTEDLY(hr)) + pidls[1] = m_pidl1; + } +} + +BOOL CFontFolderViewCB::FilterEvent(LONG lEvent) const +{ + switch (lEvent & ~SHCNE_INTERRUPT) + { + case SHCNE_CREATE: + case SHCNE_DELETE: + case SHCNE_RENAMEITEM: + case SHCNE_UPDATEDIR: + return FALSE; // OK + default: + return TRUE; // We don't want this event + } +} + +STDMETHODIMP +CFontFolderViewCB::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case SFVM_QUERYFSNOTIFY: // Registering change notification + { + // Now, we can get the view window + ATLASSERT(m_pShellView); + ATLASSERT(m_pFontExt); + m_pShellView->GetWindow(&m_hwndView); + m_pFontExt->SetViewWindow(m_hwndView); + return S_OK; + } + case SFVM_FSNOTIFY: // Change notification + { + if (FilterEvent((LONG)lParam)) + return S_FALSE; // Don't process + + TranslateTwoPIDLs((PIDLIST_ABSOLUTE*)wParam); + return S_OK; + } + } + return E_NOTIMPL; +} diff --git a/dll/shellext/fontext/CFontFolderViewCB.h b/dll/shellext/fontext/CFontFolderViewCB.h new file mode 100644 index 00000000000..5fbb42733c4 --- /dev/null +++ b/dll/shellext/fontext/CFontFolderViewCB.h @@ -0,0 +1,37 @@ +/* + * PROJECT: ReactOS Font Shell Extension + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Fonts folder view callback implementation + * COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#pragma once + +class CFontFolderViewCB + : public CComObjectRootEx + , public IShellFolderViewCB +{ + CFontExt* m_pFontExt = nullptr; // Not ref-counted! + IShellView* m_pShellView = nullptr; // Not ref-counted! + HWND m_hwndView = nullptr; + CComHeapPtr m_pidlParent; + CComHeapPtr m_pidl0; + CComHeapPtr m_pidl1; + + HRESULT TranslatePidl(LPITEMIDLIST* ppidlNew, LPCITEMIDLIST pidl); + void TranslateTwoPIDLs(PIDLIST_ABSOLUTE* pidls); + BOOL FilterEvent(LONG lEvent) const; + +public: + CFontFolderViewCB() { } + void Initialize(CFontExt* pFontExt, IShellView *psv, LPCITEMIDLIST pidlParent); + + // IShellFolderViewCB + STDMETHOD(MessageSFVCB)(UINT uMsg, WPARAM wParam, LPARAM lParam) override; + + DECLARE_NO_REGISTRY() + DECLARE_NOT_AGGREGATABLE(CFontFolderViewCB) + BEGIN_COM_MAP(CFontFolderViewCB) + COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB) + END_COM_MAP() +}; diff --git a/dll/shellext/fontext/CMakeLists.txt b/dll/shellext/fontext/CMakeLists.txt index b0ddec81245..1affe6f1ab9 100644 --- a/dll/shellext/fontext/CMakeLists.txt +++ b/dll/shellext/fontext/CMakeLists.txt @@ -8,15 +8,12 @@ list(APPEND SOURCE CDataObject.cpp CEnumFonts.cpp CFontCache.cpp - CFontCache.hpp CFontExt.cpp - CFontExt.hpp + CFontFolderViewCB.cpp CFontMenu.cpp fontext.cpp fontpidl.cpp - fontpidl.hpp - precomp.h - resource.h) + precomp.h) add_library(fontext MODULE ${SOURCE} diff --git a/dll/shellext/fontext/fontext.cpp b/dll/shellext/fontext/fontext.cpp index c72f620515a..b9013febdf1 100644 --- a/dll/shellext/fontext/fontext.cpp +++ b/dll/shellext/fontext/fontext.cpp @@ -102,11 +102,12 @@ STDAPI DllUnregisterServer() HRESULT InstallFontFiles( - _Out_ CStringW& strMsg, - _In_ PCUIDLIST_ABSOLUTE pidlParent, - _In_ UINT cidl, - _In_ PCUITEMID_CHILD_ARRAY apidl) + _Inout_ PINSTALL_FONT_DATA pData) { + PCUIDLIST_ABSOLUTE pidlParent = pData->pidlParent; + UINT cidl = pData->cSteps; + PCUITEMID_CHILD_ARRAY apidl = pData->apidl; + CAtlArray FontPaths; for (UINT n = 0; n < cidl; ++n) { @@ -138,9 +139,18 @@ InstallFontFiles( for (SIZE_T iItem = 0; iItem < FontPaths.GetCount(); ++iItem) { - HRESULT hr = DoInstallFontFile(strMsg, FontPaths[iItem], g_FontCache->FontPath(), keyFonts); + if (pData->bCanceled) + { + WARN("Canceled\n"); + return E_ABORT; + } + + HRESULT hr = DoInstallFontFile(FontPaths[iItem], g_FontCache->FontPath(), keyFonts); if (FAILED_UNEXPECTEDLY(hr)) return hr; + + if (pData->hwnd) + ::PostMessageW(pData->hwnd, WM_COMMAND, IDCONTINUE, 0); } return S_OK; @@ -148,12 +158,13 @@ InstallFontFiles( HRESULT DoInstallFontFile( - _Out_ CStringW& strMsg, _In_ PCWSTR pszFontPath, _In_ PCWSTR pszFontsDir, _In_ HKEY hkeyFonts) { - WCHAR szDestFile[MAX_PATH]; + ATLASSERT(pszFontPath); + ATLASSERT(pszFontsDir); + ATLASSERT(hkeyFonts); // Add this font to the font list, so we can query the name if (!AddFontResourceW(pszFontPath)) @@ -162,28 +173,52 @@ DoInstallFontFile( return E_FAIL; } + // Get the font name CStringW strFontName; HRESULT hr = DoGetFontTitle(pszFontPath, strFontName); - - // We got the name, remove it again - RemoveFontResourceW(pszFontPath); - - if (!SUCCEEDED(hr)) - { - ERR("DoGetFontTitle failed (err=0x%x)!\n", hr); + if (FAILED_UNEXPECTEDLY(hr)) return hr; + + // Remove it now + // WINDOWS BUG: Removing once is not enough + for (INT iTry = 0; iTry < 3; ++iTry) + { + if (!RemoveFontResourceW(pszFontPath) && + !RemoveFontResourceExW(pszFontPath, FR_PRIVATE, NULL)) + { + break; + } } - StringCchCopyW(szDestFile, sizeof(szDestFile), pszFontsDir); + // Delete font entry in registry + RegDeleteValueW(hkeyFonts, strFontName); LPCWSTR pszFileTitle = PathFindFileName(pszFontPath); - PathAppendW(szDestFile, pszFileTitle); - if (!CopyFileW(pszFontPath, szDestFile, FALSE)) + ATLASSERT(pszFileTitle); + + // Build destination path + CStringW szDestFile(pszFontsDir); // pszFontsDir has backslash at back + szDestFile += pszFileTitle; + TRACE("szDestFile: '%S'\n", (PCWSTR)szDestFile); + + if (!StrCmpIW(szDestFile, pszFontPath)) // Same file? { - ERR("CopyFileW('%S', '%S') failed\n", pszFontPath, szDestFile); + ERR("Wrongly same: %S\n", pszFontPath); return E_FAIL; } + // Delete file + if (DeleteFileW(szDestFile)) + SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, (PCWSTR)szDestFile, NULL); + + // Copy file + if (!CopyFileW(pszFontPath, szDestFile, FALSE)) + { + ERR("CopyFileW('%S', '%S') failed\n", pszFontPath, (PCWSTR)szDestFile); + return E_FAIL; + } + + // Write registry for font entry DWORD cbData = (wcslen(pszFileTitle) + 1) * sizeof(WCHAR); LONG nError = RegSetValueExW(hkeyFonts, strFontName, 0, REG_SZ, (const BYTE *)pszFileTitle, cbData); @@ -194,6 +229,9 @@ DoInstallFontFile( return E_FAIL; } + // Notify file creation + SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, (PCWSTR)szDestFile, NULL); + return AddFontResourceW(szDestFile) ? S_OK : E_FAIL; } @@ -214,14 +252,49 @@ DoGetFontTitle( ret = GetFontResourceInfoW(pszFontPath, &cbInfo, pszBuffer, 1); DWORD dwErr = GetLastError();; strFontName.ReleaseBuffer(); - if (ret) + if (!ret) { - TRACE("pszFontName: %S\n", (LPCWSTR)strFontName); - return S_OK; + ERR("GetFontResourceInfoW failed (err: %u)\n", dwErr); + return E_FAIL; } - ERR("GetFontResourceInfoW failed (err: %u)\n", dwErr); - return E_FAIL; + LPCWSTR pchDotExt = PathFindExtensionW(pszFontPath); + if (!StrCmpIW(pchDotExt, L".ttf") || !StrCmpIW(pchDotExt, L".ttc") || + !StrCmpIW(pchDotExt, L".otf") || !StrCmpIW(pchDotExt, L".otc")) + { + strFontName += L" (TrueType)"; + } + + TRACE("pszFontName: %S\n", (LPCWSTR)strFontName); + return S_OK; +} + +BOOL CheckDropFontFiles(HDROP hDrop) +{ + UINT cFiles = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); + if (cFiles == 0) + return FALSE; + + for (UINT iFile = 0; iFile < cFiles; ++iFile) + { + WCHAR szFile[MAX_PATH]; + if (!DragQueryFileW(hDrop, iFile, szFile, _countof(szFile))) + return FALSE; + LPCWSTR pchDotExt = PathFindExtensionW(szFile); + if (!IsFontDotExt(pchDotExt)) + return FALSE; + } + + return TRUE; +} + +HDROP GetDropFromDataObject(STGMEDIUM& stg, IDataObject *pDataObj) +{ + FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + HRESULT hr = pDataObj->GetData(&etc, &stg); + if (FAILED_UNEXPECTEDLY(hr)) + return NULL; + return reinterpret_cast(stg.hGlobal); } EXTERN_C diff --git a/dll/shellext/fontext/fontext.rc b/dll/shellext/fontext/fontext.rc index 933e8f56081..64529efcef4 100644 --- a/dll/shellext/fontext/fontext.rc +++ b/dll/shellext/fontext/fontext.rc @@ -1,4 +1,5 @@ #include +#include #include "resource.h" diff --git a/dll/shellext/fontext/fontpidl.cpp b/dll/shellext/fontext/fontpidl.cpp index 8e7c75dc136..9b83201873e 100644 --- a/dll/shellext/fontext/fontpidl.cpp +++ b/dll/shellext/fontext/fontpidl.cpp @@ -7,7 +7,7 @@ #include "precomp.h" -LPITEMIDLIST _ILCreate(LPCWSTR lpString, ULONG Index) +LPITEMIDLIST _ILCreate(LPCWSTR lpString) { // Because the FontPidlEntry contains one WCHAR, we do not need to take the null terminator into account size_t cbData = sizeof(FontPidlEntry) + wcslen(lpString) * sizeof(WCHAR); @@ -19,8 +19,6 @@ LPITEMIDLIST _ILCreate(LPCWSTR lpString, ULONG Index) pidl->cb = (WORD)cbData; pidl->Magic = 'fp'; - pidl->Index = Index; - wcscpy(pidl->Name, lpString); // Should be zero already, but make sure it is *(WORD*)((char*)pidl + cbData) = 0; diff --git a/dll/shellext/fontext/fontpidl.hpp b/dll/shellext/fontext/fontpidl.hpp index 4944c3bd498..b71414eda39 100644 --- a/dll/shellext/fontext/fontpidl.hpp +++ b/dll/shellext/fontext/fontpidl.hpp @@ -12,11 +12,9 @@ struct FontPidlEntry { WORD cb; WORD Magic; - ULONG Index; // Informative only, used for sorting - WCHAR Name[1]; }; #include -LPITEMIDLIST _ILCreate(LPCWSTR lpString, ULONG Index); +LPITEMIDLIST _ILCreate(LPCWSTR lpString); const FontPidlEntry* _FontFromIL(LPCITEMIDLIST pidl); diff --git a/dll/shellext/fontext/lang/de-DE.rc b/dll/shellext/fontext/lang/de-DE.rc index e0b8e82ccf4..5910a794097 100644 --- a/dll/shellext/fontext/lang/de-DE.rc +++ b/dll/shellext/fontext/lang/de-DE.rc @@ -7,9 +7,21 @@ LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "ReactOS Schriftartenordner" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END STRINGTABLE @@ -26,7 +38,6 @@ BEGIN IDS_COL_ATTR_LETTERS "RHSAC" END - STRINGTABLE BEGIN IDS_FONT_PREVIEW "Ö&ffnen" diff --git a/dll/shellext/fontext/lang/en-US.rc b/dll/shellext/fontext/lang/en-US.rc index cdc94dbe07a..8a250d6555b 100644 --- a/dll/shellext/fontext/lang/en-US.rc +++ b/dll/shellext/fontext/lang/en-US.rc @@ -2,12 +2,23 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "ReactOS Font Folder" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END - STRINGTABLE BEGIN IDS_COL_NAME "Name" diff --git a/dll/shellext/fontext/lang/it-IT.rc b/dll/shellext/fontext/lang/it-IT.rc index 1f0e558cfed..b73e0dbf304 100644 --- a/dll/shellext/fontext/lang/it-IT.rc +++ b/dll/shellext/fontext/lang/it-IT.rc @@ -7,9 +7,21 @@ LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "Cartella dei font di ReactOS" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END STRINGTABLE diff --git a/dll/shellext/fontext/lang/pl-PL.rc b/dll/shellext/fontext/lang/pl-PL.rc index ef1af44d0df..d88f9c1ed7d 100644 --- a/dll/shellext/fontext/lang/pl-PL.rc +++ b/dll/shellext/fontext/lang/pl-PL.rc @@ -2,9 +2,21 @@ LANGUAGE LANG_POLISH, SUBLANG_DEFAULT +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "Folder czcionek ReactOS" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END STRINGTABLE diff --git a/dll/shellext/fontext/lang/ro-RO.rc b/dll/shellext/fontext/lang/ro-RO.rc index a57f9092d6e..47eb365dd04 100644 --- a/dll/shellext/fontext/lang/ro-RO.rc +++ b/dll/shellext/fontext/lang/ro-RO.rc @@ -8,9 +8,21 @@ LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "Folder-ul de fonturi de ReactOS" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END STRINGTABLE diff --git a/dll/shellext/fontext/lang/tr-TR.rc b/dll/shellext/fontext/lang/tr-TR.rc index 4037f380884..69aec11ff0b 100644 --- a/dll/shellext/fontext/lang/tr-TR.rc +++ b/dll/shellext/fontext/lang/tr-TR.rc @@ -2,9 +2,21 @@ LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "ReactOS Yazı Tipi Dizini" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END STRINGTABLE diff --git a/dll/shellext/fontext/lang/zh-CN.rc b/dll/shellext/fontext/lang/zh-CN.rc index cf537e76f49..9fca1fdff84 100644 --- a/dll/shellext/fontext/lang/zh-CN.rc +++ b/dll/shellext/fontext/lang/zh-CN.rc @@ -7,9 +7,21 @@ LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 9, "宋体" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "ReactOS 字体文件夹" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END STRINGTABLE diff --git a/dll/shellext/fontext/lang/zh-HK.rc b/dll/shellext/fontext/lang/zh-HK.rc index 935ce904a7a..84eb1dc0b45 100644 --- a/dll/shellext/fontext/lang/zh-HK.rc +++ b/dll/shellext/fontext/lang/zh-HK.rc @@ -7,12 +7,23 @@ LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_HONGKONG +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 9, "新細明體" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "ReactOS 字型資料夾" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END - STRINGTABLE BEGIN IDS_COL_NAME "名稱" @@ -27,7 +38,6 @@ BEGIN IDS_COL_ATTR_LETTERS "RHSAC" END - STRINGTABLE BEGIN IDS_FONT_PREVIEW "預覽" diff --git a/dll/shellext/fontext/lang/zh-TW.rc b/dll/shellext/fontext/lang/zh-TW.rc index ef67b18f8e3..af8e8987f6c 100644 --- a/dll/shellext/fontext/lang/zh-TW.rc +++ b/dll/shellext/fontext/lang/zh-TW.rc @@ -7,12 +7,23 @@ LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL +IDD_INSTALL DIALOG 0, 0, 205, 60 +CAPTION "Installing fonts..." +STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION +FONT 9, "新細明體" +BEGIN + LTEXT "Installing fonts...", IDC_INSTALL_TEXT, 5, 10, 195, 10 + CONTROL "", IDC_INSTALL_PROGRESS, "msctls_progress32", 0, 5, 25, 195, 10 + PUSHBUTTON "Cancel", IDCANCEL, 65, 40, 70, 15 +END + STRINGTABLE BEGIN IDS_REACTOS_FONTS_FOLDER "ReactOS 字型資料夾" + IDS_INSTALL_OK "The font files have been installed successfully." + IDS_INSTALL_FAILED "Failed to install the font files." END - STRINGTABLE BEGIN IDS_COL_NAME "名稱" @@ -27,7 +38,6 @@ BEGIN IDS_COL_ATTR_LETTERS "RHSAC" END - STRINGTABLE BEGIN IDS_FONT_PREVIEW "預覽" diff --git a/dll/shellext/fontext/precomp.h b/dll/shellext/fontext/precomp.h index 609a4ce7d2c..5f7f0d280ea 100644 --- a/dll/shellext/fontext/precomp.h +++ b/dll/shellext/fontext/precomp.h @@ -27,10 +27,26 @@ extern const GUID CLSID_CFontExt; extern LONG g_ModuleRefCnt; +class CFontExt; + +typedef struct tagINSTALL_FONT_DATA +{ + CFontExt* pFontExt = nullptr; + IDataObject* pDataObj = nullptr; + HRESULT hrResult = S_OK; + HWND hwnd = nullptr; + UINT iStep = 0; + UINT cSteps = 0; + BOOL bCanceled = FALSE; + LPCITEMIDLIST pidlParent = nullptr; + PCUIDLIST_RELATIVE* apidl = nullptr; +} INSTALL_FONT_DATA, *PINSTALL_FONT_DATA; + #include "resource.h" #include "fontpidl.hpp" #include "CFontCache.hpp" #include "CFontExt.hpp" +#include "CFontFolderViewCB.h" #define FONT_HIVE HKEY_LOCAL_MACHINE #define FONT_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" @@ -49,22 +65,16 @@ inline BOOL IsFontDotExt(LPCWSTR pchDotExt) }; for (const LPCWSTR *pp = array; *pp; ++pp) { - if (!_wcsicmp(*pp, pchDotExt)) + if (!StrCmpIW(*pp, pchDotExt)) return TRUE; } return FALSE; } -HRESULT -InstallFontFiles( - _Out_ CStringW& strMessage, - _In_ PCUIDLIST_ABSOLUTE pidlParent, - _In_ UINT cidl, - _In_ PCUITEMID_CHILD_ARRAY apidl); +HRESULT InstallFontFiles(_Inout_ PINSTALL_FONT_DATA pData); HRESULT DoInstallFontFile( - _Out_ CStringW& strMsg, _In_ PCWSTR pszFontPath, _In_ PCWSTR pszFontsDir, _In_ HKEY hkeyFonts); @@ -72,3 +82,6 @@ DoInstallFontFile( HRESULT DoGetFontTitle( _In_ PCWSTR pszFontPath, _Out_ CStringW& strFontName); + +BOOL CheckDropFontFiles(HDROP hDrop); +HDROP GetDropFromDataObject(STGMEDIUM& stg, IDataObject *pDataObj); diff --git a/dll/shellext/fontext/resource.h b/dll/shellext/fontext/resource.h index 8ff4867ee4e..f2695a26fa9 100644 --- a/dll/shellext/fontext/resource.h +++ b/dll/shellext/fontext/resource.h @@ -1,8 +1,12 @@ #pragma once - +#define IDD_INSTALL 100 +#define IDC_INSTALL_TEXT 10000 +#define IDC_INSTALL_PROGRESS 10001 #define IDS_REACTOS_FONTS_FOLDER 151 +#define IDS_INSTALL_OK 152 +#define IDS_INSTALL_FAILED 153 #define IDS_COL_NAME 301 #define IDS_COL_FILENAME 304 #define IDS_COL_SIZE 305