https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6e42e63c4623bb929a968…
commit 6e42e63c4623bb929a968309b0ea4f9d82483c1f
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Nov 12 16:49:52 2019 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Nov 12 16:49:52 2019 +0900
[SHELL32_APITEST] Add DragDrop testcase (#2023)
Add DragDrop testcase to shell32_apitest for testing Drag & Drop feature of the
Shell.
This PR tests IDropTarget::DragEnter and IDropTarget::Drop. CORE-11238
---
modules/rostests/apitests/shell32/CMakeLists.txt | 1 +
modules/rostests/apitests/shell32/DragDrop.cpp | 381 +++++++++++++++++++++++
modules/rostests/apitests/shell32/testlist.c | 2 +
3 files changed, 384 insertions(+)
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt
b/modules/rostests/apitests/shell32/CMakeLists.txt
index 02b28625d63..f8d8c84e8d8 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -17,6 +17,7 @@ list(APPEND SOURCE
CShellLink.cpp
CUserNotification.cpp
Control_RunDLLW.cpp
+ DragDrop.cpp
IShellFolderViewCB.cpp
OpenAs_RunDLL.cpp
PathResolve.cpp
diff --git a/modules/rostests/apitests/shell32/DragDrop.cpp
b/modules/rostests/apitests/shell32/DragDrop.cpp
new file mode 100644
index 00000000000..43e06f5a0b2
--- /dev/null
+++ b/modules/rostests/apitests/shell32/DragDrop.cpp
@@ -0,0 +1,381 @@
+/*
+ * 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(a)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_MOVE, 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_MOVE, 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_NONE_OR_MOVE, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_MOVE,
D_NONE_OR_MOVE, D_NONE_OR_MOVE },
+ { __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_NONE_OR_MOVE, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_MOVE,
D_NONE_OR_MOVE, D_NONE_OR_MOVE },
+ { __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, "pidl is NULL\n");
+ 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);
+
+ // 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)
+{
+ 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();
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c
b/modules/rostests/apitests/shell32/testlist.c
index 7b603dff147..b16ace6cc23 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -11,6 +11,7 @@ extern void func_CMyComputer(void);
extern void func_CShellDesktop(void);
extern void func_CShellLink(void);
extern void func_CUserNotification(void);
+extern void func_DragDrop(void);
extern void func_IShellFolderViewCB(void);
extern void func_menu(void);
extern void func_OpenAs_RunDLL(void);
@@ -32,6 +33,7 @@ const struct test winetest_testlist[] =
{ "CShellDesktop", func_CShellDesktop },
{ "CShellLink", func_CShellLink },
{ "CUserNotification", func_CUserNotification },
+ { "DragDrop", func_DragDrop },
{ "IShellFolderViewCB", func_IShellFolderViewCB },
{ "menu", func_menu },
{ "OpenAs_RunDLL", func_OpenAs_RunDLL },