xref: /reactos/dll/shellext/fontext/CFontMenu.cpp (revision 7e22dc05)
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 
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 
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 
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 
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