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 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #include "precomp.h" 9 10 WINE_DEFAULT_DEBUG_CHANNEL(fontext); 11 12 13 #if 0 14 static inline void DumpDataObjectFormats(IDataObject* pObject) 15 { 16 CComPtr<IEnumFORMATETC> pEnumFmt; 17 HRESULT hr = pObject->EnumFormatEtc(DATADIR_GET, &pEnumFmt); 18 19 if (FAILED_UNEXPECTEDLY(hr)) 20 return; 21 22 FORMATETC fmt; 23 while (S_OK == pEnumFmt->Next(1, &fmt, NULL)) 24 { 25 char szBuf[512]; 26 GetClipboardFormatNameA(fmt.cfFormat, szBuf, sizeof(szBuf)); 27 ERR("Format: %s\n", szBuf); 28 ERR("Tymed: %u\n", fmt.tymed); 29 if (fmt.tymed & TYMED_HGLOBAL) 30 { 31 ERR("TYMED_HGLOBAL supported\n"); 32 } 33 } 34 } 35 #endif 36 37 38 HRESULT _CDataObject_CreateInstance(PCIDLIST_ABSOLUTE folder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 39 REFIID riid, LPVOID* ppvOut) 40 { 41 HRESULT hr = CIDLData_CreateFromIDArray(folder, cidl, apidl, (IDataObject**)ppvOut); 42 if (FAILED_UNEXPECTEDLY(hr)) 43 return hr; 44 45 // Now that we have an IDataObject with the shell itemid list (CFSTR_SHELLIDLIST, aka HIDA) format 46 // we will augment this IDataObject with the CF_HDROP format. (Full filepaths) 47 // This enabled the objects for the 'copy' and drag to copy actions 48 WCHAR FontsDir[MAX_PATH]; 49 hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, FontsDir); 50 if (FAILED_UNEXPECTEDLY(hr)) 51 return S_OK; 52 StringCchCatW(FontsDir, _countof(FontsDir), L"\\"); 53 54 CComHeapPtr<BYTE> data; 55 56 // First we allocate room for the DROPFILES structure 57 data.AllocateBytes(sizeof(DROPFILES)); 58 UINT offset = sizeof(DROPFILES); 59 60 // Then we walk all files 61 for (UINT n = 0; n < cidl; ++n) 62 { 63 const FontPidlEntry* fontEntry = _FontFromIL(apidl[n]); 64 if (fontEntry) 65 { 66 CStringW File = g_FontCache->Filename(fontEntry); 67 if (!File.IsEmpty()) 68 { 69 // Ensure this is a full path 70 if (PathIsRelativeW(File)) 71 { 72 File = FontsDir + File; 73 } 74 75 // Now append the path (+ nullterminator) to the buffer 76 UINT len = offset + (File.GetLength() + 1) * sizeof(WCHAR); 77 data.ReallocateBytes(len); 78 if (!data) 79 { 80 ERR("Unable to allocate memory for the CF_HDROP\n"); 81 return hr; 82 } 83 BYTE* dataPtr = data; 84 StringCbCopyW((STRSAFE_LPWSTR)(dataPtr + offset), len - offset, File); 85 offset = len; 86 } 87 else 88 { 89 ERR("No file found for %S\n", fontEntry->Name); 90 } 91 } 92 } 93 94 // Append the final nullterminator (double null terminated list) 95 data.ReallocateBytes(offset + sizeof(UNICODE_NULL)); 96 LPWSTR str = (LPWSTR)((BYTE*)data + offset); 97 *str = UNICODE_NULL; 98 offset += sizeof(UNICODE_NULL); 99 100 // Fill in the required fields 101 DROPFILES* pDrop = (DROPFILES*)(BYTE*)data; 102 pDrop->fWide = 1; 103 pDrop->pFiles = sizeof(DROPFILES); 104 // Zero out the rest 105 pDrop->pt.x = pDrop->pt.y = 0; 106 pDrop-> fNC = NULL; 107 108 // Prepare the format descriptors 109 STGMEDIUM medium = {0}; 110 medium.tymed = TYMED_HGLOBAL; 111 112 // Copy the data to an HGLOBAL 113 medium.hGlobal = GlobalAlloc(GHND, offset); 114 if (medium.hGlobal) 115 { 116 LPVOID blob = GlobalLock(medium.hGlobal); 117 if (blob) 118 { 119 CopyMemory(blob, (BYTE*)data, offset); 120 GlobalUnlock(medium.hGlobal); 121 122 CComPtr<IDataObject> spDataObject(*(IDataObject**)ppvOut); 123 if (spDataObject) 124 { 125 FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 126 hr = spDataObject->SetData(&etc, &medium, TRUE); 127 } 128 } 129 else 130 { 131 ERR("Unable to lock the hGlobal?!\n"); 132 } 133 } 134 else 135 { 136 ERR("Unable to allocate %u bytes for the hGlobal\n", offset); 137 } 138 139 return hr; 140 } 141 142