[SHELLEXT][FONTEXT] An attempt to implement IDropTarget (#2019)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Tue, 12 Nov 2019 11:26:56 +0000 (20:26 +0900)
committerGitHub <noreply@github.com>
Tue, 12 Nov 2019 11:26:56 +0000 (20:26 +0900)
CORE-12861

dll/shellext/fontext/CFontCache.cpp
dll/shellext/fontext/CFontExt.cpp
dll/shellext/fontext/CFontExt.hpp
dll/shellext/fontext/CFontMenu.cpp
dll/shellext/fontext/CMakeLists.txt
dll/shellext/fontext/precomp.h

index 4d3ae5f..8bccf34 100644 (file)
@@ -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)
index de502a4..1ce5325 100644 (file)
@@ -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<IDropTarget *>(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> 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> 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<CStringW> 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;
+}
index 0e7a044..19d94f6 100644 (file)
@@ -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<CFontExt, &CLSID_CFontExt>,
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
     public IShellFolder2,
-    public IPersistFolder2
+    public IPersistFolder2,
+    public IDropTarget
 {
     CComHeapPtr<ITEMIDLIST> 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);
 };
index eab4427..0a2f0e5 100644 (file)
@@ -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)
index a5ae388..2f2586b 100644 (file)
@@ -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)
index 2860682..c17b4e5 100644 (file)
@@ -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 */