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,2020 Mark Jansen (mark.jansen@reactos.org)
10 WINE_DEFAULT_DEBUG_CHANNEL(fontext
);
12 static CLIPFORMAT g_cfHIDA
;
14 HRESULT
_GetCidlFromDataObject(IDataObject
*pDataObject
, CIDA
** ppcida
)
18 g_cfHIDA
= (CLIPFORMAT
)RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
21 FORMATETC fmt
= { g_cfHIDA
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
24 HRESULT hr
= pDataObject
->GetData(&fmt
, &medium
);
25 if (FAILED_UNEXPECTEDLY(hr
))
28 LPVOID lpSrc
= GlobalLock(medium
.hGlobal
);
29 SIZE_T cbSize
= GlobalSize(medium
.hGlobal
);
31 *ppcida
= (CIDA
*)::CoTaskMemAlloc(cbSize
);
34 memcpy(*ppcida
, lpSrc
, cbSize
);
41 ReleaseStgMedium(&medium
);
45 const char* DFM_TO_STR(UINT uMsg
)
49 case DFM_MERGECONTEXTMENU
: return "DFM_MERGECONTEXTMENU";
50 case DFM_INVOKECOMMAND
: return "DFM_INVOKECOMMAND";
51 case DFM_MODIFYQCMFLAGS
: return "DFM_MODIFYQCMFLAGS";
52 case DFM_MERGECONTEXTMENU_TOP
: return "DFM_MERGECONTEXTMENU_TOP";
53 case DFM_MERGECONTEXTMENU_BOTTOM
: return "DFM_MERGECONTEXTMENU_BOTTOM";
54 case DFM_GETHELPTEXTW
: return "DFM_GETHELPTEXTW";
55 case DFM_GETVERBW
: return "DFM_GETVERBW";
56 case DFM_GETVERBA
: return "DFM_GETVERBA";
57 case DFM_WM_INITMENUPOPUP
: return "DFM_WM_INITMENUPOPUP";
58 case DFM_INVOKECOMMANDEX
: return "DFM_INVOKECOMMANDEX";
59 case DFM_GETDEFSTATICID
: return "DFM_GETDEFSTATICID";
60 case 3: return "MENU_BEGIN";
61 case 4: return "MENU_END";
67 static void RunFontViewer(HWND hwnd
, const FontPidlEntry
* fontEntry
)
69 WCHAR FontViewerPath
[MAX_PATH
] = L
"%SystemRoot%\\System32\\fontview.exe";
70 WCHAR FontPathArg
[MAX_PATH
+ 3];
72 CStringW Path
= g_FontCache
->Filename(fontEntry
, true);
75 // '/d' disables the install button
76 StringCchPrintfW(FontPathArg
, _countof(FontPathArg
), L
"/d %s", Path
.GetString());
77 PathQuoteSpacesW(FontPathArg
+ 3);
79 SHELLEXECUTEINFOW si
= { sizeof(si
) };
80 si
.fMask
= SEE_MASK_DOENVSUBST
;
82 si
.lpFile
= FontViewerPath
;
83 si
.lpParameters
= FontPathArg
;
84 si
.nShow
= SW_SHOWNORMAL
;
89 static HRESULT CALLBACK
FontFolderMenuCallback(IShellFolder
*psf
, HWND hwnd
, IDataObject
*pdtobj
,
90 UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
92 TRACE("FontFolderMenuCallback(%u {%s})\n", uMsg
, DFM_TO_STR(uMsg
));
95 case DFM_MERGECONTEXTMENU
:
97 QCMINFO
*pqcminfo
= (QCMINFO
*)lParam
;
99 CStringW
menuText(MAKEINTRESOURCEW(IDS_FONT_PREVIEW
));
100 MENUITEMINFOW cmi
= { sizeof(cmi
) };
101 cmi
.fMask
= MIIM_ID
| MIIM_STRING
| MIIM_STATE
;
102 cmi
.fType
= MFT_STRING
;
103 cmi
.fState
= MFS_DEFAULT
;
104 cmi
.wID
= pqcminfo
->idCmdFirst
++;
105 cmi
.dwTypeData
= (LPWSTR
)menuText
.GetString();
106 InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
, TRUE
, &cmi
);
110 case DFM_INVOKECOMMAND
:
111 // Preview is the only item we can handle
114 CComHeapPtr
<CIDA
> cida
;
115 HRESULT hr
= _GetCidlFromDataObject(pdtobj
, &cida
);
116 if (FAILED_UNEXPECTEDLY(hr
))
119 for (UINT n
= 0; n
< cida
->cidl
; ++n
)
121 const FontPidlEntry
* fontEntry
= _FontFromIL(HIDA_GetPIDLItem(cida
, n
));
122 RunFontViewer(hwnd
, fontEntry
);
128 case DFM_INVOKECOMMANDEX
:
130 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default
137 HRESULT
_CFontMenu_CreateInstance(HWND hwnd
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
138 IShellFolder
*psf
, REFIID riid
, LPVOID
* ppvOut
)
144 CComPtr
<IContextMenu
> spMenu
;
146 // Use the default context menu handler, but augment it from the callbacks
147 HRESULT hr
= CDefFolderMenu_Create2(NULL
, hwnd
, cidl
, apidl
, psf
, FontFolderMenuCallback
, nkeys
, keys
, &spMenu
);
149 if (FAILED_UNEXPECTEDLY(hr
))
152 // See if the requested interface (e.g. IContextMenu3) is also available
153 return spMenu
->QueryInterface(riid
, ppvOut
);
156 // We can't create a background menu