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