reactos/modules/rostests/apitests/shell32/DragDrop.cpp
Victor Perevertkin d424a0e088
[WININET_WINETEST][URLMON_WINETEST][SHELL32_APITEST] Skip some tests
Due to hangs on test machines
ROSTESTS-357 ROSTESTS-358 CORE-17057
2020-06-08 03:43:43 +03:00

413 lines
14 KiB
C++

/*
* PROJECT: ReactOS api tests
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
* PURPOSE: Test for Drag & Drop
* PROGRAMMER: Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include "shelltest.h"
#include <shlwapi.h>
#define NDEBUG
#include <debug.h>
#include <stdio.h>
#define TESTFILENAME L"DragDropTest.txt"
#define DROPPED_ON_FILE L"DragDroppedOn.lnk"
static CComPtr<IShellFolder> s_pDesktop;
static WCHAR s_szSrcTestFile[MAX_PATH];
static WCHAR s_szDestFolder[MAX_PATH];
static WCHAR s_szDestTestFile[MAX_PATH];
static WCHAR s_szDestLinkSpec[MAX_PATH];
static WCHAR s_szDroppedToItem[MAX_PATH];
enum OP
{
OP_NONE,
OP_COPY,
OP_MOVE,
OP_LINK,
OP_NONE_OR_COPY,
OP_NONE_OR_MOVE,
OP_NONE_OR_LINK
};
#define D_NONE DROPEFFECT_NONE
#define D_COPY DROPEFFECT_COPY
#define D_MOVE DROPEFFECT_MOVE
#define D_LINK DROPEFFECT_LINK
#define D_NONE_OR_COPY 0xAABBCCDD
#define D_NONE_OR_MOVE 0x11223344
#define D_NONE_OR_LINK 0x55667788
struct TEST_ENTRY
{
int line;
OP op;
HRESULT hr1;
HRESULT hr2;
DWORD dwKeyState;
DWORD dwEffects1;
DWORD dwEffects2;
DWORD dwEffects3;
};
static const TEST_ENTRY s_TestEntries[] =
{
// MK_LBUTTON
{ __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON, D_NONE, D_NONE, D_NONE },
{ __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON, D_COPY, D_COPY, D_COPY },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON, D_COPY | D_MOVE, D_MOVE, D_NONE },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON, D_COPY | D_MOVE | D_LINK, D_MOVE, D_NONE },
{ __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON, D_COPY | D_LINK, D_COPY, D_COPY },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON, D_MOVE, D_MOVE, D_NONE },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON, D_MOVE | D_LINK, D_MOVE, D_NONE },
{ __LINE__, OP_LINK, S_OK, S_OK, MK_LBUTTON, D_LINK, D_LINK, D_LINK },
// MK_LBUTTON | MK_SHIFT
{ __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_NONE, D_NONE, D_NONE },
{ __LINE__, OP_NONE_OR_COPY, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_COPY, D_NONE_OR_COPY, D_NONE_OR_COPY },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_COPY | D_MOVE, D_MOVE, D_NONE },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_COPY | D_MOVE | D_LINK, D_MOVE, D_NONE },
{ __LINE__, OP_NONE_OR_COPY, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_COPY | D_LINK, D_NONE_OR_COPY, D_NONE_OR_COPY },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_MOVE, D_MOVE, D_NONE },
{ __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_MOVE | D_LINK, D_MOVE, D_NONE },
{ __LINE__, OP_NONE_OR_LINK, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_LINK, D_NONE_OR_LINK, D_NONE_OR_LINK },
// MK_LBUTTON | MK_SHIFT | MK_CONTROL
#define MK_LBUTTON_SHIFT_CTRL (MK_LBUTTON | MK_SHIFT | MK_CONTROL)
{ __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_NONE, D_NONE, D_NONE },
{ __LINE__, OP_NONE_OR_COPY, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_COPY, D_NONE_OR_COPY, D_NONE_OR_COPY },
{ __LINE__, OP_NONE_OR_COPY, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_COPY | D_MOVE, D_NONE_OR_COPY, D_NONE_OR_COPY },
{ __LINE__, OP_LINK, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_COPY | D_MOVE | D_LINK, D_LINK, D_LINK },
{ __LINE__, OP_LINK, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_COPY | D_LINK, D_LINK, D_LINK },
{ __LINE__, OP_NONE_OR_MOVE, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_MOVE, D_NONE_OR_MOVE, D_NONE },
{ __LINE__, OP_LINK, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_MOVE | D_LINK, D_LINK, D_LINK },
{ __LINE__, OP_LINK, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_LINK, D_LINK, D_LINK },
#undef MK_LBUTTON_SHIFT_CTRL
// MK_LBUTTON | MK_CONTROL
{ __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_NONE, D_NONE, D_NONE },
{ __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_COPY, D_COPY, D_COPY },
{ __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_COPY | D_MOVE, D_COPY, D_COPY },
{ __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_COPY | D_MOVE | D_LINK, D_COPY, D_COPY },
{ __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_COPY | D_LINK, D_COPY, D_COPY },
{ __LINE__, OP_NONE_OR_MOVE, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_MOVE, D_NONE_OR_MOVE, D_NONE },
{ __LINE__, OP_NONE_OR_MOVE, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_MOVE | D_LINK, D_NONE_OR_MOVE, D_NONE },
{ __LINE__, OP_NONE_OR_LINK, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_LINK, D_NONE_OR_LINK, D_NONE_OR_LINK },
};
static void DoCreateTestFile(LPCWSTR pszFileName)
{
FILE *fp = _wfopen(pszFileName, L"wb");
ok(fp != NULL, "fp is NULL for '%S'\n", pszFileName);
fclose(fp);
}
HRESULT DoCreateShortcut(
LPCWSTR pszLnkFileName,
LPCWSTR pszTargetPathName)
{
CComPtr<IPersistFile> ppf;
CComPtr<IShellLinkW> psl;
HRESULT hr;
hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLinkW, (LPVOID *)&psl);
if (SUCCEEDED(hr))
{
psl->SetPath(pszTargetPathName);
hr = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
if (SUCCEEDED(hr))
{
hr = ppf->Save(pszLnkFileName, TRUE);
}
}
return hr;
}
static HRESULT
GetUIObjectOfAbsPidl(PIDLIST_ABSOLUTE pidl, REFIID riid, LPVOID *ppvOut)
{
*ppvOut = NULL;
LPCITEMIDLIST pidlLast;
CComPtr<IShellFolder> psf;
HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID *)&psf,
&pidlLast);
if (FAILED(hr))
return hr;
hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, riid, NULL, ppvOut);
return hr;
}
static HRESULT
GetUIObjectOfPath(LPCWSTR pszPath, REFIID riid, LPVOID *ppvOut)
{
*ppvOut = NULL;
PIDLIST_ABSOLUTE pidl = ILCreateFromPathW(pszPath);
if (!pidl)
return E_FAIL;
HRESULT hr = GetUIObjectOfAbsPidl(pidl, riid, ppvOut);
CoTaskMemFree(pidl);
return hr;
}
BOOL DoSpecExistsW(LPCWSTR pszSpec)
{
WIN32_FIND_DATAW find;
HANDLE hFind = FindFirstFileW(pszSpec, &find);
if (hFind != INVALID_HANDLE_VALUE)
{
FindClose(hFind);
return TRUE;
}
return FALSE;
}
void DoDeleteSpecW(LPCWSTR pszSpec)
{
WCHAR szPath[MAX_PATH], szFile[MAX_PATH];
lstrcpyW(szPath, pszSpec);
PathRemoveFileSpecW(szPath);
WIN32_FIND_DATAW find;
HANDLE hFind = FindFirstFileW(pszSpec, &find);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
lstrcpyW(szFile, szPath);
PathAppendW(szFile, find.cFileName);
DeleteFileW(szFile);
} while (FindNextFileW(hFind, &find));
FindClose(hFind);
}
}
static void DoTestEntry(const TEST_ENTRY *pEntry)
{
int line = pEntry->line;
HRESULT hr;
PIDLIST_ABSOLUTE pidlDesktop = NULL;
CComPtr<IDropTarget> pDropTarget;
CComPtr<IDataObject> pDataObject;
// get the desktop PIDL
SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlDesktop);
ok(!!pidlDesktop, "pidlDesktop is NULL\n");
// build paths
//
SHGetPathFromIDListW(pidlDesktop, s_szDroppedToItem);
PathAppendW(s_szDroppedToItem, DROPPED_ON_FILE);
GetModuleFileNameW(NULL, s_szSrcTestFile, _countof(s_szSrcTestFile));
PathRemoveFileSpecW(s_szSrcTestFile);
PathAppendW(s_szSrcTestFile, TESTFILENAME);
lstrcpyW(s_szDestTestFile, s_szDestFolder);
PathAppendW(s_szDestTestFile, TESTFILENAME);
lstrcpyW(s_szDestLinkSpec, s_szDestFolder);
PathAppendW(s_szDestLinkSpec, L"*DragDropTest*.lnk");
//trace("s_szSrcTestFile: '%S'\n", s_szSrcTestFile);
//trace("s_szDestTestFile: '%S'\n", s_szDestTestFile);
//trace("s_szDestLinkSpec: '%S'\n", s_szDestLinkSpec);
//trace("s_szDroppedToItem: '%S'\n", s_szDroppedToItem);
// create or delete files
//
DoCreateTestFile(s_szSrcTestFile);
DeleteFileW(s_szDestTestFile);
DoDeleteSpecW(s_szDestLinkSpec);
DeleteFileW(s_szDroppedToItem);
DoCreateShortcut(s_szDroppedToItem, s_szDestFolder);
// check file existence
//
ok(PathIsDirectoryW(s_szDestFolder), "s_szDestFolder is not directory\n");
ok(PathFileExistsW(s_szSrcTestFile), "s_szSrcTestFile doesn't exist\n");
ok(!DoSpecExistsW(s_szDestLinkSpec), "s_szDestLinkSpec doesn't exist\n");
ok(!PathFileExistsW(s_szDestTestFile), "s_szDestTestFile exists\n");
// get an IDataObject
pDataObject = NULL;
hr = GetUIObjectOfPath(s_szSrcTestFile, IID_IDataObject, (LPVOID *)&pDataObject);
ok_long(hr, S_OK);
// get an IDropTarget
CComPtr<IEnumIDList> pEnumIDList;
PIDLIST_ABSOLUTE pidl = NULL;
hr = s_pDesktop->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
&pEnumIDList);
ok_long(hr, S_OK);
while (pEnumIDList->Next(1, &pidl, NULL) == S_OK)
{
WCHAR szText[MAX_PATH];
SHGetPathFromIDListW(pidl, szText);
if (wcsstr(szText, DROPPED_ON_FILE) != NULL)
{
break;
}
CoTaskMemFree(pidl);
pidl = NULL;
}
ok(pidl != NULL, "Line %d: pidl is NULL\n", line);
pDropTarget = NULL;
PITEMID_CHILD pidlLast = ILFindLastID(pidl);
hr = s_pDesktop->GetUIObjectOf(NULL, 1, &pidlLast, IID_IDropTarget,
NULL, (LPVOID *)&pDropTarget);
CoTaskMemFree(pidl);
ok_long(hr, S_OK);
if (!pDropTarget)
{
skip("Line %d: pDropTarget was NULL\n", line);
// clean up
DeleteFileW(s_szSrcTestFile);
DeleteFileW(s_szDestTestFile);
DoDeleteSpecW(s_szDestLinkSpec);
ILFree(pidlDesktop);
return;
}
// DragEnter
POINTL ptl = { 0, 0 };
DWORD dwKeyState = pEntry->dwKeyState;
DWORD dwEffects = pEntry->dwEffects1;
hr = pDropTarget->DragEnter(pDataObject, dwKeyState, ptl, &dwEffects);
ok(hr == pEntry->hr1, "Line %d: hr1 was %08lX\n", line, hr);
switch (pEntry->dwEffects2)
{
case D_NONE_OR_COPY:
ok((dwEffects == D_NONE || dwEffects == D_COPY),
"Line %d: dwEffects2 was %08lX\n", line, dwEffects);
break;
case D_NONE_OR_MOVE:
ok((dwEffects == D_NONE || dwEffects == D_MOVE),
"Line %d: dwEffects2 was %08lX\n", line, dwEffects);
break;
case D_NONE_OR_LINK:
ok((dwEffects == D_NONE || dwEffects == D_LINK),
"Line %d: dwEffects2 was %08lX\n", line, dwEffects);
break;
default:
ok(dwEffects == pEntry->dwEffects2,
"Line %d: dwEffects2 was %08lX\n", line, dwEffects);
break;
}
// Drop
hr = pDropTarget->Drop(pDataObject, dwKeyState, ptl, &dwEffects);
ok(hr == pEntry->hr2, "Line %d: hr2 was %08lX\n", line, hr);
switch (pEntry->dwEffects3)
{
case D_NONE_OR_COPY:
ok((dwEffects == D_NONE || dwEffects == D_COPY),
"Line %d: dwEffects3 was %08lX\n", line, dwEffects);
break;
case D_NONE_OR_MOVE:
ok((dwEffects == D_NONE || dwEffects == D_MOVE),
"Line %d: dwEffects3 was %08lX\n", line, dwEffects);
break;
case D_NONE_OR_LINK:
ok((dwEffects == D_NONE || dwEffects == D_LINK),
"Line %d: dwEffects3 was %08lX\n", line, dwEffects);
break;
default:
ok(dwEffects == pEntry->dwEffects3,
"Line %d: dwEffects3 was %08lX\n", line, dwEffects);
break;
}
// check file existence by pEntry->op
switch (pEntry->op)
{
case OP_NONE:
ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line);
ok(!PathFileExistsW(s_szDestTestFile), "Line %d: dest exists\n", line);
ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line);
break;
case OP_COPY:
ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line);
ok(PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line);
ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line);
break;
case OP_MOVE:
ok(!PathFileExistsW(s_szSrcTestFile), "Line %d: src exists\n", line);
ok(PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line);
ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line);
break;
case OP_LINK:
ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line);
ok(!PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line);
ok(DoSpecExistsW(s_szDestLinkSpec), "Line %d: link not exists\n", line);
break;
case OP_NONE_OR_COPY:
ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line);
ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line);
break;
case OP_NONE_OR_MOVE:
ok(PathFileExistsW(s_szSrcTestFile) != PathFileExistsW(s_szDestTestFile),
"Line %d: It must be either None or Move\n", line);
break;
case OP_NONE_OR_LINK:
ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line);
ok(!PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line);
break;
}
// clean up
DeleteFileW(s_szSrcTestFile);
DeleteFileW(s_szDestTestFile);
DoDeleteSpecW(s_szDestLinkSpec);
ILFree(pidlDesktop);
}
START_TEST(DragDrop)
{
if (!winetest_interactive)
{
skip("Skipping the test due to crash. CORE-17057\n");
return;
}
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
ok_int(SUCCEEDED(hr), TRUE);
SHGetDesktopFolder(&s_pDesktop);
ok(!!s_pDesktop, "s_pDesktop is NULL\n");
BOOL ret = SHGetSpecialFolderPathW(NULL, s_szDestFolder, CSIDL_DESKTOP, FALSE);
ok_int(ret, TRUE);
for (size_t i = 0; i < _countof(s_TestEntries); ++i)
{
DoTestEntry(&s_TestEntries[i]);
}
DeleteFileW(s_szSrcTestFile);
DeleteFileW(s_szDestTestFile);
DoDeleteSpecW(s_szDestLinkSpec);
DeleteFileW(s_szDroppedToItem);
CoUninitialize();
}