-- v2: winex11: Get rid of X11DRV_XDND_HasHDROP helper. winex11: Use a custom IEnumFORMATETC interface implementation. winex11: Clear the XDND data object on drop event. winex11: Get rid of X11DRV_XDND_SendDropFiles helper. winex11: Assume that PostMessageW WM_DROPFILES succeeds. winex11: Only enter the CS to get a reference on the data object.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/xdnd.c | 53 ++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 14 deletions(-)
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index a898caa98b6..36ec35f6c17 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -305,6 +305,18 @@ static HRESULT data_object_create( UINT entries_size, const struct format_entry return S_OK; }
+static struct data_object *get_data_object(void) +{ + IDataObject *iface; + + EnterCriticalSection( &xdnd_cs ); + if ((iface = xdnd_data_object)) IDataObject_AddRef( iface ); + LeaveCriticalSection( &xdnd_cs ); + + if (!iface) return NULL; + return data_object_from_IDataObject( iface ); +} + /* Based on functions in dlls/ole32/ole2.c */ static HANDLE get_droptarget_local_handle(HWND hwnd) { @@ -417,9 +429,12 @@ NTSTATUS WINAPI x11drv_dnd_position_event( void *arg, ULONG size ) IDropTarget *dropTarget = NULL; DWORD effect = params->effect; POINTL pointl = { .x = params->point.x, .y = params->point.y }; + struct data_object *object; HWND targetWindow; HRESULT hr;
+ if (!(object = get_data_object())) return STATUS_INVALID_PARAMETER; + XDNDxy = params->point; targetWindow = window_from_point_dnd( UlongToHandle( params->hwnd ), XDNDxy );
@@ -449,7 +464,7 @@ NTSTATUS WINAPI x11drv_dnd_position_event( void *arg, ULONG size ) if (dropTarget) { DWORD effect_ignore = effect; - hr = IDropTarget_DragEnter(dropTarget, xdnd_data_object, + hr = IDropTarget_DragEnter(dropTarget, &object->IDataObject_iface, MK_LBUTTON, pointl, &effect_ignore); if (hr == S_OK) { @@ -493,6 +508,8 @@ NTSTATUS WINAPI x11drv_dnd_position_event( void *arg, ULONG size ) }
if (!accept) effect = DROPEFFECT_NONE; + IDataObject_Release( &object->IDataObject_iface ); + return NtCallbackReturn( &effect, sizeof(effect), STATUS_SUCCESS ); }
@@ -503,8 +520,11 @@ NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size ) IDropTarget *dropTarget; DWORD effect = XDNDDropEffect; int accept = 0; /* Assume we're not accepting */ + struct data_object *object; BOOL drop_file = TRUE;
+ if (!(object = get_data_object())) return STATUS_INVALID_PARAMETER; + /* Notify OLE of Drop */ if (XDNDAccepted) { @@ -516,7 +536,7 @@ NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size )
pointl.x = XDNDxy.x; pointl.y = XDNDxy.y; - hr = IDropTarget_Drop(dropTarget, xdnd_data_object, MK_LBUTTON, + hr = IDropTarget_Drop(dropTarget, &object->IDataObject_iface, MK_LBUTTON, pointl, &effect); if (hr == S_OK) { @@ -569,6 +589,8 @@ NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size ) XDNDDropEffect, accept, effect, XDNDxy.x, XDNDxy.y);
if (!accept) effect = DROPEFFECT_NONE; + IDataObject_Release( &object->IDataObject_iface ); + return NtCallbackReturn( &effect, sizeof(effect), STATUS_SUCCESS ); }
@@ -580,6 +602,7 @@ NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size ) NTSTATUS WINAPI x11drv_dnd_leave_event( void *params, ULONG size ) { IDropTarget *dropTarget; + IDataObject *object;
TRACE("DND Operation canceled\n");
@@ -596,6 +619,13 @@ NTSTATUS WINAPI x11drv_dnd_leave_event( void *params, ULONG size ) } }
+ EnterCriticalSection( &xdnd_cs ); + object = xdnd_data_object; + xdnd_data_object = NULL; + LeaveCriticalSection( &xdnd_cs ); + + if (object) IDataObject_Release( object ); + X11DRV_XDND_FreeDragDropOp(); return STATUS_SUCCESS; } @@ -608,7 +638,7 @@ NTSTATUS WINAPI x11drv_dnd_enter_event( void *args, ULONG size ) { UINT formats_size = size - offsetof(struct dnd_enter_event_params, entries); struct dnd_enter_event_params *params = args; - IDataObject *object; + IDataObject *object, *previous;
XDNDAccepted = FALSE; X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */ @@ -616,9 +646,11 @@ NTSTATUS WINAPI x11drv_dnd_enter_event( void *args, ULONG size ) if (FAILED(data_object_create( formats_size, params->entries, &object ))) return STATUS_NO_MEMORY;
EnterCriticalSection( &xdnd_cs ); + previous = xdnd_data_object; xdnd_data_object = object; LeaveCriticalSection( &xdnd_cs );
+ if (previous) IDataObject_Release( previous ); return STATUS_SUCCESS; }
@@ -644,13 +676,13 @@ static BOOL X11DRV_XDND_HasHDROP(void) static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd) { FORMATETC format = {.cfFormat = CF_HDROP}; + struct data_object *object; STGMEDIUM medium; HRESULT hr;
- EnterCriticalSection(&xdnd_cs); + if (!(object = get_data_object())) return E_FAIL;
- if (!xdnd_data_object) hr = E_FAIL; - else if (SUCCEEDED(hr = IDataObject_GetData( xdnd_data_object, &format, &medium ))) + if (SUCCEEDED(hr = IDataObject_GetData( &object->IDataObject_iface, &format, &medium ))) { DROPFILES *drop = GlobalLock( medium.hGlobal ); void *files = (char *)drop + drop->pFiles; @@ -673,8 +705,7 @@ static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd) } }
- LeaveCriticalSection(&xdnd_cs); - + IDataObject_Release( &object->IDataObject_iface ); return hr; }
@@ -688,12 +719,6 @@ static void X11DRV_XDND_FreeDragDropOp(void)
EnterCriticalSection(&xdnd_cs);
- if (xdnd_data_object) - { - IDataObject_Release( xdnd_data_object ); - xdnd_data_object = NULL; - } - XDNDxy.x = XDNDxy.y = 0; XDNDLastTargetWnd = NULL; XDNDLastDropTargetWnd = NULL;
From: Rémi Bernon rbernon@codeweavers.com
We assume it does, in the other function that posts the message. --- dlls/winex11.drv/xdnd.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 36ec35f6c17..737bd947c1e 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -696,13 +696,7 @@ static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd) wine_dbgstr_point( &drop->pt), drop->fNC, files, debugstr_w(files) ); GlobalUnlock( medium.hGlobal );
- if (PostMessageW( hwnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0 )) - hr = S_OK; - else - { - hr = HRESULT_FROM_WIN32(GetLastError()); - GlobalFree( medium.hGlobal ); - } + PostMessageW( hwnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0 ); }
IDataObject_Release( &object->IDataObject_iface );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/xdnd.c | 60 +++++++++++++---------------------------- 1 file changed, 18 insertions(+), 42 deletions(-)
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 737bd947c1e..461463d7212 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -41,7 +41,6 @@ static HWND XDNDLastTargetWnd; static HWND XDNDLastDropTargetWnd;
static BOOL X11DRV_XDND_HasHDROP(void); -static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd); static void X11DRV_XDND_FreeDragDropOp(void);
static CRITICAL_SECTION xdnd_cs; @@ -571,17 +570,27 @@ NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size ) { /* Only send WM_DROPFILES if Drop didn't succeed or DROPEFFECT_NONE was set. * Doing both causes winamp to duplicate the dropped files (#29081) */ - HWND hwnd_drop = window_accepting_files(window_from_point_dnd( hwnd, XDNDxy )); + FORMATETC format = {.cfFormat = CF_HDROP}; + STGMEDIUM medium;
- if (hwnd_drop && X11DRV_XDND_HasHDROP()) + if (hwnd_drop && SUCCEEDED(IDataObject_GetData( &object->IDataObject_iface, &format, &medium ))) { - HRESULT hr = X11DRV_XDND_SendDropFiles(hwnd_drop); - if (SUCCEEDED(hr)) - { - accept = 1; - effect = DROPEFFECT_COPY; - } + DROPFILES *drop = GlobalLock( medium.hGlobal ); + void *files = (char *)drop + drop->pFiles; + RECT rect; + + drop->pt.x = XDNDxy.x; + drop->pt.y = XDNDxy.y; + drop->fNC = !ScreenToClient( hwnd, &drop->pt ) || !GetClientRect( hwnd, &rect ) || !PtInRect( &rect, drop->pt ); + + TRACE( "Sending WM_DROPFILES: hwnd %p, pt %s, fNC %u, files %p (%s)\n", hwnd, + wine_dbgstr_point( &drop->pt), drop->fNC, files, debugstr_w(files) ); + GlobalUnlock( medium.hGlobal ); + + PostMessageW( hwnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0 ); + accept = 1; + effect = DROPEFFECT_COPY; } }
@@ -670,39 +679,6 @@ static BOOL X11DRV_XDND_HasHDROP(void) return found; }
-/************************************************************************** - * X11DRV_XDND_SendDropFiles - */ -static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd) -{ - FORMATETC format = {.cfFormat = CF_HDROP}; - struct data_object *object; - STGMEDIUM medium; - HRESULT hr; - - if (!(object = get_data_object())) return E_FAIL; - - if (SUCCEEDED(hr = IDataObject_GetData( &object->IDataObject_iface, &format, &medium ))) - { - DROPFILES *drop = GlobalLock( medium.hGlobal ); - void *files = (char *)drop + drop->pFiles; - RECT rect; - - drop->pt.x = XDNDxy.x; - drop->pt.y = XDNDxy.y; - drop->fNC = !ScreenToClient( hwnd, &drop->pt ) || !GetClientRect( hwnd, &rect ) || !PtInRect( &rect, drop->pt ); - - TRACE( "Sending WM_DROPFILES: hwnd %p, pt %s, fNC %u, files %p (%s)\n", hwnd, - wine_dbgstr_point( &drop->pt), drop->fNC, files, debugstr_w(files) ); - GlobalUnlock( medium.hGlobal ); - - PostMessageW( hwnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0 ); - } - - IDataObject_Release( &object->IDataObject_iface ); - return hr; -} -
/************************************************************************** * X11DRV_XDND_FreeDragDropOp
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/xdnd.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 461463d7212..6f114c5a13f 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -304,12 +304,16 @@ static HRESULT data_object_create( UINT entries_size, const struct format_entry return S_OK; }
-static struct data_object *get_data_object(void) +static struct data_object *get_data_object( BOOL clear ) { IDataObject *iface;
EnterCriticalSection( &xdnd_cs ); - if ((iface = xdnd_data_object)) IDataObject_AddRef( iface ); + if ((iface = xdnd_data_object)) + { + if (clear) xdnd_data_object = NULL; + else IDataObject_AddRef( iface ); + } LeaveCriticalSection( &xdnd_cs );
if (!iface) return NULL; @@ -432,7 +436,7 @@ NTSTATUS WINAPI x11drv_dnd_position_event( void *arg, ULONG size ) HWND targetWindow; HRESULT hr;
- if (!(object = get_data_object())) return STATUS_INVALID_PARAMETER; + if (!(object = get_data_object( FALSE ))) return STATUS_INVALID_PARAMETER;
XDNDxy = params->point; targetWindow = window_from_point_dnd( UlongToHandle( params->hwnd ), XDNDxy ); @@ -522,7 +526,7 @@ NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size ) struct data_object *object; BOOL drop_file = TRUE;
- if (!(object = get_data_object())) return STATUS_INVALID_PARAMETER; + if (!(object = get_data_object( TRUE ))) return STATUS_INVALID_PARAMETER;
/* Notify OLE of Drop */ if (XDNDAccepted) @@ -611,7 +615,7 @@ NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size ) NTSTATUS WINAPI x11drv_dnd_leave_event( void *params, ULONG size ) { IDropTarget *dropTarget; - IDataObject *object; + struct data_object *object;
TRACE("DND Operation canceled\n");
@@ -628,12 +632,7 @@ NTSTATUS WINAPI x11drv_dnd_leave_event( void *params, ULONG size ) } }
- EnterCriticalSection( &xdnd_cs ); - object = xdnd_data_object; - xdnd_data_object = NULL; - LeaveCriticalSection( &xdnd_cs ); - - if (object) IDataObject_Release( object ); + if ((object = get_data_object( TRUE ))) IDataObject_Release( &object->IDataObject_iface );
X11DRV_XDND_FreeDragDropOp(); return STATUS_SUCCESS;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/Makefile.in | 2 +- dlls/winex11.drv/xdnd.c | 160 ++++++++++++++++++++++++++++++----- 2 files changed, 141 insertions(+), 21 deletions(-)
diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index f570b026db4..7b7282574d0 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -1,7 +1,7 @@ MODULE = winex11.drv UNIXLIB = winex11.so IMPORTS = uuid user32 gdi32 win32u -DELAYIMPORTS = comctl32 ole32 shell32 imm32 +DELAYIMPORTS = combase UNIX_CFLAGS = $(X_CFLAGS) UNIX_LIBS = -lwin32u $(X_LIBS) $(PTHREAD_LIBS) -lm
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 6f114c5a13f..d2e4df373d8 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -104,6 +104,145 @@ static struct data_object *data_object_from_IDataObject( IDataObject *iface ) return CONTAINING_RECORD( iface, struct data_object, IDataObject_iface ); }
+struct format_iterator +{ + IEnumFORMATETC IEnumFORMATETC_iface; + LONG refcount; + + struct format_entry *entry; + IDataObject *object; +}; + +static inline struct format_iterator *format_iterator_from_IEnumFORMATETC( IEnumFORMATETC *iface ) +{ + return CONTAINING_RECORD(iface, struct format_iterator, IEnumFORMATETC_iface); +} + +static HRESULT WINAPI format_iterator_QueryInterface( IEnumFORMATETC *iface, REFIID iid, void **obj ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + + TRACE( "iterator %p, iid %s, obj %p\n", iterator, debugstr_guid(iid), obj ); + + if (IsEqualIID( iid, &IID_IUnknown ) || IsEqualIID( iid, &IID_IEnumFORMATETC )) + { + IEnumFORMATETC_AddRef( &iterator->IEnumFORMATETC_iface ); + *obj = &iterator->IEnumFORMATETC_iface; + return S_OK; + } + + *obj = NULL; + WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI format_iterator_AddRef( IEnumFORMATETC *iface ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + ULONG ref = InterlockedIncrement( &iterator->refcount ); + TRACE( "iterator %p increasing refcount to %lu.\n", iterator, ref ); + return ref; +} + +static ULONG WINAPI format_iterator_Release(IEnumFORMATETC *iface) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + ULONG ref = InterlockedDecrement( &iterator->refcount ); + + TRACE( "iterator %p increasing refcount to %lu.\n", iterator, ref ); + + if (!ref) + { + IDataObject_Release( iterator->object ); + free( iterator ); + } + + return ref; +} + +static HRESULT WINAPI format_iterator_Next( IEnumFORMATETC *iface, ULONG count, FORMATETC *formats, ULONG *ret ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + struct data_object *object = data_object_from_IDataObject( iterator->object ); + struct format_entry *entry; + UINT i; + + TRACE( "iterator %p, count %lu, formats %p, ret %p\n", iterator, count, formats, ret ); + + for (entry = iterator->entry, i = 0; entry < object->entries_end && i < count; entry = next_format( entry ), i++) + { + formats[i].cfFormat = entry->format; + formats[i].ptd = NULL; + formats[i].dwAspect = DVASPECT_CONTENT; + formats[i].lindex = -1; + formats[i].tymed = TYMED_HGLOBAL; + } + + iterator->entry = entry; + if (ret) *ret = i; + return (i == count) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI format_iterator_Skip( IEnumFORMATETC *iface, ULONG count ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + struct data_object *object = data_object_from_IDataObject( iterator->object ); + struct format_entry *entry; + + TRACE( "iterator %p, count %lu\n", iterator, count ); + + for (entry = iterator->entry; entry < object->entries_end; entry = next_format( entry )) + if (!count--) break; + + iterator->entry = entry; + return count ? S_FALSE : S_OK; +} + +static HRESULT WINAPI format_iterator_Reset( IEnumFORMATETC *iface ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + struct data_object *object = data_object_from_IDataObject( iterator->object ); + + TRACE( "iterator %p\n", iterator ); + iterator->entry = object->entries; + return S_OK; +} + +static HRESULT format_iterator_create( IDataObject *object, IEnumFORMATETC **out ); + +static HRESULT WINAPI format_iterator_Clone( IEnumFORMATETC *iface, IEnumFORMATETC **out ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + TRACE( "iterator %p, out %p\n", iterator, out ); + return format_iterator_create( iterator->object, out ); +} + +static const IEnumFORMATETCVtbl format_iterator_vtbl = +{ + format_iterator_QueryInterface, + format_iterator_AddRef, + format_iterator_Release, + format_iterator_Next, + format_iterator_Skip, + format_iterator_Reset, + format_iterator_Clone, +}; + +static HRESULT format_iterator_create( IDataObject *object, IEnumFORMATETC **out ) +{ + struct format_iterator *iterator; + + if (!(iterator = calloc( 1, sizeof(*iterator) ))) return E_OUTOFMEMORY; + iterator->IEnumFORMATETC_iface.lpVtbl = &format_iterator_vtbl; + iterator->refcount = 1; + IDataObject_AddRef( (iterator->object = object) ); + iterator->entry = data_object_from_IDataObject(object)->entries; + + *out = &iterator->IEnumFORMATETC_iface; + TRACE( "created object %p iterator %p\n", object, iterator ); + return S_OK; +} + static HRESULT WINAPI data_object_QueryInterface( IDataObject *iface, REFIID iid, void **obj ) { struct data_object *object = data_object_from_IDataObject( iface ); @@ -219,10 +358,6 @@ static HRESULT WINAPI data_object_SetData( IDataObject *iface, FORMATETC *format static HRESULT WINAPI data_object_EnumFormatEtc( IDataObject *iface, DWORD direction, IEnumFORMATETC **out ) { struct data_object *object = data_object_from_IDataObject( iface ); - struct format_entry *iter; - DWORD i = 0, count = 0; - FORMATETC *formats; - HRESULT hr;
TRACE( "object %p, direction %lu, out %p\n", object, direction, out );
@@ -232,22 +367,7 @@ static HRESULT WINAPI data_object_EnumFormatEtc( IDataObject *iface, DWORD direc return E_NOTIMPL; }
- for (iter = object->entries; iter < object->entries_end; iter = next_format( iter )) count++; - - if (!(formats = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*formats) ))) return E_OUTOFMEMORY; - - for (iter = object->entries; iter < object->entries_end; iter = next_format( iter ), i++) - { - formats[i].cfFormat = iter->format; - formats[i].ptd = NULL; - formats[i].dwAspect = DVASPECT_CONTENT; - formats[i].lindex = -1; - formats[i].tymed = TYMED_HGLOBAL; - } - - hr = SHCreateStdEnumFmtEtc( count, formats, out ); - HeapFree( GetProcessHeap(), 0, formats ); - return hr; + return format_iterator_create( iface, out ); }
static HRESULT WINAPI data_object_DAdvise( IDataObject *iface, FORMATETC *format, DWORD flags,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/xdnd.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index d2e4df373d8..14e33bcc087 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -40,7 +40,6 @@ static HWND XDNDLastTargetWnd; /* might be an ancestor of XDNDLastTargetWnd */ static HWND XDNDLastDropTargetWnd;
-static BOOL X11DRV_XDND_HasHDROP(void); static void X11DRV_XDND_FreeDragDropOp(void);
static CRITICAL_SECTION xdnd_cs; @@ -622,8 +621,9 @@ NTSTATUS WINAPI x11drv_dnd_position_event( void *arg, ULONG size ) else { /* fallback search for window able to accept these files. */ + FORMATETC format = {.cfFormat = CF_HDROP};
- if (window_accepting_files(targetWindow) && X11DRV_XDND_HasHDROP()) + if (window_accepting_files(targetWindow) && SUCCEEDED(IDataObject_QueryGetData( &object->IDataObject_iface, &format ))) { accept = 1; effect = DROPEFFECT_COPY; @@ -783,22 +783,6 @@ NTSTATUS WINAPI x11drv_dnd_enter_event( void *args, ULONG size ) }
-/************************************************************************** - * X11DRV_XDND_HasHDROP - */ -static BOOL X11DRV_XDND_HasHDROP(void) -{ - FORMATETC format = {.cfFormat = CF_HDROP}; - BOOL found = FALSE; - - EnterCriticalSection(&xdnd_cs); - found = xdnd_data_object && SUCCEEDED(IDataObject_QueryGetData( xdnd_data_object, &format )); - LeaveCriticalSection(&xdnd_cs); - - return found; -} - - /************************************************************************** * X11DRV_XDND_FreeDragDropOp */