iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IGraphicsWin_dnd.h
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
13#include "IPlugLogger.h"
14
15BEGIN_IPLUG_NAMESPACE
16BEGIN_IGRAPHICS_NAMESPACE
17
18namespace DragAndDropHelpers
19{
20class DropSource : public IDropSource
21{
22public:
23 DropSource() {}
25 {
26 assert(mRefCount == 0);
27 }
28
29 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID refiid, void** resultHandle) override
30 {
31 if (refiid == IID_IDropSource)
32 {
33 *resultHandle = this;
34 AddRef();
35 return S_OK;
36 }
37 *resultHandle = nullptr;
38 return E_NOINTERFACE;
39 }
40
41 ULONG STDMETHODCALLTYPE AddRef () override { return ++mRefCount; }
42 ULONG STDMETHODCALLTYPE Release() override
43 {
44 int refCount = --mRefCount;
45 assert(refCount >= 0);
46 if (refCount <= 0)
47 {
48 delete this;
49 }
50 return refCount;
51 }
52
53 // IDropSource methods
54 HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL escapeKeyPressed, DWORD grfKeyState) override
55 {
56 if (escapeKeyPressed == TRUE)
57 {
58 DBGMSG("DropSource: escapeKeyPressed, abort dnd\n");
59 return DRAGDROP_S_CANCEL;
60 }
61
62 if ((grfKeyState & MK_LBUTTON) == 0)
63 {
64 return DRAGDROP_S_DROP;
65 }
66 return S_OK;
67 }
68
69 HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD /*dwEffect*/) override
70 {
71 return DRAGDROP_S_USEDEFAULTCURSORS;
72 }
73private:
74 int mRefCount = 1;
75};
76
77static void deepFormatCopy(FORMATETC& dest, const FORMATETC& source)
78{
79 dest = source;
80 if (source.ptd != nullptr)
81 {
82 dest.ptd = (DVTARGETDEVICE*) CoTaskMemAlloc (sizeof (DVTARGETDEVICE));
83 if (dest.ptd != nullptr)
84 {
85 *(dest.ptd) = *(source.ptd);
86 }
87 }
88}
89
90// Enum class, seems necessary for some reason
91struct EnumFORMATETC final : public IEnumFORMATETC
92{
93 EnumFORMATETC (const FORMATETC* f) : mFormatPtr (f) {}
95
96 ULONG STDMETHODCALLTYPE AddRef(void) { return ++mRefCount; }
97 ULONG STDMETHODCALLTYPE Release(void)
98 {
99 int refCount = --mRefCount;
100 assert(refCount >= 0);
101 if(refCount <= 0) {
102 delete this;
103 }
104 return refCount;
105 }
106
107 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID refiid, void **resultHandle)
108 {
109 if (refiid == IID_IEnumFORMATETC)
110 {
111 AddRef();
112 *resultHandle = this;
113 return S_OK;
114 }
115 *resultHandle = nullptr;
116 return E_NOINTERFACE;
117 }
118
119 HRESULT Clone (IEnumFORMATETC** resultHandle) override
120 {
121 if (resultHandle == nullptr)
122 {
123 return E_POINTER;
124 }
125 EnumFORMATETC* copyObj = new EnumFORMATETC(mFormatPtr);
126 copyObj->mCounter = mCounter;
127 *resultHandle = copyObj;
128 return S_OK;
129 }
130
131 HRESULT Next (ULONG celt, FORMATETC *pFormat, ULONG* pceltFetched) override
132 {
133 if (pceltFetched != nullptr)
134 {
135 *pceltFetched = 0;
136 }
137 else if (celt != 1)
138 {
139 return S_FALSE;
140 }
141
142 if (mCounter == 0 && celt > 0 && pFormat != nullptr)
143 {
144 deepFormatCopy(pFormat[0], *mFormatPtr);
145 mCounter++;
146 if (pceltFetched != nullptr)
147 {
148 *pceltFetched = 1;
149 }
150 return S_OK;
151 }
152 return S_FALSE;
153 }
154
155 HRESULT Skip (ULONG celt) override
156 {
157 if (mCounter + (int) celt >= 1)
158 {
159 return S_FALSE;
160 }
161 mCounter += (int) celt;
162 return S_OK;
163 }
164
165 HRESULT Reset() override
166 {
167 mCounter = 0;
168 return S_OK;
169 }
170
171private:
172 int mRefCount = 1;
173 const FORMATETC* const mFormatPtr;
174 int mCounter = 0;
175};
176
177// Object that carries the DnD payload. TODO: also support text/string?
178class DataObject : public IDataObject
179{
180public:
181 DataObject(const FORMATETC* f, const char *filePath) : mFormatPtr (f)
182 {
183 mFilePath = filePath;
184 }
185
186 virtual ~DataObject()
187 {
188 assert(mRefCount == 0);
189 }
190
191 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID refiid, void **resultHandle)
192 {
193 if (refiid == IID_IDataObject || refiid == IID_IUnknown)
194 { // note: it seems that IUnknown must be supported here, don't know why
195 AddRef();
196 *resultHandle=this;
197 return S_OK;
198 }
199 *resultHandle = NULL;
200 return E_NOINTERFACE;
201 }
202
203 ULONG STDMETHODCALLTYPE AddRef() { return ++mRefCount; }
204 ULONG STDMETHODCALLTYPE Release()
205 {
206 int refCount = --mRefCount;
207 assert(mRefCount>=0);
208 if (mRefCount<=0)
209 {
210 delete this;
211 }
212 return refCount;
213 }
214
215 bool acceptFormat(FORMATETC *f)
216 {
217 return (f->dwAspect & DVASPECT_CONTENT) && (f->tymed & TYMED_HGLOBAL) && (f->cfFormat == CF_HDROP);
218 }
219
220 HRESULT STDMETHODCALLTYPE GetData(FORMATETC *pFormat, STGMEDIUM *pMedium)
221 {
222 if (pFormat == nullptr)
223 {
224 return E_INVALIDARG;
225 }
226
227 if (acceptFormat(pFormat) == false)
228 {
229 return DV_E_FORMATETC;
230 }
231
232 UTF8AsUTF16 pathWide(mFilePath.c_str());
233 // GHND ensures that the memory is zeroed
234 HDROP hGlobal = (HDROP)GlobalAlloc(GHND, sizeof(DROPFILES) + (sizeof(wchar_t) * (pathWide.GetLength() + 2)));
235
236 if (!hGlobal)
237 {
238 DBGMSG("DataObject::GetData ERROR: GlobalAlloc returned null, aborting.\n");
239 return false;
240 }
241
242 DROPFILES* pDropFiles = (DROPFILES*) GlobalLock(hGlobal);
243 if (!pDropFiles)
244 {
245 DBGMSG("DataObject::GetData ERROR: GlobalLock returned null, aborting.\n");
246 return false;
247 }
248 // Populate the dropfile structure and copy the file path
249 pDropFiles->pFiles = sizeof(DROPFILES);
250 pDropFiles->fWide = true;
251 std::copy_n(pathWide.Get(), pathWide.GetLength(), reinterpret_cast<wchar_t*>(&pDropFiles[1]));
252
253 // not sure if this is necessary to set the medium but why not
254 pMedium->tymed = TYMED_HGLOBAL;
255 pMedium->hGlobal = hGlobal;
256 pMedium->pUnkForRelease = nullptr;
257
258 GlobalUnlock(hGlobal);
259
260 return S_OK;
261 }
262
263 HRESULT STDMETHODCALLTYPE QueryGetData( FORMATETC *pFormat )
264 {
265 if (pFormat == nullptr)
266 {
267 return E_INVALIDARG;
268 }
269
270 if (acceptFormat(pFormat) == false)
271 {
272 return DV_E_FORMATETC;
273 }
274
275 return S_OK;
276 }
277
278 HRESULT GetCanonicalFormatEtc(FORMATETC*, FORMATETC* pFormatOut) override
279 {
280 pFormatOut->ptd = nullptr;
281 return E_NOTIMPL;
282 }
283
284 HRESULT EnumFormatEtc(DWORD direction, IEnumFORMATETC** resultHandle) override
285 {
286 if (!resultHandle)
287 {
288 return E_POINTER;
289 }
290 if (direction == DATADIR_GET)
291 {
292 *resultHandle = new EnumFORMATETC(mFormatPtr);
293 return S_OK;
294 }
295 *resultHandle = nullptr;
296 return E_NOTIMPL;
297 }
298
299 // unimplemented (unnecessary?) functions
300 HRESULT STDMETHODCALLTYPE GetDataHere(FORMATETC*, STGMEDIUM*) { return E_NOTIMPL; }
301 HRESULT STDMETHODCALLTYPE SetData(FORMATETC*, STGMEDIUM*, BOOL) { return E_NOTIMPL; }
302 HRESULT STDMETHODCALLTYPE DAdvise(FORMATETC*, DWORD, IAdviseSink*, DWORD*) { return E_NOTIMPL; }
303 HRESULT STDMETHODCALLTYPE DUnadvise(DWORD) { return E_NOTIMPL; }
304 HRESULT STDMETHODCALLTYPE EnumDAdvise(IEnumSTATDATA**) { return E_NOTIMPL; }
305private:
306 int mRefCount = 1;
307 std::string mFilePath;
308 const FORMATETC* const mFormatPtr;
309};
310} // end of DragAndDropHelpers namespace
311
312END_IGRAPHICS_NAMESPACE
313END_IPLUG_NAMESPACE
IPlug logging a.k.a tracing functionality.