mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 21:44:31 +00:00
[FONTEXT] Initial implementation
Create Fonts\desktop.ini when registering the shell ext Also list the shell extension as needing to be registered at install CORE-14690
This commit is contained in:
parent
730a99c860
commit
d9e7c48c1a
141
dll/shellext/fontext/CDataObject.cpp
Normal file
141
dll/shellext/fontext/CDataObject.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
|
||||
|
||||
|
||||
#if 0
|
||||
static inline void DumpDataObjectFormats(IDataObject* pObject)
|
||||
{
|
||||
CComPtr<IEnumFORMATETC> pEnumFmt;
|
||||
HRESULT hr = pObject->EnumFormatEtc(DATADIR_GET, &pEnumFmt);
|
||||
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return;
|
||||
|
||||
FORMATETC fmt;
|
||||
while (S_OK == pEnumFmt->Next(1, &fmt, NULL))
|
||||
{
|
||||
char szBuf[512];
|
||||
GetClipboardFormatNameA(fmt.cfFormat, szBuf, sizeof(szBuf));
|
||||
ERR("Format: %s\n", szBuf);
|
||||
ERR("Tymed: %u\n", fmt.tymed);
|
||||
if (fmt.tymed & TYMED_HGLOBAL)
|
||||
{
|
||||
ERR("TYMED_HGLOBAL supported\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
HRESULT _CDataObject_CreateInstance(PCIDLIST_ABSOLUTE folder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
|
||||
REFIID riid, LPVOID* ppvOut)
|
||||
{
|
||||
HRESULT hr = CIDLData_CreateFromIDArray(folder, cidl, apidl, (IDataObject**)ppvOut);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
// Now that we have an IDataObject with the shell itemid list (CFSTR_SHELLIDLIST, aka HIDA) format
|
||||
// we will augment this IDataObject with the CF_HDROP format. (Full filepaths)
|
||||
// This enabled the objects for the 'copy' and drag to copy actions
|
||||
WCHAR FontsDir[MAX_PATH];
|
||||
hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, FontsDir);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return S_OK;
|
||||
StringCchCatW(FontsDir, _countof(FontsDir), L"\\");
|
||||
|
||||
CComHeapPtr<BYTE> data;
|
||||
|
||||
// First we allocate room for the DROPFILES structure
|
||||
data.AllocateBytes(sizeof(DROPFILES));
|
||||
UINT offset = sizeof(DROPFILES);
|
||||
|
||||
// Then we walk all files
|
||||
for (UINT n = 0; n < cidl; ++n)
|
||||
{
|
||||
const FontPidlEntry* fontEntry = _FontFromIL(apidl[n]);
|
||||
if (fontEntry)
|
||||
{
|
||||
CStringW File = g_FontCache->Filename(fontEntry);
|
||||
if (!File.IsEmpty())
|
||||
{
|
||||
// Ensure this is a full path
|
||||
if (PathIsRelativeW(File))
|
||||
{
|
||||
File = FontsDir + File;
|
||||
}
|
||||
|
||||
// Now append the path (+ nullterminator) to the buffer
|
||||
UINT len = offset + (File.GetLength() + 1) * sizeof(WCHAR);
|
||||
data.ReallocateBytes(len);
|
||||
if (!data)
|
||||
{
|
||||
ERR("Unable to allocate memory for the CF_HDROP\n");
|
||||
return hr;
|
||||
}
|
||||
BYTE* dataPtr = data;
|
||||
StringCbCopyW((STRSAFE_LPWSTR)(dataPtr + offset), len - offset, File);
|
||||
offset = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("No file found for %S\n", fontEntry->Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append the final nullterminator (double null terminated list)
|
||||
data.ReallocateBytes(offset + sizeof(UNICODE_NULL));
|
||||
LPWSTR str = (LPWSTR)((BYTE*)data + offset);
|
||||
*str = UNICODE_NULL;
|
||||
offset += sizeof(UNICODE_NULL);
|
||||
|
||||
// Fill in the required fields
|
||||
DROPFILES* pDrop = (DROPFILES*)(BYTE*)data;
|
||||
pDrop->fWide = 1;
|
||||
pDrop->pFiles = sizeof(DROPFILES);
|
||||
// Zero out the rest
|
||||
pDrop->pt.x = pDrop->pt.y = 0;
|
||||
pDrop-> fNC = NULL;
|
||||
|
||||
// Prepare the format descriptors
|
||||
STGMEDIUM medium = {0};
|
||||
medium.tymed = TYMED_HGLOBAL;
|
||||
|
||||
// Copy the data to an HGLOBAL
|
||||
medium.hGlobal = GlobalAlloc(GHND, offset);
|
||||
if (medium.hGlobal)
|
||||
{
|
||||
LPVOID blob = GlobalLock(medium.hGlobal);
|
||||
if (blob)
|
||||
{
|
||||
CopyMemory(blob, (BYTE*)data, offset);
|
||||
GlobalUnlock(medium.hGlobal);
|
||||
|
||||
CComPtr<IDataObject> spDataObject(*(IDataObject**)ppvOut);
|
||||
if (spDataObject)
|
||||
{
|
||||
FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
hr = spDataObject->SetData(&etc, &medium, TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Unable to lock the hGlobal?!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Unable to allocate %u bytes for the hGlobal\n", offset);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
91
dll/shellext/fontext/CEnumFonts.cpp
Normal file
91
dll/shellext/fontext/CEnumFonts.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: CEnumFonts implementation
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
|
||||
|
||||
|
||||
|
||||
class CEnumFonts :
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
public IEnumIDList
|
||||
{
|
||||
private:
|
||||
DWORD m_dwFlags;
|
||||
ULONG m_Index;
|
||||
|
||||
public:
|
||||
CEnumFonts()
|
||||
:m_dwFlags(0)
|
||||
,m_Index(0)
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP Initialize(CFontExt* folder, DWORD flags)
|
||||
{
|
||||
m_dwFlags = flags;
|
||||
m_Index = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// *** IEnumIDList methods ***
|
||||
STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
|
||||
{
|
||||
if (!pceltFetched || !rgelt)
|
||||
return E_POINTER;
|
||||
|
||||
ULONG Fetched = 0;
|
||||
|
||||
while (celt)
|
||||
{
|
||||
celt--;
|
||||
|
||||
if (m_Index < g_FontCache->Size())
|
||||
{
|
||||
CStringW Name = g_FontCache->Name(m_Index);
|
||||
rgelt[Fetched] = _ILCreate(Name, m_Index);
|
||||
|
||||
m_Index++;
|
||||
Fetched++;
|
||||
}
|
||||
}
|
||||
|
||||
*pceltFetched = Fetched;
|
||||
return Fetched ? S_OK : S_FALSE;
|
||||
}
|
||||
STDMETHODIMP Skip(ULONG celt)
|
||||
{
|
||||
m_Index += celt;
|
||||
return S_OK;
|
||||
}
|
||||
STDMETHODIMP Reset()
|
||||
{
|
||||
m_Index = 0;
|
||||
return S_OK;
|
||||
}
|
||||
STDMETHODIMP Clone(IEnumIDList **ppenum)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
DECLARE_NOT_AGGREGATABLE(CEnumFonts)
|
||||
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||
|
||||
BEGIN_COM_MAP(CEnumFonts)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
|
||||
END_COM_MAP()
|
||||
};
|
||||
|
||||
|
||||
HRESULT _CEnumFonts_CreateInstance(CFontExt* zip, DWORD flags, REFIID riid, LPVOID * ppvOut)
|
||||
{
|
||||
return ShellObjectCreatorInit<CEnumFonts>(zip, flags, riid, ppvOut);
|
||||
}
|
||||
|
173
dll/shellext/fontext/CFontCache.cpp
Normal file
173
dll/shellext/fontext/CFontCache.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: font list cache handling
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
|
||||
|
||||
|
||||
#define FONT_HIVE HKEY_LOCAL_MACHINE
|
||||
#define FONT_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
|
||||
|
||||
CFontCache* g_FontCache = NULL;
|
||||
|
||||
CFontInfo::CFontInfo(LPCWSTR name)
|
||||
: m_Name(name)
|
||||
, m_FileRead(false)
|
||||
{
|
||||
}
|
||||
|
||||
const CStringW& CFontInfo::Name() const
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
|
||||
const bool CFontInfo::Valid() const
|
||||
{
|
||||
return !m_Name.IsEmpty();
|
||||
}
|
||||
|
||||
const CStringW& CFontInfo::File()
|
||||
{
|
||||
if (!m_FileRead)
|
||||
{
|
||||
if (Valid())
|
||||
{
|
||||
// Read the filename stored in the registry.
|
||||
// This can be either a filename or a full path
|
||||
CRegKey key;
|
||||
if (key.Open(FONT_HIVE, FONT_KEY, KEY_READ) == ERROR_SUCCESS)
|
||||
{
|
||||
CStringW Value;
|
||||
DWORD dwAllocated = 128;
|
||||
LSTATUS Status;
|
||||
do
|
||||
{
|
||||
DWORD dwSize = dwAllocated;
|
||||
PWSTR Buffer = Value.GetBuffer(dwSize);
|
||||
Status = key.QueryStringValue(m_Name, Buffer, &dwSize);
|
||||
Value.ReleaseBuffer(dwSize);
|
||||
if (Status == ERROR_SUCCESS)
|
||||
{
|
||||
// Ensure we do not re-use the same string object, by passing it a PCWSTR
|
||||
m_File = Value.GetString();
|
||||
break;
|
||||
}
|
||||
dwAllocated += 128;
|
||||
} while (Status == ERROR_MORE_DATA);
|
||||
}
|
||||
}
|
||||
m_FileRead = true;
|
||||
}
|
||||
return m_File;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CFontCache::CFontCache()
|
||||
{
|
||||
}
|
||||
|
||||
size_t CFontCache::Size()
|
||||
{
|
||||
if (m_Fonts.GetCount() == 0u)
|
||||
Read();
|
||||
|
||||
return m_Fonts.GetCount();
|
||||
}
|
||||
|
||||
CStringW CFontCache::Name(size_t Index)
|
||||
{
|
||||
if (m_Fonts.GetCount() == 0u)
|
||||
Read();
|
||||
|
||||
if (Index >= m_Fonts.GetCount())
|
||||
return CStringW();
|
||||
|
||||
return m_Fonts[Index].Name();
|
||||
}
|
||||
|
||||
CStringW CFontCache::Filename(const FontPidlEntry* fontEntry)
|
||||
{
|
||||
if (fontEntry->Index < m_Fonts.GetCount())
|
||||
{
|
||||
CFontInfo& info = m_Fonts[fontEntry->Index];
|
||||
|
||||
if (info.Name().CompareNoCase(fontEntry->Name) == 0)
|
||||
return info.File();
|
||||
}
|
||||
|
||||
for (UINT n = 0; n < Size(); ++n)
|
||||
{
|
||||
if (m_Fonts[n].Name().CompareNoCase(fontEntry->Name) == 0)
|
||||
return m_Fonts[n].File();
|
||||
}
|
||||
|
||||
return CStringW();
|
||||
}
|
||||
|
||||
void CFontCache::Insert(CAtlList<CFontInfo>& fonts, const CStringW& KeyName)
|
||||
{
|
||||
POSITION it = fonts.GetHeadPosition();
|
||||
while (it != NULL)
|
||||
{
|
||||
POSITION lastit = it;
|
||||
const CFontInfo& info = fonts.GetNext(it);
|
||||
if (info.Name().CompareNoCase(KeyName) >= 0)
|
||||
{
|
||||
fonts.InsertBefore(lastit, CFontInfo(KeyName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
fonts.AddTail(CFontInfo(KeyName));
|
||||
}
|
||||
|
||||
void CFontCache::Read()
|
||||
{
|
||||
CAtlList<CFontInfo> fonts;
|
||||
CRegKey key;
|
||||
|
||||
// Enumerate all registered font names
|
||||
if (key.Open(FONT_HIVE, FONT_KEY, KEY_READ) == ERROR_SUCCESS)
|
||||
{
|
||||
LSTATUS Status;
|
||||
DWORD dwAllocated = 128;
|
||||
DWORD ilIndex = 0;
|
||||
CStringW KeyName;
|
||||
do
|
||||
{
|
||||
DWORD dwSize = dwAllocated;
|
||||
PWSTR Buffer = KeyName.GetBuffer(dwSize);
|
||||
Status = RegEnumValueW(key.m_hKey, ilIndex, Buffer, &dwSize, NULL, NULL, NULL, NULL);
|
||||
KeyName.ReleaseBuffer(dwSize);
|
||||
if (Status == ERROR_SUCCESS)
|
||||
{
|
||||
// Insert will create an ordered list
|
||||
Insert(fonts, KeyName);
|
||||
ilIndex++;
|
||||
continue;
|
||||
}
|
||||
if (Status == ERROR_NO_MORE_ITEMS)
|
||||
break;
|
||||
else if (Status == ERROR_MORE_DATA)
|
||||
{
|
||||
dwAllocated += 128;
|
||||
}
|
||||
} while (Status == ERROR_MORE_DATA || Status == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
// Move the fonts from a list to an array (for easy indexing)
|
||||
m_Fonts.SetCount(fonts.GetCount());
|
||||
size_t Index = 0;
|
||||
POSITION it = fonts.GetHeadPosition();
|
||||
while (it != NULL)
|
||||
{
|
||||
m_Fonts[Index] = fonts.GetNext(it);
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
|
48
dll/shellext/fontext/CFontCache.hpp
Normal file
48
dll/shellext/fontext/CFontCache.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: font list cache handling
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class CFontInfo
|
||||
{
|
||||
private:
|
||||
CStringW m_Name;
|
||||
CStringW m_File;
|
||||
bool m_FileRead;
|
||||
public:
|
||||
CFontInfo(LPCWSTR name = L"");
|
||||
|
||||
const CStringW& Name() const;
|
||||
const CStringW& File();
|
||||
const bool Valid() const;
|
||||
};
|
||||
|
||||
|
||||
class CFontCache
|
||||
{
|
||||
private:
|
||||
CAtlArray<CFontInfo> m_Fonts;
|
||||
|
||||
protected:
|
||||
CFontCache();
|
||||
|
||||
void Insert(CAtlList<CFontInfo>& fonts, const CStringW& KeyName);
|
||||
void Read();
|
||||
|
||||
public:
|
||||
size_t Size();
|
||||
CStringW Name(size_t Index);
|
||||
CStringW Filename(const FontPidlEntry* fontEntry);
|
||||
|
||||
friend class CFontExtModule;
|
||||
};
|
||||
|
||||
|
||||
extern CFontCache* g_FontCache;
|
||||
|
||||
|
365
dll/shellext/fontext/CFontExt.cpp
Normal file
365
dll/shellext/fontext/CFontExt.cpp
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: CFontExt implementation
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
|
||||
|
||||
|
||||
struct FolderViewColumns
|
||||
{
|
||||
int iResource;
|
||||
DWORD dwDefaultState;
|
||||
int cxChar;
|
||||
int fmt;
|
||||
};
|
||||
|
||||
static FolderViewColumns g_ColumnDefs[] =
|
||||
{
|
||||
{ IDS_COL_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 25, LVCFMT_LEFT },
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Should fix our headers..
|
||||
EXTERN_C HRESULT WINAPI SHCreateFileExtractIconW(LPCWSTR pszPath, DWORD dwFileAttributes, REFIID riid, void **ppv);
|
||||
|
||||
|
||||
// Helper functions to translate a guid to a readable name
|
||||
bool GetInterfaceName(const WCHAR* InterfaceString, WCHAR* buf, size_t size)
|
||||
{
|
||||
WCHAR LocalBuf[100];
|
||||
DWORD dwType = 0, dwDataSize = size * sizeof(WCHAR);
|
||||
|
||||
if (!SUCCEEDED(StringCchPrintfW(LocalBuf, _countof(LocalBuf), L"Interface\\%s", InterfaceString)))
|
||||
return false;
|
||||
|
||||
return RegGetValueW(HKEY_CLASSES_ROOT, LocalBuf, NULL, RRF_RT_REG_SZ, &dwType, buf, &dwDataSize) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
WCHAR* g2s(REFCLSID iid)
|
||||
{
|
||||
static WCHAR buf[2][300];
|
||||
static int idx = 0;
|
||||
|
||||
idx ^= 1;
|
||||
|
||||
LPOLESTR tmp;
|
||||
HRESULT hr = ProgIDFromCLSID(iid, &tmp);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
wcscpy(buf[idx], tmp);
|
||||
CoTaskMemFree(tmp);
|
||||
return buf[idx];
|
||||
}
|
||||
StringFromGUID2(iid, buf[idx], _countof(buf[idx]));
|
||||
if (GetInterfaceName(buf[idx], buf[idx], _countof(buf[idx])))
|
||||
{
|
||||
return buf[idx];
|
||||
}
|
||||
StringFromGUID2(iid, buf[idx], _countof(buf[idx]));
|
||||
|
||||
return buf[idx];
|
||||
}
|
||||
|
||||
|
||||
CFontExt::CFontExt()
|
||||
{
|
||||
InterlockedIncrement(&g_ModuleRefCnt);
|
||||
}
|
||||
|
||||
CFontExt::~CFontExt()
|
||||
{
|
||||
InterlockedDecrement(&g_ModuleRefCnt);
|
||||
}
|
||||
|
||||
// *** IShellFolder2 methods ***
|
||||
STDMETHODIMP CFontExt::GetDefaultSearchGUID(GUID *lpguid)
|
||||
{
|
||||
ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::EnumSearches(IEnumExtraSearch **ppenum)
|
||||
{
|
||||
ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
|
||||
{
|
||||
ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags)
|
||||
{
|
||||
if (!pcsFlags || iColumn >= _countof(g_ColumnDefs))
|
||||
return E_INVALIDARG;
|
||||
|
||||
*pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
|
||||
{
|
||||
ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
|
||||
{
|
||||
if (iColumn >= _countof(g_ColumnDefs))
|
||||
return E_FAIL;
|
||||
|
||||
psd->cxChar = g_ColumnDefs[iColumn].cxChar;
|
||||
psd->fmt = g_ColumnDefs[iColumn].fmt;
|
||||
|
||||
// No item requested, so return the column name
|
||||
if (pidl == NULL)
|
||||
{
|
||||
return SHSetStrRet(&psd->str, _AtlBaseModule.GetResourceInstance(), g_ColumnDefs[iColumn].iResource);
|
||||
}
|
||||
|
||||
// Validate that this pidl is the last one
|
||||
PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl);
|
||||
if (curpidl->mkid.cb != 0)
|
||||
{
|
||||
ERR("ERROR, unhandled PIDL!\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
switch (iColumn)
|
||||
{
|
||||
case 0: /* Name, ReactOS specific? */
|
||||
return GetDisplayNameOf(pidl, 0, &psd->str);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
|
||||
{
|
||||
//ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// *** IShellFolder2 methods ***
|
||||
STDMETHODIMP CFontExt::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
|
||||
{
|
||||
ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
|
||||
{
|
||||
return _CEnumFonts_CreateInstance(this, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
ERR("%s(riid=%S) UNIMPLEMENTED\n", __FUNCTION__, g2s(riid));
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
|
||||
{
|
||||
const FontPidlEntry* fontEntry1 = _FontFromIL(pidl1);
|
||||
const FontPidlEntry* fontEntry2 = _FontFromIL(pidl2);
|
||||
|
||||
if (!fontEntry1 || !fontEntry2)
|
||||
return E_INVALIDARG;
|
||||
|
||||
int result = (int)fontEntry1->Index - (int)fontEntry2->Index;
|
||||
|
||||
return MAKE_COMPARE_HRESULT(result);
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
HRESULT hr = E_NOINTERFACE;
|
||||
|
||||
*ppvOut = NULL;
|
||||
|
||||
if (IsEqualIID(riid, IID_IDropTarget))
|
||||
{
|
||||
// Needed to drop files into the fonts folder, we should probably install them?
|
||||
ERR("IDropTarget not implemented\n");
|
||||
hr = E_NOTIMPL;
|
||||
}
|
||||
else if (IsEqualIID(riid, IID_IContextMenu))
|
||||
{
|
||||
ERR("IContextMenu not implemented\n");
|
||||
hr = E_NOTIMPL;
|
||||
}
|
||||
else if (IsEqualIID(riid, IID_IShellView))
|
||||
{
|
||||
// Just create a default shell folder view, and register ourself as folder
|
||||
SFV_CREATE sfv = { sizeof(SFV_CREATE) };
|
||||
sfv.pshf = this;
|
||||
hr = SHCreateShellFolderView(&sfv, (IShellView**)ppvOut);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
|
||||
{
|
||||
if (!rgfInOut || !cidl || !apidl)
|
||||
return E_INVALIDARG;
|
||||
|
||||
DWORD rgf = 0;
|
||||
while (cidl > 0 && *apidl)
|
||||
{
|
||||
const FontPidlEntry* fontEntry = _FontFromIL(*apidl);
|
||||
if (fontEntry)
|
||||
{
|
||||
// We don't support delete yet
|
||||
rgf |= (/*SFGAO_CANDELETE |*/ SFGAO_HASPROPSHEET | SFGAO_CANCOPY | SFGAO_FILESYSTEM);
|
||||
}
|
||||
else
|
||||
{
|
||||
rgf = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
apidl++;
|
||||
cidl--;
|
||||
}
|
||||
|
||||
*rgfInOut = rgf;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
else if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
|
||||
{
|
||||
if (cidl == 1)
|
||||
{
|
||||
const FontPidlEntry* fontEntry = _FontFromIL(*apidl);
|
||||
if (fontEntry)
|
||||
{
|
||||
DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
CStringW File = g_FontCache->Filename(fontEntry);
|
||||
// Just create a default icon extractor based on the filename
|
||||
// We might want to create a preview with the font to get really fancy one day.
|
||||
return SHCreateFileExtractIconW(File, dwAttributes, riid, ppvOut);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("IID_IExtractIcon with cidl != 1 UNIMPLEMENTED\n");
|
||||
}
|
||||
}
|
||||
else if (riid == IID_IDataObject)
|
||||
{
|
||||
if (cidl >= 1)
|
||||
{
|
||||
return _CDataObject_CreateInstance(m_Folder, cidl, apidl, riid, ppvOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("IID_IDataObject with cidl == 0 UNIMPLEMENTED\n");
|
||||
}
|
||||
}
|
||||
|
||||
//ERR("%s(riid=%S) UNIMPLEMENTED\n", __FUNCTION__, g2s(riid));
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
|
||||
{
|
||||
if (!pidl)
|
||||
return S_FALSE;
|
||||
|
||||
// Validate that this pidl is the last one
|
||||
PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl);
|
||||
if (curpidl->mkid.cb != 0)
|
||||
{
|
||||
ERR("ERROR, unhandled PIDL!\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
const FontPidlEntry* fontEntry = _FontFromIL(pidl);
|
||||
if (!fontEntry)
|
||||
return E_FAIL;
|
||||
|
||||
return SHSetStrRet(strRet, fontEntry->Name);
|
||||
}
|
||||
|
||||
STDMETHODIMP CFontExt::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
|
||||
{
|
||||
ERR("%s() UNIMPLEMENTED\n", __FUNCTION__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// *** IPersistFolder2 methods ***
|
||||
STDMETHODIMP CFontExt::GetCurFolder(LPITEMIDLIST *ppidl)
|
||||
{
|
||||
if (ppidl && m_Folder)
|
||||
{
|
||||
*ppidl = ILClone(m_Folder);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
|
||||
// *** IPersistFolder methods ***
|
||||
STDMETHODIMP CFontExt::Initialize(LPCITEMIDLIST pidl)
|
||||
{
|
||||
WCHAR PidlPath[MAX_PATH + 1] = {0}, Expected[MAX_PATH + 1];
|
||||
if (!SHGetPathFromIDListW(pidl, PidlPath))
|
||||
{
|
||||
ERR("Unable to extract path from pidl\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, Expected);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
ERR("Unable to get fonts path (0x%x)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (_wcsicmp(PidlPath, Expected))
|
||||
{
|
||||
ERR("CFontExt View initializing on unexpected folder: '%S'\n", PidlPath);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
m_Folder.Attach(ILClone(pidl));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// *** IPersist methods ***
|
||||
STDMETHODIMP CFontExt::GetClassID(CLSID *lpClassId)
|
||||
{
|
||||
*lpClassId = CLSID_CFontExt;
|
||||
return S_OK;
|
||||
}
|
||||
|
84
dll/shellext/fontext/CFontExt.hpp
Normal file
84
dll/shellext/fontext/CFontExt.hpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: CFontExt definition
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class CFontExt :
|
||||
public CComCoClass<CFontExt, &CLSID_CFontExt>,
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
public IShellFolder2,
|
||||
public IPersistFolder2
|
||||
{
|
||||
CComHeapPtr<ITEMIDLIST> m_Folder;
|
||||
|
||||
public:
|
||||
|
||||
CFontExt();
|
||||
~CFontExt();
|
||||
|
||||
// *** IShellFolder2 methods ***
|
||||
virtual STDMETHODIMP GetDefaultSearchGUID(GUID *lpguid);
|
||||
virtual STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum);
|
||||
virtual STDMETHODIMP GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay);
|
||||
virtual STDMETHODIMP GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags);
|
||||
virtual STDMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv);
|
||||
virtual STDMETHODIMP GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd);
|
||||
virtual STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid);
|
||||
|
||||
// *** IShellFolder methods ***
|
||||
virtual STDMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes);
|
||||
virtual STDMETHODIMP EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList);
|
||||
virtual STDMETHODIMP BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut);
|
||||
virtual STDMETHODIMP BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut);
|
||||
virtual STDMETHODIMP CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2);
|
||||
virtual STDMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut);
|
||||
virtual STDMETHODIMP GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut);
|
||||
virtual STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
|
||||
virtual STDMETHODIMP GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet);
|
||||
virtual STDMETHODIMP SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut);
|
||||
|
||||
|
||||
// *** IPersistFolder2 methods ***
|
||||
virtual STDMETHODIMP GetCurFolder(LPITEMIDLIST *ppidl);
|
||||
|
||||
// *** IPersistFolder methods ***
|
||||
virtual STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
|
||||
|
||||
// *** IPersist methods ***
|
||||
virtual STDMETHODIMP GetClassID(CLSID *lpClassId);
|
||||
|
||||
|
||||
#if 0
|
||||
static HRESULT WINAPI log_stuff(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw)
|
||||
{
|
||||
WCHAR* g2s(REFCLSID iid);
|
||||
|
||||
WCHAR buffer[MAX_PATH];
|
||||
StringCchPrintfW(buffer, _countof(buffer), L"CFontExt::QueryInterface(%s)\n", g2s(riid));
|
||||
OutputDebugStringW(buffer);
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_REGISTRY_RESOURCEID(IDR_FONTEXT)
|
||||
DECLARE_NOT_AGGREGATABLE(CFontExt)
|
||||
|
||||
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||
|
||||
BEGIN_COM_MAP(CFontExt)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
|
||||
//COM_INTERFACE_ENTRY_FUNC_BLIND(0, log_stuff)
|
||||
END_COM_MAP()
|
||||
};
|
180
dll/shellext/fontext/CFontMenu.cpp
Normal file
180
dll/shellext/fontext/CFontMenu.cpp
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* 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 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
|
||||
|
||||
|
||||
static inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida)
|
||||
{
|
||||
return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]);
|
||||
}
|
||||
|
||||
static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i)
|
||||
{
|
||||
return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]);
|
||||
}
|
||||
|
||||
static CLIPFORMAT g_cfHIDA;
|
||||
HRESULT _GetCidlFromDataObject(IDataObject *pDataObject, CIDA** ppcida)
|
||||
{
|
||||
if (g_cfHIDA == NULL)
|
||||
{
|
||||
g_cfHIDA = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
|
||||
}
|
||||
|
||||
FORMATETC fmt = { g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM medium;
|
||||
|
||||
HRESULT hr = pDataObject->GetData(&fmt, &medium);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
LPVOID lpSrc = GlobalLock(medium.hGlobal);
|
||||
SIZE_T cbSize = GlobalSize(medium.hGlobal);
|
||||
|
||||
*ppcida = (CIDA *)::CoTaskMemAlloc(cbSize);
|
||||
if (*ppcida)
|
||||
{
|
||||
memcpy(*ppcida, lpSrc, cbSize);
|
||||
hr = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_FAIL;
|
||||
}
|
||||
ReleaseStgMedium(&medium);
|
||||
return hr;
|
||||
}
|
||||
|
||||
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(fontEntry);
|
||||
if (!Path.IsEmpty())
|
||||
{
|
||||
if (PathIsRelativeW(Path))
|
||||
{
|
||||
WCHAR FontsDir[MAX_PATH];
|
||||
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, FontsDir);
|
||||
if (!FAILED_UNEXPECTEDLY(hr))
|
||||
{
|
||||
StringCchCatW(FontsDir, _countof(FontsDir), L"\\");
|
||||
Path = FontsDir + Path;
|
||||
}
|
||||
}
|
||||
|
||||
// '/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 can handle
|
||||
if (wParam == 0)
|
||||
{
|
||||
CComHeapPtr<CIDA> cida;
|
||||
HRESULT hr = _GetCidlFromDataObject(pdtobj, &cida);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
for (UINT n = 0; n < cida->cidl; ++n)
|
||||
{
|
||||
const FontPidlEntry* fontEntry = _FontFromIL(HIDA_GetPIDLItem(cida, n));
|
||||
RunFontViewer(hwnd, fontEntry);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,18 +1,38 @@
|
|||
|
||||
add_definitions(
|
||||
-D_ATL_NO_EXCEPTIONS)
|
||||
|
||||
remove_definitions(-D_WIN32_WINNT=0x502 -DWINVER=0x502)
|
||||
add_definitions(-D_WIN32_WINNT=0x601 -DWINVER=0x601)
|
||||
|
||||
set_cpp(WITH_RUNTIME)
|
||||
|
||||
spec2def(fontext.dll fontext.spec)
|
||||
|
||||
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/atl)
|
||||
|
||||
list(APPEND SOURCE
|
||||
fontext.c
|
||||
regsvr.c
|
||||
fontext.h)
|
||||
CDataObject.cpp
|
||||
CEnumFonts.cpp
|
||||
CFontCache.cpp
|
||||
CFontCache.hpp
|
||||
CFontExt.cpp
|
||||
CFontExt.hpp
|
||||
CFontMenu.cpp
|
||||
fontext.cpp
|
||||
fontpidl.cpp
|
||||
fontpidl.hpp
|
||||
precomp.h)
|
||||
|
||||
add_library(fontext MODULE
|
||||
${SOURCE}
|
||||
fontext.rc
|
||||
fontext.spec
|
||||
${CMAKE_CURRENT_BINARY_DIR}/fontext.def)
|
||||
|
||||
set_module_type(fontext win32dll UNICODE)
|
||||
target_link_libraries(fontext uuid)
|
||||
add_importlibs(fontext user32 gdi32 ole32 shlwapi lz32 advapi32 setupapi msvcrt kernel32 ntdll)
|
||||
add_pch(fontext fontext.h SOURCE)
|
||||
target_link_libraries(fontext uuid wine)
|
||||
add_delay_importlibs(fontext ole32 oleaut32 shlwapi)
|
||||
add_importlibs(fontext shell32 advapi32 user32 msvcrt kernel32 ntdll)
|
||||
add_pch(fontext precomp.h SOURCE)
|
||||
add_cd_file(TARGET fontext DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* PROJECT: fontext.dll
|
||||
* FILE: dll/shellext/fontext/fontext.c
|
||||
* PURPOSE: fontext.dll
|
||||
* PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
|
||||
* UPDATE HISTORY:
|
||||
* 10-06-2008 Created
|
||||
*/
|
||||
|
||||
#include "fontext.h"
|
||||
|
||||
#include <winbase.h>
|
||||
#include <debug.h>
|
||||
|
||||
static HINSTANCE hInstance;
|
||||
|
||||
HRESULT WINAPI
|
||||
DllCanUnloadNow(VOID)
|
||||
{
|
||||
DPRINT1("DllCanUnloadNow() stubs\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
DllGetClassObject(REFCLSID rclsid,
|
||||
REFIID riid,
|
||||
LPVOID *ppv)
|
||||
{
|
||||
DPRINT1("DllGetClassObject() stubs\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DllMain(HINSTANCE hinstDLL,
|
||||
DWORD dwReason,
|
||||
LPVOID lpvReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
hInstance = hinstDLL;
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
120
dll/shellext/fontext/fontext.cpp
Normal file
120
dll/shellext/fontext/fontext.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Shell extension entry point
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fontext);
|
||||
|
||||
const GUID CLSID_CFontExt = { 0xbd84b380, 0x8ca2, 0x1069, { 0xab, 0x1d, 0x08, 0x00, 0x09, 0x48, 0xf5, 0x34 } };
|
||||
|
||||
|
||||
class CFontExtModule : public CComModule
|
||||
{
|
||||
public:
|
||||
void Init(_ATL_OBJMAP_ENTRY *p, HINSTANCE h, const GUID *plibid)
|
||||
{
|
||||
g_FontCache = new CFontCache();
|
||||
CComModule::Init(p, h, plibid);
|
||||
}
|
||||
|
||||
void Term()
|
||||
{
|
||||
delete g_FontCache;
|
||||
g_FontCache = NULL;
|
||||
CComModule::Term();
|
||||
}
|
||||
};
|
||||
|
||||
BEGIN_OBJECT_MAP(ObjectMap)
|
||||
OBJECT_ENTRY(CLSID_CFontExt, CFontExt)
|
||||
END_OBJECT_MAP()
|
||||
|
||||
|
||||
LONG g_ModuleRefCnt;
|
||||
CFontExtModule gModule;
|
||||
|
||||
|
||||
STDAPI DllCanUnloadNow()
|
||||
{
|
||||
if (g_ModuleRefCnt)
|
||||
return S_FALSE;
|
||||
return gModule.DllCanUnloadNow();
|
||||
}
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
|
||||
{
|
||||
return gModule.DllGetClassObject(rclsid, riid, ppv);
|
||||
}
|
||||
|
||||
|
||||
STDAPI DllRegisterServer()
|
||||
{
|
||||
WCHAR Path[MAX_PATH] = { 0 };
|
||||
static const char DesktopIniContents[] = "[.ShellClassInfo]\r\nCLSID={BD84B380-8CA2-1069-AB1D-08000948F534}\r\n";
|
||||
HANDLE hFile;
|
||||
HRESULT hr;
|
||||
|
||||
hr = gModule.DllRegisterServer(FALSE);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, Path);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
// Make this a system folder:
|
||||
// Ideally this should not be done here, but when installing
|
||||
// Otherwise, livecd won't have this set properly
|
||||
DWORD dwAttributes = GetFileAttributesW(Path);
|
||||
if (dwAttributes != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
dwAttributes |= FILE_ATTRIBUTE_SYSTEM;
|
||||
SetFileAttributesW(Path, dwAttributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Unable to get attributes for fonts folder (%d)\n", GetLastError());
|
||||
}
|
||||
|
||||
if (!PathAppendW(Path, L"desktop.ini"))
|
||||
return E_FAIL;
|
||||
|
||||
hFile = CreateFileW(Path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
DWORD BytesWritten, BytesToWrite = strlen(DesktopIniContents);
|
||||
if (WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL))
|
||||
hr = (BytesToWrite == BytesWritten) ? S_OK : E_FAIL;
|
||||
else
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDAPI DllUnregisterServer()
|
||||
{
|
||||
return gModule.DllUnregisterServer(FALSE);
|
||||
}
|
||||
|
||||
|
||||
EXTERN_C
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
gModule.Init(ObjectMap, hInstance, NULL);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
gModule.Term();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -1,11 +1,24 @@
|
|||
#ifndef _FONTEXT_PCH_
|
||||
#define _FONTEXT_PCH_
|
||||
#ifndef FONTEXT_PRECOMP_H
|
||||
#define FONTEXT_PRECOMP_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#define COBJMACROS
|
||||
#define _INC_WINDOWS
|
||||
#define COM_NO_WINDOWS_H
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <shlobj.h>
|
||||
#include <tchar.h>
|
||||
#include <strsafe.h>
|
||||
#include <atlbase.h>
|
||||
#include <atlcom.h>
|
||||
#include <atlsimpcoll.h>
|
||||
#include <atlstr.h>
|
||||
|
||||
#endif /* _FONTEXT_PCH_ */
|
||||
extern const GUID CLSID_CFontExt;
|
||||
|
||||
#include "CFontExt.hpp"
|
||||
|
||||
|
||||
#endif /* FONTEXT_PRECOMP_H */
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#define REACTOS_STR_ORIGINAL_FILENAME "fontext.dll"
|
||||
#include <reactos/version.rc>
|
||||
|
||||
IDR_FONTEXT REGISTRY "res/fontext.rgs"
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
|
|
38
dll/shellext/fontext/fontpidl.cpp
Normal file
38
dll/shellext/fontext/fontpidl.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: pidl handling
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
LPITEMIDLIST _ILCreate(LPCWSTR lpString, ULONG Index)
|
||||
{
|
||||
// Because the FontPidlEntry contains one WCHAR, we do not need to take the null terminator into account
|
||||
size_t cbData = sizeof(FontPidlEntry) + wcslen(lpString) * sizeof(WCHAR);
|
||||
FontPidlEntry* pidl = (FontPidlEntry*)CoTaskMemAlloc(cbData + sizeof(WORD));
|
||||
if (!pidl)
|
||||
return NULL;
|
||||
|
||||
ZeroMemory(pidl, cbData + sizeof(WORD));
|
||||
|
||||
pidl->cb = (WORD)cbData;
|
||||
pidl->Magic = 'fp';
|
||||
pidl->Index = Index;
|
||||
|
||||
wcscpy(pidl->Name, lpString);
|
||||
// Should be zero already, but make sure it is
|
||||
*(WORD*)((char*)pidl + cbData) = 0;
|
||||
|
||||
return (LPITEMIDLIST)pidl;
|
||||
}
|
||||
|
||||
|
||||
const FontPidlEntry* _FontFromIL(LPCITEMIDLIST pidl)
|
||||
{
|
||||
const FontPidlEntry* zipPidl = (const FontPidlEntry*)pidl;
|
||||
if (zipPidl->Magic == 'fp')
|
||||
return zipPidl;
|
||||
return NULL;
|
||||
}
|
24
dll/shellext/fontext/fontpidl.hpp
Normal file
24
dll/shellext/fontext/fontpidl.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Font Shell Extension
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: pidl handling
|
||||
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pshpack1.h>
|
||||
struct FontPidlEntry
|
||||
{
|
||||
WORD cb;
|
||||
WORD Magic;
|
||||
ULONG Index; // Informative only
|
||||
|
||||
WCHAR Name[1];
|
||||
};
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
LPITEMIDLIST _ILCreate(LPCWSTR lpString, ULONG Index);
|
||||
const FontPidlEntry* _FontFromIL(LPCITEMIDLIST pidl);
|
||||
|
|
@ -6,3 +6,15 @@ STRINGTABLE
|
|||
BEGIN
|
||||
IDS_REACTOS_FONTS_FOLDER "ReactOS Font Folder"
|
||||
END
|
||||
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_COL_NAME "Name"
|
||||
END
|
||||
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_FONT_PREVIEW "Preview"
|
||||
END
|
||||
|
|
39
dll/shellext/fontext/precomp.h
Normal file
39
dll/shellext/fontext/precomp.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef FONTEXT_PRECOMP_H
|
||||
#define FONTEXT_PRECOMP_H
|
||||
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#define COM_NO_WINDOWS_H
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winreg.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <tchar.h>
|
||||
#include <strsafe.h>
|
||||
#include <atlbase.h>
|
||||
#include <atlcom.h>
|
||||
#include <atlcoll.h>
|
||||
#include <atlstr.h>
|
||||
#include <wine/debug.h>
|
||||
#include <shellutils.h>
|
||||
|
||||
extern const GUID CLSID_CFontExt;
|
||||
extern LONG g_ModuleRefCnt;
|
||||
|
||||
#include "resource.h"
|
||||
#include "fontpidl.hpp"
|
||||
#include "CFontCache.hpp"
|
||||
#include "CFontExt.hpp"
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
#endif /* FONTEXT_PRECOMP_H */
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* PROJECT: fontext.dll
|
||||
* FILE: dll/shellext/fontext/regsvr.c
|
||||
* PURPOSE: fontext.dll
|
||||
* PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
|
||||
* UPDATE HISTORY:
|
||||
* 10-06-2008 Created
|
||||
*/
|
||||
|
||||
#include "fontext.h"
|
||||
|
||||
static HRESULT
|
||||
REGSVR_RegisterServer()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
REGSVR_UnregisterServer()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
DllRegisterServer(VOID)
|
||||
{
|
||||
return REGSVR_RegisterServer();
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
DllUnregisterServer(VOID)
|
||||
{
|
||||
return REGSVR_UnregisterServer();
|
||||
}
|
14
dll/shellext/fontext/res/fontext.rgs
Normal file
14
dll/shellext/fontext/res/fontext.rgs
Normal file
|
@ -0,0 +1,14 @@
|
|||
HKCR
|
||||
{
|
||||
NoRemove CLSID
|
||||
{
|
||||
ForceRemove {BD84B380-8CA2-1069-AB1D-08000948F534} = s 'Fonts'
|
||||
{
|
||||
InprocServer32 = s 'fontext.dll'
|
||||
{
|
||||
val ThreadingModel = s 'Apartment'
|
||||
}
|
||||
DefaultIcon = s '%MODULE%'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
|
||||
#define IDS_REACTOS_FONTS_FOLDER 151
|
||||
#define IDS_COL_NAME 301
|
||||
#define IDS_FONT_PREVIEW 401
|
||||
|
||||
#define IDR_FONTEXT 8000
|
||||
|
|
|
@ -62,6 +62,7 @@ AddReg=Classes
|
|||
11,,dplayx.dll,1
|
||||
11,,dsound.dll,1
|
||||
11,,dxdiagn.dll,1
|
||||
11,,fontext.dll,1
|
||||
11,,hhctrl.ocx,1
|
||||
11,,hlink.dll,1
|
||||
11,,hnetcfg.dll,1
|
||||
|
|
Loading…
Reference in a new issue