All pastes #1165372 Raw Edit

Spore patch for wine 1.1.2-GIT

public text v1 · immutable
#1165372 ·published 2008-08-11 00:01 UTC
rendered paste body
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c
index 7376525..5f7abc4 100644
--- a/dlls/d3d9/device.c
+++ b/dlls/d3d9/device.c
@@ -746,7 +746,7 @@ static HRESULT  WINAPI  IDirect3DDevice9Impl_GetDepthStencilSurface(LPDIRECT3DDE
         }
     } else {
         WARN("Call to IWineD3DDevice_GetDepthStencilSurface failed\n");
-        *ppZStencilSurface = NULL;
+        // *ppZStencilSurface = NULL;
     }
     LeaveCriticalSection(&d3d9_cs);
     return hr;
diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index bc2ee97..59f56d8 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -108,7 +108,7 @@ NTSTATUS WINAPI NtQueryObject(IN HANDLE handle,
         }
         break;
     default:
-        FIXME("Unsupported information class %u\n", info_class);
+        FIXME("Unsupported information class %u compared to %u\n", info_class, ObjectAllInformation);
         status = STATUS_NOT_IMPLEMENTED;
         break;
     }
diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c
index 5cee7a1..8294131 100644
--- a/dlls/ole32/ole2.c
+++ b/dlls/ole32/ole2.c
@@ -279,7 +279,7 @@ HRESULT WINAPI RegisterDragDrop(
 {
   DropTargetNode* dropTargetInfo;
 
-  TRACE("(%p,%p)\n", hwnd, pDropTarget);
+  FIXME("(%p,%p)\n", hwnd, pDropTarget);
 
   if (!COM_CurrentApt())
   {
@@ -323,6 +323,7 @@ HRESULT WINAPI RegisterDragDrop(
 
   list_add_tail(&targetListHead, &dropTargetInfo->entry);
 
+  FIXME("Okay\n");
   return S_OK;
 }
 
@@ -334,7 +335,7 @@ HRESULT WINAPI RevokeDragDrop(
 {
   DropTargetNode* dropTargetInfo;
 
-  TRACE("(%p)\n", hwnd);
+  FIXME("(%p)\n", hwnd);
 
   if (!IsWindow(hwnd))
   {
@@ -1940,6 +1941,14 @@ static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
   return NULL;
 }
 
+IDropTarget* wine_oledd_find_drop_target(HWND hwndOfTarget)
+{
+    DropTargetNode *node = OLEDD_FindDropTarget(hwndOfTarget);
+    if (node)
+        return node->dropTarget;
+    return NULL;
+}
+
 /***
  * OLEDD_DragTrackerWindowProc()
  *
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec
index 7561156..5c4761f 100644
--- a/dlls/ole32/ole32.spec
+++ b/dlls/ole32/ole32.spec
@@ -277,3 +277,5 @@
 @ stdcall WriteFmtUserTypeStg(ptr long ptr)
 @ stub WriteOleStg
 @ stub WriteStringStream
+@ cdecl wine_oledd_find_drop_target(long)
+
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 49a72eb..e626912 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3382,7 +3382,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, C
 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
 
-    *pRect = This->updateStateBlock->scissorRect;
+    // For some, as of yet unexplained, reason, this breaks Spore Creature Creator.
+    // *pRect = This->updateStateBlock->scissorRect;
+    // Go back to previous version for now
+    memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
     TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
     return WINED3D_OK;
 }
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c
index 1422578..240e494 100644
--- a/dlls/winex11.drv/xdnd.c
+++ b/dlls/winex11.drv/xdnd.c
@@ -19,6 +19,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#define COBJMACROS
+#include <initguid.h>
+
 #include "config.h"
 #include "wine/port.h"
 
@@ -36,6 +39,8 @@
 
 #include "x11drv.h"
 #include "shlobj.h"  /* DROPFILES */
+#include "oleidl.h"
+#include "objidl.h"
 
 #include "wine/unicode.h"
 #include "wine/debug.h"
@@ -57,6 +62,10 @@ typedef struct tagXDNDDATA
 
 static LPXDNDDATA XDNDData = NULL;
 static POINT XDNDxy = { 0, 0 };
+extern IDataObject xdndDataObject;
+static BOOL XDNDEntered = FALSE;
+static BOOL XDNDAccepted = FALSE;
+static DWORD XDNDDropEffect = DROPEFFECT_NONE;
 
 static void X11DRV_XDND_InsertXDNDData(int property, int format, void* data, unsigned int len);
 static int X11DRV_XDND_DeconstructTextURIList(int property, void* data, int len);
@@ -70,6 +79,10 @@ static void X11DRV_XDND_FreeDragDropOp(void);
 static unsigned int X11DRV_XDND_UnixToDos(char** lpdest, char* lpsrc, int len);
 static WCHAR* X11DRV_XDND_URIToDOS(char *encodedURI);
 
+static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat, char *buffer, int size);
+static DWORD X11DRV_XDND_ActionToDROPEFFECT(long action);
+static long X11DRV_XDND_DROPEFFECTToAction(DWORD effect);
+
 static CRITICAL_SECTION xdnd_cs;
 static CRITICAL_SECTION_DEBUG critsect_debug =
 {
@@ -150,15 +163,75 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event )
 {
     XClientMessageEvent e;
     int accept = 0; /* Assume we're not accepting */
+    HMODULE ole32;
+    IDropTarget *dropTarget = NULL;
+    DWORD effect;
+    POINTL pointl;
 
     XDNDxy.x = event->data.l[2] >> 16;
     XDNDxy.y = event->data.l[2] & 0xFFFF;
+    pointl.x = XDNDxy.x;
+    pointl.y = XDNDxy.y;
+
+    effect = X11DRV_XDND_ActionToDROPEFFECT(event->data.l[4]);
+
+    /* Notify OLE of DragEnter. Result determines if we accept */
+    ole32 = GetModuleHandleA("OLE32.DLL");
+    if (ole32)
+    {
+        IDropTarget *(CDECL *wine_oledd_find_drop_target)(HWND) = (void*)
+            GetProcAddress(ole32, "wine_oledd_find_drop_target");
+        if (wine_oledd_find_drop_target)
+        {
+            dropTarget = wine_oledd_find_drop_target(hWnd);
+            if (dropTarget)
+            {
+                HRESULT hr;
+                if (XDNDEntered == FALSE)
+                {
+                    XDNDEntered = TRUE;
+                    hr = IDropTarget_DragEnter(dropTarget, &xdndDataObject,
+                                               MK_LBUTTON, pointl, &effect);
+                    if (SUCCEEDED(hr))
+                    {
+                        if (effect != DROPEFFECT_NONE)
+                        {
+                            XDNDAccepted = TRUE;
+                            TRACE("the application accepted the drop\n");
+                        }
+                        else
+                            TRACE("the application refused the drop\n");
+                    }
+                    else
+                        WARN("IDropTarget_DragEnter failed, error 0x%X\n", hr);
+                }
+            }
+            else
+                TRACE("no drop target\n");
+        }
+        else
+            WARN("wine_oledd_find_drop_target not found\n");
+    }
+    else
+        WARN("loading ole32 failed\n");
 
-    /* FIXME: Notify OLE of DragEnter. Result determines if we accept */
+    if (XDNDAccepted)
+        accept = 1;
 
     if (GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)
         accept = 1;
 
+ 
+    /* If drag accepted notify OLE of DragOver */
+    if (dropTarget && accept)
+    {
+        HRESULT hr = IDropTarget_DragOver(dropTarget, MK_LBUTTON, pointl, &effect);
+        if (SUCCEEDED(hr))
+            XDNDDropEffect = effect;
+        else
+            WARN("IDropTarget_DragOver failed, error 0x%X\n", hr);
+    }
+
     TRACE("action req: %ld accept(%d) at x(%d),y(%d)\n",
           event->data.l[4], accept, XDNDxy.x, XDNDxy.y);
 
@@ -176,14 +249,12 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event )
     e.data.l[2] = 0; /* Empty Rect */
     e.data.l[3] = 0; /* Empty Rect */
     if (accept)
-        e.data.l[4] = event->data.l[4];
+        e.data.l[4] = X11DRV_XDND_DROPEFFECTToAction(effect);
     else
         e.data.l[4] = None;
     wine_tsx11_lock();
     XSendEvent(event->display, event->data.l[0], False, NoEventMask, (XEvent*)&e);
     wine_tsx11_unlock();
-
-    /* FIXME: if drag accepted notify OLE of DragOver */
 }
 
 /**************************************************************************
@@ -194,6 +265,7 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event )
 void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
 {
     XClientMessageEvent e;
+    HMODULE ole32;
 
     TRACE("\n");
 
@@ -201,7 +273,44 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
     if (GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)
         X11DRV_XDND_SendDropFiles( hWnd );
 
-    /* FIXME: Notify OLE of Drop */
+    /* Notify OLE of Drop */
+    ole32 = GetModuleHandleA("OLE32.DLL");
+    if (ole32)
+    {
+        IDropTarget *(CDECL *wine_oledd_find_drop_target)(HWND) = (void*)
+            GetProcAddress(ole32, "wine_oledd_find_drop_target");
+        if (wine_oledd_find_drop_target)
+        {
+            IDropTarget *dropTarget = wine_oledd_find_drop_target(hWnd);
+            if (dropTarget)
+            {
+                HRESULT hr;
+                POINTL pointl;
+                DWORD effect = XDNDDropEffect;
+
+                pointl.x = XDNDxy.x;
+                pointl.y = XDNDxy.y;
+                hr = IDropTarget_Drop(dropTarget, &xdndDataObject, MK_LBUTTON,
+                                      pointl, &effect);
+                if (SUCCEEDED(hr))
+                {
+                    if (effect != DROPEFFECT_NONE)
+                        TRACE("drop succeeded\n");
+                    else
+                        TRACE("the application refused the drop\n");
+                }
+                else
+                    WARN("drop failed, error 0x%X\n", hr);
+           }
+           else
+                TRACE("no drop target\n");
+        }
+        else
+            WARN("wine_oledd_find_drop_target failed\n");
+    }
+    else
+        WARN("failed loading ole32\n");
+
     X11DRV_XDND_FreeDragDropOp();
 
     /* Tell the target we are finished. */
@@ -215,6 +324,8 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
     wine_tsx11_lock();
     XSendEvent(event->display, event->data.l[0], False, NoEventMask, (XEvent*)&e);
     wine_tsx11_unlock();
+    
+    XDNDEntered = XDNDAccepted = FALSE;
 }
 
 /**************************************************************************
@@ -224,11 +335,36 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
  */
 void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event )
 {
+    HMODULE ole32;
     TRACE("DND Operation canceled\n");
 
     X11DRV_XDND_FreeDragDropOp();
 
-    /* FIXME: Notify OLE of DragLeave */
+    /* Notify OLE of DragLeave */
+    ole32 = GetModuleHandleA("OLE32.DLL");
+    if (ole32)
+    {
+        IDropTarget *(CDECL *wine_oledd_find_drop_target)(HWND) = (void*)
+            GetProcAddress(ole32, "wine_oledd_find_drop_target");
+        if (wine_oledd_find_drop_target)
+        {
+            IDropTarget *dropTarget = wine_oledd_find_drop_target(hWnd);
+            if (dropTarget)
+            {
+                HRESULT hr = IDropTarget_DragLeave(dropTarget);
+                if (FAILED(hr))
+                    WARN("IDropTarget_DragLeave failed, error 0x%X\n", hr);
+            }
+            else
+                TRACE("drop target not found\n");
+        }
+        else
+            WARN("wine_oledd_find_drop_target not found\n");        
+    }
+    else
+        WARN("loading ole32 failed\n");
+
+    XDNDEntered = XDNDAccepted = FALSE;
 }
 
 
@@ -248,6 +384,9 @@ static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm,
     unsigned long bytesret, icount;
     int entries = 0;
     unsigned char* data = NULL;
+    XDNDDATA *previous = NULL;
+    XDNDDATA *current, *next;
+    BOOL haveHDROP = FALSE;
 
     TRACE("count(%ld)\n", *count);
 
@@ -292,6 +431,67 @@ static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm,
         wine_tsx11_unlock();
     }
 
