[FONTEXT] Initial implementation
[reactos.git] / dll / shellext / fontext / CDataObject.cpp
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