2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test for Drag & Drop
5 * PROGRAMMER: Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
15 #define TESTFILENAME L"DragDropTest.txt"
16 #define DROPPED_ON_FILE L"DragDroppedOn.lnk"
18 static CComPtr
<IShellFolder
> s_pDesktop
;
20 static WCHAR s_szSrcTestFile
[MAX_PATH
];
21 static WCHAR s_szDestFolder
[MAX_PATH
];
22 static WCHAR s_szDestTestFile
[MAX_PATH
];
23 static WCHAR s_szDestLinkSpec
[MAX_PATH
];
24 static WCHAR s_szDroppedToItem
[MAX_PATH
];
37 #define D_NONE DROPEFFECT_NONE
38 #define D_COPY DROPEFFECT_COPY
39 #define D_MOVE DROPEFFECT_MOVE
40 #define D_LINK DROPEFFECT_LINK
41 #define D_NONE_OR_COPY 0xAABBCCDD
42 #define D_NONE_OR_MOVE 0x11223344
43 #define D_NONE_OR_LINK 0x55667788
57 static const TEST_ENTRY s_TestEntries
[] =
60 { __LINE__
, OP_NONE
, S_OK
, S_OK
, MK_LBUTTON
, D_NONE
, D_NONE
, D_NONE
},
61 { __LINE__
, OP_COPY
, S_OK
, S_OK
, MK_LBUTTON
, D_COPY
, D_COPY
, D_COPY
},
62 { __LINE__
, OP_MOVE
, S_OK
, S_OK
, MK_LBUTTON
, D_COPY
| D_MOVE
, D_MOVE
, D_NONE
},
63 { __LINE__
, OP_MOVE
, S_OK
, S_OK
, MK_LBUTTON
, D_MOVE
, D_MOVE
, D_NONE
},
64 { __LINE__
, OP_LINK
, S_OK
, S_OK
, MK_LBUTTON
, D_LINK
, D_LINK
, D_LINK
},
66 // MK_LBUTTON | MK_SHIFT
67 { __LINE__
, OP_NONE
, S_OK
, S_OK
, MK_LBUTTON
| MK_SHIFT
, D_NONE
, D_NONE
, D_NONE
},
68 { __LINE__
, OP_NONE_OR_COPY
, S_OK
, S_OK
, MK_LBUTTON
| MK_SHIFT
, D_COPY
, D_NONE_OR_COPY
, D_NONE_OR_COPY
},
69 { __LINE__
, OP_MOVE
, S_OK
, S_OK
, MK_LBUTTON
| MK_SHIFT
, D_COPY
| D_MOVE
, D_MOVE
, D_NONE
},
70 { __LINE__
, OP_MOVE
, S_OK
, S_OK
, MK_LBUTTON
| MK_SHIFT
, D_MOVE
, D_MOVE
, D_NONE
},
71 { __LINE__
, OP_NONE_OR_LINK
, S_OK
, S_OK
, MK_LBUTTON
| MK_SHIFT
, D_LINK
, D_NONE_OR_LINK
, D_NONE_OR_LINK
},
73 // MK_LBUTTON | MK_SHIFT | MK_CONTROL
74 #define MK_LBUTTON_SHIFT_CTRL (MK_LBUTTON | MK_SHIFT | MK_CONTROL)
75 { __LINE__
, OP_NONE
, S_OK
, S_OK
, MK_LBUTTON_SHIFT_CTRL
, D_NONE
, D_NONE
, D_NONE
},
76 { __LINE__
, OP_NONE_OR_COPY
, S_OK
, S_OK
, MK_LBUTTON_SHIFT_CTRL
, D_COPY
, D_NONE_OR_COPY
, D_NONE_OR_COPY
},
77 { __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
},
78 { __LINE__
, OP_NONE_OR_MOVE
, S_OK
, S_OK
, MK_LBUTTON_SHIFT_CTRL
, D_MOVE
, D_NONE_OR_MOVE
, D_NONE_OR_MOVE
},
79 { __LINE__
, OP_LINK
, S_OK
, S_OK
, MK_LBUTTON_SHIFT_CTRL
, D_LINK
, D_LINK
, D_LINK
},
80 #undef MK_LBUTTON_SHIFT_CTRL
82 // MK_LBUTTON | MK_CONTROL
83 { __LINE__
, OP_NONE
, S_OK
, S_OK
, MK_LBUTTON
| MK_CONTROL
, D_NONE
, D_NONE
, D_NONE
},
84 { __LINE__
, OP_COPY
, S_OK
, S_OK
, MK_LBUTTON
| MK_CONTROL
, D_COPY
, D_COPY
, D_COPY
},
85 { __LINE__
, OP_COPY
, S_OK
, S_OK
, MK_LBUTTON
| MK_CONTROL
, D_COPY
| D_MOVE
, D_COPY
, D_COPY
},
86 { __LINE__
, OP_NONE_OR_MOVE
, S_OK
, S_OK
, MK_LBUTTON
| MK_CONTROL
, D_MOVE
, D_NONE_OR_MOVE
, D_NONE_OR_MOVE
},
87 { __LINE__
, OP_NONE_OR_LINK
, S_OK
, S_OK
, MK_LBUTTON
| MK_CONTROL
, D_LINK
, D_NONE_OR_LINK
, D_NONE_OR_LINK
},
90 static void DoCreateTestFile(LPCWSTR pszFileName
)
92 FILE *fp
= _wfopen(pszFileName
, L
"wb");
93 ok(fp
!= NULL
, "fp is NULL for '%S'\n", pszFileName
);
97 HRESULT
DoCreateShortcut(
98 LPCWSTR pszLnkFileName
,
99 LPCWSTR pszTargetPathName
)
101 CComPtr
<IPersistFile
> ppf
;
102 CComPtr
<IShellLinkW
> psl
;
105 hr
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
106 IID_IShellLinkW
, (LPVOID
*)&psl
);
109 psl
->SetPath(pszTargetPathName
);
111 hr
= psl
->QueryInterface(IID_IPersistFile
, (LPVOID
*)&ppf
);
114 hr
= ppf
->Save(pszLnkFileName
, TRUE
);
122 GetUIObjectOfAbsPidl(PIDLIST_ABSOLUTE pidl
, REFIID riid
, LPVOID
*ppvOut
)
126 LPCITEMIDLIST pidlLast
;
127 CComPtr
<IShellFolder
> psf
;
128 HRESULT hr
= SHBindToParent(pidl
, IID_IShellFolder
, (LPVOID
*)&psf
,
133 hr
= psf
->GetUIObjectOf(NULL
, 1, &pidlLast
, riid
, NULL
, ppvOut
);
138 GetUIObjectOfPath(LPCWSTR pszPath
, REFIID riid
, LPVOID
*ppvOut
)
142 PIDLIST_ABSOLUTE pidl
= ILCreateFromPathW(pszPath
);
146 HRESULT hr
= GetUIObjectOfAbsPidl(pidl
, riid
, ppvOut
);
153 BOOL
DoSpecExistsW(LPCWSTR pszSpec
)
155 WIN32_FIND_DATAW find
;
156 HANDLE hFind
= FindFirstFileW(pszSpec
, &find
);
157 if (hFind
!= INVALID_HANDLE_VALUE
)
165 void DoDeleteSpecW(LPCWSTR pszSpec
)
167 WCHAR szPath
[MAX_PATH
], szFile
[MAX_PATH
];
168 lstrcpyW(szPath
, pszSpec
);
169 PathRemoveFileSpecW(szPath
);
171 WIN32_FIND_DATAW find
;
172 HANDLE hFind
= FindFirstFileW(pszSpec
, &find
);
173 if (hFind
!= INVALID_HANDLE_VALUE
)
177 lstrcpyW(szFile
, szPath
);
178 PathAppendW(szFile
, find
.cFileName
);
180 } while (FindNextFileW(hFind
, &find
));
186 static void DoTestEntry(const TEST_ENTRY
*pEntry
)
188 int line
= pEntry
->line
;
190 PIDLIST_ABSOLUTE pidlDesktop
= NULL
;
191 CComPtr
<IDropTarget
> pDropTarget
;
192 CComPtr
<IDataObject
> pDataObject
;
194 // get the desktop PIDL
195 SHGetSpecialFolderLocation(NULL
, CSIDL_DESKTOP
, &pidlDesktop
);
196 ok(!!pidlDesktop
, "pidlDesktop is NULL\n");
200 SHGetPathFromIDListW(pidlDesktop
, s_szDroppedToItem
);
201 PathAppendW(s_szDroppedToItem
, DROPPED_ON_FILE
);
203 GetModuleFileNameW(NULL
, s_szSrcTestFile
, _countof(s_szSrcTestFile
));
204 PathRemoveFileSpecW(s_szSrcTestFile
);
205 PathAppendW(s_szSrcTestFile
, TESTFILENAME
);
207 lstrcpyW(s_szDestTestFile
, s_szDestFolder
);
208 PathAppendW(s_szDestTestFile
, TESTFILENAME
);
210 lstrcpyW(s_szDestLinkSpec
, s_szDestFolder
);
211 PathAppendW(s_szDestLinkSpec
, L
"*DragDropTest*.lnk");
213 //trace("s_szSrcTestFile: '%S'\n", s_szSrcTestFile);
214 //trace("s_szDestTestFile: '%S'\n", s_szDestTestFile);
215 //trace("s_szDestLinkSpec: '%S'\n", s_szDestLinkSpec);
216 //trace("s_szDroppedToItem: '%S'\n", s_szDroppedToItem);
218 // create or delete files
220 DoCreateTestFile(s_szSrcTestFile
);
221 DeleteFileW(s_szDestTestFile
);
222 DoDeleteSpecW(s_szDestLinkSpec
);
223 DeleteFileW(s_szDroppedToItem
);
224 DoCreateShortcut(s_szDroppedToItem
, s_szDestFolder
);
226 // check file existence
228 ok(PathIsDirectoryW(s_szDestFolder
), "s_szDestFolder is not directory\n");
229 ok(PathFileExistsW(s_szSrcTestFile
), "s_szSrcTestFile doesn't exist\n");
230 ok(!DoSpecExistsW(s_szDestLinkSpec
), "s_szDestLinkSpec doesn't exist\n");
231 ok(!PathFileExistsW(s_szDestTestFile
), "s_szDestTestFile exists\n");
233 // get an IDataObject
235 hr
= GetUIObjectOfPath(s_szSrcTestFile
, IID_IDataObject
, (LPVOID
*)&pDataObject
);
238 // get an IDropTarget
239 CComPtr
<IEnumIDList
> pEnumIDList
;
240 PIDLIST_ABSOLUTE pidl
= NULL
;
241 hr
= s_pDesktop
->EnumObjects(NULL
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
,
244 while (pEnumIDList
->Next(1, &pidl
, NULL
) == S_OK
)
246 WCHAR szText
[MAX_PATH
];
247 SHGetPathFromIDListW(pidl
, szText
);
248 if (wcsstr(szText
, DROPPED_ON_FILE
) != NULL
)
255 ok(pidl
!= NULL
, "pidl is NULL\n");
257 PITEMID_CHILD pidlLast
= ILFindLastID(pidl
);
258 hr
= s_pDesktop
->GetUIObjectOf(NULL
, 1, &pidlLast
, IID_IDropTarget
,
259 NULL
, (LPVOID
*)&pDropTarget
);
264 POINTL ptl
= { 0, 0 };
265 DWORD dwKeyState
= pEntry
->dwKeyState
;
266 DWORD dwEffects
= pEntry
->dwEffects1
;
267 hr
= pDropTarget
->DragEnter(pDataObject
, dwKeyState
, ptl
, &dwEffects
);
269 ok(hr
== pEntry
->hr1
, "Line %d: hr1 was %08lX\n", line
, hr
);
271 switch (pEntry
->dwEffects2
)
274 ok((dwEffects
== D_NONE
|| dwEffects
== D_COPY
),
275 "Line %d: dwEffects2 was %08lX\n", line
, dwEffects
);
278 ok((dwEffects
== D_NONE
|| dwEffects
== D_MOVE
),
279 "Line %d: dwEffects2 was %08lX\n", line
, dwEffects
);
282 ok((dwEffects
== D_NONE
|| dwEffects
== D_LINK
),
283 "Line %d: dwEffects2 was %08lX\n", line
, dwEffects
);
286 ok(dwEffects
== pEntry
->dwEffects2
,
287 "Line %d: dwEffects2 was %08lX\n", line
, dwEffects
);
292 hr
= pDropTarget
->Drop(pDataObject
, dwKeyState
, ptl
, &dwEffects
);
293 ok(hr
== pEntry
->hr2
, "Line %d: hr2 was %08lX\n", line
, hr
);
295 switch (pEntry
->dwEffects3
)
298 ok((dwEffects
== D_NONE
|| dwEffects
== D_COPY
),
299 "Line %d: dwEffects3 was %08lX\n", line
, dwEffects
);
302 ok((dwEffects
== D_NONE
|| dwEffects
== D_MOVE
),
303 "Line %d: dwEffects3 was %08lX\n", line
, dwEffects
);
306 ok((dwEffects
== D_NONE
|| dwEffects
== D_LINK
),
307 "Line %d: dwEffects3 was %08lX\n", line
, dwEffects
);
310 ok(dwEffects
== pEntry
->dwEffects3
,
311 "Line %d: dwEffects3 was %08lX\n", line
, dwEffects
);
315 // check file existence by pEntry->op
319 ok(PathFileExistsW(s_szSrcTestFile
), "Line %d: src not exists\n", line
);
320 ok(!PathFileExistsW(s_szDestTestFile
), "Line %d: dest exists\n", line
);
321 ok(!DoSpecExistsW(s_szDestLinkSpec
), "Line %d: link exists\n", line
);
324 ok(PathFileExistsW(s_szSrcTestFile
), "Line %d: src not exists\n", line
);
325 ok(PathFileExistsW(s_szDestTestFile
), "Line %d: dest not exists\n", line
);
326 ok(!DoSpecExistsW(s_szDestLinkSpec
), "Line %d: link exists\n", line
);
329 ok(!PathFileExistsW(s_szSrcTestFile
), "Line %d: src exists\n", line
);
330 ok(PathFileExistsW(s_szDestTestFile
), "Line %d: dest not exists\n", line
);
331 ok(!DoSpecExistsW(s_szDestLinkSpec
), "Line %d: link exists\n", line
);
334 ok(PathFileExistsW(s_szSrcTestFile
), "Line %d: src not exists\n", line
);
335 ok(!PathFileExistsW(s_szDestTestFile
), "Line %d: dest not exists\n", line
);
336 ok(DoSpecExistsW(s_szDestLinkSpec
), "Line %d: link not exists\n", line
);
338 case OP_NONE_OR_COPY
:
339 ok(PathFileExistsW(s_szSrcTestFile
), "Line %d: src not exists\n", line
);
340 ok(!DoSpecExistsW(s_szDestLinkSpec
), "Line %d: link exists\n", line
);
342 case OP_NONE_OR_MOVE
:
343 ok(PathFileExistsW(s_szSrcTestFile
) != PathFileExistsW(s_szDestTestFile
),
344 "Line %d: It must be either None or Move\n", line
);
346 case OP_NONE_OR_LINK
:
347 ok(PathFileExistsW(s_szSrcTestFile
), "Line %d: src not exists\n", line
);
348 ok(!PathFileExistsW(s_szDestTestFile
), "Line %d: dest not exists\n", line
);
353 DeleteFileW(s_szSrcTestFile
);
354 DeleteFileW(s_szDestTestFile
);
355 DoDeleteSpecW(s_szDestLinkSpec
);
361 HRESULT hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
362 ok_int(SUCCEEDED(hr
), TRUE
);
364 SHGetDesktopFolder(&s_pDesktop
);
365 ok(!!s_pDesktop
, "s_pDesktop is NULL\n");
367 BOOL ret
= SHGetSpecialFolderPathW(NULL
, s_szDestFolder
, CSIDL_DESKTOP
, FALSE
);
370 for (size_t i
= 0; i
< _countof(s_TestEntries
); ++i
)
372 DoTestEntry(&s_TestEntries
[i
]);
375 DeleteFileW(s_szSrcTestFile
);
376 DeleteFileW(s_szDestTestFile
);
377 DoDeleteSpecW(s_szDestLinkSpec
);
378 DeleteFileW(s_szDroppedToItem
);