+    /* We get the list of formats in descending order of preference, yet the linked
+     * list is a stack so the order is inverted. Reverse the linked list here so
+     * that we get the right order.
+     */
+    current = XDNDData;
+    while (current != NULL)
+    {
+        next = current->next;
+        current->next = previous;
+        previous = current;
+        current = next;
+    }
+    if (previous)
+        XDNDData = previous;
+
+    /* On Windows when there is a CF_HDROP, there is no other CF_ formats.
+     * foobar2000 relies on this (spaces -> %20's without it).
+     */
+    current = XDNDData;
+    while (current != NULL)
+    {
+        if (current->cf_win == CF_HDROP)
+        {
+            haveHDROP = TRUE;
+            break;
+        }
+        current = current->next;
+    }
+    if (haveHDROP)
+    {
+        current = XDNDData;
+        while (current != NULL
+            && current->cf_win != CF_HDROP
+            && current->cf_win < CF_MAX)
+        {
+            next = current->next;
+            HeapFree(GetProcessHeap(), 0, current->data);
+            HeapFree(GetProcessHeap(), 0, current);
+            current = next;
+            --entries;
+        }
+        XDNDData = previous = current;
+        while (current != NULL)
+        {
+            current = current->next;
+            while (current != NULL
+                && current->cf_win != CF_HDROP
+                && current->cf_win < CF_MAX)
+            {
+                next = current->next;
+                HeapFree(GetProcessHeap(), 0, current->data);
+                HeapFree(GetProcessHeap(), 0, current);
+                current = next;
+                --entries;
+            }
+            previous->next = current;
+            previous = current;
+        }
+    }
+
+
     *count = entries;
 }
 
