From 9540fdc5b1668e4b575ce00539454b8ac66457a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 2 Apr 2016 04:15:02 +0200
Subject: shell32: Add support for setting/getting PREFERREDDROPEFFECT in
 IDataObject.

---
 dlls/shell32/clipboard.c    | 40 ++++++++++++++++++++++++++++++++++++++++
 dlls/shell32/dataobject.c   | 24 +++++++++++++++++++++---
 dlls/shell32/shell32_main.h |  2 ++
 3 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/dlls/shell32/clipboard.c b/dlls/shell32/clipboard.c
index 82df534..9c6f284 100644
--- a/dlls/shell32/clipboard.c
+++ b/dlls/shell32/clipboard.c
@@ -38,6 +38,8 @@
 #include <stdarg.h>
 #include <string.h>
 
+#define NONAMELESSUNION
+
 #include "windef.h"
 #include "winbase.h"
 #include "winreg.h"
@@ -214,3 +216,41 @@ HGLOBAL RenderFILENAMEW (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl)
 
 	return hGlobal;
 }
+
+HGLOBAL RenderPREFERREDDROPEFFECT (DWORD value)
+{
+    DWORD *pEffect;
+    HGLOBAL hGlobal;
+
+    TRACE("(%d)\n", value);
+
+    hGlobal = GlobalAlloc(GHND|GMEM_SHARE, sizeof(DWORD));
+    if(!hGlobal) return hGlobal;
+
+    pEffect = GlobalLock(hGlobal);
+    if (pEffect)
+    {
+        *pEffect = value;
+        GlobalUnlock(hGlobal);
+    }
+
+    return hGlobal;
+}
+
+HRESULT GetPREFERREDDROPEFFECT (STGMEDIUM *pmedium, DWORD *value)
+{
+    DWORD *pEffect;
+    BOOL result = E_OUTOFMEMORY;
+
+    TRACE("(%p, %p)\n", pmedium, value);
+
+    pEffect = GlobalLock(pmedium->u.hGlobal);
+    if (pEffect)
+    {
+        *value = *pEffect;
+        result = S_OK;
+        GlobalUnlock(pmedium->u.hGlobal);
+    }
+
+    return result;
+}
diff --git a/dlls/shell32/dataobject.c b/dlls/shell32/dataobject.c
index cc7b63e..5a18a1a 100644
--- a/dlls/shell32/dataobject.c
+++ b/dlls/shell32/dataobject.c
@@ -197,7 +197,7 @@ LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[])
 */
 
 /* number of supported formats */
-#define MAX_FORMATS 4
+#define MAX_FORMATS 5
 
 typedef struct
 {
@@ -209,12 +209,13 @@ typedef struct
 	LPITEMIDLIST	pidl;
 	LPITEMIDLIST *	apidl;
 	UINT		cidl;
+    DWORD       dropEffect;
 
 	FORMATETC	pFormatEtc[MAX_FORMATS];
 	UINT		cfShellIDList;
 	UINT		cfFileNameA;
 	UINT		cfFileNameW;
-
+	UINT        cfDropEffect;
 } IDataObjectImpl;
 
 static inline IDataObjectImpl *impl_from_IDataObject(IDataObject *iface)
@@ -314,6 +315,10 @@ static HRESULT WINAPI IDataObject_fnGetData(IDataObject *iface, LPFORMATETC pfor
 	  if (This->cidl < 1) return(E_UNEXPECTED);
 	  pmedium->u.hGlobal = RenderFILENAMEW(This->pidl, This->apidl, This->cidl);
 	}
+    else if (pformatetcIn->cfFormat == This->cfDropEffect)
+    {
+        pmedium->u.hGlobal = RenderPREFERREDDROPEFFECT(This->dropEffect);
+    }
 	else
 	{
 	  FIXME("-- expected clipformat not implemented\n");
@@ -368,7 +373,17 @@ static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(IDataObject *iface, LP
 static HRESULT WINAPI IDataObject_fnSetData(IDataObject *iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
 {
 	IDataObjectImpl *This = impl_from_IDataObject(iface);
-	FIXME("(%p)->()\n", This);
+
+    FIXME("(%p)->(%p, %p, %u): semi-stub\n", This, pformatetc, pmedium, fRelease);
+
+    if (pformatetc->cfFormat == This->cfDropEffect)
+    {
+        if (pmedium->tymed == TYMED_HGLOBAL)
+            return GetPREFERREDDROPEFFECT(pmedium, &This->dropEffect);
+        else
+            return DV_E_TYMED;
+    }
+
 	return E_NOTIMPL;
 }
 
@@ -441,14 +456,17 @@ IDataObject* IDataObject_Constructor(HWND hwndOwner,
         dto->pidl = ILClone(pMyPidl);
         dto->apidl = _ILCopyaPidl(apidl, cidl);
         dto->cidl = cidl;
+        dto->dropEffect = 0;
 
         dto->cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
         dto->cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA);
         dto->cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW);
+        dto->cfDropEffect = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW);
         InitFormatEtc(dto->pFormatEtc[0], dto->cfShellIDList, TYMED_HGLOBAL);
         InitFormatEtc(dto->pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
         InitFormatEtc(dto->pFormatEtc[2], dto->cfFileNameA, TYMED_HGLOBAL);
         InitFormatEtc(dto->pFormatEtc[3], dto->cfFileNameW, TYMED_HGLOBAL);
+        InitFormatEtc(dto->pFormatEtc[4], dto->cfDropEffect, TYMED_HGLOBAL);
     }
 
     TRACE("(%p)->(apidl=%p cidl=%u)\n",dto, apidl, cidl);
diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h
index 492f79f..29822b7 100644
--- a/dlls/shell32/shell32_main.h
+++ b/dlls/shell32/shell32_main.h
@@ -130,6 +130,8 @@ HGLOBAL RenderHDROP(LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECL
 HGLOBAL RenderSHELLIDLIST (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
 HGLOBAL RenderFILENAMEA (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
 HGLOBAL RenderFILENAMEW (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
+HGLOBAL RenderPREFERREDDROPEFFECT (DWORD value);
+HRESULT GetPREFERREDDROPEFFECT (STGMEDIUM *pmedium, DWORD *value);
 
 /* Change Notification */
 void InitChangeNotifications(void) DECLSPEC_HIDDEN;
-- 
2.7.1

