From c214c0496477a9f3e7aa65c063cbf0cdf66f175a Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Tue, 12 Nov 2019 20:26:56 +0900 Subject: [PATCH] [SHELLEXT][FONTEXT] An attempt to implement IDropTarget (#2019) CORE-12861 --- dll/shellext/fontext/CFontCache.cpp | 4 - dll/shellext/fontext/CFontExt.cpp | 173 +++++++++++++++++++++++++++- dll/shellext/fontext/CFontExt.hpp | 13 ++- dll/shellext/fontext/CFontMenu.cpp | 12 +- dll/shellext/fontext/CMakeLists.txt | 2 +- dll/shellext/fontext/precomp.h | 26 +++++ 6 files changed, 211 insertions(+), 19 deletions(-) diff --git a/dll/shellext/fontext/CFontCache.cpp b/dll/shellext/fontext/CFontCache.cpp index 4d3ae5fcdf5..8bccf346582 100644 --- a/dll/shellext/fontext/CFontCache.cpp +++ b/dll/shellext/fontext/CFontCache.cpp @@ -9,10 +9,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(fontext); - -#define FONT_HIVE HKEY_LOCAL_MACHINE -#define FONT_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" - CFontCache* g_FontCache = NULL; CFontInfo::CFontInfo(LPCWSTR name) diff --git a/dll/shellext/fontext/CFontExt.cpp b/dll/shellext/fontext/CFontExt.cpp index de502a43fdb..1ce5325500a 100644 --- a/dll/shellext/fontext/CFontExt.cpp +++ b/dll/shellext/fontext/CFontExt.cpp @@ -3,6 +3,7 @@ * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontExt implementation * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org) + * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ #include "precomp.h" @@ -196,9 +197,10 @@ STDMETHODIMP CFontExt::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppv if (IsEqualIID(riid, IID_IDropTarget)) { - // Needed to drop files into the fonts folder, we should probably install them? ERR("IDropTarget not implemented\n"); - hr = E_NOTIMPL; + *ppvOut = static_cast(this); + AddRef(); + hr = S_OK; } else if (IsEqualIID(riid, IID_IContextMenu)) { @@ -363,3 +365,170 @@ STDMETHODIMP CFontExt::GetClassID(CLSID *lpClassId) return S_OK; } +// *** IDropTarget methods *** +STDMETHODIMP CFontExt::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) +{ + *pdwEffect = DROPEFFECT_NONE; + + CComHeapPtr cida; + HRESULT hr = _GetCidlFromDataObject(pDataObj, &cida); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + +#if 1 // Please implement DoGetFontTitle + return DRAGDROP_S_CANCEL; +#else + *pdwEffect = DROPEFFECT_COPY; + return S_OK; +#endif +} + +STDMETHODIMP CFontExt::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) +{ + return S_OK; +} + +STDMETHODIMP CFontExt::DragLeave() +{ + return S_OK; +} + +STDMETHODIMP CFontExt::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) +{ + *pdwEffect = DROPEFFECT_NONE; + + WCHAR szFontsDir[MAX_PATH]; + HRESULT hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, szFontsDir); + if (FAILED_UNEXPECTEDLY(hr)) + return E_FAIL; + + CComHeapPtr cida; + hr = _GetCidlFromDataObject(pDataObj, &cida); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(cida); + if (!pidlParent) + { + ERR("pidlParent is NULL\n"); + return E_FAIL; + } + + BOOL bOK = TRUE; + CAtlArray FontPaths; + for (UINT n = 0; n < cida->cidl; ++n) + { + PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(cida, n); + if (!pidlRelative) + continue; + + PIDLIST_ABSOLUTE pidl = ILCombine(pidlParent, pidlRelative); + if (!pidl) + { + ERR("ILCombine failed\n"); + bOK = FALSE; + break; + } + + WCHAR szPath[MAX_PATH]; + BOOL ret = SHGetPathFromIDListW(pidl, szPath); + ILFree(pidl); + + if (!ret) + { + ERR("SHGetPathFromIDListW failed\n"); + bOK = FALSE; + break; + } + + if (PathIsDirectoryW(szPath)) + { + ERR("PathIsDirectory\n"); + bOK = FALSE; + break; + } + + LPCWSTR pchDotExt = PathFindExtensionW(szPath); + if (!IsFontDotExt(pchDotExt)) + { + ERR("'%S' is not supported\n", pchDotExt); + bOK = FALSE; + break; + } + + FontPaths.Add(szPath); + } + + if (!bOK) + return E_FAIL; + + CRegKey keyFonts; + if (keyFonts.Open(FONT_HIVE, FONT_KEY, KEY_WRITE) != ERROR_SUCCESS) + { + ERR("keyFonts.Open failed\n"); + return E_FAIL; + } + + for (size_t iItem = 0; iItem < FontPaths.GetCount(); ++iItem) + { + HRESULT hr = DoInstallFontFile(FontPaths[iItem], szFontsDir, keyFonts.m_hKey); + if (FAILED_UNEXPECTEDLY(hr)) + { + bOK = FALSE; + break; + } + } + + // TODO: update g_FontCache + + SendMessageW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); + + // TODO: Show message + + return bOK ? S_OK : E_FAIL; +} + +HRESULT CFontExt::DoInstallFontFile(LPCWSTR pszFontPath, LPCWSTR pszFontsDir, HKEY hkeyFonts) +{ + WCHAR szDestFile[MAX_PATH]; + LPCWSTR pszFileTitle = PathFindFileName(pszFontPath); + + WCHAR szFontName[512]; + if (!DoGetFontTitle(pszFontPath, szFontName)) + return E_FAIL; + + RemoveFontResourceW(pszFileTitle); + + StringCchCopyW(szDestFile, sizeof(szDestFile), pszFontsDir); + PathAppendW(szDestFile, pszFileTitle); + if (!CopyFileW(pszFontPath, szDestFile, FALSE)) + { + ERR("CopyFileW('%S', '%S') failed\n", pszFontPath, szDestFile); + return E_FAIL; + } + + if (!AddFontResourceW(pszFileTitle)) + { + ERR("AddFontResourceW('%S') failed\n", pszFileTitle); + DeleteFileW(szDestFile); + return E_FAIL; + } + + DWORD cbData = (wcslen(pszFileTitle) + 1) * sizeof(WCHAR); + LONG nError = RegSetValueExW(hkeyFonts, szFontName, 0, REG_SZ, (const BYTE *)szFontName, cbData); + if (nError) + { + ERR("RegSetValueExW failed with %ld\n", nError); + RemoveFontResourceW(pszFileTitle); + DeleteFileW(szDestFile); + return E_FAIL; + } + + return S_OK; +} + +HRESULT CFontExt::DoGetFontTitle(LPCWSTR pszFontPath, LPCWSTR pszFontName) +{ + // TODO: + return E_FAIL; +} diff --git a/dll/shellext/fontext/CFontExt.hpp b/dll/shellext/fontext/CFontExt.hpp index 0e7a04482d9..19d94f6fa1c 100644 --- a/dll/shellext/fontext/CFontExt.hpp +++ b/dll/shellext/fontext/CFontExt.hpp @@ -3,6 +3,7 @@ * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontExt definition * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org) + * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ #pragma once @@ -11,7 +12,8 @@ class CFontExt : public CComCoClass, public CComObjectRootEx, public IShellFolder2, - public IPersistFolder2 + public IPersistFolder2, + public IDropTarget { CComHeapPtr m_Folder; @@ -51,6 +53,11 @@ public: // *** IPersist methods *** virtual STDMETHODIMP GetClassID(CLSID *lpClassId); + // *** IDropTarget methods *** + virtual STDMETHODIMP DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect); + virtual STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect); + virtual STDMETHODIMP DragLeave(); + virtual STDMETHODIMP Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect); #if 0 static HRESULT WINAPI log_stuff(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw) @@ -79,6 +86,10 @@ public: COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) //COM_INTERFACE_ENTRY_FUNC_BLIND(0, log_stuff) END_COM_MAP() + + HRESULT DoInstallFontFile(LPCWSTR pszFontPath, LPCWSTR pszFontsDir, HKEY hkeyFonts); + HRESULT DoGetFontTitle(LPCWSTR pszFontPath, LPCWSTR pszFontName); }; diff --git a/dll/shellext/fontext/CFontMenu.cpp b/dll/shellext/fontext/CFontMenu.cpp index eab4427202d..0a2f0e55856 100644 --- a/dll/shellext/fontext/CFontMenu.cpp +++ b/dll/shellext/fontext/CFontMenu.cpp @@ -9,18 +9,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(fontext); - -static inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida) -{ - return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]); -} - -static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i) -{ - return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]); -} - static CLIPFORMAT g_cfHIDA; + HRESULT _GetCidlFromDataObject(IDataObject *pDataObject, CIDA** ppcida) { if (g_cfHIDA == NULL) diff --git a/dll/shellext/fontext/CMakeLists.txt b/dll/shellext/fontext/CMakeLists.txt index a5ae38822cf..2f2586b2517 100644 --- a/dll/shellext/fontext/CMakeLists.txt +++ b/dll/shellext/fontext/CMakeLists.txt @@ -32,7 +32,7 @@ add_library(fontext MODULE set_module_type(fontext win32dll UNICODE) target_link_libraries(fontext uuid wine) -add_delay_importlibs(fontext ole32 oleaut32 shlwapi) +add_delay_importlibs(fontext ole32 oleaut32 shlwapi gdi32) add_importlibs(fontext shell32 advapi32 user32 msvcrt kernel32 ntdll) add_pch(fontext precomp.h SOURCE) add_cd_file(TARGET fontext DESTINATION reactos/system32 FOR all) diff --git a/dll/shellext/fontext/precomp.h b/dll/shellext/fontext/precomp.h index 28606824c1f..c17b4e53c71 100644 --- a/dll/shellext/fontext/precomp.h +++ b/dll/shellext/fontext/precomp.h @@ -27,6 +27,8 @@ extern LONG g_ModuleRefCnt; #include "CFontCache.hpp" #include "CFontExt.hpp" +#define FONT_HIVE HKEY_LOCAL_MACHINE +#define FONT_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" HRESULT _CEnumFonts_CreateInstance(CFontExt* zip, DWORD flags, REFIID riid, LPVOID* ppvOut); HRESULT _CFontMenu_CreateInstance(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, @@ -34,6 +36,30 @@ HRESULT _CFontMenu_CreateInstance(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY ap HRESULT _CDataObject_CreateInstance(PCIDLIST_ABSOLUTE folder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, LPVOID* ppvOut); +HRESULT _GetCidlFromDataObject(IDataObject *pDataObject, CIDA** ppcida); +inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida) +{ + return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]); +} + +inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i) +{ + return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]); +} + +inline BOOL IsFontDotExt(LPCWSTR pchDotExt) +{ + static const LPCWSTR array[] = + { + L".ttf", L".ttc", L".otf", L".otc", L".fon", L".fnt", NULL + }; + for (const LPCWSTR *pp = array; *pp; ++pp) + { + if (!_wcsicmp(*pp, pchDotExt)) + return TRUE; + } + return FALSE; +} #endif /* FONTEXT_PRECOMP_H */ -- 2.17.1