[SHELL32] Update CDataObject,
authorMark Jansen <mark.jansen@reactos.org>
Sat, 12 Oct 2019 00:11:25 +0000 (02:11 +0200)
committerMark Jansen <mark.jansen@reactos.org>
Sat, 19 Oct 2019 16:42:15 +0000 (18:42 +0200)
allowing it to accept new formats and behave a bit more like windows

dll/win32/shell32/CIDLDataObj.cpp

index a28aed1..b1704ff 100644 (file)
@@ -1,23 +1,9 @@
 /*
- *    IEnumFORMATETC, IDataObject
- *
- * selecting and droping objects within the shell and/or common dialogs
- *
- *    Copyright 1998, 1999    <juergen.schmied@metronet.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     IEnumFORMATETC, IDataObject implementation
+ * COPYRIGHT:   Copyright 1998, 1999 <juergen.schmied@metronet.de>
+ *              Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
  */
 
 #include "precomp.h"
@@ -65,7 +51,7 @@ IEnumFORMATETCImpl::~IEnumFORMATETCImpl()
 
 HRESULT WINAPI IEnumFORMATETCImpl::Initialize(UINT cfmt, const FORMATETC afmt[])
 {
-    DWORD                        size;
+    DWORD size;
 
     size = cfmt * sizeof(FORMATETC);
     countFmt = cfmt;
@@ -83,16 +69,20 @@ HRESULT WINAPI IEnumFORMATETCImpl::Next(ULONG celt, FORMATETC *rgelt, ULONG *pce
 
     TRACE("(%p)->(%u,%p)\n", this, celt, rgelt);
 
-    if(!pFmt)return S_FALSE;
-    if(!rgelt) return E_INVALIDARG;
-    if (pceltFethed)  *pceltFethed = 0;
+    if (!pFmt)
+        return S_FALSE;
+    if (!rgelt)
+        return E_INVALIDARG;
+    if (pceltFethed)
+        *pceltFethed = 0;
 
-    for(i = 0; posFmt < countFmt && celt > i; i++)
+    for (i = 0; posFmt < countFmt && celt > i; i++)
     {
-      *rgelt++ = pFmt[posFmt++];
+        *rgelt++ = pFmt[posFmt++];
     }
 
-    if (pceltFethed) *pceltFethed = i;
+    if (pceltFethed)
+        *pceltFethed = i;
 
     return ((i == celt) ? S_OK : S_FALSE);
 }
@@ -101,7 +91,8 @@ HRESULT WINAPI IEnumFORMATETCImpl::Skip(ULONG celt)
 {
     TRACE("(%p)->(num=%u)\n", this, celt);
 
-    if (posFmt + celt >= countFmt) return S_FALSE;
+    if (posFmt + celt >= countFmt)
+        return S_FALSE;
     posFmt += celt;
     return S_OK;
 }
@@ -110,19 +101,19 @@ HRESULT WINAPI IEnumFORMATETCImpl::Reset()
 {
     TRACE("(%p)->()\n", this);
 
-        posFmt = 0;
-        return S_OK;
+    posFmt = 0;
+    return S_OK;
 }
 
 HRESULT WINAPI IEnumFORMATETCImpl::Clone(LPENUMFORMATETC* ppenum)
 {
-    HRESULT                                    hResult;
+    HRESULT hResult;
 
     TRACE("(%p)->(ppenum=%p)\n", this, ppenum);
 
     if (!ppenum) return E_INVALIDARG;
     hResult = IEnumFORMATETC_Constructor(countFmt, pFmt, ppenum);
-    if (FAILED (hResult))
+    if (FAILED_UNEXPECTEDLY(hResult))
         return hResult;
     return (*ppenum)->Skip(posFmt);
 }
@@ -135,34 +126,26 @@ HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMA
 
 /***********************************************************************
 *   IDataObject implementation
+*   For now (2019-10-12) it's compatible with 2k3's data object
+*   See shell32_apitest!CIDLData for changes between versions
 */
 
-/* number of supported formats */
-#define MAX_FORMATS 5
-
 class CIDLDataObj :
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
     public IDataObject,
     public IAsyncOperation 
 {
 private:
-    LPITEMIDLIST    pidl;
-    PIDLIST_RELATIVE *apidl;
-    UINT        cidl;
-    DWORD        dropeffect;
-
-    FORMATETC    pFormatEtc[MAX_FORMATS];
-    UINT        cfShellIDList;
-    UINT        cfFileNameA;
-    UINT        cfFileNameW;
-    UINT        cfPreferredDropEffect;
-    BOOL        doasync;
+    CSimpleArray<FORMATETC> m_Formats;
+    CSimpleArray<STGMEDIUM> m_Storage;
+    UINT m_cfShellIDList;
+    BOOL m_doasync;
 public:
     CIDLDataObj();
     ~CIDLDataObj();
     HRESULT WINAPI Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidlx, UINT cidlx);
 
-    ///////////
+    // *** IDataObject methods ***
     virtual HRESULT WINAPI GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium);
     virtual HRESULT WINAPI GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium);
     virtual HRESULT WINAPI QueryGetData(LPFORMATETC pformatetc);