@@ -329,7 +529,7 @@ static int X11DRV_XDND_MapFormat(unsigned int property, unsigned char *data, int
     void* xdata;
     int count = 0;
 
-    TRACE("%d: %s\n", property, data);
+    TRACE("%d: len %i\n", property, strlen((char*) data));
 
     /* Always include the raw type */
     xdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
@@ -424,6 +624,7 @@ static int X11DRV_XDND_DeconstructTextURIList(int property, void* data, int len)
             dropFiles->fNC = 0;
             dropFiles->fWide = FALSE;
             out[size] = '\0';
+            FIXME("Out: %s\n", out);
             memcpy(((char*)dropFiles) + dropFiles->pFiles, out, size + 1);
             X11DRV_XDND_InsertXDNDData(property, CF_HDROP, dropFiles, sizeof(DROPFILES) + size + 1);
             count = 1;
@@ -652,6 +853,331 @@ static WCHAR* X11DRV_XDND_URIToDOS(char *encodedURI)
             ret = wine_get_dos_file_name(&uri[5]);
         }
     }
+    else if (strncmp(uri, "http://", 7) == 0)
+    {
+      FIXME("Hack ensues.\n");
+      char tmp[1024];
+      char *tn = tmpnam(tmp);
+      int len = strlen(tn) + strlen("wget ") + strlen(" -O ") + strlen(uri) + strlen(strrchr(uri, '/')+1);
+      char *cmd = (char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+      strcpy(cmd, "wget "); strcat(cmd, uri); strcat(cmd, " -O "); strcat(cmd, tn); strcat(cmd, strrchr(uri, '/')+1);
+      system(cmd);
+      ret = wine_get_dos_file_name(strstr(cmd, " -O ")+4);
+      HeapFree(GetProcessHeap(), 0, cmd);
+    }
     HeapFree(GetProcessHeap(), 0, uri);
     return ret;
 }
