[FONTEXT] Implement paste operation (#8615)

Support paste operation on Fonts folder.
JIRA issue: CORE-12861
- Add CFontBackgroundMenu.cpp and CFontBackgroundMenu.h
  to support background menu.
- Modify CFontExt::CreateViewObject and
  CFontExt::GetUIObjectOf methods.
- Re-implement foreground menu by using
  CDefFolderMenu_Create2 and CFontExt::MenuCallBack.
- Delete needless CFontMenu.cpp.
- Add IDS_PROPERTIES resource string.
This commit is contained in:
Katayama Hirofumi MZ
2026-01-23 14:28:09 +09:00
committed by GitHub
parent 2865b6353b
commit 789f6c5481
18 changed files with 439 additions and 294 deletions

View File

@@ -0,0 +1,125 @@
/*
* PROJECT: ReactOS Font Shell Extension
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Fonts folder shell extension background menu
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include "precomp.h"
#include <shlwapi_undoc.h>
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
CFontBackgroundMenu::CFontBackgroundMenu()
{
}
CFontBackgroundMenu::~CFontBackgroundMenu()
{
}
HRESULT WINAPI CFontBackgroundMenu::Initialize(CFontExt* pFontExt, const DEFCONTEXTMENU *pdcm)
{
m_pFontExt = pFontExt;
m_psf = pdcm->psf;
m_pmcb = pdcm->pcmcb;
m_hwnd = pdcm->hwnd;
return S_OK;
}
// IContextMenu
STDMETHODIMP CFontBackgroundMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
TRACE("%d\n", idCmdFirst);
CString strProp(MAKEINTRESOURCEW(IDS_PROPERTIES));
INT idCmd = idCmdFirst;
AppendMenuW(hMenu, MF_STRING, idCmd++, strProp);
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmd - idCmdFirst);
}
STDMETHODIMP CFontBackgroundMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
INT idCmd = IS_INTRESOURCE(lpcmi->lpVerb) ? LOWORD(lpcmi->lpVerb) : -1;
TRACE("%d\n", idCmd);
if (idCmd == 0 || (idCmd == -1 && !lstrcmpiA(lpcmi->lpVerb, "properties")))
{
// Open "Fonts" properties
LPITEMIDLIST pidl = NULL;
HRESULT hr = SHGetSpecialFolderLocation(m_hwnd, CSIDL_FONTS, &pidl);
if (FAILED_UNEXPECTEDLY(hr) || !pidl)
return E_FAIL;
SHELLEXECUTEINFOW sei = {
sizeof(sei), SEE_MASK_INVOKEIDLIST | SEE_MASK_ASYNCOK, NULL, L"properties",
NULL, NULL, NULL, SW_SHOWNORMAL, NULL, const_cast<LPITEMIDLIST>(pidl)
};
BOOL bOK = ShellExecuteExW(&sei);
if (pidl)
CoTaskMemFree(pidl);
return bOK ? S_OK : E_FAIL;
}
if (idCmd == FCIDM_SHVIEW_INSERT || (idCmd == -1 && !lstrcmpiA(lpcmi->lpVerb, "paste")))
{
CComPtr<IDataObject> pDataObj;
HRESULT hr = OleGetClipboard(&pDataObj);
if (FAILED_UNEXPECTEDLY(hr) || !CheckDataObject(pDataObj))
{
// Show error message
CStringW text, title;
title.LoadStringW(IDS_REACTOS_FONTS_FOLDER);
text.LoadStringW(IDS_INSTALL_FAILED);
MessageBoxW(m_hwnd, text, title, MB_ICONERROR);
return E_FAIL;
}
return SHSimulateDrop(m_pFontExt, pDataObj, 0, NULL, NULL);
}
return S_OK;
}
STDMETHODIMP CFontBackgroundMenu::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
{
TRACE("%d\n", idCommand);
if (idCommand == 0)
{
lstrcpynA(lpszName, "properties", uMaxNameLen);
return S_OK;
}
return E_FAIL;
}
// IContextMenu2
STDMETHODIMP CFontBackgroundMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return HandleMenuMsg2(uMsg, wParam, lParam, NULL);
}
// IContextMenu3
STDMETHODIMP CFontBackgroundMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
{
if (uMsg == WM_INITMENUPOPUP)
{
HMENU hMenu = (HMENU)wParam;
::DeleteMenu(hMenu, FCIDM_SHVIEW_INSERTLINK, MF_BYCOMMAND);
return S_OK;
}
return E_NOTIMPL;
}
HRESULT
APIENTRY
CFontBackgroundMenu_Create(
CFontExt* pFontExt,
HWND hwnd,
IShellFolder* psf,
IContextMenu** ppcm)
{
DEFCONTEXTMENU dcm;
ZeroMemory(&dcm, sizeof(dcm));
dcm.hwnd = hwnd;
dcm.psf = psf;
return ShellObjectCreatorInit<CFontBackgroundMenu>(pFontExt, &dcm, IID_PPV_ARG(IContextMenu, ppcm));
}

View File

@@ -0,0 +1,41 @@
/*
* PROJECT: ReactOS Font Shell Extension
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Fonts folder shell extension background menu
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#pragma once
class CFontBackgroundMenu
: public CComObjectRootEx<CComMultiThreadModelNoCS>
, public IContextMenu3
{
HWND m_hwnd = nullptr;
CFontExt* m_pFontExt = nullptr;
CComPtr<IShellFolder> m_psf;
CComPtr<IContextMenuCB> m_pmcb;
LPFNDFMCALLBACK m_pfnmcb = nullptr;
public:
CFontBackgroundMenu();
virtual ~CFontBackgroundMenu();
HRESULT WINAPI Initialize(CFontExt* pFontExt, const DEFCONTEXTMENU *pdcm);
// IContextMenu
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override;
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) override;
STDMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) override;
// IContextMenu2
STDMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
// IContextMenu3
STDMETHODIMP HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) override;
BEGIN_COM_MAP(CFontBackgroundMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu3, IContextMenu3)
END_COM_MAP()
};

View File

@@ -87,6 +87,27 @@ CFontExt::~CFontExt()
InterlockedDecrement(&g_ModuleRefCnt);
}
void CFontExt::SetViewWindow(HWND hwndView)
{
m_hwndView = hwndView;
}
HRESULT CALLBACK
CFontExt::MenuCallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
TRACE("%u, %p, %p\n", uMsg, wParam, lParam);
switch (uMsg)
{
case DFM_MERGECONTEXTMENU:
return S_OK; // Yes, I want verbs
case DFM_INVOKECOMMAND:
return S_FALSE; // Do it for me please
case DFM_GETDEFSTATICID:
return S_FALSE; // Supposedly "required for Windows 7 to pick a default"
}
return E_NOTIMPL;
}
// *** IShellFolder2 methods ***
STDMETHODIMP CFontExt::GetDefaultSearchGUID(GUID *lpguid)
{
@@ -317,8 +338,8 @@ STDMETHODIMP CFontExt::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppv
}
else if (IsEqualIID(riid, IID_IContextMenu))
{
ERR("IContextMenu not implemented\n");
hr = E_NOTIMPL;
TRACE("IContextMenu\n");
return CFontBackgroundMenu_Create(this, hwndOwner, this, (IContextMenu**)ppvOut);
}
else if (IsEqualIID(riid, IID_IShellView))
{
@@ -363,13 +384,51 @@ STDMETHODIMP CFontExt::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, D
return S_OK;
}
HRESULT CFontExt::CreateForegroundMenu(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, LPVOID* ppvOut)
{
if (cidl <= 0)
{
ERR("cidl: %u\n", cidl);
return E_NOTIMPL;
}
const FontPidlEntry* pEntry = _FontFromIL(apidl[0]);
if (!pEntry)
{
ERR("!pEntry\n");
return E_FAIL;
}
auto info = g_FontCache->Find(pEntry);
if (!info)
{
ERR("!info\n");
return E_FAIL;
}
LPCWSTR extension = PathFindExtensionW(info->File());
CRegKeyHandleArray keys;
WCHAR wszClass[MAX_PATH];
DWORD dwSize = sizeof(wszClass);
if (RegGetValueW(HKEY_CLASSES_ROOT, extension, NULL, RRF_RT_REG_SZ, NULL, wszClass, &dwSize) != ERROR_SUCCESS ||
!*wszClass || AddClassKeyToArray(wszClass, keys, keys) != ERROR_SUCCESS)
{
AddClassKeyToArray(extension, keys, keys);
if (cidl == 1)
AddClassKeyToArray(L"Unknown", keys, keys);
}
return CDefFolderMenu_Create2(m_Folder, hwndOwner, cidl, apidl, this, MenuCallBack, keys, keys, (IContextMenu**)ppvOut);
}
STDMETHODIMP CFontExt::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
{
if (riid == IID_IContextMenu ||
riid == IID_IContextMenu2 ||
riid == IID_IContextMenu3)
{
return _CFontMenu_CreateInstance(hwndOwner, cidl, apidl, this, riid, ppvOut);
return CreateForegroundMenu(hwndOwner, cidl, apidl, ppvOut);
}
else if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
{
@@ -398,7 +457,12 @@ STDMETHODIMP CFontExt::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_
}
else
{
ERR("IID_IDataObject with cidl == 0 UNIMPLEMENTED\n");
CComPtr<IDataObject> pDataObj;
HRESULT hr = OleGetClipboard(&pDataObj);
if (FAILED_UNEXPECTEDLY(hr))
return E_FAIL;
*ppvOut = pDataObj.Detach();
return S_OK;
}
}
else if (riid == IID_IDropTarget)
@@ -499,20 +563,7 @@ STDMETHODIMP CFontExt::GetClassID(CLSID *lpClassId)
// *** IDropTarget methods ***
STDMETHODIMP CFontExt::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
m_bDragAccepted = FALSE;
STGMEDIUM stg;
HDROP hDrop = GetDropFromDataObject(stg, pDataObj);
if (!hDrop)
{
*pdwEffect = DROPEFFECT_NONE;
DragLeave();
return E_FAIL;
}
m_bDragAccepted = CheckDropFontFiles(hDrop);
::ReleaseStgMedium(&stg);
m_bDragAccepted = CheckDataObject(pDataObj);
if (!m_bDragAccepted)
{
*pdwEffect = DROPEFFECT_NONE;
@@ -539,138 +590,31 @@ 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)
{
// 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)
{
ERR("pidlParent is NULL\n");
return E_FAIL;
}
CAtlArray<PCUIDLIST_RELATIVE> apidl;
for (UINT n = 0; n < cida->cidl; ++n)
{
PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(cida, n);
if (!pidlRelative)
{
ERR("!pidlRelative\n");
return E_FAIL;
}
apidl.Add(pidlRelative);
}
// 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;
ATLASSERT(m_hwndView);
HRESULT hr = InstallFontsFromDataObject(m_hwndView, pDataObj);
CStringW text, title;
title.LoadStringW(IDS_REACTOS_FONTS_FOLDER);
if (SUCCEEDED(data.hrResult))
{
// 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
if (FAILED_UNEXPECTEDLY(hr))
{
// Show error message
text.LoadStringW(IDS_INSTALL_FAILED);
MessageBoxW(m_hwndView, text, title, MB_ICONERROR);
}
else if (hr == S_OK)
{
// Refresh font cache and notify the system about the font change
if (g_FontCache)
g_FontCache->Read();
return data.hrResult;
SendMessageTimeoutW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0, SMTO_ABORTIFHUNG, 1000, NULL);
// Show successful message
text.LoadStringW(IDS_INSTALL_OK);
MessageBoxW(m_hwndView, text, title, MB_ICONINFORMATION);
}
return hr;
}

View File

@@ -18,18 +18,14 @@ class CFontExt :
CComHeapPtr<ITEMIDLIST> 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;
}
void SetViewWindow(HWND hwndView);
static HRESULT CALLBACK MenuCallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT CreateForegroundMenu(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, LPVOID* ppvOut);
// *** IShellFolder2 methods ***
STDMETHODIMP GetDefaultSearchGUID(GUID *lpguid) override;

View File

@@ -1,132 +0,0 @@
/*
* PROJECT: ReactOS Font Shell Extension
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: CFontMenu implementation
* COPYRIGHT: Copyright 2019-2021 Mark Jansen <mark.jansen@reactos.org>
*/
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
const char* DFM_TO_STR(UINT uMsg)
{
switch(uMsg)
{
case DFM_MERGECONTEXTMENU: return "DFM_MERGECONTEXTMENU";
case DFM_INVOKECOMMAND: return "DFM_INVOKECOMMAND";
case DFM_MODIFYQCMFLAGS: return "DFM_MODIFYQCMFLAGS";
case DFM_MERGECONTEXTMENU_TOP: return "DFM_MERGECONTEXTMENU_TOP";
case DFM_MERGECONTEXTMENU_BOTTOM: return "DFM_MERGECONTEXTMENU_BOTTOM";
case DFM_GETHELPTEXTW: return "DFM_GETHELPTEXTW";
case DFM_GETVERBW: return "DFM_GETVERBW";
case DFM_GETVERBA: return "DFM_GETVERBA";
case DFM_WM_INITMENUPOPUP: return "DFM_WM_INITMENUPOPUP";
case DFM_INVOKECOMMANDEX: return "DFM_INVOKECOMMANDEX";
case DFM_GETDEFSTATICID: return "DFM_GETDEFSTATICID";
case 3: return "MENU_BEGIN";
case 4: return "MENU_END";
default: return "";
}
}
static void RunFontViewer(HWND hwnd, const FontPidlEntry* fontEntry)
{
WCHAR FontViewerPath[MAX_PATH] = L"%SystemRoot%\\System32\\fontview.exe";
WCHAR FontPathArg[MAX_PATH + 3];
CStringW Path = g_FontCache->Filename(g_FontCache->Find(fontEntry), true);
if (!Path.IsEmpty())
{
// '/d' disables the install button
StringCchPrintfW(FontPathArg, _countof(FontPathArg), L"/d %s", Path.GetString());
PathQuoteSpacesW(FontPathArg + 3);
SHELLEXECUTEINFOW si = { sizeof(si) };
si.fMask = SEE_MASK_DOENVSUBST;
si.hwnd = hwnd;
si.lpFile = FontViewerPath;
si.lpParameters = FontPathArg;
si.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&si);
}
}
static HRESULT CALLBACK FontFolderMenuCallback(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj,
UINT uMsg, WPARAM wParam, LPARAM lParam)
{
TRACE("FontFolderMenuCallback(%u {%s})\n", uMsg, DFM_TO_STR(uMsg));
switch (uMsg)
{
case DFM_MERGECONTEXTMENU:
{
QCMINFO *pqcminfo = (QCMINFO *)lParam;
CStringW menuText(MAKEINTRESOURCEW(IDS_FONT_PREVIEW));
MENUITEMINFOW cmi = { sizeof(cmi) };
cmi.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
cmi.fType = MFT_STRING;
cmi.fState = MFS_DEFAULT;
cmi.wID = pqcminfo->idCmdFirst++;
cmi.dwTypeData = (LPWSTR)menuText.GetString();
InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu, TRUE, &cmi);
return S_OK;
}
case DFM_INVOKECOMMAND:
// Preview is the only item we handle
if (wParam == 0)
{
CDataObjectHIDA cida(pdtobj);
if (FAILED_UNEXPECTEDLY(cida.hr()))
return cida.hr();
for (UINT n = 0; n < cida->cidl; ++n)
{
const FontPidlEntry* fontEntry = _FontFromIL(HIDA_GetPIDLItem(cida, n));
RunFontViewer(hwnd, fontEntry);
}
return S_OK;
}
else if (wParam == DFM_CMD_PROPERTIES)
{
TRACE("Default properties handling!\n");
return S_FALSE;
}
else
{
ERR("Unhandled DFM_INVOKECOMMAND(wParam=0x%x)\n", wParam);
}
return S_FALSE;
case DFM_INVOKECOMMANDEX:
return E_NOTIMPL;
case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
return S_FALSE;
}
return E_NOTIMPL;
}
HRESULT _CFontMenu_CreateInstance(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
IShellFolder *psf, REFIID riid, LPVOID* ppvOut)
{
if (cidl > 0)
{
HKEY keys[1] = {0};
int nkeys = 0;
CComPtr<IContextMenu> spMenu;
// Use the default context menu handler, but augment it from the callbacks
HRESULT hr = CDefFolderMenu_Create2(NULL, hwnd, cidl, apidl, psf, FontFolderMenuCallback, nkeys, keys, &spMenu);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
// See if the requested interface (e.g. IContextMenu3) is also available
return spMenu->QueryInterface(riid, ppvOut);
}
// We can't create a background menu
return E_FAIL;
}

