[SHELL32_APITEST] Add test for CIDLData_CreateFromIDArray
authorMark Jansen <mark.jansen@reactos.org>
Thu, 10 Oct 2019 22:15:41 +0000 (00:15 +0200)
committerMark Jansen <mark.jansen@reactos.org>
Sat, 19 Oct 2019 16:42:15 +0000 (18:42 +0200)
modules/rostests/apitests/shell32/CIDLData.cpp [new file with mode: 0644]
modules/rostests/apitests/shell32/CMakeLists.txt
modules/rostests/apitests/shell32/testlist.c

diff --git a/modules/rostests/apitests/shell32/CIDLData.cpp b/modules/rostests/apitests/shell32/CIDLData.cpp
new file mode 100644 (file)
index 0000000..8169666
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * PROJECT:     ReactOS api tests
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Test for CIDLDataObj
+ * COPYRIGHT:   Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
+ */
+
+#include "shelltest.h"
+#include <ndk/rtlfuncs.h>
+#include <stdio.h>
+#include <shellutils.h>
+#include <shlwapi.h>
+
+static DWORD g_WinVersion;
+
+
+static void TestAdviseAndCanonical(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUIDLIST_RELATIVE_ARRAY apidl)
+{
+    CComPtr<IDataObject> spDataObj;
+    HRESULT hr = CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, &spDataObj);
+
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    hr = spDataObj->DAdvise(NULL, 0, NULL, NULL);
+    ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
+
+    hr = spDataObj->DUnadvise(0);
+    ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
+
+    hr = spDataObj->EnumDAdvise(NULL);
+    ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
+
+
+    FORMATETC in = {1, (DVTARGETDEVICE*)2, 3, 4, 5};
+    FORMATETC out = {6, (DVTARGETDEVICE*)7, 8, 9, 10};
+
+    hr = spDataObj->GetCanonicalFormatEtc(&in, &out);
+    ok_hex(hr, DATA_S_SAMEFORMATETC);
+
+    if (g_WinVersion < _WIN32_WINNT_VISTA)
+    {
+        ok_int(out.cfFormat, 6);
+        ok_ptr(out.ptd, (void*)7);
+        ok_int(out.dwAspect, 8);
+        ok_int(out.lindex, 9);
+        ok_int(out.tymed, 10);
+        trace("out unmodified\n");
+    }
+    else
+    {
+        ok_int(out.cfFormat, in.cfFormat);
+        ok_ptr(out.ptd, NULL);
+        ok_int(out.dwAspect, (int)in.dwAspect);
+        ok_int(out.lindex, in.lindex);
+        ok_int(out.tymed, (int)in.tymed);
+        trace("in copied to out\n");
+    }
+}
+
+
+static inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida)
+{
+    return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]);
+}
+
+static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i)
+{
+    return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]);
+}
+
+#define ok_wstri(x, y) \
+    ok(wcsicmp(x, y) == 0, "Wrong string. Expected '%S', got '%S'\n", y, x)
+
+static void TestHIDA(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2)
+{
+    LPIDA pida = (LPIDA)pData;
+
+    ok_int(pida->cidl, 2);
+    if (pida->cidl != 2)
+        return;
+
+    WCHAR FolderPath[MAX_PATH], Item1[MAX_PATH], Item2[MAX_PATH];
+    BOOL bRet = SHGetPathFromIDListW(HIDA_GetPIDLFolder(pida), FolderPath);
+    ok_int(bRet, TRUE);
+    if (!bRet)
+        return;
+    ok_wstri(FolderPath, ExpectRoot);
+
+    CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl1(ILCombine(HIDA_GetPIDLFolder(pida), HIDA_GetPIDLItem(pida, 0)));
+    CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl2(ILCombine(HIDA_GetPIDLFolder(pida), HIDA_GetPIDLItem(pida, 1)));
+
+    bRet = SHGetPathFromIDListW(pidl1, Item1);
+    ok_int(bRet, TRUE);
+    if (!bRet)
+        return;
+    ok_wstri(Item1, ExpectPath1);
+
+    bRet = SHGetPathFromIDListW(pidl2, Item2);
+    ok_int(bRet, TRUE);
+    if (!bRet)
+        return;
+    ok_wstri(Item2, ExpectPath2);
+}
+
+static void TestHDROP(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2)
+{
+    DROPFILES* pDropFiles = (DROPFILES*)pData;
+    ok_int(pDropFiles->fWide, TRUE);
+
+    LPCWSTR Expected[2] = { ExpectPath1, ExpectPath2 };
+
+    DWORD offset = pDropFiles->pFiles;
+    UINT Count = 0;
+    for (;;Count++)
+    {
+        LPCWSTR ptr = (LPCWSTR)(((BYTE*)pDropFiles) + offset);
+        if (!*ptr)
+            break;
+
+        if (Count < _countof(Expected))
+            ok_wstri(Expected[Count], ptr);
+
+        offset += (wcslen(ptr) + 1) * sizeof(WCHAR);
+    }
+    ok_int(Count, 2);
+}
+
+static void TestFilenameA(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2)
+{
+    LPCSTR FirstFile = (LPCSTR)pData;
+    LPWSTR FirstFileW;
+
+    HRESULT hr = SHStrDupA(FirstFile, &FirstFileW);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    ok_wstri(ExpectPath1, FirstFileW);
+    CoTaskMemFree(FirstFileW);
+}
+
+static void TestFilenameW(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2)
+{
+    LPCWSTR FirstFile = (LPCWSTR)pData;
+    ok_wstri(ExpectPath1, FirstFile);
+}
+
+
+static void TestDefaultFormat(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUIDLIST_RELATIVE_ARRAY apidl)
+{
+    CComPtr<IDataObject> spDataObj;
+    HRESULT hr = CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, &spDataObj);
+
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    CComPtr<IEnumFORMATETC> pEnumFmt;
+    hr = spDataObj->EnumFormatEtc(DATADIR_GET, &pEnumFmt);
+
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    UINT Expected[4] = {
+        RegisterClipboardFormatA(CFSTR_SHELLIDLISTA),
+        CF_HDROP,
+        RegisterClipboardFormatA(CFSTR_FILENAMEA),
+        RegisterClipboardFormatA("FileNameW"),
+    };
+
+    UINT Count = 0;
+    FORMATETC fmt;
+    while (S_OK == (hr=pEnumFmt->Next(1, &fmt, NULL)))
+    {
+        char szGot[512], szExpected[512];
+        GetClipboardFormatNameA(fmt.cfFormat, szGot, sizeof(szGot));
+        ok(Count < _countof(Expected), "%u\n", Count);
+        if (Count < _countof(Expected))
+        {
+            GetClipboardFormatNameA(Expected[Count], szExpected, sizeof(szExpected));
+            ok(fmt.cfFormat == Expected[Count], "Got 0x%x(%s), expected 0x%x(%s) for %u\n",
+               fmt.cfFormat, szGot, Expected[Count], szExpected, Count);
+        }
+
+        ok(fmt.ptd == NULL, "Got 0x%p, expected 0x%p for [%u].ptd\n", fmt.ptd, (void*)NULL, Count);
+        ok(fmt.dwAspect == DVASPECT_CONTENT, "Got 0x%lu, expected 0x%d for [%u].dwAspect\n", fmt.dwAspect, DVASPECT_CONTENT, Count);
+        ok(fmt.lindex == -1, "Got 0x%lx, expected 0x%x for [%u].lindex\n", fmt.lindex, -1, Count);
+        ok(fmt.tymed == TYMED_HGLOBAL, "Got 0x%lu, expected 0x%d for [%u].tymed\n", fmt.tymed, TYMED_HGLOBAL, Count);
+
+        Count++;
+    }
+    trace("Got %u formats\n", Count);
+    ULONG ExpectedCount = (g_WinVersion < _WIN32_WINNT_WIN8) ? 1 : 4;
+    ok_int(Count, (int)ExpectedCount);
+    ok_hex(hr, S_FALSE);
+
+    typedef void (*TestFunction)(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2);
+    TestFunction TestFormats[] = {
+        TestHIDA,
+        TestHDROP,
+        TestFilenameA,
+        TestFilenameW,
+    };
+
+    WCHAR ExpectRoot[MAX_PATH], ExpectItem1[MAX_PATH], ExpectItem2[MAX_PATH];
+
+    hr = SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, ExpectRoot);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    hr = SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, ExpectItem1);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    hr = SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, 0, ExpectItem2);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+
+    /* The formats are not synthesized on request */
+    for (Count = 0; Count < _countof(Expected); ++Count)
+    {
+        STGMEDIUM medium = {0};
+        FORMATETC etc = { (CLIPFORMAT)Expected[Count], NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+        char szExpected[512];
+
+        GetClipboardFormatNameA(etc.cfFormat, szExpected, sizeof(szExpected));
+        hr = spDataObj->GetData(&etc, &medium);
+        HRESULT hr2 = spDataObj->QueryGetData(&etc);
+        ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+
+        if (Count < ExpectedCount)
+        {
+            ok(hr == S_OK, "0x%x (0x%x(%s))\n", (unsigned int)hr, Expected[Count], szExpected);
+            ok(medium.tymed == TYMED_HGLOBAL, "0x%lx (0x%x(%s))\n", medium.tymed, Expected[Count], szExpected);
+            if (hr == S_OK && medium.tymed == TYMED_HGLOBAL)
+            {
+                PVOID pData = GlobalLock(medium.hGlobal);
+                SIZE_T Size = GlobalSize(medium.hGlobal);
+                TestFormats[Count](pData, Size, ExpectRoot, ExpectItem1, ExpectItem2);
+                GlobalUnlock(medium.hGlobal);
+            }
+        }
+        else
+        {
+            if (g_WinVersion < _WIN32_WINNT_VISTA)
+                ok(hr == E_INVALIDARG, "0x%x (0x%x(%s))\n", (unsigned int)hr, Expected[Count], szExpected);
+            else
+                ok(hr == DV_E_FORMATETC, "0x%x (0x%x(%s))\n", (unsigned int)hr, Expected[Count], szExpected);
+        }
+
+        if (SUCCEEDED(hr))
+            ReleaseStgMedium(&medium);
+    }
+}
+
+
+static void TestSetAndGetExtraFormat(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUIDLIST_RELATIVE_ARRAY apidl)
+{
+    CComPtr<IDataObject> spDataObj;
+    HRESULT hr = CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, &spDataObj);
+
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    STGMEDIUM medium = {0};
+    medium.tymed = TYMED_HGLOBAL;
+    medium.hGlobal = GlobalAlloc(GHND, sizeof(DWORD));
+    ok(medium.hGlobal != NULL, "Download more ram\n");
+    PDWORD data = (PDWORD)GlobalLock(medium.hGlobal);
+    *data = 12345;
+    GlobalUnlock(medium.hGlobal);
+
+    UINT flags = GlobalFlags(medium.hGlobal);
+    SIZE_T size = GlobalSize(medium.hGlobal);
+    ok_hex(flags, 0);
+    ok_size_t(size, sizeof(DWORD));
+
+    FORMATETC etc = { (CLIPFORMAT)RegisterClipboardFormatA(CFSTR_INDRAGLOOPA), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+    FORMATETC etc2 = etc;
+
+    /* Not supported! */
+    hr = spDataObj->SetData(&etc, &medium, FALSE);
+    if (g_WinVersion < _WIN32_WINNT_WIN8)
+        ok_hex(hr, E_INVALIDARG);
+    else
+        ok_hex(hr, E_NOTIMPL);
+
+    /* Object takes ownership! */
+    hr = spDataObj->SetData(&etc, &medium, TRUE);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    /* Does not touch the hGlobal! */
+    flags = GlobalFlags(medium.hGlobal);
+    size = GlobalSize(medium.hGlobal);
+    ok_hex(flags, 0);
+    ok_size_t(size, sizeof(DWORD));
+
+    STGMEDIUM medium2 = {0};
+
+    /* No conversion */
+    etc2.dwAspect = DVASPECT_DOCPRINT;
+    hr = spDataObj->GetData(&etc2, &medium2);
+    HRESULT hr2 = spDataObj->QueryGetData(&etc2);
+    ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+    if (g_WinVersion < _WIN32_WINNT_VISTA)
+        ok_hex(hr, E_INVALIDARG);
+    else
+        ok_hex(hr, DV_E_FORMATETC);
+
+    etc2.dwAspect = DVASPECT_CONTENT;
+    etc2.tymed = TYMED_NULL;
+    hr = spDataObj->GetData(&etc2, &medium2);
+    hr2 = spDataObj->QueryGetData(&etc2);
+    ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+    if (g_WinVersion < _WIN32_WINNT_VISTA)
+        ok_hex(hr, E_INVALIDARG);
+    else
+        ok_hex(hr, DV_E_FORMATETC);
+    etc2.tymed = TYMED_HGLOBAL;
+
+    ok_ptr(medium2.pUnkForRelease, NULL);
+    hr = spDataObj->GetData(&etc2, &medium2);
+    hr2 = spDataObj->QueryGetData(&etc2);
+    ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+    ok_hex(hr, S_OK);
+    if (hr == S_OK)
+    {
+        ok_hex(medium2.tymed, TYMED_HGLOBAL);
+        if (g_WinVersion < _WIN32_WINNT_VISTA)
+        {
+            /* The IDataObject is set as pUnkForRelease */
+            ok(medium2.pUnkForRelease == (IUnknown*)spDataObj, "Expected the data object (0x%p), got 0x%p\n",
+                (IUnknown*)spDataObj, medium2.pUnkForRelease);
+            ok(medium.hGlobal == medium2.hGlobal, "Pointers are not the same!, got 0x%p and 0x%p\n", medium.hGlobal, medium2.hGlobal);
+        }
+        else
+        {
+            ok_ptr(medium2.pUnkForRelease, NULL);
+            ok(medium.hGlobal != medium2.hGlobal, "Pointers are the same!\n");
+        }
+
+        flags = GlobalFlags(medium2.hGlobal);
+        size = GlobalSize(medium2.hGlobal);
+        ok_hex(flags, 0);
+        ok_size_t(size, sizeof(DWORD));
+
+        data = (PDWORD)GlobalLock(medium2.hGlobal);
+        if (data)
+            ok_int(*data, 12345);
+        else
+            ok(0, "GlobalLock: %lu\n", GetLastError());
+        GlobalUnlock(medium2.hGlobal);
+
+        HGLOBAL backup = medium2.hGlobal;
+        ReleaseStgMedium(&medium2);
+
+        flags = GlobalFlags(backup);
+        size = GlobalSize(backup);
+        if (g_WinVersion < _WIN32_WINNT_VISTA)
+        {
+            /* Same object! just the pUnkForRelease was set, so original hGlobal is still valid */
+            ok_hex(flags, 0);
+            ok_size_t(size, sizeof(DWORD));
+        }
+        else
+        {
+            ok_hex(flags, GMEM_INVALID_HANDLE);
+            ok_size_t(size, 0);
+        }
+
+        /* Original is still intact (but no longer ours!) */
+        flags = GlobalFlags(medium.hGlobal);
+        size = GlobalSize(medium.hGlobal);
+        ok_hex(flags, 0);
+        ok_size_t(size, sizeof(DWORD));
+    }
+
+    HGLOBAL backup = medium.hGlobal;
+    spDataObj.Release();
+
+    /* Now our hGlobal is deleted */
+    flags = GlobalFlags(backup);
+    size = GlobalSize(backup);
+    ok_hex(flags, GMEM_INVALID_HANDLE);
+    ok_size_t(size, 0);
+}
+
+START_TEST(CIDLData)
+{
+    HRESULT hr;
+
+    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+    RTL_OSVERSIONINFOEXW rtlinfo = {0};
+
+    rtlinfo.dwOSVersionInfoSize = sizeof(rtlinfo);
+    RtlGetVersion((PRTL_OSVERSIONINFOW)&rtlinfo);
+    g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion;
+
+    CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlWindows;
+    CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlSystem32;
+    CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlResources;
+
+    hr = SHGetFolderLocation(NULL, CSIDL_WINDOWS, NULL, 0, &pidlWindows);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, 0, &pidlSystem32);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    hr = SHGetFolderLocation(NULL, CSIDL_RESOURCES, NULL, 0, &pidlResources);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    CComPtr<IShellFolder> shellFolder;
+    PCUITEMID_CHILD child1;
+    hr = SHBindToParent(pidlSystem32, IID_PPV_ARG(IShellFolder, &shellFolder), &child1);
+    ok_hex(hr, S_OK);
+    if (!SUCCEEDED(hr))
+        return;
+
+    PCUITEMID_CHILD child2 = ILFindLastID(pidlResources);
+
+    UINT cidl = 2;
+    PCUIDLIST_RELATIVE apidl[2] = {
+        child1, child2
+    };
+
+    TestAdviseAndCanonical(pidlWindows, cidl, apidl);
+    TestDefaultFormat(pidlWindows, cidl, apidl);
+    TestSetAndGetExtraFormat(pidlWindows, cidl, apidl);
+}
index 868b686..df1e6cf 100644 (file)
@@ -11,6 +11,7 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/atl)
 list(APPEND SOURCE
     AddCommas.cpp
     CFSFolder.cpp
+    CIDLData.cpp
     CMyComputer.cpp
     CShellDesktop.cpp
     CShellLink.cpp
index 1b5339e..ffd832f 100644 (file)
@@ -6,6 +6,7 @@
 extern void func_AddCommas(void);
 extern void func_Control_RunDLLW(void);
 extern void func_CFSFolder(void);
+extern void func_CIDLData(void);
 extern void func_CMyComputer(void);
 extern void func_CShellDesktop(void);
 extern void func_CShellLink(void);
@@ -25,6 +26,7 @@ const struct test winetest_testlist[] =
     { "AddCommas", func_AddCommas },
     { "Control_RunDLLW", func_Control_RunDLLW },
     { "CFSFolder", func_CFSFolder },
+    { "CIDLData", func_CIDLData },
     { "CMyComputer", func_CMyComputer },
     { "CShellDesktop", func_CShellDesktop },
     { "CShellLink", func_CShellLink },