@@ -172,10 +155,12 @@ public:
     virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
     virtual HRESULT WINAPI DUnadvise(DWORD dwConnection);
     virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
-    virtual HRESULT WINAPI GetAsyncMode(BOOL *pfIsOpAsync);
-    virtual HRESULT WINAPI InOperation(BOOL *pfInAsyncOp);
+
+    // *** IAsyncOperation methods ***
     virtual HRESULT WINAPI SetAsyncMode(BOOL fDoOpAsync);
+    virtual HRESULT WINAPI GetAsyncMode(BOOL *pfIsOpAsync);
     virtual HRESULT WINAPI StartOperation(IBindCtx *pbcReserved);
+    virtual HRESULT WINAPI InOperation(BOOL *pfInAsyncOp);
     virtual HRESULT WINAPI EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
 
 BEGIN_COM_MAP(CIDLDataObj)
@@ -186,107 +171,71 @@ END_COM_MAP()
 
 CIDLDataObj::CIDLDataObj()
 {
-    pidl = NULL;
-    apidl = NULL;
-    cidl = 0;
-    dropeffect = 0;
-    cfShellIDList = 0;
-    cfFileNameA = 0;
-    cfFileNameW = 0;
-    cfPreferredDropEffect = 0;
-    doasync = FALSE;
+    m_cfShellIDList = 0;
+    m_doasync = FALSE;
 }
 
 CIDLDataObj::~CIDLDataObj()
 {
-    TRACE(" destroying IDataObject(%p)\n",this);
-    _ILFreeaPidl(apidl, cidl);
-    ILFree(pidl);
+    TRACE(" destroying IDataObject(%p)\n", this);
+
+    for (int n = 0; n < m_Storage.GetSize(); ++n)
+    {
+        ReleaseStgMedium(&m_Storage[n]);
+    }
+    m_Formats.RemoveAll();
+    m_Storage.RemoveAll();
 }
 
 HRESULT WINAPI CIDLDataObj::Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidlx, UINT cidlx)
 {
-    pidl = ILClone(pMyPidl);
-    apidl = _ILCopyaPidl(apidlx, cidlx);
-    if (pidl == NULL || apidl == NULL)
+    HGLOBAL hida = RenderSHELLIDLIST((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx);
+    if (!hida)
+    {
+        ERR("Failed to render " CFSTR_SHELLIDLISTA "\n");
         return E_OUTOFMEMORY;
-    cidl = cidlx;
-    dropeffect = DROPEFFECT_COPY;
-
-    cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
-    cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA);
-    cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW);
-    cfPreferredDropEffect = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW);
-    InitFormatEtc(pFormatEtc[0], cfShellIDList, TYMED_HGLOBAL);
-    InitFormatEtc(pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
-    InitFormatEtc(pFormatEtc[2], cfFileNameA, TYMED_HGLOBAL);
-    InitFormatEtc(pFormatEtc[3], cfFileNameW, TYMED_HGLOBAL);
-    InitFormatEtc(pFormatEtc[4], cfPreferredDropEffect, TYMED_HGLOBAL);
-    return S_OK;
-}
+    }
 