+
+/**************************************************************************
+ * X11DRV_XDND_DescribeClipboardFormat
+ */
+static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat, char *buffer, int size)
+{
+#define D(x) case x: lstrcpynA(buffer, #x, size); return;
+    switch (cfFormat)
+    {
+        D(CF_TEXT)
+        D(CF_BITMAP)
+        D(CF_METAFILEPICT)
+        D(CF_SYLK)
+        D(CF_DIF)
+        D(CF_TIFF)
+        D(CF_OEMTEXT)
+        D(CF_DIB)
+        D(CF_PALETTE)
+        D(CF_PENDATA)
+        D(CF_RIFF)
+        D(CF_WAVE)
+        D(CF_UNICODETEXT)
+        D(CF_ENHMETAFILE)
+        D(CF_HDROP)
+        D(CF_LOCALE)
+        D(CF_DIBV5)
+    }
+#undef D
+
+    if (CF_PRIVATEFIRST <= cfFormat && cfFormat <= CF_PRIVATELAST)
+    {
+        GetClipboardFormatNameA(cfFormat, buffer, size);
+        return;
+    }
+
+    if (CF_GDIOBJFIRST <= cfFormat && cfFormat <= CF_GDIOBJLAST)
+    {
+        lstrcpynA(buffer, "some GDI object", size);
+        return;
+    }
+
+    snprintf(buffer, size, "unknown format %d", cfFormat);
+}
+
+
+/**************************************************************************
+ * X11DRV_XDND_ActionToDROPEFFECT
+ */
+static DWORD X11DRV_XDND_ActionToDROPEFFECT(long action)
+{
+    /* In Windows, nothing but the given effects is allowed.
+     * In X the given action is just a hint, and you can always
+     * XdndActionCopy and XdndActionPrivate, so be more permissive. */
+    if (action == x11drv_atom(XdndActionCopy))
+        return DROPEFFECT_COPY;
+    else if (action == x11drv_atom(XdndActionMove))
+        return DROPEFFECT_MOVE | DROPEFFECT_COPY;
+    else if (action == x11drv_atom(XdndActionLink))
+        return DROPEFFECT_LINK | DROPEFFECT_COPY;
+    else if (action == x11drv_atom(XdndActionAsk))
+        /* FIXME: should we somehow ask the user what to do here? */
+        return DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
+    FIXME("unknown action %ld, assuming DROPEFFECT_COPY\n", action);
+    return DROPEFFECT_COPY;
+}
+
+
+/**************************************************************************
+ * X11DRV_XDND_DROPEFFECTToAction
+ */
+static long X11DRV_XDND_DROPEFFECTToAction(DWORD effect)
+{
+    if (effect == DROPEFFECT_COPY)
+        return x11drv_atom(XdndActionCopy);
+    else if (effect == DROPEFFECT_MOVE)
+        return x11drv_atom(XdndActionMove);
+    else if (effect == DROPEFFECT_LINK)
+        return x11drv_atom(XdndActionLink);
+    FIXME("unknown drop effect %u, assuming XdndActionCopy\n", effect);
+    return x11drv_atom(XdndActionCopy);
+}
+
+
+/* The IDataObject singleton we feed to OLE follows */
+
+static HRESULT WINAPI DATAOBJECT_QueryInterface(IDataObject *dataObject,
+                                                REFIID riid, void **ppvObject)
+{
+    TRACE("(%p, %s, %p)\n", dataObject, debugstr_guid(riid), ppvObject);
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDataObject))
+    {
+        *ppvObject = dataObject;
+        IDataObject_AddRef(dataObject);
+        return S_OK;
+    }
+    *ppvObject = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI DATAOBJECT_AddRef(IDataObject *dataObject)
+{
+    TRACE("(%p)\n", dataObject);
+    return 2;
+}
+
+static ULONG WINAPI DATAOBJECT_Release(IDataObject *dataObject)
+{
+    TRACE("(%p)\n", dataObject);
+    return 1;
+}
+
+static HRESULT WINAPI DATAOBJECT_GetData(IDataObject *dataObject,
+                                         FORMATETC *formatEtc,
+                                         STGMEDIUM *pMedium)
+{
+    XDNDDATA *data = XDNDData;
+    HRESULT hr;
+    char buffer[1024];
+
+    TRACE("(%p, %p, %p)\n", dataObject, formatEtc, pMedium);
+    X11DRV_XDND_DescribeClipboardFormat(formatEtc->cfFormat,
+                                        buffer, sizeof(buffer));
+    TRACE("application is looking for %s\n", buffer);
+
+    hr = IDataObject_QueryGetData(dataObject, formatEtc);
+    if (SUCCEEDED(hr))
+    {
+        while (data != NULL)
+        {
+            if (data->cf_win == formatEtc->cfFormat)
+            {
+                pMedium->tymed = TYMED_HGLOBAL;
+                pMedium->hGlobal = HeapAlloc(GetProcessHeap(), 0, data->size);
+                if (pMedium->hGlobal == NULL)
+                    return E_OUTOFMEMORY;
+                memcpy(pMedium->hGlobal, data->data, data->size);
+                pMedium->pUnkForRelease = 0;
+                return S_OK;
+            }
+            data = data->next;
+        }
+    }
+    return hr;
+}
+
+static HRESULT WINAPI DATAOBJECT_GetDataHere(IDataObject *dataObject,
+                                             FORMATETC *formatEtc,
+                                             STGMEDIUM *pMedium)
+{
+    FIXME("(%p, %p, %p): stub\n", dataObject, formatEtc, pMedium);
+    return DATA_E_FORMATETC;
+}
+
+static HRESULT WINAPI DATAOBJECT_QueryGetData(IDataObject *dataObject,
+                                              FORMATETC *formatEtc)
+{
+   XDNDDATA *data = XDNDData;
+   char buffer[1024];
+
+    TRACE("(%p, %p)\n", dataObject, formatEtc);
+    X11DRV_XDND_DescribeClipboardFormat(formatEtc->cfFormat, buffer,
+                                        sizeof(buffer));
+
+    if (formatEtc->tymed != TYMED_HGLOBAL)
+    {
+        FIXME("only HGLOBAL medium types supported right now\n");
+        return E_NOTIMPL;
+    }
+    if (formatEtc->dwAspect != DVASPECT_CONTENT)
+    {
+        FIXME("only the content aspect is supported right now\n");
+        return E_NOTIMPL;
+    }
+
+    while (data != NULL)
+    {
+        if (data->cf_win == formatEtc->cfFormat)
+        {
+            TRACE("application found %s\n", buffer);
+            TRACE("Data is: %i %.*s\n", data->size, data->size, (char*) data->data);
+            return S_OK;
+        }
+        data = data->next;
+    }
+    TRACE("application didn't find %s\n", buffer);
+    return DV_E_FORMATETC;
+}
+
+static HRESULT WINAPI DATAOBJECT_GetCanonicalFormatEtc(IDataObject *dataObject,
+                                                       FORMATETC *formatEtc,
+                                                       FORMATETC *formatEtcOut)
+{
+    FIXME("(%p, %p, %p): stub\n", dataObject, formatEtc, formatEtcOut);
+    formatEtcOut->ptd = NULL;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DATAOBJECT_SetData(IDataObject *dataObject,
+                                         FORMATETC *formatEtc,
+                                         STGMEDIUM *pMedium, BOOL fRelease)
+{
+    FIXME("(%p, %p, %p, %s): stub\n", dataObject, formatEtc,
+        pMedium, fRelease?"TRUE":"FALSE");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DATAOBJECT_EnumFormatEtc(IDataObject *dataObject,
+                                               DWORD dwDirection,
+                                               IEnumFORMATETC **ppEnumFormatEtc)
+{
+    HMODULE shell32;
+    XDNDDATA *data = XDNDData;
+    int i;
+    DWORD count = 0;
+    FORMATETC *formats;
+    HRESULT hr;
+
+    TRACE("(%u, %p)\n", dwDirection, ppEnumFormatEtc);
+
+    if (dwDirection != DATADIR_GET)
+    {
+        FIXME("only the get direction is implemented\n");
+        return E_NOTIMPL;
+    }
+
+    while (data != NULL)
+    {
+        data = data->next;
+        ++count;
+    }
+
+    formats = HeapAlloc(GetProcessHeap(), 0, count * sizeof(FORMATETC));
+    if (formats)
+    {
+        data = XDNDData;
+        for (i = 0; i < count; ++i)
+        {
+            formats[i].cfFormat = data->cf_win;
+            formats[i].ptd = NULL;
+            formats[i].dwAspect = DVASPECT_CONTENT;
+            formats[i].lindex = -1;
+            formats[i].tymed = TYMED_HGLOBAL;
+            data = data->next;
+        }
+        /* For some strange reason, load-time linking SHELL32.DLL to WINEX11.DRV
+         * causes wine to segfault on startup. So rather use run-time linking.
+         */
+        shell32 = LoadLibraryA("SHELL32.DLL");
+        if (shell32)
+        {
+            HRESULT (WINAPI *SHCreateStdEnumFmtEtc)(DWORD, FORMATETC*, IEnumFORMATETC**) = (void*)
+                GetProcAddress(shell32, (char*) MAKELONG(74, 0));
+            if (SHCreateStdEnumFmtEtc)
+                hr = SHCreateStdEnumFmtEtc(count, formats, ppEnumFormatEtc);
+            else
+            {
+                ERR("symbol lookup of SHCreateStdEnumFmtEtc failed\n");
+                hr = E_FAIL;
+            }
+        }
+        else
+        {
+            WARN("loading SHELL32.DLL failed\n");
+            hr = E_FAIL;
+        }
+        HeapFree(GetProcessHeap(), 0, formats);
+        return hr;
+    }
+    else
+        return E_OUTOFMEMORY;
+}
+
+static HRESULT WINAPI DATAOBJECT_DAdvise(IDataObject *dataObject,
+                                         FORMATETC *formatEtc, DWORD advf,
+                                         IAdviseSink *adviseSink,
+                                         DWORD *pdwConnection)
+{
+    FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject, formatEtc, advf,
+        adviseSink, pdwConnection);
+    return OLE_E_ADVISENOTSUPPORTED;
+}
+
+static HRESULT WINAPI DATAOBJECT_DUnadvise(IDataObject *dataObject,
+                                           DWORD dwConnection)
+{
+    FIXME("(%p, %u): stub\n", dataObject, dwConnection);
+    return OLE_E_ADVISENOTSUPPORTED;
+}
+
+static HRESULT WINAPI DATAOBJECT_EnumDAdvise(IDataObject *dataObject,
+                                             IEnumSTATDATA **pEnumAdvise)
+{
+    FIXME("(%p, %p): stub\n", dataObject, pEnumAdvise);
+    return OLE_E_ADVISENOTSUPPORTED;
+}
+
+static IDataObjectVtbl xdndDataObjectVtbl =
+{
+    DATAOBJECT_QueryInterface,
+    DATAOBJECT_AddRef,
+    DATAOBJECT_Release,
+    DATAOBJECT_GetData,
+    DATAOBJECT_GetDataHere,
+    DATAOBJECT_QueryGetData,
+    DATAOBJECT_GetCanonicalFormatEtc,
+    DATAOBJECT_SetData,
+    DATAOBJECT_EnumFormatEtc,
+    DATAOBJECT_DAdvise,
+    DATAOBJECT_DUnadvise,
+    DATAOBJECT_EnumDAdvise
+};
+
+IDataObject xdndDataObject = { &xdndDataObjectVtbl };