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