1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qwindowsole.h"
41 #include "qwindowsmime.h"
42 #include "qwindowscontext.h"
43 \
44 #include <QtGui/qevent.h>
45 #include <QtGui/qwindow.h>
46 #include <QtGui/qpainter.h>
47 #include <QtGui/qcursor.h>
48 #include <QtGui/qguiapplication.h>
49
50 #include <QtCore/qmimedata.h>
51 #include <QtCore/qdebug.h>
52
53 #include <shlobj.h>
54
55 QT_BEGIN_NAMESPACE
56
57 /*!
58 \class QWindowsOleDataObject
59 \brief OLE data container
60
61 The following methods are NOT supported for data transfer using the
62 clipboard or drag-drop:
63 \list
64 \li IDataObject::SetData -- return E_NOTIMPL
65 \li IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED
66 \li ::DUnadvise
67 \li ::EnumDAdvise
68 \li IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
69 (NOTE: must set pformatetcOut->ptd = NULL)
70 \endlist
71
72 \internal
73 */
74
QWindowsOleDataObject(QMimeData * mimeData)75 QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) :
76 data(mimeData),
77 CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT))
78 {
79 qCDebug(lcQpaMime) << __FUNCTION__ << mimeData->formats();
80 }
81
82 QWindowsOleDataObject::~QWindowsOleDataObject() = default;
83
releaseQt()84 void QWindowsOleDataObject::releaseQt()
85 {
86 data = nullptr;
87 }
88
mimeData() const89 QMimeData *QWindowsOleDataObject::mimeData() const
90 {
91 return data.data();
92 }
93
reportedPerformedEffect() const94 DWORD QWindowsOleDataObject::reportedPerformedEffect() const
95 {
96 return performedEffect;
97 }
98
99 STDMETHODIMP
GetData(LPFORMATETC pformatetc,LPSTGMEDIUM pmedium)100 QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
101 {
102 HRESULT hr = ResultFromScode(DATA_E_FORMATETC);
103
104 if (data) {
105 const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
106 if (QWindowsMime *converter = mc.converterFromMime(*pformatetc, data))
107 if (converter->convertFromMime(*pformatetc, data, pmedium))
108 hr = ResultFromScode(S_OK);
109 }
110
111 if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled())
112 qCDebug(lcQpaMime) <<__FUNCTION__ << *pformatetc << "returns" << Qt::hex << Qt::showbase << quint64(hr);
113
114 return hr;
115 }
116
117 STDMETHODIMP
GetDataHere(LPFORMATETC,LPSTGMEDIUM)118 QWindowsOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM)
119 {
120 return ResultFromScode(DATA_E_FORMATETC);
121 }
122
123 STDMETHODIMP
QueryGetData(LPFORMATETC pformatetc)124 QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc)
125 {
126 HRESULT hr = ResultFromScode(DATA_E_FORMATETC);
127
128 if (QWindowsContext::verbose > 1)
129 qCDebug(lcQpaMime) << __FUNCTION__;
130
131 if (data) {
132 const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
133 hr = mc.converterFromMime(*pformatetc, data) ?
134 ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
135 }
136 if (QWindowsContext::verbose > 1)
137 qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << Qt::hex << int(hr);
138 return hr;
139 }
140
141 STDMETHODIMP
GetCanonicalFormatEtc(LPFORMATETC,LPFORMATETC pformatetcOut)142 QWindowsOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut)
143 {
144 pformatetcOut->ptd = nullptr;
145 return ResultFromScode(E_NOTIMPL);
146 }
147
148 STDMETHODIMP
SetData(LPFORMATETC pFormatetc,STGMEDIUM * pMedium,BOOL fRelease)149 QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease)
150 {
151 if (QWindowsContext::verbose > 1)
152 qCDebug(lcQpaMime) << __FUNCTION__;
153
154 HRESULT hr = ResultFromScode(E_NOTIMPL);
155
156 if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) {
157 auto * val = (DWORD*)GlobalLock(pMedium->hGlobal);
158 performedEffect = *val;
159 GlobalUnlock(pMedium->hGlobal);
160 if (fRelease)
161 ReleaseStgMedium(pMedium);
162 hr = ResultFromScode(S_OK);
163 }
164 if (QWindowsContext::verbose > 1)
165 qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << Qt::hex << int(hr);
166 return hr;
167 }
168
169
170 STDMETHODIMP
EnumFormatEtc(DWORD dwDirection,LPENUMFORMATETC FAR * ppenumFormatEtc)171 QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
172 {
173 if (QWindowsContext::verbose > 1)
174 qCDebug(lcQpaMime) << __FUNCTION__ << "dwDirection=" << dwDirection;
175
176 if (!data)
177 return ResultFromScode(DATA_E_FORMATETC);
178
179 SCODE sc = S_OK;
180
181 QVector<FORMATETC> fmtetcs;
182 if (dwDirection == DATADIR_GET) {
183 QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
184 fmtetcs = mc.allFormatsForMime(data);
185 } else {
186 FORMATETC formatetc;
187 formatetc.cfFormat = CLIPFORMAT(CF_PERFORMEDDROPEFFECT);
188 formatetc.dwAspect = DVASPECT_CONTENT;
189 formatetc.lindex = -1;
190 formatetc.ptd = nullptr;
191 formatetc.tymed = TYMED_HGLOBAL;
192 fmtetcs.append(formatetc);
193 }
194
195 auto *enumFmtEtc = new QWindowsOleEnumFmtEtc(fmtetcs);
196 *ppenumFormatEtc = enumFmtEtc;
197 if (enumFmtEtc->isNull()) {
198 delete enumFmtEtc;
199 *ppenumFormatEtc = nullptr;
200 sc = E_OUTOFMEMORY;
201 }
202
203 return ResultFromScode(sc);
204 }
205
206 STDMETHODIMP
DAdvise(FORMATETC FAR *,DWORD,LPADVISESINK,DWORD FAR *)207 QWindowsOleDataObject::DAdvise(FORMATETC FAR*, DWORD,
208 LPADVISESINK, DWORD FAR*)
209 {
210 return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
211 }
212
213
214 STDMETHODIMP
DUnadvise(DWORD)215 QWindowsOleDataObject::DUnadvise(DWORD)
216 {
217 return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
218 }
219
220 STDMETHODIMP
EnumDAdvise(LPENUMSTATDATA FAR *)221 QWindowsOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
222 {
223 return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
224 }
225
226 /*!
227 \class QWindowsOleEnumFmtEtc
228 \brief Enumerates the FORMATETC structures supported by QWindowsOleDataObject.
229 \internal
230 */
231
QWindowsOleEnumFmtEtc(const QVector<FORMATETC> & fmtetcs)232 QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs)
233 {
234 if (QWindowsContext::verbose > 1)
235 qCDebug(lcQpaMime) << __FUNCTION__ << fmtetcs;
236 m_lpfmtetcs.reserve(fmtetcs.count());
237 for (int idx = 0; idx < fmtetcs.count(); ++idx) {
238 auto destetc = new FORMATETC();
239 if (copyFormatEtc(destetc, &(fmtetcs.at(idx)))) {
240 m_lpfmtetcs.append(destetc);
241 } else {
242 m_isNull = true;
243 delete destetc;
244 break;
245 }
246 }
247 }
248
QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> & lpfmtetcs)249 QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs)
250 {
251 if (QWindowsContext::verbose > 1)
252 qCDebug(lcQpaMime) << __FUNCTION__;
253 m_lpfmtetcs.reserve(lpfmtetcs.count());
254 for (int idx = 0; idx < lpfmtetcs.count(); ++idx) {
255 LPFORMATETC srcetc = lpfmtetcs.at(idx);
256 auto destetc = new FORMATETC();
257 if (copyFormatEtc(destetc, srcetc)) {
258 m_lpfmtetcs.append(destetc);
259 } else {
260 m_isNull = true;
261 delete destetc;
262 break;
263 }
264 }
265 }
266
~QWindowsOleEnumFmtEtc()267 QWindowsOleEnumFmtEtc::~QWindowsOleEnumFmtEtc()
268 {
269 LPMALLOC pmalloc;
270
271 if (CoGetMalloc(MEMCTX_TASK, &pmalloc) == NOERROR) {
272 for (int idx = 0; idx < m_lpfmtetcs.count(); ++idx) {
273 LPFORMATETC tmpetc = m_lpfmtetcs.at(idx);
274 if (tmpetc->ptd)
275 pmalloc->Free(tmpetc->ptd);
276 delete tmpetc;
277 }
278
279 pmalloc->Release();
280 }
281 m_lpfmtetcs.clear();
282 }
283
isNull() const284 bool QWindowsOleEnumFmtEtc::isNull() const
285 {
286 return m_isNull;
287 }
288
289 // IEnumFORMATETC methods
290 STDMETHODIMP
Next(ULONG celt,LPFORMATETC rgelt,ULONG FAR * pceltFetched)291 QWindowsOleEnumFmtEtc::Next(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched)
292 {
293 ULONG i=0;
294 ULONG nOffset;
295
296 if (rgelt == nullptr)
297 return ResultFromScode(E_INVALIDARG);
298
299 while (i < celt) {
300 nOffset = m_nIndex + i;
301
302 if (nOffset < ULONG(m_lpfmtetcs.count())) {
303 copyFormatEtc(rgelt + i, m_lpfmtetcs.at(int(nOffset)));
304 i++;
305 } else {
306 break;
307 }
308 }
309
310 m_nIndex += i;
311
312 if (pceltFetched != nullptr)
313 *pceltFetched = i;
314
315 if (i != celt)
316 return ResultFromScode(S_FALSE);
317
318 return NOERROR;
319 }
320
321 STDMETHODIMP
Skip(ULONG celt)322 QWindowsOleEnumFmtEtc::Skip(ULONG celt)
323 {
324 ULONG i=0;
325 ULONG nOffset;
326
327 while (i < celt) {
328 nOffset = m_nIndex + i;
329
330 if (nOffset < ULONG(m_lpfmtetcs.count())) {
331 i++;
332 } else {
333 break;
334 }
335 }
336
337 m_nIndex += i;
338
339 if (i != celt)
340 return ResultFromScode(S_FALSE);
341
342 return NOERROR;
343 }
344
345 STDMETHODIMP
Reset()346 QWindowsOleEnumFmtEtc::Reset()
347 {
348 m_nIndex = 0;
349 return NOERROR;
350 }
351
352 STDMETHODIMP
Clone(LPENUMFORMATETC FAR * newEnum)353 QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum)
354 {
355 if (newEnum == nullptr)
356 return ResultFromScode(E_INVALIDARG);
357
358 auto *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs);
359 result->m_nIndex = m_nIndex;
360
361 if (result->isNull()) {
362 delete result;
363 return ResultFromScode(E_OUTOFMEMORY);
364 }
365
366 *newEnum = result;
367 return NOERROR;
368 }
369
copyFormatEtc(LPFORMATETC dest,const FORMATETC * src) const370 bool QWindowsOleEnumFmtEtc::copyFormatEtc(LPFORMATETC dest, const FORMATETC *src) const
371 {
372 if (dest == nullptr || src == nullptr)
373 return false;
374
375 *dest = *src;
376
377 if (src->ptd) {
378 LPMALLOC pmalloc;
379
380 if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR)
381 return false;
382
383 pmalloc->Alloc(src->ptd->tdSize);
384 memcpy(dest->ptd, src->ptd, size_t(src->ptd->tdSize));
385
386 pmalloc->Release();
387 }
388
389 return true;
390 }
391
392 QT_END_NAMESPACE
393