1 /*
2 * PROJECT: ReactOS Font Shell Extension
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: CFontMenu implementation
5 * COPYRIGHT: Copyright 2019-2021 Mark Jansen <mark.jansen@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 WINE_DEFAULT_DEBUG_CHANNEL(fontext);
11
12
DFM_TO_STR(UINT uMsg)13 const char* DFM_TO_STR(UINT uMsg)
14 {
15 switch(uMsg)
16 {
17 case DFM_MERGECONTEXTMENU: return "DFM_MERGECONTEXTMENU";
18 case DFM_INVOKECOMMAND: return "DFM_INVOKECOMMAND";
19 case DFM_MODIFYQCMFLAGS: return "DFM_MODIFYQCMFLAGS";
20 case DFM_MERGECONTEXTMENU_TOP: return "DFM_MERGECONTEXTMENU_TOP";
21 case DFM_MERGECONTEXTMENU_BOTTOM: return "DFM_MERGECONTEXTMENU_BOTTOM";
22 case DFM_GETHELPTEXTW: return "DFM_GETHELPTEXTW";
23 case DFM_GETVERBW: return "DFM_GETVERBW";
24 case DFM_GETVERBA: return "DFM_GETVERBA";
25 case DFM_WM_INITMENUPOPUP: return "DFM_WM_INITMENUPOPUP";
26 case DFM_INVOKECOMMANDEX: return "DFM_INVOKECOMMANDEX";
27 case DFM_GETDEFSTATICID: return "DFM_GETDEFSTATICID";
28 case 3: return "MENU_BEGIN";
29 case 4: return "MENU_END";
30 default: return "";
31 }
32 }
33
34
RunFontViewer(HWND hwnd,const FontPidlEntry * fontEntry)35 static void RunFontViewer(HWND hwnd, const FontPidlEntry* fontEntry)
36 {
37 WCHAR FontViewerPath[MAX_PATH] = L"%SystemRoot%\\System32\\fontview.exe";
38 WCHAR FontPathArg[MAX_PATH + 3];
39
40 CStringW Path = g_FontCache->Filename(g_FontCache->Find(fontEntry), true);
41 if (!Path.IsEmpty())
42 {
43 // '/d' disables the install button
44 StringCchPrintfW(FontPathArg, _countof(FontPathArg), L"/d %s", Path.GetString());
45 PathQuoteSpacesW(FontPathArg + 3);
46
47 SHELLEXECUTEINFOW si = { sizeof(si) };
48 si.fMask = SEE_MASK_DOENVSUBST;
49 si.hwnd = hwnd;
50 si.lpFile = FontViewerPath;
51 si.lpParameters = FontPathArg;
52 si.nShow = SW_SHOWNORMAL;
53 ShellExecuteExW(&si);
54 }
55 }
56
FontFolderMenuCallback(IShellFolder * psf,HWND hwnd,IDataObject * pdtobj,UINT uMsg,WPARAM wParam,LPARAM lParam)57 static HRESULT CALLBACK FontFolderMenuCallback(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj,
58 UINT uMsg, WPARAM wParam, LPARAM lParam)
59 {
60 TRACE("FontFolderMenuCallback(%u {%s})\n", uMsg, DFM_TO_STR(uMsg));
61 switch (uMsg)
62 {
63 case DFM_MERGECONTEXTMENU:
64 {
65 QCMINFO *pqcminfo = (QCMINFO *)lParam;
66
67 CStringW menuText(MAKEINTRESOURCEW(IDS_FONT_PREVIEW));
68 MENUITEMINFOW cmi = { sizeof(cmi) };
69 cmi.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
70 cmi.fType = MFT_STRING;
71 cmi.fState = MFS_DEFAULT;
72 cmi.wID = pqcminfo->idCmdFirst++;
73 cmi.dwTypeData = (LPWSTR)menuText.GetString();
74 InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu, TRUE, &cmi);
75
76 return S_OK;
77 }
78 case DFM_INVOKECOMMAND:
79 // Preview is the only item we handle
80 if (wParam == 0)
81 {
82 CDataObjectHIDA cida(pdtobj);
83
84 if (FAILED_UNEXPECTEDLY(cida.hr()))
85 return cida.hr();
86
87 for (UINT n = 0; n < cida->cidl; ++n)
88 {
89 const FontPidlEntry* fontEntry = _FontFromIL(HIDA_GetPIDLItem(cida, n));
90 RunFontViewer(hwnd, fontEntry);
91 }
92 return S_OK;
93 }
94 else if (wParam == DFM_CMD_PROPERTIES)
95 {
96 TRACE("Default properties handling!\n");
97 return S_FALSE;
98 }
99 else
100 {
101 ERR("Unhandled DFM_INVOKECOMMAND(wParam=0x%x)\n", wParam);
102 }
103 return S_FALSE;
104
105 case DFM_INVOKECOMMANDEX:
106 return E_NOTIMPL;
107 case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
108 return S_FALSE;
109 }
110 return E_NOTIMPL;
111 }
112
113
_CFontMenu_CreateInstance(HWND hwnd,UINT cidl,PCUITEMID_CHILD_ARRAY apidl,IShellFolder * psf,REFIID riid,LPVOID * ppvOut)114 HRESULT _CFontMenu_CreateInstance(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
115 IShellFolder *psf, REFIID riid, LPVOID* ppvOut)
116 {
117 if (cidl > 0)
118 {
119 HKEY keys[1] = {0};
120 int nkeys = 0;
121 CComPtr<IContextMenu> spMenu;
122
123 // Use the default context menu handler, but augment it from the callbacks
124 HRESULT hr = CDefFolderMenu_Create2(NULL, hwnd, cidl, apidl, psf, FontFolderMenuCallback, nkeys, keys, &spMenu);
125
126 if (FAILED_UNEXPECTEDLY(hr))
127 return hr;
128
129 // See if the requested interface (e.g. IContextMenu3) is also available
130 return spMenu->QueryInterface(riid, ppvOut);
131 }
132
133 // We can't create a background menu
134 return E_FAIL;
135 }
136
137