2 * PROJECT: ReactOS Font Shell Extension
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: CFontExt implementation
5 * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
10 WINE_DEFAULT_DEBUG_CHANNEL(fontext
);
13 struct FolderViewColumns
21 static FolderViewColumns g_ColumnDefs
[] =
23 { IDS_COL_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, 25, LVCFMT_LEFT
},
28 // Should fix our headers..
29 EXTERN_C HRESULT WINAPI
SHCreateFileExtractIconW(LPCWSTR pszPath
, DWORD dwFileAttributes
, REFIID riid
, void **ppv
);
32 // Helper functions to translate a guid to a readable name
33 bool GetInterfaceName(const WCHAR
* InterfaceString
, WCHAR
* buf
, size_t size
)
36 DWORD dwType
= 0, dwDataSize
= size
* sizeof(WCHAR
);
38 if (!SUCCEEDED(StringCchPrintfW(LocalBuf
, _countof(LocalBuf
), L
"Interface\\%s", InterfaceString
)))
41 return RegGetValueW(HKEY_CLASSES_ROOT
, LocalBuf
, NULL
, RRF_RT_REG_SZ
, &dwType
, buf
, &dwDataSize
) == ERROR_SUCCESS
;
44 WCHAR
* g2s(REFCLSID iid
)
46 static WCHAR buf
[2][300];
52 HRESULT hr
= ProgIDFromCLSID(iid
, &tmp
);
55 wcscpy(buf
[idx
], tmp
);
59 StringFromGUID2(iid
, buf
[idx
], _countof(buf
[idx
]));
60 if (GetInterfaceName(buf
[idx
], buf
[idx
], _countof(buf
[idx
])))
64 StringFromGUID2(iid
, buf
[idx
], _countof(buf
[idx
]));
72 InterlockedIncrement(&g_ModuleRefCnt
);
77 InterlockedDecrement(&g_ModuleRefCnt
);
80 // *** IShellFolder2 methods ***
81 STDMETHODIMP
CFontExt::GetDefaultSearchGUID(GUID
*lpguid
)
83 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__
);
87 STDMETHODIMP
CFontExt::EnumSearches(IEnumExtraSearch
**ppenum
)
89 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__
);
93 STDMETHODIMP
CFontExt::GetDefaultColumn(DWORD dwReserved
, ULONG
*pSort
, ULONG
*pDisplay
)
95 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__
);
99 STDMETHODIMP
CFontExt::GetDefaultColumnState(UINT iColumn
, SHCOLSTATEF
*pcsFlags
)
101 if (!pcsFlags
|| iColumn
>= _countof(g_ColumnDefs
))
104 *pcsFlags
= g_ColumnDefs
[iColumn
].dwDefaultState
;
108 STDMETHODIMP
CFontExt::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
110 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__
);
114 STDMETHODIMP
CFontExt::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*psd
)
116 if (iColumn
>= _countof(g_ColumnDefs
))
119 psd
->cxChar
= g_ColumnDefs
[iColumn
].cxChar
;
120 psd
->fmt
= g_ColumnDefs
[iColumn
].fmt
;
122 // No item requested, so return the column name
125 return SHSetStrRet(&psd
->str
, _AtlBaseModule
.GetResourceInstance(), g_ColumnDefs
[iColumn
].iResource
);
128 // Validate that this pidl is the last one
129 PCUIDLIST_RELATIVE curpidl
= ILGetNext(pidl
);
130 if (curpidl
->mkid
.cb
!= 0)
132 ERR("ERROR, unhandled PIDL!\n");
138 case 0: /* Name, ReactOS specific? */
139 return GetDisplayNameOf(pidl
, 0, &psd
->str
);
148 STDMETHODIMP
CFontExt::MapColumnToSCID(UINT iColumn
, SHCOLUMNID
*pscid
)
150 //ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
154 // *** IShellFolder2 methods ***
155 STDMETHODIMP
CFontExt::ParseDisplayName(HWND hwndOwner
, LPBC pbc
, LPOLESTR lpszDisplayName
, DWORD
*pchEaten
, PIDLIST_RELATIVE
*ppidl
, DWORD
*pdwAttributes
)
157 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__
);
161 STDMETHODIMP
CFontExt::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
163 return _CEnumFonts_CreateInstance(this, dwFlags
, IID_PPV_ARG(IEnumIDList
, ppEnumIDList
));
166 STDMETHODIMP
CFontExt::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
168 ERR("%s(riid=%S) UNIMPLEMENTED\n", __FUNCTION__
, g2s(riid
));
172 STDMETHODIMP
CFontExt::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
174 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__
);
178 STDMETHODIMP
CFontExt::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
180 const FontPidlEntry
* fontEntry1
= _FontFromIL(pidl1
);
181 const FontPidlEntry
* fontEntry2
= _FontFromIL(pidl2
);
183 if (!fontEntry1
|| !fontEntry2
)
186 int result
= (int)fontEntry1
->Index
- (int)fontEntry2
->Index
;
188 return MAKE_COMPARE_HRESULT(result
);
191 STDMETHODIMP
CFontExt::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
*ppvOut
)
193 HRESULT hr
= E_NOINTERFACE
;
197 if (IsEqualIID(riid
, IID_IDropTarget
))
199 // Needed to drop files into the fonts folder, we should probably install them?
200 ERR("IDropTarget not implemented\n");
203 else if (IsEqualIID(riid
, IID_IContextMenu
))
205 ERR("IContextMenu not implemented\n");
208 else if (IsEqualIID(riid
, IID_IShellView
))
210 // Just create a default shell folder view, and register ourself as folder
211 SFV_CREATE sfv
= { sizeof(SFV_CREATE
) };
213 hr
= SHCreateShellFolderView(&sfv
, (IShellView
**)ppvOut
);
219 STDMETHODIMP
CFontExt::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
*rgfInOut
)
221 if (!rgfInOut
|| !cidl
|| !apidl
)
225 while (cidl
> 0 && *apidl
)
227 const FontPidlEntry
* fontEntry
= _FontFromIL(*apidl
);
230 // We don't support delete yet
231 rgf
|= (/*SFGAO_CANDELETE |*/ SFGAO_HASPROPSHEET
| SFGAO_CANCOPY
| SFGAO_FILESYSTEM
);
248 STDMETHODIMP
CFontExt::GetUIObjectOf(HWND hwndOwner
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, REFIID riid
, UINT
* prgfInOut
, LPVOID
* ppvOut
)
250 if (riid
== IID_IContextMenu
||
251 riid
== IID_IContextMenu2
||
252 riid
== IID_IContextMenu3
)
254 return _CFontMenu_CreateInstance(hwndOwner
, cidl
, apidl
, this, riid
, ppvOut
);
256 else if (riid
== IID_IExtractIconA
|| riid
== IID_IExtractIconW
)
260 const FontPidlEntry
* fontEntry
= _FontFromIL(*apidl
);
263 DWORD dwAttributes
= FILE_ATTRIBUTE_NORMAL
;
264 CStringW File
= g_FontCache
->Filename(fontEntry
);
265 // Just create a default icon extractor based on the filename
266 // We might want to create a preview with the font to get really fancy one day.
267 return SHCreateFileExtractIconW(File
, dwAttributes
, riid
, ppvOut
);
272 ERR("IID_IExtractIcon with cidl != 1 UNIMPLEMENTED\n");
275 else if (riid
== IID_IDataObject
)
279 return _CDataObject_CreateInstance(m_Folder
, cidl
, apidl
, riid
, ppvOut
);
283 ERR("IID_IDataObject with cidl == 0 UNIMPLEMENTED\n");
287 //ERR("%s(riid=%S) UNIMPLEMENTED\n", __FUNCTION__, g2s(riid));
291 STDMETHODIMP
CFontExt::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET strRet
)
296 // Validate that this pidl is the last one
297 PCUIDLIST_RELATIVE curpidl
= ILGetNext(pidl
);
298 if (curpidl
->mkid
.cb
!= 0)
300 ERR("ERROR, unhandled PIDL!\n");
304 const FontPidlEntry
* fontEntry
= _FontFromIL(pidl
);
308 return SHSetStrRet(strRet
, fontEntry
->Name
);
311 STDMETHODIMP
CFontExt::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
, LPCOLESTR lpName
, DWORD dwFlags
, PITEMID_CHILD
*pPidlOut
)
313 ERR("%s() UNIMPLEMENTED\n", __FUNCTION__
);
317 // *** IPersistFolder2 methods ***
318 STDMETHODIMP
CFontExt::GetCurFolder(LPITEMIDLIST
*ppidl
)
320 if (ppidl
&& m_Folder
)
322 *ppidl
= ILClone(m_Folder
);
330 // *** IPersistFolder methods ***
331 STDMETHODIMP
CFontExt::Initialize(LPCITEMIDLIST pidl
)
333 WCHAR PidlPath
[MAX_PATH
+ 1] = {0}, Expected
[MAX_PATH
+ 1];
334 if (!SHGetPathFromIDListW(pidl
, PidlPath
))
336 ERR("Unable to extract path from pidl\n");
340 HRESULT hr
= SHGetFolderPathW(NULL
, CSIDL_FONTS
, NULL
, 0, Expected
);
343 ERR("Unable to get fonts path (0x%x)\n", hr
);
347 if (_wcsicmp(PidlPath
, Expected
))
349 ERR("CFontExt View initializing on unexpected folder: '%S'\n", PidlPath
);
353 m_Folder
.Attach(ILClone(pidl
));
359 // *** IPersist methods ***
360 STDMETHODIMP
CFontExt::GetClassID(CLSID
*lpClassId
)
362 *lpClassId
= CLSID_CFontExt
;