]> git.saurik.com Git - wxWidgets.git/blame - src/msw/ole/droptgt.cpp
Make "More windows..." menu item in MDI "Window" menu work in wxMSW.
[wxWidgets.git] / src / msw / ole / droptgt.cpp
CommitLineData
bbf1f0e5 1///////////////////////////////////////////////////////////////////////////////
521bf4ff 2// Name: src/msw/ole/droptgt.cpp
bbf1f0e5
KB
3// Purpose: wxDropTarget implementation
4// Author: Vadim Zeitlin
3f480da3
VZ
5// Modified by:
6// Created:
bbf1f0e5
KB
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
bbf1f0e5
KB
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// Declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
bbf1f0e5 20// For compilers that support precompilation, includes "wx.h".
bbf1f0e5
KB
21#include "wx/wxprec.h"
22
23#if defined(__BORLANDC__)
e4db172a 24 #pragma hdrstop
bbf1f0e5
KB
25#endif
26
21709999 27#if wxUSE_OLE && wxUSE_DRAG_AND_DROP
bbf1f0e5 28
e4db172a 29#ifndef WX_PRECOMP
57bd4c60 30 #include "wx/msw/wrapwin.h"
e4db172a
WS
31 #include "wx/log.h"
32#endif
33
4676948b 34#include "wx/msw/private.h"
bbf1f0e5 35
4676948b
JS
36#ifdef __WXWINCE__
37 #include <winreg.h>
38 #include <ole2.h>
39#endif
40
bbf1f0e5 41#ifdef __WIN32__
b64f0a5f 42 #if !defined(__GNUWIN32__) || wxUSE_NORLANDER_HEADERS
3f480da3
VZ
43 #include <shlobj.h> // for DROPFILES structure
44 #endif
bbf1f0e5 45#else
3f480da3 46 #include <shellapi.h>
bbf1f0e5
KB
47#endif
48
9e2896e5 49#include "wx/dnd.h"
bbf1f0e5 50
3f480da3 51#include "wx/msw/ole/oleutils.h"
bbf1f0e5 52
4d604ad3
VZ
53#include <initguid.h>
54
55// Some (very) old SDKs don't define IDropTargetHelper, so define our own
56// version of it here.
57struct wxIDropTargetHelper : public IUnknown
58{
59 virtual HRESULT STDMETHODCALLTYPE DragEnter(HWND hwndTarget,
60 IDataObject *pDataObject,
61 POINT *ppt,
62 DWORD dwEffect) = 0;
63 virtual HRESULT STDMETHODCALLTYPE DragLeave() = 0;
64 virtual HRESULT STDMETHODCALLTYPE DragOver(POINT *ppt, DWORD dwEffect) = 0;
65 virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObject,
66 POINT *ppt,
67 DWORD dwEffect) = 0;
68 virtual HRESULT STDMETHODCALLTYPE Show(BOOL fShow) = 0;
69};
70
71namespace
72{
b3d774bf
VZ
73 DEFINE_GUID(wxCLSID_DragDropHelper,
74 0x4657278A,0x411B,0x11D2,0x83,0x9A,0x00,0xC0,0x4F,0xD9,0x18,0xD0);
4d604ad3
VZ
75 DEFINE_GUID(wxIID_IDropTargetHelper,
76 0x4657278B,0x411B,0x11D2,0x83,0x9A,0x00,0xC0,0x4F,0xD9,0x18,0xD0);
77}
78
bbf1f0e5
KB
79// ----------------------------------------------------------------------------
80// IDropTarget interface: forward all interesting things to wxDropTarget
81// (the name is unfortunate, but wx_I_DropTarget is not at all the same thing
82// as wxDropTarget which is 'public' class, while this one is private)
83// ----------------------------------------------------------------------------
84
85class wxIDropTarget : public IDropTarget
86{
87public:
8ee9d618 88 wxIDropTarget(wxDropTarget *p);
33ac7e6f 89 virtual ~wxIDropTarget();
bbf1f0e5 90
8ee9d618 91 // accessors for wxDropTarget
40375032 92 HWND GetHWND() const { return m_hwnd; }
8ee9d618 93 void SetHwnd(HWND hwnd) { m_hwnd = hwnd; }
bbf1f0e5 94
8ee9d618
VZ
95 // IDropTarget methods
96 STDMETHODIMP DragEnter(LPDATAOBJECT, DWORD, POINTL, LPDWORD);
97 STDMETHODIMP DragOver(DWORD, POINTL, LPDWORD);
98 STDMETHODIMP DragLeave();
99 STDMETHODIMP Drop(LPDATAOBJECT, DWORD, POINTL, LPDWORD);
100
101 DECLARE_IUNKNOWN_METHODS;
bbf1f0e5
KB
102
103protected:
8ee9d618
VZ
104 IDataObject *m_pIDataObject; // !NULL between DragEnter and DragLeave/Drop
105 wxDropTarget *m_pTarget; // the real target (we're just a proxy)
106
107 HWND m_hwnd; // window we're associated with
bbf1f0e5 108
8ee9d618 109 // get default drop effect for given keyboard flags
c25db584 110 static DWORD GetDropEffect(DWORD flags, wxDragResult defaultAction, DWORD pdwEffect);
22f3361e 111
c0c133e1 112 wxDECLARE_NO_COPY_CLASS(wxIDropTarget);
bbf1f0e5
KB
113};
114
c9057ae1
VZ
115// ----------------------------------------------------------------------------
116// private functions
117// ----------------------------------------------------------------------------
118
119static wxDragResult ConvertDragEffectToResult(DWORD dwEffect);
120static DWORD ConvertDragResultToEffect(wxDragResult result);
121
bbf1f0e5
KB
122// ============================================================================
123// wxIDropTarget implementation
124// ============================================================================
125
8ee9d618 126// Name : static wxIDropTarget::GetDropEffect
bbf1f0e5 127// Purpose : determine the drop operation from keyboard/mouse state.
3f480da3 128// Returns : DWORD combined from DROPEFFECT_xxx constants
08291def
VZ
129// Params : [in] DWORD flags kbd & mouse flags as passed to
130// IDropTarget methods
131// [in] wxDragResult defaultAction the default action of the drop target
03647350 132// [in] DWORD pdwEffect the supported actions of the drop
08291def 133// source passed to IDropTarget methods
bbf1f0e5 134// Notes : We do "move" normally and "copy" if <Ctrl> is pressed,
3f480da3 135// which is the standard behaviour (currently there is no
bbf1f0e5 136// way to redefine it)
c25db584
VZ
137DWORD wxIDropTarget::GetDropEffect(DWORD flags,
138 wxDragResult defaultAction,
139 DWORD pdwEffect)
bbf1f0e5 140{
c25db584
VZ
141 DWORD effectiveAction;
142 if ( defaultAction == wxDragCopy )
143 effectiveAction = flags & MK_SHIFT ? DROPEFFECT_MOVE : DROPEFFECT_COPY;
144 else
145 effectiveAction = flags & MK_CONTROL ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
146
147 if ( !(effectiveAction & pdwEffect) )
148 {
149 // the action is not supported by drag source, fall back to something
150 // that it does support
151 if ( pdwEffect & DROPEFFECT_MOVE )
152 effectiveAction = DROPEFFECT_MOVE;
153 else if ( pdwEffect & DROPEFFECT_COPY )
154 effectiveAction = DROPEFFECT_COPY;
155 else if ( pdwEffect & DROPEFFECT_LINK )
156 effectiveAction = DROPEFFECT_LINK;
157 else
158 effectiveAction = DROPEFFECT_NONE;
159 }
160
161 return effectiveAction;
bbf1f0e5
KB
162}
163
164wxIDropTarget::wxIDropTarget(wxDropTarget *pTarget)
3f480da3 165{
bbf1f0e5 166 m_pTarget = pTarget;
3f480da3 167 m_pIDataObject = NULL;
bbf1f0e5
KB
168}
169
3f480da3
VZ
170wxIDropTarget::~wxIDropTarget()
171{
bbf1f0e5
KB
172}
173
174BEGIN_IID_TABLE(wxIDropTarget)
175 ADD_IID(Unknown)
176 ADD_IID(DropTarget)
177END_IID_TABLE;
178
179IMPLEMENT_IUNKNOWN_METHODS(wxIDropTarget)
180
bbf1f0e5
KB
181// Name : wxIDropTarget::DragEnter
182// Purpose : Called when the mouse enters the window (dragging something)
183// Returns : S_OK
08291def
VZ
184// Params : [in] IDataObject *pIDataSource : source data
185// [in] DWORD grfKeyState : kbd & mouse state
186// [in] POINTL pt : mouse coordinates
187// [in/out]DWORD *pdwEffect : effect flag
188// In: Supported effects
189// Out: Resulting effect
3f480da3 190// Notes :
bbf1f0e5
KB
191STDMETHODIMP wxIDropTarget::DragEnter(IDataObject *pIDataSource,
192 DWORD grfKeyState,
193 POINTL pt,
194 DWORD *pdwEffect)
195{
c5639a87 196 wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::DragEnter"));
bbf1f0e5 197
c5639a87 198 wxASSERT_MSG( m_pIDataObject == NULL,
9a83f860 199 wxT("drop target must have data object") );
c5639a87
VZ
200
201 // show the list of formats supported by the source data object for the
444ad3a7 202 // debugging purposes, this is quite useful sometimes - please don't remove
c5639a87
VZ
203#if 0
204 IEnumFORMATETC *penumFmt;
205 if ( SUCCEEDED(pIDataSource->EnumFormatEtc(DATADIR_GET, &penumFmt)) )
206 {
207 FORMATETC fmt;
208 while ( penumFmt->Next(1, &fmt, NULL) == S_OK )
209 {
9a83f860 210 wxLogDebug(wxT("Drop source supports format %s"),
c5639a87
VZ
211 wxDataObject::GetFormatName(fmt.cfFormat));
212 }
213
214 penumFmt->Release();
215 }
216 else
217 {
9a83f860 218 wxLogLastError(wxT("IDataObject::EnumFormatEtc"));
c5639a87
VZ
219 }
220#endif // 0
bbf1f0e5 221
81a1c686
RR
222 // for use in OnEnter and OnDrag calls
223 m_pTarget->MSWSetDataSource(pIDataSource);
03647350 224
8ee9d618
VZ
225 // get hold of the data object
226 m_pIDataObject = pIDataSource;
227 m_pIDataObject->AddRef();
bbf1f0e5 228
40375032
VZ
229 if ( !m_pTarget->MSWIsAcceptedData(pIDataSource) ) {
230 // we don't accept this kind of data
231 *pdwEffect = DROPEFFECT_NONE;
232 }
233 else
8ee9d618 234 {
40375032
VZ
235 // we need client coordinates to pass to wxWin functions
236 if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
237 {
238 wxLogLastError(wxT("ScreenToClient"));
239 }
240
241 // give some visual feedback
242 *pdwEffect = ConvertDragResultToEffect(
243 m_pTarget->OnEnter(pt.x, pt.y, ConvertDragEffectToResult(
244 GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect))
245 )
246 );
8ee9d618 247 }
bbf1f0e5 248
40375032
VZ
249 // update drag image
250 const wxDragResult res = ConvertDragEffectToResult(*pdwEffect);
251 m_pTarget->MSWUpdateDragImageOnEnter(pt.x, pt.y, res);
252 m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y, res);
8ee9d618
VZ
253
254 return S_OK;
bbf1f0e5
KB
255}
256
40375032
VZ
257
258
bbf1f0e5
KB
259// Name : wxIDropTarget::DragOver
260// Purpose : Indicates that the mouse was moved inside the window represented
261// by this drop target.
262// Returns : S_OK
08291def
VZ
263// Params : [in] DWORD grfKeyState kbd & mouse state
264// [in] POINTL pt mouse coordinates
265// [in/out]LPDWORD pdwEffect current effect flag
3f480da3 266// Notes : We're called on every WM_MOUSEMOVE, so this function should be
bbf1f0e5
KB
267// very efficient.
268STDMETHODIMP wxIDropTarget::DragOver(DWORD grfKeyState,
269 POINTL pt,
270 LPDWORD pdwEffect)
271{
8ee9d618 272 // there are too many of them... wxLogDebug("IDropTarget::DragOver");
bbf1f0e5 273
8ee9d618
VZ
274 wxDragResult result;
275 if ( m_pIDataObject ) {
917ae499 276 result = ConvertDragEffectToResult(
c25db584 277 GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect));
8ee9d618
VZ
278 }
279 else {
280 // can't accept data anyhow normally
281 result = wxDragNone;
282 }
c9057ae1 283
4095fb14
VZ
284 if ( result != wxDragNone ) {
285 // we need client coordinates to pass to wxWin functions
286 if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
287 {
288 wxLogLastError(wxT("ScreenToClient"));
289 }
c9057ae1 290
4095fb14
VZ
291 *pdwEffect = ConvertDragResultToEffect(
292 m_pTarget->OnDragOver(pt.x, pt.y, result)
293 );
294 }
295 else {
296 *pdwEffect = DROPEFFECT_NONE;
297 }
8ee9d618 298
40375032
VZ
299 // update drag image
300 m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y,
301 ConvertDragEffectToResult(*pdwEffect));
302
8ee9d618 303 return S_OK;
bbf1f0e5
KB
304}
305
306// Name : wxIDropTarget::DragLeave
307// Purpose : Informs the drop target that the operation has left its window.
308// Returns : S_OK
309// Notes : good place to do any clean-up
310STDMETHODIMP wxIDropTarget::DragLeave()
311{
c5639a87 312 wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::DragLeave"));
bbf1f0e5
KB
313
314 // remove the UI feedback
315 m_pTarget->OnLeave();
316
317 // release the held object
318 RELEASE_AND_NULL(m_pIDataObject);
3f480da3 319
40375032
VZ
320 // update drag image
321 m_pTarget->MSWUpdateDragImageOnLeave();
322
bbf1f0e5
KB
323 return S_OK;
324}
325
326// Name : wxIDropTarget::Drop
3f480da3 327// Purpose : Instructs the drop target to paste data that was just now
bbf1f0e5
KB
328// dropped on it.
329// Returns : S_OK
08291def
VZ
330// Params : [in] IDataObject *pIDataSource the data to paste
331// [in] DWORD grfKeyState kbd & mouse state
332// [in] POINTL pt where the drop occurred?
333// [in/out]DWORD *pdwEffect operation effect
3f480da3
VZ
334// Notes :
335STDMETHODIMP wxIDropTarget::Drop(IDataObject *pIDataSource,
336 DWORD grfKeyState,
337 POINTL pt,
bbf1f0e5
KB
338 DWORD *pdwEffect)
339{
c5639a87 340 wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::Drop"));
9e2896e5
VZ
341
342 // TODO I don't know why there is this parameter, but so far I assume
343 // that it's the same we've already got in DragEnter
344 wxASSERT( m_pIDataObject == pIDataSource );
345
8ee9d618
VZ
346 // we need client coordinates to pass to wxWin functions
347 if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
348 {
f6bcfd97 349 wxLogLastError(wxT("ScreenToClient"));
8ee9d618
VZ
350 }
351
9e2896e5
VZ
352 // first ask the drop target if it wants data
353 if ( m_pTarget->OnDrop(pt.x, pt.y) ) {
354 // it does, so give it the data source
81a1c686 355 m_pTarget->MSWSetDataSource(pIDataSource);
9e2896e5
VZ
356
357 // and now it has the data
917ae499 358 wxDragResult rc = ConvertDragEffectToResult(
c25db584 359 GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect));
87a1e308 360 rc = m_pTarget->OnData(pt.x, pt.y, rc);
8ee9d618 361 if ( wxIsDragResultOk(rc) ) {
9e2896e5 362 // operation succeeded
8ee9d618 363 *pdwEffect = ConvertDragResultToEffect(rc);
9e2896e5 364 }
c25db584
VZ
365 else {
366 *pdwEffect = DROPEFFECT_NONE;
367 }
368 }
369 else {
370 // OnDrop() returned false, no need to copy data
371 *pdwEffect = DROPEFFECT_NONE;
bbf1f0e5 372 }
bbf1f0e5 373
9e2896e5
VZ
374 // release the held object
375 RELEASE_AND_NULL(m_pIDataObject);
bbf1f0e5 376
40375032
VZ
377 // update drag image
378 m_pTarget->MSWUpdateDragImageOnData(pt.x, pt.y,
379 ConvertDragEffectToResult(*pdwEffect));
380
9e2896e5 381 return S_OK;
bbf1f0e5
KB
382}
383
384// ============================================================================
385// wxDropTarget implementation
386// ============================================================================
387
388// ----------------------------------------------------------------------------
389// ctor/dtor
390// ----------------------------------------------------------------------------
391
9e2896e5 392wxDropTarget::wxDropTarget(wxDataObject *dataObj)
40375032
VZ
393 : wxDropTargetBase(dataObj),
394 m_dropTargetHelper(NULL)
bbf1f0e5 395{
9e2896e5
VZ
396 // create an IDropTarget implementation which will notify us about d&d
397 // operations.
398 m_pIDropTarget = new wxIDropTarget(this);
399 m_pIDropTarget->AddRef();
bbf1f0e5
KB
400}
401
402wxDropTarget::~wxDropTarget()
403{
9e2896e5 404 ReleaseInterface(m_pIDropTarget);
bbf1f0e5
KB
405}
406
407// ----------------------------------------------------------------------------
408// [un]register drop handler
409// ----------------------------------------------------------------------------
410
411bool wxDropTarget::Register(WXHWND hwnd)
412{
a40b3f5d
JS
413 // FIXME
414 // RegisterDragDrop not available on Windows CE >= 400?
415 // Or maybe we can dynamically load them from ceshell.dll
416 // or similar.
417#if defined(__WXWINCE__) && _WIN32_WCE >= 400
abf912c5 418 wxUnusedVar(hwnd);
0a0e6a5b 419 return false;
a40b3f5d 420#else
4cb88a72
JS
421 HRESULT hr;
422
423 // May exist in later WinCE versions
424#ifndef __WXWINCE__
425 hr = ::CoLockObjectExternal(m_pIDropTarget, TRUE, FALSE);
9e2896e5 426 if ( FAILED(hr) ) {
161f4f73 427 wxLogApiError(wxT("CoLockObjectExternal"), hr);
0a0e6a5b 428 return false;
9e2896e5 429 }
4cb88a72 430#endif
bbf1f0e5 431
9e2896e5
VZ
432 hr = ::RegisterDragDrop((HWND) hwnd, m_pIDropTarget);
433 if ( FAILED(hr) ) {
4cb88a72
JS
434 // May exist in later WinCE versions
435#ifndef __WXWINCE__
9e2896e5 436 ::CoLockObjectExternal(m_pIDropTarget, FALSE, FALSE);
4cb88a72 437#endif
161f4f73 438 wxLogApiError(wxT("RegisterDragDrop"), hr);
0a0e6a5b 439 return false;
9e2896e5 440 }
bbf1f0e5 441
8ee9d618
VZ
442 // we will need the window handle for coords transformation later
443 m_pIDropTarget->SetHwnd((HWND)hwnd);
444
40375032
VZ
445 MSWInitDragImageSupport();
446
0a0e6a5b 447 return true;
a40b3f5d 448#endif
bbf1f0e5
KB
449}
450
451void wxDropTarget::Revoke(WXHWND hwnd)
452{
a40b3f5d
JS
453#if defined(__WXWINCE__) && _WIN32_WCE >= 400
454 // Not available, see note above
abf912c5 455 wxUnusedVar(hwnd);
a40b3f5d 456#else
9e2896e5 457 HRESULT hr = ::RevokeDragDrop((HWND) hwnd);
bbf1f0e5 458
9e2896e5 459 if ( FAILED(hr) ) {
161f4f73 460 wxLogApiError(wxT("RevokeDragDrop"), hr);
9e2896e5 461 }
bbf1f0e5 462
4cb88a72
JS
463 // May exist in later WinCE versions
464#ifndef __WXWINCE__
9e2896e5 465 ::CoLockObjectExternal(m_pIDropTarget, FALSE, TRUE);
4cb88a72 466#endif
8ee9d618 467
40375032
VZ
468 MSWEndDragImageSupport();
469
470 // remove window reference
8ee9d618 471 m_pIDropTarget->SetHwnd(0);
a40b3f5d 472#endif
bbf1f0e5
KB
473}
474
475// ----------------------------------------------------------------------------
9e2896e5 476// base class pure virtuals
bbf1f0e5 477// ----------------------------------------------------------------------------
9e2896e5 478
0a0e6a5b 479// OnDrop() is called only if we previously returned true from
9e2896e5
VZ
480// IsAcceptedData(), so no need to check anything here
481bool wxDropTarget::OnDrop(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
482{
0a0e6a5b 483 return true;
9e2896e5
VZ
484}
485
486// copy the data from the data source to the target data object
487bool wxDropTarget::GetData()
bbf1f0e5 488{
81a1c686 489 wxDataFormat format = MSWGetSupportedFormat(m_pIDataSource);
9e2896e5 490 if ( format == wxDF_INVALID ) {
0a0e6a5b 491 return false;
9e2896e5
VZ
492 }
493
494 STGMEDIUM stm;
495 FORMATETC fmtMemory;
496 fmtMemory.cfFormat = format;
497 fmtMemory.ptd = NULL;
498 fmtMemory.dwAspect = DVASPECT_CONTENT;
499 fmtMemory.lindex = -1;
500 fmtMemory.tymed = TYMED_HGLOBAL; // TODO to add other media
501
0a0e6a5b 502 bool rc = false;
9e2896e5
VZ
503
504 HRESULT hr = m_pIDataSource->GetData(&fmtMemory, &stm);
505 if ( SUCCEEDED(hr) ) {
506 IDataObject *dataObject = m_dataObject->GetInterface();
507
508 hr = dataObject->SetData(&fmtMemory, &stm, TRUE);
509 if ( SUCCEEDED(hr) ) {
0a0e6a5b 510 rc = true;
9e2896e5
VZ
511 }
512 else {
444ad3a7 513 wxLogApiError(wxT("IDataObject::SetData()"), hr);
9e2896e5
VZ
514 }
515 }
516 else {
444ad3a7 517 wxLogApiError(wxT("IDataObject::GetData()"), hr);
bbf1f0e5 518 }
bbf1f0e5 519
9e2896e5 520 return rc;
bbf1f0e5
KB
521}
522
9e2896e5
VZ
523// ----------------------------------------------------------------------------
524// callbacks used by wxIDropTarget
525// ----------------------------------------------------------------------------
bbf1f0e5 526
9e2896e5 527// we need a data source, so wxIDropTarget gives it to us using this function
81a1c686 528void wxDropTarget::MSWSetDataSource(IDataObject *pIDataSource)
bbf1f0e5 529{
9e2896e5 530 m_pIDataSource = pIDataSource;
bbf1f0e5
KB
531}
532
9e2896e5 533// determine if we accept data of this type
81a1c686 534bool wxDropTarget::MSWIsAcceptedData(IDataObject *pIDataSource) const
bbf1f0e5 535{
81a1c686 536 return MSWGetSupportedFormat(pIDataSource) != wxDF_INVALID;
bbf1f0e5
KB
537}
538
9e2896e5
VZ
539// ----------------------------------------------------------------------------
540// helper functions
541// ----------------------------------------------------------------------------
542
51c9c13c
RR
543wxDataFormat wxDropTarget::GetMatchingPair()
544{
81a1c686 545 return MSWGetSupportedFormat( m_pIDataSource );
51c9c13c
RR
546}
547
81a1c686 548wxDataFormat wxDropTarget::MSWGetSupportedFormat(IDataObject *pIDataSource) const
bbf1f0e5 549{
9e2896e5
VZ
550 // this strucutre describes a data of any type (first field will be
551 // changing) being passed through global memory block.
552 static FORMATETC s_fmtMemory = {
553 0,
554 NULL,
555 DVASPECT_CONTENT,
556 -1,
557 TYMED_HGLOBAL // TODO is it worth supporting other tymeds here?
558 };
559
560 // get the list of supported formats
561 size_t nFormats = m_dataObject->GetFormatCount(wxDataObject::Set);
33ac7e6f 562 wxDataFormat format;
c5639a87 563 wxDataFormat *formats;
9e2896e5
VZ
564 formats = nFormats == 1 ? &format : new wxDataFormat[nFormats];
565
566 m_dataObject->GetAllFormats(formats, wxDataObject::Set);
567
568 // cycle through all supported formats
569 size_t n;
570 for ( n = 0; n < nFormats; n++ ) {
571 s_fmtMemory.cfFormat = formats[n];
572
573 // NB: don't use SUCCEEDED macro here: QueryGetData returns S_FALSE
574 // for file drag and drop (format == CF_HDROP)
575 if ( pIDataSource->QueryGetData(&s_fmtMemory) == S_OK ) {
576 format = formats[n];
577
578 break;
579 }
580 }
581
582 if ( formats != &format ) {
583 // free memory if we allocated it
584 delete [] formats;
585 }
586
90bc25c7 587 return n < nFormats ? format : wxFormatInvalid;
bbf1f0e5
KB
588}
589
40375032
VZ
590// ----------------------------------------------------------------------------
591// drag image functions
592// ----------------------------------------------------------------------------
593
594void
595wxDropTarget::MSWEndDragImageSupport()
596{
597 // release drop target helper
598 if ( m_dropTargetHelper != NULL )
599 {
600 m_dropTargetHelper->Release();
601 m_dropTargetHelper = NULL;
602 }
603}
604
605void
606wxDropTarget::MSWInitDragImageSupport()
607{
608 // Use the default drop target helper to show shell drag images
b3d774bf 609 CoCreateInstance(wxCLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,
4d604ad3 610 wxIID_IDropTargetHelper, (LPVOID*)&m_dropTargetHelper);
40375032
VZ
611}
612
613void
614wxDropTarget::MSWUpdateDragImageOnData(wxCoord x,
615 wxCoord y,
616 wxDragResult dragResult)
617{
618 // call corresponding event on drop target helper
619 if ( m_dropTargetHelper != NULL )
620 {
621 POINT pt = {x, y};
622 DWORD dwEffect = ConvertDragResultToEffect(dragResult);
623 m_dropTargetHelper->Drop(m_pIDataSource, &pt, dwEffect);
624 }
625}
626
627void
628wxDropTarget::MSWUpdateDragImageOnDragOver(wxCoord x,
629 wxCoord y,
630 wxDragResult dragResult)
631{
632 // call corresponding event on drop target helper
633 if ( m_dropTargetHelper != NULL )
634 {
635 POINT pt = {x, y};
636 DWORD dwEffect = ConvertDragResultToEffect(dragResult);
637 m_dropTargetHelper->DragOver(&pt, dwEffect);
638 }
639}
640
641void
642wxDropTarget::MSWUpdateDragImageOnEnter(wxCoord x,
643 wxCoord y,
644 wxDragResult dragResult)
645{
646 // call corresponding event on drop target helper
647 if ( m_dropTargetHelper != NULL )
648 {
649 POINT pt = {x, y};
650 DWORD dwEffect = ConvertDragResultToEffect(dragResult);
651 m_dropTargetHelper->DragEnter(m_pIDropTarget->GetHWND(), m_pIDataSource, &pt, dwEffect);
652 }
653}
654
655void
656wxDropTarget::MSWUpdateDragImageOnLeave()
657{
658 // call corresponding event on drop target helper
659 if ( m_dropTargetHelper != NULL )
660 {
661 m_dropTargetHelper->DragLeave();
662 }
663}
664
c9057ae1
VZ
665// ----------------------------------------------------------------------------
666// private functions
667// ----------------------------------------------------------------------------
668
669static wxDragResult ConvertDragEffectToResult(DWORD dwEffect)
670{
671 switch ( dwEffect ) {
672 case DROPEFFECT_COPY:
673 return wxDragCopy;
674
e6d318c2
RD
675 case DROPEFFECT_LINK:
676 return wxDragLink;
677
c9057ae1
VZ
678 case DROPEFFECT_MOVE:
679 return wxDragMove;
680
681 default:
682 wxFAIL_MSG(wxT("invalid value in ConvertDragEffectToResult"));
683 // fall through
684
685 case DROPEFFECT_NONE:
686 return wxDragNone;
687 }
688}
689
690static DWORD ConvertDragResultToEffect(wxDragResult result)
691{
692 switch ( result ) {
693 case wxDragCopy:
694 return DROPEFFECT_COPY;
695
e6d318c2
RD
696 case wxDragLink:
697 return DROPEFFECT_LINK;
698
c9057ae1
VZ
699 case wxDragMove:
700 return DROPEFFECT_MOVE;
701
702 default:
703 wxFAIL_MSG(wxT("invalid value in ConvertDragResultToEffect"));
704 // fall through
705
706 case wxDragNone:
707 return DROPEFFECT_NONE;
708 }
709}
710
e4db172a 711#endif // wxUSE_OLE && wxUSE_DRAG_AND_DROP