juce_win32_DragAndDrop.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. namespace DragAndDropHelpers
  18. {
  19. //==============================================================================
  20. class JuceDropSource : public ComBaseClassHelper <IDropSource>
  21. {
  22. public:
  23. JuceDropSource() {}
  24. JUCE_COMRESULT QueryContinueDrag (BOOL escapePressed, DWORD keys)
  25. {
  26. if (escapePressed)
  27. return DRAGDROP_S_CANCEL;
  28. if ((keys & (MK_LBUTTON | MK_RBUTTON)) == 0)
  29. return DRAGDROP_S_DROP;
  30. return S_OK;
  31. }
  32. JUCE_COMRESULT GiveFeedback (DWORD)
  33. {
  34. return DRAGDROP_S_USEDEFAULTCURSORS;
  35. }
  36. };
  37. //==============================================================================
  38. class JuceEnumFormatEtc : public ComBaseClassHelper <IEnumFORMATETC>
  39. {
  40. public:
  41. JuceEnumFormatEtc (const FORMATETC* const format_)
  42. : format (format_),
  43. index (0)
  44. {
  45. }
  46. JUCE_COMRESULT Clone (IEnumFORMATETC** result)
  47. {
  48. if (result == 0)
  49. return E_POINTER;
  50. JuceEnumFormatEtc* const newOne = new JuceEnumFormatEtc (format);
  51. newOne->index = index;
  52. *result = newOne;
  53. return S_OK;
  54. }
  55. JUCE_COMRESULT Next (ULONG celt, LPFORMATETC lpFormatEtc, ULONG* pceltFetched)
  56. {
  57. if (pceltFetched != nullptr)
  58. *pceltFetched = 0;
  59. else if (celt != 1)
  60. return S_FALSE;
  61. if (index == 0 && celt > 0 && lpFormatEtc != 0)
  62. {
  63. copyFormatEtc (lpFormatEtc [0], *format);
  64. ++index;
  65. if (pceltFetched != nullptr)
  66. *pceltFetched = 1;
  67. return S_OK;
  68. }
  69. return S_FALSE;
  70. }
  71. JUCE_COMRESULT Skip (ULONG celt)
  72. {
  73. if (index + (int) celt >= 1)
  74. return S_FALSE;
  75. index += celt;
  76. return S_OK;
  77. }
  78. JUCE_COMRESULT Reset()
  79. {
  80. index = 0;
  81. return S_OK;
  82. }
  83. private:
  84. const FORMATETC* const format;
  85. int index;
  86. static void copyFormatEtc (FORMATETC& dest, const FORMATETC& source)
  87. {
  88. dest = source;
  89. if (source.ptd != 0)
  90. {
  91. dest.ptd = (DVTARGETDEVICE*) CoTaskMemAlloc (sizeof (DVTARGETDEVICE));
  92. *(dest.ptd) = *(source.ptd);
  93. }
  94. }
  95. JUCE_DECLARE_NON_COPYABLE (JuceEnumFormatEtc)
  96. };
  97. //==============================================================================
  98. class JuceDataObject : public ComBaseClassHelper <IDataObject>
  99. {
  100. public:
  101. JuceDataObject (JuceDropSource* const dropSource_,
  102. const FORMATETC* const format_,
  103. const STGMEDIUM* const medium_)
  104. : dropSource (dropSource_),
  105. format (format_),
  106. medium (medium_)
  107. {
  108. }
  109. ~JuceDataObject()
  110. {
  111. jassert (refCount == 0);
  112. }
  113. JUCE_COMRESULT GetData (FORMATETC* pFormatEtc, STGMEDIUM* pMedium)
  114. {
  115. if ((pFormatEtc->tymed & format->tymed) != 0
  116. && pFormatEtc->cfFormat == format->cfFormat
  117. && pFormatEtc->dwAspect == format->dwAspect)
  118. {
  119. pMedium->tymed = format->tymed;
  120. pMedium->pUnkForRelease = 0;
  121. if (format->tymed == TYMED_HGLOBAL)
  122. {
  123. const SIZE_T len = GlobalSize (medium->hGlobal);
  124. void* const src = GlobalLock (medium->hGlobal);
  125. void* const dst = GlobalAlloc (GMEM_FIXED, len);
  126. memcpy (dst, src, len);
  127. GlobalUnlock (medium->hGlobal);
  128. pMedium->hGlobal = dst;
  129. return S_OK;
  130. }
  131. }
  132. return DV_E_FORMATETC;
  133. }
  134. JUCE_COMRESULT QueryGetData (FORMATETC* f)
  135. {
  136. if (f == 0)
  137. return E_INVALIDARG;
  138. if (f->tymed == format->tymed
  139. && f->cfFormat == format->cfFormat
  140. && f->dwAspect == format->dwAspect)
  141. return S_OK;
  142. return DV_E_FORMATETC;
  143. }
  144. JUCE_COMRESULT GetCanonicalFormatEtc (FORMATETC*, FORMATETC* pFormatEtcOut)
  145. {
  146. pFormatEtcOut->ptd = 0;
  147. return E_NOTIMPL;
  148. }
  149. JUCE_COMRESULT EnumFormatEtc (DWORD direction, IEnumFORMATETC** result)
  150. {
  151. if (result == 0)
  152. return E_POINTER;
  153. if (direction == DATADIR_GET)
  154. {
  155. *result = new JuceEnumFormatEtc (format);
  156. return S_OK;
  157. }
  158. *result = 0;
  159. return E_NOTIMPL;
  160. }
  161. JUCE_COMRESULT GetDataHere (FORMATETC*, STGMEDIUM*) { return DATA_E_FORMATETC; }
  162. JUCE_COMRESULT SetData (FORMATETC*, STGMEDIUM*, BOOL) { return E_NOTIMPL; }
  163. JUCE_COMRESULT DAdvise (FORMATETC*, DWORD, IAdviseSink*, DWORD*) { return OLE_E_ADVISENOTSUPPORTED; }
  164. JUCE_COMRESULT DUnadvise (DWORD) { return E_NOTIMPL; }
  165. JUCE_COMRESULT EnumDAdvise (IEnumSTATDATA**) { return OLE_E_ADVISENOTSUPPORTED; }
  166. private:
  167. JuceDropSource* const dropSource;
  168. const FORMATETC* const format;
  169. const STGMEDIUM* const medium;
  170. JUCE_DECLARE_NON_COPYABLE (JuceDataObject)
  171. };
  172. //==============================================================================
  173. HDROP createHDrop (const StringArray& fileNames)
  174. {
  175. int totalBytes = 0;
  176. for (int i = fileNames.size(); --i >= 0;)
  177. totalBytes += (int) CharPointer_UTF16::getBytesRequiredFor (fileNames[i].getCharPointer()) + sizeof (WCHAR);
  178. HDROP hDrop = (HDROP) GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (DROPFILES) + totalBytes + 4);
  179. if (hDrop != 0)
  180. {
  181. LPDROPFILES pDropFiles = (LPDROPFILES) GlobalLock (hDrop);
  182. pDropFiles->pFiles = sizeof (DROPFILES);
  183. pDropFiles->fWide = true;
  184. WCHAR* fname = reinterpret_cast<WCHAR*> (addBytesToPointer (pDropFiles, sizeof (DROPFILES)));
  185. for (int i = 0; i < fileNames.size(); ++i)
  186. {
  187. const size_t bytesWritten = fileNames[i].copyToUTF16 (fname, 2048);
  188. fname = reinterpret_cast<WCHAR*> (addBytesToPointer (fname, bytesWritten));
  189. }
  190. *fname = 0;
  191. GlobalUnlock (hDrop);
  192. }
  193. return hDrop;
  194. }
  195. bool performDragDrop (FORMATETC* const format, STGMEDIUM* const medium, const DWORD whatToDo)
  196. {
  197. JuceDropSource* const source = new JuceDropSource();
  198. JuceDataObject* const data = new JuceDataObject (source, format, medium);
  199. DWORD effect;
  200. const HRESULT res = DoDragDrop (data, source, whatToDo, &effect);
  201. data->Release();
  202. source->Release();
  203. return res == DRAGDROP_S_DROP;
  204. }
  205. }
  206. //==============================================================================
  207. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMove)
  208. {
  209. FORMATETC format = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  210. STGMEDIUM medium = { TYMED_HGLOBAL, { 0 }, 0 };
  211. medium.hGlobal = DragAndDropHelpers::createHDrop (files);
  212. return DragAndDropHelpers::performDragDrop (&format, &medium, canMove ? (DWORD) (DROPEFFECT_COPY | DROPEFFECT_MOVE)
  213. : (DWORD) DROPEFFECT_COPY);
  214. }
  215. bool DragAndDropContainer::performExternalDragDropOfText (const String& text)
  216. {
  217. FORMATETC format = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  218. STGMEDIUM medium = { TYMED_HGLOBAL, { 0 }, 0 };
  219. const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
  220. medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, numBytes + 2);
  221. WCHAR* const data = static_cast <WCHAR*> (GlobalLock (medium.hGlobal));
  222. text.copyToUTF16 (data, numBytes);
  223. format.cfFormat = CF_UNICODETEXT;
  224. GlobalUnlock (medium.hGlobal);
  225. return DragAndDropHelpers::performDragDrop (&format, &medium, DROPEFFECT_COPY | DROPEFFECT_MOVE);
  226. }