4 * Copyright 2003 Ulrich Czekalla
5 * Copyright 2007 Damjan Jovanovic
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
32 #define NONAMELESSUNION
42 #include "shlobj.h" /* DROPFILES */
46 #include "wine/unicode.h"
47 #include "wine/debug.h"
48 #include "wine/list.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(xdnd
);
52 typedef struct tagXDNDDATA
58 } XDNDDATA
, *LPXDNDDATA
;
60 static struct list xdndData
= LIST_INIT(xdndData
);
61 static POINT XDNDxy
= { 0, 0 };
62 static IDataObject XDNDDataObject
;
63 static BOOL XDNDAccepted
= FALSE
;
64 static DWORD XDNDDropEffect
= DROPEFFECT_NONE
;
65 /* the last window the mouse was over */
66 static HWND XDNDLastTargetWnd
;
67 /* might be an ancestor of XDNDLastTargetWnd */
68 static HWND XDNDLastDropTargetWnd
;
70 static void X11DRV_XDND_InsertXDNDData( Atom property
, UINT format
, HANDLE contents
);
71 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
72 Atom
*types
, unsigned long count
);
73 static BOOL
X11DRV_XDND_HasHDROP(void);
74 static HRESULT
X11DRV_XDND_SendDropFiles(HWND hwnd
);
75 static void X11DRV_XDND_FreeDragDropOp(void);
77 static CRITICAL_SECTION xdnd_cs
;
78 static CRITICAL_SECTION_DEBUG critsect_debug
=
81 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
82 0, 0, { (DWORD_PTR
)(__FILE__
": xdnd_cs") }
84 static CRITICAL_SECTION xdnd_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
87 /* Based on functions in dlls/ole32/ole2.c */
88 static HANDLE
get_droptarget_local_handle(HWND hwnd
)
90 static const WCHAR prop_marshalleddroptarget
[] =
91 {'W','i','n','e','M','a','r','s','h','a','l','l','e','d','D','r','o','p','T','a','r','g','e','t',0};
93 HANDLE local_handle
= 0;
95 handle
= GetPropW(hwnd
, prop_marshalleddroptarget
);
101 GetWindowThreadProcessId(hwnd
, &pid
);
102 process
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, pid
);
105 DuplicateHandle(process
, handle
, GetCurrentProcess(), &local_handle
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
106 CloseHandle(process
);
112 static HRESULT
create_stream_from_map(HANDLE map
, IStream
**stream
)
114 HRESULT hr
= E_OUTOFMEMORY
;
117 MEMORY_BASIC_INFORMATION info
;
119 data
= MapViewOfFile(map
, FILE_MAP_READ
, 0, 0, 0);
122 VirtualQuery(data
, &info
, sizeof(info
));
123 TRACE("size %d\n", (int)info
.RegionSize
);
125 hmem
= GlobalAlloc(GMEM_MOVEABLE
, info
.RegionSize
);
128 memcpy(GlobalLock(hmem
), data
, info
.RegionSize
);
130 hr
= CreateStreamOnHGlobal(hmem
, TRUE
, stream
);
132 UnmapViewOfFile(data
);
136 static IDropTarget
* get_droptarget_pointer(HWND hwnd
)
138 IDropTarget
*droptarget
= NULL
;
142 map
= get_droptarget_local_handle(hwnd
);
143 if(!map
) return NULL
;
145 if(SUCCEEDED(create_stream_from_map(map
, &stream
)))
147 CoUnmarshalInterface(stream
, &IID_IDropTarget
, (void**)&droptarget
);
148 IStream_Release(stream
);
154 /**************************************************************************
155 * X11DRV_XDND_XdndActionToDROPEFFECT
157 static DWORD
X11DRV_XDND_XdndActionToDROPEFFECT(long action
)
159 /* In Windows, nothing but the given effects is allowed.
160 * In X the given action is just a hint, and you can always
161 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
162 if (action
== x11drv_atom(XdndActionCopy
))
163 return DROPEFFECT_COPY
;
164 else if (action
== x11drv_atom(XdndActionMove
))
165 return DROPEFFECT_MOVE
| DROPEFFECT_COPY
;
166 else if (action
== x11drv_atom(XdndActionLink
))
167 return DROPEFFECT_LINK
| DROPEFFECT_COPY
;
168 else if (action
== x11drv_atom(XdndActionAsk
))
169 /* FIXME: should we somehow ask the user what to do here? */
170 return DROPEFFECT_COPY
| DROPEFFECT_MOVE
| DROPEFFECT_LINK
;
171 FIXME("unknown action %ld, assuming DROPEFFECT_COPY\n", action
);
172 return DROPEFFECT_COPY
;
175 /**************************************************************************
176 * X11DRV_XDND_DROPEFFECTToXdndAction
178 static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect
)
180 if (effect
== DROPEFFECT_COPY
)
181 return x11drv_atom(XdndActionCopy
);
182 else if (effect
== DROPEFFECT_MOVE
)
183 return x11drv_atom(XdndActionMove
);
184 else if (effect
== DROPEFFECT_LINK
)
185 return x11drv_atom(XdndActionLink
);
186 FIXME("unknown drop effect %u, assuming XdndActionCopy\n", effect
);
187 return x11drv_atom(XdndActionCopy
);
190 /**************************************************************************
191 * X11DRV_XDND_EnterEvent
193 * Handle an XdndEnter event.
195 void X11DRV_XDND_EnterEvent( HWND hWnd
, XClientMessageEvent
*event
)
199 unsigned long count
= 0;
201 version
= (event
->data
.l
[1] & 0xFF000000) >> 24;
202 TRACE("ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
203 version
, (event
->data
.l
[1] & 1),
204 event
->data
.l
[0], event
->data
.l
[1], event
->data
.l
[2],
205 event
->data
.l
[3], event
->data
.l
[4]);
207 if (version
> WINE_XDND_VERSION
)
209 ERR("ignoring unsupported XDND version %d\n", version
);
213 XDNDAccepted
= FALSE
;
215 /* If the source supports more than 3 data types we retrieve
216 * the entire list. */
217 if (event
->data
.l
[1] & 1)
221 unsigned long bytesret
;
223 /* Request supported formats from source window */
224 XGetWindowProperty(event
->display
, event
->data
.l
[0], x11drv_atom(XdndTypeList
),
225 0, 65535, FALSE
, AnyPropertyType
, &acttype
, &actfmt
, &count
,
226 &bytesret
, (unsigned char**)&xdndtypes
);
231 xdndtypes
= (Atom
*) &event
->data
.l
[2];
238 for (i
= 0; i
< count
; i
++)
240 if (xdndtypes
[i
] != 0)
242 char * pn
= XGetAtomName(event
->display
, xdndtypes
[i
]);
243 TRACE("XDNDEnterAtom %ld: %s\n", xdndtypes
[i
], pn
);
249 /* Do a one-time data read and cache results */
250 X11DRV_XDND_ResolveProperty(event
->display
, event
->window
,
251 event
->data
.l
[1], xdndtypes
, count
);
253 if (event
->data
.l
[1] & 1)
257 /* Recursively searches for a window on given coordinates in a drag&drop specific manner.
259 * Don't use WindowFromPoint instead, because it omits the STATIC and transparent
260 * windows, but they can be a valid drop targets if have WS_EX_ACCEPTFILES set.
262 static HWND
window_from_point_dnd(HWND hwnd
, POINT point
)
265 ScreenToClient(hwnd
, &point
);
266 while ((child
= ChildWindowFromPointEx(hwnd
, point
, CWP_SKIPDISABLED
| CWP_SKIPINVISIBLE
)) && child
!= hwnd
)
268 MapWindowPoints(hwnd
, child
, &point
, 1);
275 /* Returns the first window down the hierarchy that has WS_EX_ACCEPTFILES set or
276 * returns NULL, if such window does not exists.
278 static HWND
window_accepting_files(HWND hwnd
)
280 while (hwnd
&& !(GetWindowLongW(hwnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
))
281 /* MUST to be GetParent, not GetAncestor, because the owner window
282 * (with WS_EX_ACCEPTFILES) of a window with WS_POPUP is a valid
283 * drop target. GetParent works exactly this way!
285 hwnd
= GetParent(hwnd
);
289 /**************************************************************************
290 * X11DRV_XDND_PositionEvent
292 * Handle an XdndPosition event.
294 void X11DRV_XDND_PositionEvent( HWND hWnd
, XClientMessageEvent
*event
)
296 XClientMessageEvent e
;
297 int accept
= 0; /* Assume we're not accepting */
298 IDropTarget
*dropTarget
= NULL
;
304 XDNDxy
= root_to_virtual_screen( event
->data
.l
[2] >> 16, event
->data
.l
[2] & 0xFFFF );
305 targetWindow
= window_from_point_dnd(hWnd
, XDNDxy
);
309 effect
= X11DRV_XDND_XdndActionToDROPEFFECT(event
->data
.l
[4]);
311 if (!XDNDAccepted
|| XDNDLastTargetWnd
!= targetWindow
)
313 /* Notify OLE of DragEnter. Result determines if we accept */
314 HWND dropTargetWindow
;
316 if (XDNDAccepted
&& XDNDLastDropTargetWnd
)
318 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
321 hr
= IDropTarget_DragLeave(dropTarget
);
323 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
324 IDropTarget_Release(dropTarget
);
327 dropTargetWindow
= targetWindow
;
330 dropTarget
= get_droptarget_pointer(dropTargetWindow
);
331 } while (dropTarget
== NULL
&& (dropTargetWindow
= GetParent(dropTargetWindow
)) != NULL
);
332 XDNDLastTargetWnd
= targetWindow
;
333 XDNDLastDropTargetWnd
= dropTargetWindow
;
336 DWORD effect_ignore
= effect
;
337 hr
= IDropTarget_DragEnter(dropTarget
, &XDNDDataObject
,
338 MK_LBUTTON
, pointl
, &effect_ignore
);
342 TRACE("the application accepted the drop (effect = %d)\n", effect_ignore
);
346 XDNDAccepted
= FALSE
;
347 WARN("IDropTarget_DragEnter failed, error 0x%08X\n", hr
);
349 IDropTarget_Release(dropTarget
);
352 if (XDNDAccepted
&& XDNDLastTargetWnd
== targetWindow
)
354 /* If drag accepted notify OLE of DragOver */
355 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
358 hr
= IDropTarget_DragOver(dropTarget
, MK_LBUTTON
, pointl
, &effect
);
360 XDNDDropEffect
= effect
;
362 WARN("IDropTarget_DragOver failed, error 0x%08X\n", hr
);
363 IDropTarget_Release(dropTarget
);
371 /* fallback search for window able to accept these files. */
373 if (window_accepting_files(targetWindow
) && X11DRV_XDND_HasHDROP())
376 effect
= DROPEFFECT_COPY
;
380 TRACE("actionRequested(%ld) accept(%d) chosen(0x%x) at x(%d),y(%d)\n",
381 event
->data
.l
[4], accept
, effect
, XDNDxy
.x
, XDNDxy
.y
);
384 * Let source know if we're accepting the drop by
385 * sending a status message.
387 e
.type
= ClientMessage
;
388 e
.display
= event
->display
;
389 e
.window
= event
->data
.l
[0];
390 e
.message_type
= x11drv_atom(XdndStatus
);
392 e
.data
.l
[0] = event
->window
;
393 e
.data
.l
[1] = accept
;
394 e
.data
.l
[2] = 0; /* Empty Rect */
395 e
.data
.l
[3] = 0; /* Empty Rect */
397 e
.data
.l
[4] = X11DRV_XDND_DROPEFFECTToXdndAction(effect
);
400 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
403 /**************************************************************************
404 * X11DRV_XDND_DropEvent
406 * Handle an XdndDrop event.
408 void X11DRV_XDND_DropEvent( HWND hWnd
, XClientMessageEvent
*event
)
410 XClientMessageEvent e
;
411 IDropTarget
*dropTarget
;
412 DWORD effect
= XDNDDropEffect
;
413 int accept
= 0; /* Assume we're not accepting */
414 BOOL drop_file
= TRUE
;
416 /* Notify OLE of Drop */
419 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
420 if (dropTarget
&& effect
!=DROPEFFECT_NONE
)
427 hr
= IDropTarget_Drop(dropTarget
, &XDNDDataObject
, MK_LBUTTON
,
431 if (effect
!= DROPEFFECT_NONE
)
433 TRACE("drop succeeded\n");
438 TRACE("the application refused the drop\n");
441 WARN("drop failed, error 0x%08X\n", hr
);
444 WARN("drop returned 0x%08X\n", hr
);
447 IDropTarget_Release(dropTarget
);
451 HRESULT hr
= IDropTarget_DragLeave(dropTarget
);
453 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
454 IDropTarget_Release(dropTarget
);
460 /* Only send WM_DROPFILES if Drop didn't succeed or DROPEFFECT_NONE was set.
461 * Doing both causes winamp to duplicate the dropped files (#29081) */
463 HWND hwnd_drop
= window_accepting_files(window_from_point_dnd(hWnd
, XDNDxy
));
465 if (hwnd_drop
&& X11DRV_XDND_HasHDROP())
467 HRESULT hr
= X11DRV_XDND_SendDropFiles(hwnd_drop
);
471 effect
= DROPEFFECT_COPY
;
476 TRACE("effectRequested(0x%x) accept(%d) performed(0x%x) at x(%d),y(%d)\n",
477 XDNDDropEffect
, accept
, effect
, XDNDxy
.x
, XDNDxy
.y
);
479 X11DRV_XDND_FreeDragDropOp();
481 /* Tell the target we are finished. */
482 memset(&e
, 0, sizeof(e
));
483 e
.type
= ClientMessage
;
484 e
.display
= event
->display
;
485 e
.window
= event
->data
.l
[0];
486 e
.message_type
= x11drv_atom(XdndFinished
);
488 e
.data
.l
[0] = event
->window
;
489 e
.data
.l
[1] = accept
;
491 e
.data
.l
[2] = X11DRV_XDND_DROPEFFECTToXdndAction(effect
);
494 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
497 /**************************************************************************
498 * X11DRV_XDND_LeaveEvent
500 * Handle an XdndLeave event.
502 void X11DRV_XDND_LeaveEvent( HWND hWnd
, XClientMessageEvent
*event
)
504 IDropTarget
*dropTarget
;
506 TRACE("DND Operation canceled\n");
508 /* Notify OLE of DragLeave */
511 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
514 HRESULT hr
= IDropTarget_DragLeave(dropTarget
);
516 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
517 IDropTarget_Release(dropTarget
);
521 X11DRV_XDND_FreeDragDropOp();
525 /**************************************************************************
526 * X11DRV_XDND_ResolveProperty
528 * Resolve all MIME types to windows clipboard formats. All data is cached.
530 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
531 Atom
*types
, unsigned long count
)
533 XDNDDATA
*current
, *next
;
534 BOOL haveHDROP
= FALSE
;
536 TRACE("count(%ld)\n", count
);
538 X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
540 X11DRV_CLIPBOARD_ImportSelection( display
, xwin
, x11drv_atom(XdndSelection
),
541 types
, count
, X11DRV_XDND_InsertXDNDData
);
543 /* On Windows when there is a CF_HDROP, there are no other CF_ formats.
544 * foobar2000 relies on this (spaces -> %20's without it).
546 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
548 if (current
->cf_win
== CF_HDROP
)
556 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
558 if (current
->cf_win
!= CF_HDROP
&& current
->cf_win
< CF_MAX
)
560 list_remove(¤t
->entry
);
561 GlobalFree(current
->contents
);
562 HeapFree(GetProcessHeap(), 0, current
);
569 /**************************************************************************
570 * X11DRV_XDND_InsertXDNDData
572 * Cache available XDND property
574 static void X11DRV_XDND_InsertXDNDData( Atom property
, UINT format
, HANDLE contents
)
576 LPXDNDDATA current
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(XDNDDATA
));
580 EnterCriticalSection(&xdnd_cs
);
581 current
->cf_xdnd
= property
;
582 current
->cf_win
= format
;
583 current
->contents
= contents
;
584 list_add_tail(&xdndData
, ¤t
->entry
);
585 LeaveCriticalSection(&xdnd_cs
);
590 /**************************************************************************
591 * X11DRV_XDND_HasHDROP
593 static BOOL
X11DRV_XDND_HasHDROP(void)
595 LPXDNDDATA current
= NULL
;
598 EnterCriticalSection(&xdnd_cs
);
600 /* Find CF_HDROP type if any */
601 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
603 if (current
->cf_win
== CF_HDROP
)
610 LeaveCriticalSection(&xdnd_cs
);
615 /**************************************************************************
616 * X11DRV_XDND_SendDropFiles
618 static HRESULT
X11DRV_XDND_SendDropFiles(HWND hwnd
)
621 LPXDNDDATA current
= NULL
;
624 EnterCriticalSection(&xdnd_cs
);
626 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
628 if (current
->cf_win
== CF_HDROP
)
636 HGLOBAL dropHandle
= GlobalAlloc(GMEM_FIXED
, GlobalSize(current
->contents
));
640 DROPFILES
*lpDrop
= GlobalLock(dropHandle
);
641 memcpy(lpDrop
, GlobalLock(current
->contents
), GlobalSize(current
->contents
));
642 GlobalUnlock(current
->contents
);
643 lpDrop
->pt
.x
= XDNDxy
.x
;
644 lpDrop
->pt
.y
= XDNDxy
.y
;
645 lpDrop
->fNC
= !(ScreenToClient(hwnd
, &lpDrop
->pt
) &&
646 GetClientRect(hwnd
, &rect
) &&
647 PtInRect(&rect
, lpDrop
->pt
));
648 TRACE("Sending WM_DROPFILES: hWnd=0x%p, fNC=%d, x=%d, y=%d, files=%p(%s)\n", hwnd
,
649 lpDrop
->fNC
, lpDrop
->pt
.x
, lpDrop
->pt
.y
, ((char*)lpDrop
) + lpDrop
->pFiles
,
650 debugstr_w((WCHAR
*)(((char*)lpDrop
) + lpDrop
->pFiles
)));
651 GlobalUnlock(dropHandle
);
652 if (PostMessageW(hwnd
, WM_DROPFILES
, (WPARAM
)dropHandle
, 0))
656 hr
= HRESULT_FROM_WIN32(GetLastError());
657 GlobalFree(dropHandle
);
661 hr
= HRESULT_FROM_WIN32(GetLastError());
666 LeaveCriticalSection(&xdnd_cs
);
672 /**************************************************************************
673 * X11DRV_XDND_FreeDragDropOp
675 static void X11DRV_XDND_FreeDragDropOp(void)
682 EnterCriticalSection(&xdnd_cs
);
684 /** Free data cache */
685 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
687 list_remove(¤t
->entry
);
688 GlobalFree(current
->contents
);
689 HeapFree(GetProcessHeap(), 0, current
);
692 XDNDxy
.x
= XDNDxy
.y
= 0;
693 XDNDLastTargetWnd
= NULL
;
694 XDNDLastDropTargetWnd
= NULL
;
695 XDNDAccepted
= FALSE
;
697 LeaveCriticalSection(&xdnd_cs
);
701 /**************************************************************************
702 * X11DRV_XDND_DescribeClipboardFormat
704 static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat
, char *buffer
, int size
)
706 #define D(x) case x: lstrcpynA(buffer, #x, size); return;
729 if (CF_PRIVATEFIRST
<= cfFormat
&& cfFormat
<= CF_PRIVATELAST
)
731 lstrcpynA(buffer
, "some private object", size
);
734 if (CF_GDIOBJFIRST
<= cfFormat
&& cfFormat
<= CF_GDIOBJLAST
)
736 lstrcpynA(buffer
, "some GDI object", size
);
740 GetClipboardFormatNameA(cfFormat
, buffer
, size
);
744 /* The IDataObject singleton we feed to OLE follows */
746 static HRESULT WINAPI
XDNDDATAOBJECT_QueryInterface(IDataObject
*dataObject
,
747 REFIID riid
, void **ppvObject
)
749 TRACE("(%p, %s, %p)\n", dataObject
, debugstr_guid(riid
), ppvObject
);
750 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDataObject
))
752 *ppvObject
= dataObject
;
753 IDataObject_AddRef(dataObject
);
757 return E_NOINTERFACE
;
760 static ULONG WINAPI
XDNDDATAOBJECT_AddRef(IDataObject
*dataObject
)
762 TRACE("(%p)\n", dataObject
);
766 static ULONG WINAPI
XDNDDATAOBJECT_Release(IDataObject
*dataObject
)
768 TRACE("(%p)\n", dataObject
);
772 static HRESULT WINAPI
XDNDDATAOBJECT_GetData(IDataObject
*dataObject
,
773 FORMATETC
*formatEtc
,
777 char formatDesc
[1024];
779 TRACE("(%p, %p, %p)\n", dataObject
, formatEtc
, pMedium
);
780 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
,
781 formatDesc
, sizeof(formatDesc
));
782 TRACE("application is looking for %s\n", formatDesc
);
784 hr
= IDataObject_QueryGetData(dataObject
, formatEtc
);
788 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
790 if (current
->cf_win
== formatEtc
->cfFormat
)
792 pMedium
->tymed
= TYMED_HGLOBAL
;
793 pMedium
->u
.hGlobal
= GlobalAlloc(GMEM_FIXED
| GMEM_ZEROINIT
, GlobalSize(current
->contents
));
794 if (pMedium
->u
.hGlobal
== NULL
)
795 return E_OUTOFMEMORY
;
796 memcpy(GlobalLock(pMedium
->u
.hGlobal
), GlobalLock(current
->contents
), GlobalSize(current
->contents
));
797 GlobalUnlock(pMedium
->u
.hGlobal
);
798 GlobalUnlock(current
->contents
);
799 pMedium
->pUnkForRelease
= 0;
807 static HRESULT WINAPI
XDNDDATAOBJECT_GetDataHere(IDataObject
*dataObject
,
808 FORMATETC
*formatEtc
,
811 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, pMedium
);
812 return DATA_E_FORMATETC
;
815 static HRESULT WINAPI
XDNDDATAOBJECT_QueryGetData(IDataObject
*dataObject
,
816 FORMATETC
*formatEtc
)
818 char formatDesc
[1024];
821 TRACE("(%p, %p={.tymed=0x%x, .dwAspect=%d, .cfFormat=%d}\n",
822 dataObject
, formatEtc
, formatEtc
->tymed
, formatEtc
->dwAspect
, formatEtc
->cfFormat
);
823 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
, formatDesc
, sizeof(formatDesc
));
825 if (formatEtc
->tymed
&& !(formatEtc
->tymed
& TYMED_HGLOBAL
))
827 FIXME("only HGLOBAL medium types supported right now\n");
830 if (formatEtc
->dwAspect
!= DVASPECT_CONTENT
)
832 FIXME("only the content aspect is supported right now\n");
836 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
838 if (current
->cf_win
== formatEtc
->cfFormat
)
840 TRACE("application found %s\n", formatDesc
);
844 TRACE("application didn't find %s\n", formatDesc
);
845 return DV_E_FORMATETC
;
848 static HRESULT WINAPI
XDNDDATAOBJECT_GetCanonicalFormatEtc(IDataObject
*dataObject
,
849 FORMATETC
*formatEtc
,
850 FORMATETC
*formatEtcOut
)
852 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, formatEtcOut
);
853 formatEtcOut
->ptd
= NULL
;
857 static HRESULT WINAPI
XDNDDATAOBJECT_SetData(IDataObject
*dataObject
,
858 FORMATETC
*formatEtc
,
859 STGMEDIUM
*pMedium
, BOOL fRelease
)
861 FIXME("(%p, %p, %p, %s): stub\n", dataObject
, formatEtc
,
862 pMedium
, fRelease
?"TRUE":"FALSE");
866 static HRESULT WINAPI
XDNDDATAOBJECT_EnumFormatEtc(IDataObject
*dataObject
,
868 IEnumFORMATETC
**ppEnumFormatEtc
)
873 TRACE("(%p, %u, %p)\n", dataObject
, dwDirection
, ppEnumFormatEtc
);
875 if (dwDirection
!= DATADIR_GET
)
877 FIXME("only the get direction is implemented\n");
881 count
= list_count(&xdndData
);
882 formats
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(FORMATETC
));
888 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
890 formats
[i
].cfFormat
= current
->cf_win
;
891 formats
[i
].ptd
= NULL
;
892 formats
[i
].dwAspect
= DVASPECT_CONTENT
;
893 formats
[i
].lindex
= -1;
894 formats
[i
].tymed
= TYMED_HGLOBAL
;
897 hr
= SHCreateStdEnumFmtEtc(count
, formats
, ppEnumFormatEtc
);
898 HeapFree(GetProcessHeap(), 0, formats
);
902 return E_OUTOFMEMORY
;
905 static HRESULT WINAPI
XDNDDATAOBJECT_DAdvise(IDataObject
*dataObject
,
906 FORMATETC
*formatEtc
, DWORD advf
,
907 IAdviseSink
*adviseSink
,
908 DWORD
*pdwConnection
)
910 FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject
, formatEtc
, advf
,
911 adviseSink
, pdwConnection
);
912 return OLE_E_ADVISENOTSUPPORTED
;
915 static HRESULT WINAPI
XDNDDATAOBJECT_DUnadvise(IDataObject
*dataObject
,
918 FIXME("(%p, %u): stub\n", dataObject
, dwConnection
);
919 return OLE_E_ADVISENOTSUPPORTED
;
922 static HRESULT WINAPI
XDNDDATAOBJECT_EnumDAdvise(IDataObject
*dataObject
,
923 IEnumSTATDATA
**pEnumAdvise
)
925 FIXME("(%p, %p): stub\n", dataObject
, pEnumAdvise
);
926 return OLE_E_ADVISENOTSUPPORTED
;
929 static IDataObjectVtbl xdndDataObjectVtbl
=
931 XDNDDATAOBJECT_QueryInterface
,
932 XDNDDATAOBJECT_AddRef
,
933 XDNDDATAOBJECT_Release
,
934 XDNDDATAOBJECT_GetData
,
935 XDNDDATAOBJECT_GetDataHere
,
936 XDNDDATAOBJECT_QueryGetData
,
937 XDNDDATAOBJECT_GetCanonicalFormatEtc
,
938 XDNDDATAOBJECT_SetData
,
939 XDNDDATAOBJECT_EnumFormatEtc
,
940 XDNDDATAOBJECT_DAdvise
,
941 XDNDDATAOBJECT_DUnadvise
,
942 XDNDDATAOBJECT_EnumDAdvise
945 static IDataObject XDNDDataObject
= { &xdndDataObjectVtbl
};