View File

@@ -7,10 +7,10 @@ spec2def(fontext.dll fontext.spec)
list(APPEND SOURCE
CDataObject.cpp
CEnumFonts.cpp
CFontBackgroundMenu.cpp
CFontCache.cpp
CFontExt.cpp
CFontFolderViewCB.cpp
CFontMenu.cpp
fontext.cpp
fontpidl.cpp
precomp.h)

View File

@@ -100,6 +100,27 @@ STDAPI DllUnregisterServer()
return gModule.DllUnregisterServer(FALSE);
}
void CloseRegKeyArray(HKEY* array, UINT cKeys)
{
for (UINT i = 0; i < cKeys; ++i)
RegCloseKey(array[i]);
}
LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys)
{
if (*cKeys >= 16)
return ERROR_MORE_DATA;
HKEY hkey;
LSTATUS result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, KEY_READ | KEY_QUERY_VALUE, &hkey);
if (result == ERROR_SUCCESS)
{
array[*cKeys] = hkey;
*cKeys += 1;
}
return result;
}
HRESULT
InstallFontFiles(
_Inout_ PINSTALL_FONT_DATA pData)
@@ -207,10 +228,6 @@ DoInstallFontFile(
return E_FAIL;
}
// Delete file
if (DeleteFileW(szDestFile))
SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, (PCWSTR)szDestFile, NULL);
// Copy file
if (!CopyFileW(pszFontPath, szDestFile, FALSE))
{
@@ -288,13 +305,135 @@ BOOL CheckDropFontFiles(HDROP hDrop)
return TRUE;
}
HDROP GetDropFromDataObject(STGMEDIUM& stg, IDataObject *pDataObj)
BOOL CheckDataObject(IDataObject *pDataObj)
{
STGMEDIUM stg;
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<HDROP>(stg.hGlobal);
return FALSE;
HDROP hDrop = reinterpret_cast<HDROP>(stg.hGlobal);
BOOL bOK = CheckDropFontFiles(hDrop);
ReleaseStgMedium(&stg);
return bOK;
}
static DWORD WINAPI 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;
}
static INT_PTR CALLBACK
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(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;
}
static INT_PTR CALLBACK
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);
return InstallDlgProc(hwnd, uMsg, wParam, lParam, pData);
}
HRESULT InstallFontsFromDataObject(HWND hwndView, IDataObject* pDataObj)
{
if (!CheckDataObject(pDataObj))
{
ERR("!CheckDataObject\n");
return E_FAIL;
}
CDataObjectHIDA cida(pDataObj);
if (!cida || cida->cidl <= 0)
{
ERR("E_UNEXPECTED\n");
return E_FAIL;
}
PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(cida);
if (!pidlParent)
{
ERR("pidlParent is NULL\n");
return E_FAIL;
}
CAtlArray<PCUIDLIST_RELATIVE> apidl;
for (UINT n = 0; n < cida->cidl; ++n)
{
PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(cida, n);
if (!pidlRelative)
{
ERR("!pidlRelative\n");
return E_FAIL;
}
apidl.Add(pidlRelative);
}
// Show progress dialog
INSTALL_FONT_DATA data;
data.pDataObj = pDataObj;
data.pidlParent = pidlParent;
data.apidl = &apidl[0];
data.cSteps = cida->cidl;
pDataObj->AddRef();
DialogBoxParamW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDD_INSTALL),
hwndView, InstallDialogProc, (LPARAM)&data);
if (data.bCanceled)
return S_FALSE;
return FAILED_UNEXPECTEDLY(data.hrResult) ? E_FAIL : S_OK;
}
EXTERN_C