-static HGLOBAL RenderPREFEREDDROPEFFECT (DWORD dwFlags)
-{
-    DWORD * pdwFlag;
-    HGLOBAL hGlobal;
+    m_cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
 
-    TRACE("(0x%08x)\n", dwFlags);
+    FORMATETC HIDAFormat = { (CLIPFORMAT)m_cfShellIDList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+    STGMEDIUM medium = {0};
+    medium.tymed = TYMED_HGLOBAL;
+    medium.hGlobal = hida;
 
-    hGlobal = GlobalAlloc(GHND|GMEM_SHARE, sizeof(DWORD));
-    if(!hGlobal) return hGlobal;
-        pdwFlag = (DWORD*)GlobalLock(hGlobal);
-    *pdwFlag = dwFlags;
-    GlobalUnlock(hGlobal);
-    return hGlobal;
+    return SetData(&HIDAFormat, &medium, TRUE);
 }
 
-/**************************************************************************
-* IDataObject_fnGetData
-*/
+
 HRESULT WINAPI CIDLDataObj::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
 {
-    char    szTemp[256];
-
-    szTemp[0] = 0;
-    GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
-    TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
-
-    if (pformatetcIn->cfFormat == cfShellIDList)
-    {
-      if (cidl < 1) return(E_UNEXPECTED);
-      pmedium->hGlobal = RenderSHELLIDLIST(pidl, apidl, cidl);
-    }
-    else if    (pformatetcIn->cfFormat == CF_HDROP)
+    if (TRACE_ON(shell))
     {
-      if (cidl < 1) return(E_UNEXPECTED);
-      pmedium->hGlobal = RenderHDROP(pidl, apidl, cidl);
+        char szTemp[256] = {0};
+        GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
+        TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
     }
-    else if    (pformatetcIn->cfFormat == cfFileNameA)
+    for (int n = 0; n < m_Formats.GetSize(); ++n)
     {
-      if (cidl < 1) return(E_UNEXPECTED);
-      pmedium->hGlobal = RenderFILENAMEA(pidl, apidl, cidl);
+        const FORMATETC& fmt = m_Formats[n];
+        if (fmt.cfFormat == pformatetcIn->cfFormat &&
+            fmt.dwAspect == pformatetcIn->dwAspect &&
+            fmt.tymed == pformatetcIn->tymed)
+        {
+            if (pformatetcIn->tymed != TYMED_HGLOBAL)
+            {
+                UNIMPLEMENTED;
+                return E_INVALIDARG;
+            }
+            else
+            {
+                *pmedium = m_Storage[n];
+                return QueryInterface(IID_PPV_ARG(IUnknown, &pmedium->pUnkForRelease));
+            }
+        }
     }
-    else if    (pformatetcIn->cfFormat == cfFileNameW)
-    {
-      if (cidl < 1) return(E_UNEXPECTED);
-      pmedium->hGlobal = RenderFILENAMEW(pidl, apidl, cidl);
-    }
-    else if    (pformatetcIn->cfFormat == cfPreferredDropEffect)
-    {
-      pmedium->hGlobal = RenderPREFEREDDROPEFFECT(dropeffect);
-    }
-    else
-    {
-      FIXME("-- expected clipformat not implemented\n");
-      return (E_INVALIDARG);
-    }
-    if (pmedium->hGlobal)
-    {
-      pmedium->tymed = TYMED_HGLOBAL;
-      pmedium->pUnkForRelease = NULL;
-      return S_OK;
-    }
-    return E_OUTOFMEMORY;
+
+    return E_INVALIDARG;
 }
 
 HRESULT WINAPI CIDLDataObj::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium)
@@ -297,49 +246,50 @@ HRESULT WINAPI CIDLDataObj::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedi
 
 HRESULT WINAPI CIDLDataObj::QueryGetData(LPFORMATETC pformatetc)
 {
-    UINT i;
-
     TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed);
 
-    if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
-      return DV_E_DVASPECT;
-
-    /* check our formats table what we have */
-    for (i=0; i<MAX_FORMATS; i++)
+    for (int n = 0; n < m_Formats.GetSize(); ++n)
     {
-      if ((pFormatEtc[i].cfFormat == pformatetc->cfFormat)
-       && (pFormatEtc[i].tymed == pformatetc->tymed))
-      {
-        return S_OK;
-      }
+        const FORMATETC& fmt = m_Formats[n];
+        if (fmt.cfFormat == pformatetc->cfFormat &&
+            fmt.dwAspect == pformatetc->dwAspect &&
+            fmt.tymed == pformatetc->tymed)
+        {
+            return S_OK;
+        }
     }
 
