mirror of
https://github.com/reactos/reactos.git
synced 2026-05-31 16:31:07 +08:00
[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:
committed by
GitHub
parent
2865b6353b
commit
789f6c5481
125
dll/shellext/fontext/CFontBackgroundMenu.cpp
Normal file
125
dll/shellext/fontext/CFontBackgroundMenu.cpp
Normal 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));
|
||||
}
|
||||
41
dll/shellext/fontext/CFontBackgroundMenu.h
Normal file
41
dll/shellext/fontext/CFontBackgroundMenu.h
Normal 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()
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]; }
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user