View File

@@ -22,6 +22,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -17,6 +17,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -22,6 +22,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -17,6 +17,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -23,6 +23,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -17,6 +17,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -22,6 +22,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -22,6 +22,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -22,6 +22,7 @@ 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."
IDS_PROPERTIES "P&roperties"
END
STRINGTABLE

View File

@@ -27,11 +27,8 @@
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;
@@ -47,13 +44,12 @@ typedef struct tagINSTALL_FONT_DATA
#include "CFontCache.hpp"
#include "CFontExt.hpp"
#include "CFontFolderViewCB.h"
#include "CFontBackgroundMenu.h"
#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,
IShellFolder *psf, REFIID riid, LPVOID* ppvOut);
HRESULT _CDataObject_CreateInstance(PCIDLIST_ABSOLUTE folder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
REFIID riid, LPVOID* ppvOut);
@@ -84,4 +80,29 @@ HRESULT DoGetFontTitle(
_Out_ CStringW& strFontName);
BOOL CheckDropFontFiles(HDROP hDrop);
HDROP GetDropFromDataObject(STGMEDIUM& stg, IDataObject *pDataObj);
BOOL CheckDataObject(IDataObject *pDataObj);
HRESULT InstallFontsFromDataObject(HWND hwndView, IDataObject* pDataObj);
HRESULT
APIENTRY
CFontBackgroundMenu_Create(
CFontExt* pFontExt,
HWND hwnd,
IShellFolder* psf,
IContextMenu** ppcm);
LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys);
void CloseRegKeyArray(HKEY* array, UINT cKeys);
struct CRegKeyHandleArray
{
HKEY hKeys[16];
UINT cKeys;
CRegKeyHandleArray() : cKeys(0) {}
~CRegKeyHandleArray() { CloseRegKeyArray(hKeys, cKeys); }
operator HKEY*() { return hKeys; }
operator UINT*() { return &cKeys; }
operator UINT() { return cKeys; }
HKEY& operator [](SIZE_T i) { return hKeys[i]; }
};

View File

@@ -7,6 +7,8 @@
#define IDS_REACTOS_FONTS_FOLDER 151
#define IDS_INSTALL_OK 152
#define IDS_INSTALL_FAILED 153
#define IDS_PROPERTIES 154
#define IDS_COL_NAME 301
#define IDS_COL_FILENAME 304
#define IDS_COL_SIZE 305