-    return DV_E_TYMED;
+    return S_FALSE;
 }
 
 HRESULT WINAPI CIDLDataObj::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
 {
-    FIXME("(%p)->()\n", this);
-    return E_NOTIMPL;
+    //FIXME("(%p)->()\n", this);
+    return DATA_S_SAMEFORMATETC;
 }
 
 HRESULT WINAPI CIDLDataObj::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
 {
-    if (pformatetc->cfFormat == cfPreferredDropEffect)
+    if (!fRelease)
+        return E_INVALIDARG;
+
+    for (int n = 0; n < m_Formats.GetSize(); ++n)
     {
-      const DWORD *src = (const DWORD *)GlobalLock(pmedium->hGlobal);
-      if (src != 0)
-      {
-        dropeffect = *src;
-        GlobalUnlock(pmedium->hGlobal);
-        return S_OK;
-      }
-      FIXME("Error setting data");
-      return E_FAIL;
+        const FORMATETC& fmt = m_Formats[n];
+        if (fmt.cfFormat == pformatetc->cfFormat &&
+            fmt.dwAspect == pformatetc->dwAspect &&
+            fmt.tymed == pformatetc->tymed)
+        {
+            ReleaseStgMedium(&m_Storage[n]);
+            m_Storage[n] = *pmedium;
+            return S_OK;
+        }
     }
 
-    FIXME("(%p)->()\n", this);
-    return E_NOTIMPL;
+    m_Formats.Add(*pformatetc);
+    m_Storage.Add(*pmedium);
+
+    return S_OK;
 }
 
 HRESULT WINAPI CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
@@ -350,7 +300,7 @@ HRESULT WINAPI CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **pp
     /* only get data */
     if (DATADIR_GET == dwDirection)
     {
-        return IEnumFORMATETC_Constructor(MAX_FORMATS, pFormatEtc, ppenumFormatEtc);
+        return IEnumFORMATETC_Constructor(m_Formats.GetSize(), m_Formats.GetData(), ppenumFormatEtc);
     }
 
     return E_NOTIMPL;
@@ -358,26 +308,23 @@ HRESULT WINAPI CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **pp
 
 HRESULT WINAPI CIDLDataObj::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
 {
-    FIXME("(%p)->()\n", this);
-    return E_NOTIMPL;
+    return OLE_E_ADVISENOTSUPPORTED;
 }
 
 HRESULT WINAPI CIDLDataObj::DUnadvise(DWORD dwConnection)
 {
-    FIXME("(%p)->()\n", this);
-    return E_NOTIMPL;
+    return OLE_E_ADVISENOTSUPPORTED;
 }
 
 HRESULT WINAPI CIDLDataObj::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
 {
-    FIXME("(%p)->()\n", this);
-    return E_NOTIMPL;
+    return OLE_E_ADVISENOTSUPPORTED;
 }
 
 HRESULT WINAPI CIDLDataObj::GetAsyncMode(BOOL *pfIsOpAsync)
 {
     TRACE("(%p)->()\n", this);
-    *pfIsOpAsync = doasync;
+    *pfIsOpAsync = m_doasync;
     return S_OK;
 }
 HRESULT WINAPI CIDLDataObj::InOperation(BOOL *pfInAsyncOp)
@@ -388,7 +335,7 @@ HRESULT WINAPI CIDLDataObj::InOperation(BOOL *pfInAsyncOp)
 HRESULT WINAPI CIDLDataObj::SetAsyncMode(BOOL fDoOpAsync) 
 {
     TRACE("(%p)->()\n", this);
-    doasync = fDoOpAsync;
+    m_doasync = fDoOpAsync;
     return S_OK;
 }
 
@@ -406,8 +353,8 @@ HRESULT WINAPI CIDLDataObj::EndOperation(HRESULT hResult, IBindCtx *pbcReserved,
 
 
 /**************************************************************************
-*  IDataObject_Constructor
-*/
+ *  IDataObject_Constructor
+ */
 HRESULT IDataObject_Constructor(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidl, UINT cidl, IDataObject **dataObject)
 {
     if (!dataObject)
@@ -424,6 +371,8 @@ HRESULT WINAPI SHCreateDataObject(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUIT
 {
     if (IsEqualIID(riid, IID_IDataObject))
     {
+        if (pdtInner)
+            UNIMPLEMENTED;
         return CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, (IDataObject **)ppv);
     }
     return E_FAIL;