1c2c66affSColin Finck 
2c2c66affSColin Finck /*
3c2c66affSColin Finck  * file system folder drop target
4c2c66affSColin Finck  *
5c2c66affSColin Finck  * Copyright 1997             Marcus Meissner
6c2c66affSColin Finck  * Copyright 1998, 1999, 2002 Juergen Schmied
7c2c66affSColin Finck  *
8c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
9c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
10c2c66affSColin Finck  * License as published by the Free Software Foundation; either
11c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
12c2c66affSColin Finck  *
13c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
14c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16c2c66affSColin Finck  * Lesser General Public License for more details.
17c2c66affSColin Finck  *
18c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
19c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
20c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21c2c66affSColin Finck  */
22c2c66affSColin Finck 
23c2c66affSColin Finck #include <precomp.h>
24c2c66affSColin Finck 
25c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL (shell);
26c2c66affSColin Finck 
27*aebaa14eSWhindmar Saksit #define D_NONE DROPEFFECT_NONE
28*aebaa14eSWhindmar Saksit #define D_COPY DROPEFFECT_COPY
29*aebaa14eSWhindmar Saksit #define D_MOVE DROPEFFECT_MOVE
30*aebaa14eSWhindmar Saksit #define D_LINK DROPEFFECT_LINK
31*aebaa14eSWhindmar Saksit 
SHELL_StripIllegalFsNameCharacters(_Inout_ LPWSTR Buf)32fa95a96eSWhindmar Saksit static void SHELL_StripIllegalFsNameCharacters(_Inout_ LPWSTR Buf)
33fa95a96eSWhindmar Saksit {
34fa95a96eSWhindmar Saksit     for (LPWSTR src = Buf, dst = src;;)
35fa95a96eSWhindmar Saksit     {
36fa95a96eSWhindmar Saksit         *dst = *src;
37fa95a96eSWhindmar Saksit         if (!*dst)
38fa95a96eSWhindmar Saksit             break;
39fa95a96eSWhindmar Saksit         else if (wcschr(INVALID_FILETITLE_CHARACTERSW, *dst))
40fa95a96eSWhindmar Saksit             src = CharNextW(src);
41fa95a96eSWhindmar Saksit         else
42fa95a96eSWhindmar Saksit             ++src, ++dst;
43fa95a96eSWhindmar Saksit     }
44fa95a96eSWhindmar Saksit }
45fa95a96eSWhindmar Saksit 
PathIsSameDrive(LPCWSTR Path1,LPCWSTR Path2)46*aebaa14eSWhindmar Saksit static bool PathIsSameDrive(LPCWSTR Path1, LPCWSTR Path2)
47*aebaa14eSWhindmar Saksit {
48*aebaa14eSWhindmar Saksit     int d1 = PathGetDriveNumberW(Path1), d2 = PathGetDriveNumberW(Path2);
49*aebaa14eSWhindmar Saksit     return d1 == d2 && d2 >= 0;
50*aebaa14eSWhindmar Saksit }
51*aebaa14eSWhindmar Saksit 
PathIsDriveRoot(LPCWSTR Path)52*aebaa14eSWhindmar Saksit static bool PathIsDriveRoot(LPCWSTR Path)
53*aebaa14eSWhindmar Saksit {
54*aebaa14eSWhindmar Saksit     return PathIsRootW(Path) && PathGetDriveNumberW(Path) >= 0;
55*aebaa14eSWhindmar Saksit }
56*aebaa14eSWhindmar Saksit 
57fa95a96eSWhindmar Saksit static HRESULT
SHELL_LimitDropEffectToItemAttributes(_In_ IDataObject * pDataObject,_Inout_ PDWORD pdwEffect)58fa95a96eSWhindmar Saksit SHELL_LimitDropEffectToItemAttributes(_In_ IDataObject *pDataObject, _Inout_ PDWORD pdwEffect)
59fa95a96eSWhindmar Saksit {
60fa95a96eSWhindmar Saksit     DWORD att = *pdwEffect & (SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK); // DROPEFFECT maps perfectly to these SFGAO bits
61fa95a96eSWhindmar Saksit     HRESULT hr = SHGetAttributesFromDataObject(pDataObject, att, &att, NULL);
62fa95a96eSWhindmar Saksit     if (FAILED(hr))
63fa95a96eSWhindmar Saksit         return S_FALSE;
64fa95a96eSWhindmar Saksit     *pdwEffect &= ~(SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK) | att;
65fa95a96eSWhindmar Saksit     return hr;
66fa95a96eSWhindmar Saksit }
67fa95a96eSWhindmar Saksit 
GetDefaultCopyMoveEffect()68fa95a96eSWhindmar Saksit static void GetDefaultCopyMoveEffect()
69fa95a96eSWhindmar Saksit {
70fa95a96eSWhindmar Saksit     // FIXME: When the source is on a different volume than the target, change default from move to copy
71fa95a96eSWhindmar Saksit }
72c2c66affSColin Finck 
73c2c66affSColin Finck /****************************************************************************
74fd209faaSGiannis Adamopoulos  * CFSDropTarget::_CopyItems
75c2c66affSColin Finck  *
761273bbe4SHuw Campbell  * copies or moves items to this folder
77c2c66affSColin Finck  */
_CopyItems(IShellFolder * pSFFrom,UINT cidl,LPCITEMIDLIST * apidl,BOOL bCopy)78fd209faaSGiannis Adamopoulos HRESULT CFSDropTarget::_CopyItems(IShellFolder * pSFFrom, UINT cidl,
79c2c66affSColin Finck                                   LPCITEMIDLIST * apidl, BOOL bCopy)
80c2c66affSColin Finck {
811273bbe4SHuw Campbell     HRESULT ret;
821273bbe4SHuw Campbell     WCHAR wszDstPath[MAX_PATH + 1] = {0};
831273bbe4SHuw Campbell     PWCHAR pwszSrcPathsList = (PWCHAR) HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) * cidl + 1);
841273bbe4SHuw Campbell     if (!pwszSrcPathsList)
85c2c66affSColin Finck         return E_OUTOFMEMORY;
86c2c66affSColin Finck 
871273bbe4SHuw Campbell     PWCHAR pwszListPos = pwszSrcPathsList;
881273bbe4SHuw Campbell     STRRET strretFrom;
891273bbe4SHuw Campbell     SHFILEOPSTRUCTW fop;
90520577a8SKatayama Hirofumi MZ     BOOL bRenameOnCollision = FALSE;
91c2c66affSColin Finck 
921273bbe4SHuw Campbell     /* Build a double null terminated list of C strings from source paths */
931273bbe4SHuw Campbell     for (UINT i = 0; i < cidl; i++)
94a5a30fc2SKyle Katarn     {
951273bbe4SHuw Campbell         ret = pSFFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strretFrom);
961273bbe4SHuw Campbell         if (FAILED(ret))
971273bbe4SHuw Campbell             goto cleanup;
981273bbe4SHuw Campbell 
991273bbe4SHuw Campbell         ret = StrRetToBufW(&strretFrom, NULL, pwszListPos, MAX_PATH);
1001273bbe4SHuw Campbell         if (FAILED(ret))
1011273bbe4SHuw Campbell             goto cleanup;
1021273bbe4SHuw Campbell 
1031273bbe4SHuw Campbell         pwszListPos += lstrlenW(pwszListPos) + 1;
104a5a30fc2SKyle Katarn     }
1051273bbe4SHuw Campbell     /* Append the final null. */
1061273bbe4SHuw Campbell     *pwszListPos = L'\0';
1071273bbe4SHuw Campbell 
1081273bbe4SHuw Campbell     /* Build a double null terminated target (this path) */
1091273bbe4SHuw Campbell     ret = StringCchCopyW(wszDstPath, MAX_PATH, m_sPathTarget);
1101273bbe4SHuw Campbell     if (FAILED(ret))
1111273bbe4SHuw Campbell         goto cleanup;
1121273bbe4SHuw Campbell 
113520577a8SKatayama Hirofumi MZ     wszDstPath[lstrlenW(wszDstPath) + 1] = UNICODE_NULL;
114520577a8SKatayama Hirofumi MZ 
115520577a8SKatayama Hirofumi MZ     /* Set bRenameOnCollision to TRUE if necesssary */
116520577a8SKatayama Hirofumi MZ     if (bCopy)
117520577a8SKatayama Hirofumi MZ     {
118520577a8SKatayama Hirofumi MZ         WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
119520577a8SKatayama Hirofumi MZ         GetFullPathNameW(pwszSrcPathsList, _countof(szPath1), szPath1, NULL);
120520577a8SKatayama Hirofumi MZ         GetFullPathNameW(wszDstPath, _countof(szPath2), szPath2, NULL);
121520577a8SKatayama Hirofumi MZ         PathRemoveFileSpecW(szPath1);
122520577a8SKatayama Hirofumi MZ         if (_wcsicmp(szPath1, szPath2) == 0)
123520577a8SKatayama Hirofumi MZ             bRenameOnCollision = TRUE;
124520577a8SKatayama Hirofumi MZ     }
1251273bbe4SHuw Campbell 
1261273bbe4SHuw Campbell     ZeroMemory(&fop, sizeof(fop));
1271273bbe4SHuw Campbell     fop.hwnd = m_hwndSite;
1281273bbe4SHuw Campbell     fop.wFunc = bCopy ? FO_COPY : FO_MOVE;
1291273bbe4SHuw Campbell     fop.pFrom = pwszSrcPathsList;
1301273bbe4SHuw Campbell     fop.pTo = wszDstPath;
1311273bbe4SHuw Campbell     fop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
132520577a8SKatayama Hirofumi MZ     if (bRenameOnCollision)
133520577a8SKatayama Hirofumi MZ         fop.fFlags |= FOF_RENAMEONCOLLISION;
134520577a8SKatayama Hirofumi MZ 
1351273bbe4SHuw Campbell     ret = S_OK;
1361273bbe4SHuw Campbell 
1371273bbe4SHuw Campbell     if (SHFileOperationW(&fop))
1381273bbe4SHuw Campbell     {
1391273bbe4SHuw Campbell         ERR("SHFileOperationW failed\n");
1401273bbe4SHuw Campbell         ret = E_FAIL;
1411273bbe4SHuw Campbell     }
1421273bbe4SHuw Campbell 
1431273bbe4SHuw Campbell cleanup:
1441273bbe4SHuw Campbell     HeapFree(GetProcessHeap(), 0, pwszSrcPathsList);
1451273bbe4SHuw Campbell     return ret;
146c2c66affSColin Finck }
147c2c66affSColin Finck 
CFSDropTarget()148c2c66affSColin Finck CFSDropTarget::CFSDropTarget():
149fd209faaSGiannis Adamopoulos     m_cfShellIDList(0),
150fd209faaSGiannis Adamopoulos     m_fAcceptFmt(FALSE),
151fd209faaSGiannis Adamopoulos     m_sPathTarget(NULL),
1526d91269eSGiannis Adamopoulos     m_hwndSite(NULL),
153*aebaa14eSWhindmar Saksit     m_grfKeyState(0),
154*aebaa14eSWhindmar Saksit     m_AllowedEffects(0)
155c2c66affSColin Finck {
156c2c66affSColin Finck }
157c2c66affSColin Finck 
Initialize(LPWSTR PathTarget)158fd209faaSGiannis Adamopoulos HRESULT CFSDropTarget::Initialize(LPWSTR PathTarget)
159c2c66affSColin Finck {
160c2c66affSColin Finck     if (!PathTarget)
161c2c66affSColin Finck         return E_UNEXPECTED;
162c2c66affSColin Finck 
163fd209faaSGiannis Adamopoulos     m_cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
164fd209faaSGiannis Adamopoulos     if (!m_cfShellIDList)
165c2c66affSColin Finck         return E_FAIL;
166c2c66affSColin Finck 
167*aebaa14eSWhindmar Saksit     return SHStrDupW(PathTarget, &m_sPathTarget);
168c2c66affSColin Finck }
169c2c66affSColin Finck 
~CFSDropTarget()170c2c66affSColin Finck CFSDropTarget::~CFSDropTarget()
171c2c66affSColin Finck {
172fd209faaSGiannis Adamopoulos     SHFree(m_sPathTarget);
173c2c66affSColin Finck }
174c2c66affSColin Finck 
175c2c66affSColin Finck BOOL
_GetUniqueFileName(LPCWSTR pwszBasePath,LPCWSTR pwszExt,LPWSTR pwszTarget,BOOL bShortcut)1760f5fb478SKatayama Hirofumi MZ CFSDropTarget::_GetUniqueFileName(LPCWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
177c2c66affSColin Finck {
178c2c66affSColin Finck     WCHAR wszLink[40];
179c2c66affSColin Finck 
180c2c66affSColin Finck     if (!bShortcut)
181c2c66affSColin Finck     {
182c2c66affSColin Finck         if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
183c2c66affSColin Finck             wszLink[0] = L'\0';
184c2c66affSColin Finck     }
185c2c66affSColin Finck 
186c2c66affSColin Finck     if (!bShortcut)
187c2c66affSColin Finck         swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
188c2c66affSColin Finck     else
189c2c66affSColin Finck         swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
190c2c66affSColin Finck 
191c2c66affSColin Finck     for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
192c2c66affSColin Finck     {
193c2c66affSColin Finck         if (!bShortcut)
194c2c66affSColin Finck             swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
195c2c66affSColin Finck         else
196c2c66affSColin Finck             swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
197c2c66affSColin Finck     }
198c2c66affSColin Finck 
199c2c66affSColin Finck     return TRUE;
200c2c66affSColin Finck }
201c2c66affSColin Finck 
202c2c66affSColin Finck /****************************************************************************
203c2c66affSColin Finck  * IDropTarget implementation
204c2c66affSColin Finck  */
_QueryDrop(DWORD dwKeyState,LPDWORD pdwEffect)205fd209faaSGiannis Adamopoulos BOOL CFSDropTarget::_QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
206c2c66affSColin Finck {
207c2c66affSColin Finck     /* TODO Windows does different drop effects if dragging across drives.
208c2c66affSColin Finck     i.e., it will copy instead of move if the directories are on different disks. */
209fa95a96eSWhindmar Saksit     GetDefaultCopyMoveEffect();
210c2c66affSColin Finck 
2116f25b42aSGiannis Adamopoulos     DWORD dwEffect = m_dwDefaultEffect;
212c2c66affSColin Finck 
213c2c66affSColin Finck     *pdwEffect = DROPEFFECT_NONE;
214c2c66affSColin Finck 
215fd209faaSGiannis Adamopoulos     if (m_fAcceptFmt) { /* Does our interpretation of the keystate ... */
216c2c66affSColin Finck         *pdwEffect = KeyStateToDropEffect(dwKeyState);
217c2c66affSColin Finck 
218*aebaa14eSWhindmar Saksit         // Transform disallowed move to a copy
219*aebaa14eSWhindmar Saksit         if ((*pdwEffect & D_MOVE) && (m_AllowedEffects & (D_MOVE | D_COPY)) == D_COPY)
220*aebaa14eSWhindmar Saksit             *pdwEffect = D_COPY;
221*aebaa14eSWhindmar Saksit 
222*aebaa14eSWhindmar Saksit         *pdwEffect &= m_AllowedEffects;
223*aebaa14eSWhindmar Saksit 
224c2c66affSColin Finck         if (*pdwEffect == DROPEFFECT_NONE)
225c2c66affSColin Finck             *pdwEffect = dwEffect;
226c2c66affSColin Finck 
227c2c66affSColin Finck         /* ... matches the desired effect ? */
228c2c66affSColin Finck         if (dwEffect & *pdwEffect) {
229c2c66affSColin Finck             return TRUE;
230c2c66affSColin Finck         }
231c2c66affSColin Finck     }
232c2c66affSColin Finck     return FALSE;
233c2c66affSColin Finck }
234c2c66affSColin Finck 
_GetEffectFromMenu(IDataObject * pDataObject,POINTL pt,DWORD * pdwEffect,DWORD dwAvailableEffects)2356f25b42aSGiannis Adamopoulos HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, DWORD *pdwEffect, DWORD dwAvailableEffects)
2366d91269eSGiannis Adamopoulos {
2376d91269eSGiannis Adamopoulos     HMENU hmenu = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(IDM_DRAGFILE));
2386d91269eSGiannis Adamopoulos     if (!hmenu)
2396d91269eSGiannis Adamopoulos         return E_OUTOFMEMORY;
2406d91269eSGiannis Adamopoulos 
2416f25b42aSGiannis Adamopoulos     HMENU hpopupmenu = GetSubMenu(hmenu, 0);
2426f25b42aSGiannis Adamopoulos 
243fa95a96eSWhindmar Saksit     SHELL_LimitDropEffectToItemAttributes(pDataObject, &dwAvailableEffects);
2446f25b42aSGiannis Adamopoulos     if ((dwAvailableEffects & DROPEFFECT_COPY) == 0)
2456f25b42aSGiannis Adamopoulos         DeleteMenu(hpopupmenu, IDM_COPYHERE, MF_BYCOMMAND);
246fa95a96eSWhindmar Saksit     if ((dwAvailableEffects & DROPEFFECT_MOVE) == 0)
2476f25b42aSGiannis Adamopoulos         DeleteMenu(hpopupmenu, IDM_MOVEHERE, MF_BYCOMMAND);
248fa95a96eSWhindmar Saksit     if ((dwAvailableEffects & DROPEFFECT_LINK) == 0 && (dwAvailableEffects & (DROPEFFECT_COPY | DROPEFFECT_MOVE)))
2496f25b42aSGiannis Adamopoulos         DeleteMenu(hpopupmenu, IDM_LINKHERE, MF_BYCOMMAND);
2506f25b42aSGiannis Adamopoulos 
251fa95a96eSWhindmar Saksit     GetDefaultCopyMoveEffect();
252fa95a96eSWhindmar Saksit     if (*pdwEffect & dwAvailableEffects & DROPEFFECT_COPY)
2536f25b42aSGiannis Adamopoulos         SetMenuDefaultItem(hpopupmenu, IDM_COPYHERE, FALSE);
254fa95a96eSWhindmar Saksit     else if (*pdwEffect & dwAvailableEffects & DROPEFFECT_MOVE)
2556f25b42aSGiannis Adamopoulos         SetMenuDefaultItem(hpopupmenu, IDM_MOVEHERE, FALSE);
256fa95a96eSWhindmar Saksit     else if (dwAvailableEffects & DROPEFFECT_LINK)
2576f25b42aSGiannis Adamopoulos         SetMenuDefaultItem(hpopupmenu, IDM_LINKHERE, FALSE);
2586f25b42aSGiannis Adamopoulos 
2596d91269eSGiannis Adamopoulos     /* FIXME: We need to support shell extensions here */
2606d91269eSGiannis Adamopoulos 
2611d55f459SGiannis Adamopoulos     /* We shouldn't use the site window here because the menu should work even when we don't have a site */
2621d55f459SGiannis Adamopoulos     HWND hwndDummy = CreateWindowEx(0,
2631d55f459SGiannis Adamopoulos                               WC_STATIC,
2641d55f459SGiannis Adamopoulos                               NULL,
2651d55f459SGiannis Adamopoulos                               WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
2661d55f459SGiannis Adamopoulos                               pt.x,
2671d55f459SGiannis Adamopoulos                               pt.y,
2681d55f459SGiannis Adamopoulos                               1,
2691d55f459SGiannis Adamopoulos                               1,
2701d55f459SGiannis Adamopoulos                               NULL,
2711d55f459SGiannis Adamopoulos                               NULL,
2721d55f459SGiannis Adamopoulos                               NULL,
2731d55f459SGiannis Adamopoulos                               NULL);
2741d55f459SGiannis Adamopoulos 
275fa95a96eSWhindmar Saksit     SetForegroundWindow(hwndDummy); // Required for aborting by pressing Esc when dragging from Explorer to desktop
2766f25b42aSGiannis Adamopoulos     UINT uCommand = TrackPopupMenu(hpopupmenu,
2776f25b42aSGiannis Adamopoulos                                    TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY,
2781d55f459SGiannis Adamopoulos                                    pt.x, pt.y, 0, hwndDummy, NULL);
2791d55f459SGiannis Adamopoulos 
2801d55f459SGiannis Adamopoulos     DestroyWindow(hwndDummy);
2811d55f459SGiannis Adamopoulos 
2826d91269eSGiannis Adamopoulos     if (uCommand == 0)
2836d91269eSGiannis Adamopoulos         return S_FALSE;
2846d91269eSGiannis Adamopoulos     else if (uCommand == IDM_COPYHERE)
2856d91269eSGiannis Adamopoulos         *pdwEffect = DROPEFFECT_COPY;
2866d91269eSGiannis Adamopoulos     else if (uCommand == IDM_MOVEHERE)
2876d91269eSGiannis Adamopoulos         *pdwEffect = DROPEFFECT_MOVE;
2886d91269eSGiannis Adamopoulos     else if (uCommand == IDM_LINKHERE)
2896d91269eSGiannis Adamopoulos         *pdwEffect = DROPEFFECT_LINK;
2906d91269eSGiannis Adamopoulos 
2916d91269eSGiannis Adamopoulos     return S_OK;
2926d91269eSGiannis Adamopoulos }
2936d91269eSGiannis Adamopoulos 
_RepositionItems(IShellFolderView * psfv,IDataObject * pdtobj,POINTL pt)2946d91269eSGiannis Adamopoulos HRESULT CFSDropTarget::_RepositionItems(IShellFolderView *psfv, IDataObject *pdtobj, POINTL pt)
2956d91269eSGiannis Adamopoulos {
2966d91269eSGiannis Adamopoulos     CComPtr<IFolderView> pfv;
2976d91269eSGiannis Adamopoulos     POINT ptDrag;
2986d91269eSGiannis Adamopoulos     HRESULT hr = psfv->QueryInterface(IID_PPV_ARG(IFolderView, &pfv));
2996d91269eSGiannis Adamopoulos     if (FAILED_UNEXPECTEDLY(hr))
3006d91269eSGiannis Adamopoulos         return hr;
3016d91269eSGiannis Adamopoulos 
3026d91269eSGiannis Adamopoulos     hr = psfv->GetDragPoint(&ptDrag);
3036d91269eSGiannis Adamopoulos     if (FAILED_UNEXPECTEDLY(hr))
3046d91269eSGiannis Adamopoulos         return hr;
3056d91269eSGiannis Adamopoulos 
3066d91269eSGiannis Adamopoulos     PIDLIST_ABSOLUTE pidlFolder;
3076d91269eSGiannis Adamopoulos     PUITEMID_CHILD *apidl;
3086d91269eSGiannis Adamopoulos     UINT cidl;
3096d91269eSGiannis Adamopoulos     hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
3106d91269eSGiannis Adamopoulos     if (FAILED_UNEXPECTEDLY(hr))
3116d91269eSGiannis Adamopoulos         return hr;
3126d91269eSGiannis Adamopoulos 
3136d91269eSGiannis Adamopoulos     CComHeapPtr<POINT> apt;
3146d91269eSGiannis Adamopoulos     if (!apt.Allocate(cidl))
3156d91269eSGiannis Adamopoulos     {
3166d91269eSGiannis Adamopoulos         SHFree(pidlFolder);
3176d91269eSGiannis Adamopoulos         _ILFreeaPidl(apidl, cidl);
3186d91269eSGiannis Adamopoulos         return E_OUTOFMEMORY;
3196d91269eSGiannis Adamopoulos     }
3206d91269eSGiannis Adamopoulos 
3216d91269eSGiannis Adamopoulos     for (UINT i = 0; i<cidl; i++)
3226d91269eSGiannis Adamopoulos     {
3236d91269eSGiannis Adamopoulos         pfv->GetItemPosition(apidl[i], &apt[i]);
3246d91269eSGiannis Adamopoulos         apt[i].x += pt.x - ptDrag.x;
3256d91269eSGiannis Adamopoulos         apt[i].y += pt.y - ptDrag.y;
3266d91269eSGiannis Adamopoulos     }
3276d91269eSGiannis Adamopoulos 
3286d91269eSGiannis Adamopoulos     pfv->SelectAndPositionItems(cidl, apidl, apt, SVSI_SELECT);
3296d91269eSGiannis Adamopoulos 
3306d91269eSGiannis Adamopoulos     SHFree(pidlFolder);
3316d91269eSGiannis Adamopoulos     _ILFreeaPidl(apidl, cidl);
3326d91269eSGiannis Adamopoulos     return S_OK;
3336d91269eSGiannis Adamopoulos }
3346d91269eSGiannis Adamopoulos 
DragEnter(IDataObject * pDataObject,DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)335c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject *pDataObject,
336c2c66affSColin Finck                                         DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
337c2c66affSColin Finck {
338c2c66affSColin Finck     TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
3398f129932SKatayama Hirofumi MZ 
340*aebaa14eSWhindmar Saksit     const BOOL bAnyKeyMod = dwKeyState & (MK_SHIFT | MK_CONTROL);
341*aebaa14eSWhindmar Saksit     m_AllowedEffects = *pdwEffect;
342*aebaa14eSWhindmar Saksit 
3438f129932SKatayama Hirofumi MZ     if (*pdwEffect == DROPEFFECT_NONE)
3448f129932SKatayama Hirofumi MZ         return S_OK;
3458f129932SKatayama Hirofumi MZ 
346c2c66affSColin Finck     FORMATETC fmt;
347c2c66affSColin Finck     FORMATETC fmt2;
348fd209faaSGiannis Adamopoulos     m_fAcceptFmt = FALSE;
349c2c66affSColin Finck 
350fd209faaSGiannis Adamopoulos     InitFormatEtc (fmt, m_cfShellIDList, TYMED_HGLOBAL);
351c2c66affSColin Finck     InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
352c2c66affSColin Finck 
353c2c66affSColin Finck     if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
354fd209faaSGiannis Adamopoulos         m_fAcceptFmt = TRUE;
355c2c66affSColin Finck     else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
356fd209faaSGiannis Adamopoulos         m_fAcceptFmt = TRUE;
357c2c66affSColin Finck 
3586d91269eSGiannis Adamopoulos     m_grfKeyState = dwKeyState;
359cd75a87cSKatayama Hirofumi MZ 
360*aebaa14eSWhindmar Saksit     SHELL_LimitDropEffectToItemAttributes(pDataObject, pdwEffect);
361*aebaa14eSWhindmar Saksit     m_AllowedEffects = *pdwEffect;
362*aebaa14eSWhindmar Saksit     m_dwDefaultEffect = m_AllowedEffects;
363cd75a87cSKatayama Hirofumi MZ     switch (*pdwEffect & (D_COPY | D_MOVE | D_LINK))
364cd75a87cSKatayama Hirofumi MZ     {
365cd75a87cSKatayama Hirofumi MZ         case D_COPY | D_MOVE:
366cd75a87cSKatayama Hirofumi MZ             if (dwKeyState & MK_CONTROL)
367cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_COPY;
368cd75a87cSKatayama Hirofumi MZ             else
369cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_MOVE;
370cd75a87cSKatayama Hirofumi MZ             break;
371cd75a87cSKatayama Hirofumi MZ         case D_COPY | D_MOVE | D_LINK:
372cd75a87cSKatayama Hirofumi MZ             if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == (MK_SHIFT | MK_CONTROL))
373cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_LINK;
374cd75a87cSKatayama Hirofumi MZ             else if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == MK_CONTROL)
375cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_COPY;
376cd75a87cSKatayama Hirofumi MZ             else
377cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_MOVE;
378cd75a87cSKatayama Hirofumi MZ             break;
379cd75a87cSKatayama Hirofumi MZ         case D_COPY | D_LINK:
380cd75a87cSKatayama Hirofumi MZ             if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == (MK_SHIFT | MK_CONTROL))
381cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_LINK;
382cd75a87cSKatayama Hirofumi MZ             else
383cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_COPY;
384cd75a87cSKatayama Hirofumi MZ             break;
385cd75a87cSKatayama Hirofumi MZ         case D_MOVE | D_LINK:
386cd75a87cSKatayama Hirofumi MZ             if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == (MK_SHIFT | MK_CONTROL))
387cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_LINK;
388cd75a87cSKatayama Hirofumi MZ             else
389cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_MOVE;
390cd75a87cSKatayama Hirofumi MZ             break;
391cd75a87cSKatayama Hirofumi MZ     }
3926f25b42aSGiannis Adamopoulos 
3936f25b42aSGiannis Adamopoulos     STGMEDIUM medium;
3946f25b42aSGiannis Adamopoulos     if (SUCCEEDED(pDataObject->GetData(&fmt2, &medium)))
3956f25b42aSGiannis Adamopoulos     {
3966f25b42aSGiannis Adamopoulos         WCHAR wstrFirstFile[MAX_PATH];
3976f25b42aSGiannis Adamopoulos         if (DragQueryFileW((HDROP)medium.hGlobal, 0, wstrFirstFile, _countof(wstrFirstFile)))
3986f25b42aSGiannis Adamopoulos         {
399*aebaa14eSWhindmar Saksit             if (!PathIsSameDrive(wstrFirstFile, m_sPathTarget) && m_dwDefaultEffect != D_LINK)
4006f25b42aSGiannis Adamopoulos             {
4016f25b42aSGiannis Adamopoulos                 m_dwDefaultEffect = DROPEFFECT_COPY;
4026f25b42aSGiannis Adamopoulos             }
403*aebaa14eSWhindmar Saksit 
404*aebaa14eSWhindmar Saksit             if (!bAnyKeyMod && PathIsDriveRoot(wstrFirstFile) && (m_AllowedEffects & DROPEFFECT_LINK))
405*aebaa14eSWhindmar Saksit             {
406*aebaa14eSWhindmar Saksit                 m_dwDefaultEffect = DROPEFFECT_LINK; // Don't copy a drive by default
407*aebaa14eSWhindmar Saksit             }
4086f25b42aSGiannis Adamopoulos         }
4096f25b42aSGiannis Adamopoulos         ReleaseStgMedium(&medium);
4106f25b42aSGiannis Adamopoulos     }
4116d91269eSGiannis Adamopoulos 
412cd75a87cSKatayama Hirofumi MZ     if (!m_fAcceptFmt)
413*aebaa14eSWhindmar Saksit         m_AllowedEffects = DROPEFFECT_NONE;
414cd75a87cSKatayama Hirofumi MZ     else
415cd75a87cSKatayama Hirofumi MZ         *pdwEffect = m_dwDefaultEffect;
416*aebaa14eSWhindmar Saksit     *pdwEffect &= m_AllowedEffects;
417cd75a87cSKatayama Hirofumi MZ 
418c2c66affSColin Finck     return S_OK;
419c2c66affSColin Finck }
420c2c66affSColin Finck 
DragOver(DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)421c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::DragOver(DWORD dwKeyState, POINTL pt,
422c2c66affSColin Finck                                        DWORD *pdwEffect)
423c2c66affSColin Finck {
424c2c66affSColin Finck     TRACE("(%p)\n", this);
425c2c66affSColin Finck 
426c2c66affSColin Finck     if (!pdwEffect)
427c2c66affSColin Finck         return E_INVALIDARG;
428c2c66affSColin Finck 
4296d91269eSGiannis Adamopoulos     m_grfKeyState = dwKeyState;
4306d91269eSGiannis Adamopoulos 
431fd209faaSGiannis Adamopoulos     _QueryDrop(dwKeyState, pdwEffect);
432c2c66affSColin Finck 
433c2c66affSColin Finck     return S_OK;
434c2c66affSColin Finck }
435c2c66affSColin Finck 
DragLeave()436c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::DragLeave()
437c2c66affSColin Finck {
438c2c66affSColin Finck     TRACE("(%p)\n", this);
439c2c66affSColin Finck 
440fd209faaSGiannis Adamopoulos     m_fAcceptFmt = FALSE;
441c2c66affSColin Finck 
442c2c66affSColin Finck     return S_OK;
443c2c66affSColin Finck }
444c2c66affSColin Finck 
Drop(IDataObject * pDataObject,DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)445c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::Drop(IDataObject *pDataObject,
446c2c66affSColin Finck                                    DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
447c2c66affSColin Finck {
448c2c66affSColin Finck     TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
449c2c66affSColin Finck 
450c2c66affSColin Finck     if (!pdwEffect)
451c2c66affSColin Finck         return E_INVALIDARG;
452c2c66affSColin Finck 
4536d91269eSGiannis Adamopoulos     IUnknown_GetWindow(m_site, &m_hwndSite);
4546d91269eSGiannis Adamopoulos 
4556f25b42aSGiannis Adamopoulos     DWORD dwAvailableEffects = *pdwEffect;
4566f25b42aSGiannis Adamopoulos 
457fd209faaSGiannis Adamopoulos     _QueryDrop(dwKeyState, pdwEffect);
458c2c66affSColin Finck 
4596f25b42aSGiannis Adamopoulos     TRACE("pdwEffect: 0x%x, m_dwDefaultEffect: 0x%x, dwAvailableEffects: 0x%x\n", *pdwEffect, m_dwDefaultEffect, dwAvailableEffects);
4606f25b42aSGiannis Adamopoulos 
4616d91269eSGiannis Adamopoulos     if (m_grfKeyState & MK_RBUTTON)
4626d91269eSGiannis Adamopoulos     {
4636f25b42aSGiannis Adamopoulos         HRESULT hr = _GetEffectFromMenu(pDataObject, pt, pdwEffect, dwAvailableEffects);
4646d91269eSGiannis Adamopoulos         if (FAILED_UNEXPECTEDLY(hr) || hr == S_FALSE)
4656d91269eSGiannis Adamopoulos             return hr;
4666d91269eSGiannis Adamopoulos     }
4676d91269eSGiannis Adamopoulos 
4686d91269eSGiannis Adamopoulos     if (*pdwEffect == DROPEFFECT_MOVE && m_site)
4696d91269eSGiannis Adamopoulos     {
4706d91269eSGiannis Adamopoulos         CComPtr<IShellFolderView> psfv;
4716d91269eSGiannis Adamopoulos         HRESULT hr = IUnknown_QueryService(m_site, SID_IFolderView, IID_PPV_ARG(IShellFolderView, &psfv));
4726d91269eSGiannis Adamopoulos         if (SUCCEEDED(hr) && psfv->IsDropOnSource(this) == S_OK)
4736d91269eSGiannis Adamopoulos         {
4746d91269eSGiannis Adamopoulos             _RepositionItems(psfv, pDataObject, pt);
4756d91269eSGiannis Adamopoulos             return S_OK;
4766d91269eSGiannis Adamopoulos         }
4776d91269eSGiannis Adamopoulos     }
4786d91269eSGiannis Adamopoulos 
479c2c66affSColin Finck     BOOL fIsOpAsync = FALSE;
480c2c66affSColin Finck     CComPtr<IAsyncOperation> pAsyncOperation;
481c2c66affSColin Finck 
482c2c66affSColin Finck     if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
483c2c66affSColin Finck     {
484c2c66affSColin Finck         if (SUCCEEDED(pAsyncOperation->GetAsyncMode(&fIsOpAsync)) && fIsOpAsync)
485c2c66affSColin Finck         {
486c2c66affSColin Finck             _DoDropData *data = static_cast<_DoDropData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData)));
487c2c66affSColin Finck             data->This = this;
488c2c66affSColin Finck             // Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
489c2c66affSColin Finck             pDataObject->AddRef();
490c2c66affSColin Finck             pAsyncOperation->StartOperation(NULL);
491c2c66affSColin Finck             CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &data->pStream);
492c2c66affSColin Finck             this->AddRef();
493c2c66affSColin Finck             data->dwKeyState = dwKeyState;
494c2c66affSColin Finck             data->pt = pt;
495c2c66affSColin Finck             // Need to dereference as pdweffect gets freed.
496c2c66affSColin Finck             data->pdwEffect = *pdwEffect;
497*aebaa14eSWhindmar Saksit             SHCreateThread(CFSDropTarget::_DoDropThreadProc, data, CTF_COINIT | CTF_PROCESS_REF, NULL);
498c2c66affSColin Finck             return S_OK;
499c2c66affSColin Finck         }
500c2c66affSColin Finck     }
501c2c66affSColin Finck     return this->_DoDrop(pDataObject, dwKeyState, pt, pdwEffect);
502c2c66affSColin Finck }
503c2c66affSColin Finck 
5046d91269eSGiannis Adamopoulos HRESULT
5056d91269eSGiannis Adamopoulos WINAPI
SetSite(IUnknown * pUnkSite)5066d91269eSGiannis Adamopoulos CFSDropTarget::SetSite(IUnknown *pUnkSite)
5076d91269eSGiannis Adamopoulos {
5086d91269eSGiannis Adamopoulos     m_site = pUnkSite;
5096d91269eSGiannis Adamopoulos     return S_OK;
5106d91269eSGiannis Adamopoulos }
5116d91269eSGiannis Adamopoulos 
5126d91269eSGiannis Adamopoulos HRESULT
5136d91269eSGiannis Adamopoulos WINAPI
GetSite(REFIID riid,void ** ppvSite)5146d91269eSGiannis Adamopoulos CFSDropTarget::GetSite(REFIID riid, void **ppvSite)
5156d91269eSGiannis Adamopoulos {
5166d91269eSGiannis Adamopoulos     if (!m_site)
5176d91269eSGiannis Adamopoulos         return E_FAIL;
5186d91269eSGiannis Adamopoulos 
5196d91269eSGiannis Adamopoulos     return m_site->QueryInterface(riid, ppvSite);
5206d91269eSGiannis Adamopoulos }
5216d91269eSGiannis Adamopoulos 
_DoDrop(IDataObject * pDataObject,DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)522fd209faaSGiannis Adamopoulos HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
523c2c66affSColin Finck                                DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
524c2c66affSColin Finck {
525c2c66affSColin Finck     TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect);
526c2c66affSColin Finck     FORMATETC fmt;
527c2c66affSColin Finck     FORMATETC fmt2;
528c2c66affSColin Finck     STGMEDIUM medium;
529c2c66affSColin Finck 
530fd209faaSGiannis Adamopoulos     InitFormatEtc (fmt, m_cfShellIDList, TYMED_HGLOBAL);
531c2c66affSColin Finck     InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
532c2c66affSColin Finck 
533c2c66affSColin Finck     HRESULT hr;
534c2c66affSColin Finck     bool bCopy = TRUE;
535c2c66affSColin Finck     bool bLinking = FALSE;
536c2c66affSColin Finck 
537c2c66affSColin Finck     /* Figure out what drop operation we're doing */
538c2c66affSColin Finck     if (pdwEffect)
539c2c66affSColin Finck     {
540c2c66affSColin Finck         TRACE("Current drop effect flag %i\n", *pdwEffect);
541c2c66affSColin Finck         if ((*pdwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
542c2c66affSColin Finck             bCopy = FALSE;
543c2c66affSColin Finck         if ((*pdwEffect & DROPEFFECT_LINK) == DROPEFFECT_LINK)
544c2c66affSColin Finck             bLinking = TRUE;
545c2c66affSColin Finck     }
546c2c66affSColin Finck 
547c2c66affSColin Finck     if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
548c2c66affSColin Finck     {
549c2c66affSColin Finck         hr = pDataObject->GetData(&fmt, &medium);
5506f91b6c0SJoachim Henze         TRACE("CFSTR_SHELLIDLIST\n");
551a5a30fc2SKyle Katarn         if (FAILED(hr))
552a5a30fc2SKyle Katarn         {
553a5a30fc2SKyle Katarn             ERR("CFSTR_SHELLIDLIST failed\n");
554a5a30fc2SKyle Katarn         }
555c2c66affSColin Finck         /* lock the handle */
556c2c66affSColin Finck         LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
557c2c66affSColin Finck         if (!lpcida)
558c2c66affSColin Finck         {
559c2c66affSColin Finck             ReleaseStgMedium(&medium);
560c2c66affSColin Finck             return E_FAIL;
561c2c66affSColin Finck         }
562c2c66affSColin Finck 
563c2c66affSColin Finck         /* convert the data into pidl */
564c2c66affSColin Finck         LPITEMIDLIST pidl;
565c2c66affSColin Finck         LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
566c2c66affSColin Finck         if (!apidl)
567c2c66affSColin Finck         {
568c2c66affSColin Finck             ReleaseStgMedium(&medium);
569c2c66affSColin Finck             return E_FAIL;
570c2c66affSColin Finck         }
571c2c66affSColin Finck 
572c2c66affSColin Finck         CComPtr<IShellFolder> psfDesktop;
573c2c66affSColin Finck         CComPtr<IShellFolder> psfFrom = NULL;
574c2c66affSColin Finck 
575c2c66affSColin Finck         /* Grab the desktop shell folder */
576c2c66affSColin Finck         hr = SHGetDesktopFolder(&psfDesktop);
577c2c66affSColin Finck         if (FAILED(hr))
578c2c66affSColin Finck         {
579c2c66affSColin Finck             ERR("SHGetDesktopFolder failed\n");
580c2c66affSColin Finck             SHFree(pidl);
581c2c66affSColin Finck             _ILFreeaPidl(apidl, lpcida->cidl);
582c2c66affSColin Finck             ReleaseStgMedium(&medium);
583c2c66affSColin Finck             return E_FAIL;
584c2c66affSColin Finck         }
585c2c66affSColin Finck 
586c2c66affSColin Finck         /* Find source folder, this is where the clipboard data was copied from */
587c2c66affSColin Finck         if (_ILIsDesktop(pidl))
588c2c66affSColin Finck         {
589c2c66affSColin Finck             /* use desktop shell folder */
590c2c66affSColin Finck             psfFrom = psfDesktop;
591c2c66affSColin Finck         }
592c2c66affSColin Finck         else
593c2c66affSColin Finck         {
594c2c66affSColin Finck             hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
595c2c66affSColin Finck             if (FAILED(hr))
596c2c66affSColin Finck             {
597c2c66affSColin Finck                 ERR("no IShellFolder\n");
598c2c66affSColin Finck                 SHFree(pidl);
599c2c66affSColin Finck                 _ILFreeaPidl(apidl, lpcida->cidl);
600c2c66affSColin Finck                 ReleaseStgMedium(&medium);
601c2c66affSColin Finck                 return E_FAIL;
602c2c66affSColin Finck             }
603c2c66affSColin Finck         }
604c2c66affSColin Finck 
605c2c66affSColin Finck         if (bLinking)
606c2c66affSColin Finck         {
607fa95a96eSWhindmar Saksit             WCHAR wszNewLnk[MAX_PATH];
608c2c66affSColin Finck 
6090f5fb478SKatayama Hirofumi MZ             TRACE("target path = %s\n", debugstr_w(m_sPathTarget));
610c2c66affSColin Finck 
611c2c66affSColin Finck             /* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
612c2c66affSColin Finck             for (UINT i = 0; i < lpcida->cidl; i++)
613c2c66affSColin Finck             {
614cca9acfaSWhindmar Saksit                 SFGAOF att = SHGetAttributes(psfFrom, apidl[i], SFGAO_FOLDER | SFGAO_STREAM | SFGAO_FILESYSTEM);
615fa95a96eSWhindmar Saksit                 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlFull;
616fa95a96eSWhindmar Saksit                 hr = SHILCombine(pidl, apidl[i], &pidlFull);
617c2c66affSColin Finck 
618fa95a96eSWhindmar Saksit                 WCHAR targetName[MAX_PATH];
6190f5fb478SKatayama Hirofumi MZ                 if (SUCCEEDED(hr))
620cca9acfaSWhindmar Saksit                 {
621cca9acfaSWhindmar Saksit                     // If the target is a file, we use SHGDN_FORPARSING because "NeverShowExt" will hide the ".lnk" extension.
622cca9acfaSWhindmar Saksit                     // If the target is a virtual item, we ask for the friendly name because SHGDN_FORPARSING will return a GUID.
623cca9acfaSWhindmar Saksit                     BOOL UseParsing = (att & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) == SFGAO_FILESYSTEM;
624cca9acfaSWhindmar Saksit                     DWORD ShgdnFor = UseParsing ? SHGDN_FORPARSING : SHGDN_FOREDITING;
625cca9acfaSWhindmar Saksit                     hr = Shell_DisplayNameOf(psfFrom, apidl[i], ShgdnFor | SHGDN_INFOLDER, targetName, _countof(targetName));
626cca9acfaSWhindmar Saksit                 }
627fa95a96eSWhindmar Saksit                 if (FAILED_UNEXPECTEDLY(hr))
6280f5fb478SKatayama Hirofumi MZ                 {
629fa95a96eSWhindmar Saksit                     SHELL_ErrorBox(m_hwndSite, hr);
630fa95a96eSWhindmar Saksit                     break;
6310f5fb478SKatayama Hirofumi MZ                 }
632fa95a96eSWhindmar Saksit                 SHELL_StripIllegalFsNameCharacters(targetName);
6330f5fb478SKatayama Hirofumi MZ 
634fa95a96eSWhindmar Saksit                 WCHAR wszCombined[MAX_PATH + _countof(targetName)];
635fa95a96eSWhindmar Saksit                 PathCombineW(wszCombined, m_sPathTarget, targetName);
6360f5fb478SKatayama Hirofumi MZ 
6370f5fb478SKatayama Hirofumi MZ                 // Check to see if the source is a link
6380f5fb478SKatayama Hirofumi MZ                 BOOL fSourceIsLink = FALSE;
639e4930be4STimo Kreuzer                 if (!_wcsicmp(PathFindExtensionW(targetName), L".lnk") && (att & (SFGAO_FOLDER | SFGAO_STREAM)) != SFGAO_FOLDER)
6400f5fb478SKatayama Hirofumi MZ                 {
6410f5fb478SKatayama Hirofumi MZ                     fSourceIsLink = TRUE;
6420f5fb478SKatayama Hirofumi MZ                     PathRemoveExtensionW(wszCombined);
6430f5fb478SKatayama Hirofumi MZ                 }
6440f5fb478SKatayama Hirofumi MZ 
6450f5fb478SKatayama Hirofumi MZ                 // Create a pathname to save the new link.
646fa95a96eSWhindmar Saksit                 _GetUniqueFileName(wszCombined, L".lnk", wszNewLnk, TRUE);
6470f5fb478SKatayama Hirofumi MZ 
648c2c66affSColin Finck                 CComPtr<IPersistFile> ppf;
6490f5fb478SKatayama Hirofumi MZ                 if (fSourceIsLink)
650c2c66affSColin Finck                 {
651fa95a96eSWhindmar Saksit                     PWSTR pwszTargetFull;
652fa95a96eSWhindmar Saksit                     hr = SHGetNameFromIDList(pidlFull, SIGDN_DESKTOPABSOLUTEPARSING, &pwszTargetFull);
653fa95a96eSWhindmar Saksit                     if (!FAILED_UNEXPECTEDLY(hr))
654fa95a96eSWhindmar Saksit                     {
655fa95a96eSWhindmar Saksit                         hr = IShellLink_ConstructFromPath(pwszTargetFull, IID_PPV_ARG(IPersistFile, &ppf));
656fa95a96eSWhindmar Saksit                         FAILED_UNEXPECTEDLY(hr);
657fa95a96eSWhindmar Saksit                         SHFree(pwszTargetFull);
658fa95a96eSWhindmar Saksit                     }
659c2c66affSColin Finck                 }
660c2c66affSColin Finck                 else
661c2c66affSColin Finck                 {
662c2c66affSColin Finck                     CComPtr<IShellLinkW> pLink;
663c2c66affSColin Finck                     hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
664fa95a96eSWhindmar Saksit                     if (!FAILED_UNEXPECTEDLY(hr))
665fa95a96eSWhindmar Saksit                     {
666fa95a96eSWhindmar Saksit                         hr = pLink->SetIDList(pidlFull);
667fa95a96eSWhindmar Saksit                         if (!FAILED_UNEXPECTEDLY(hr))
668c2c66affSColin Finck                             hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
669fa95a96eSWhindmar Saksit 
670fa95a96eSWhindmar Saksit                         PWSTR pwszPath, pSep;
671fa95a96eSWhindmar Saksit                         if ((att & SFGAO_FILESYSTEM) && SUCCEEDED(SHGetNameFromIDList(pidlFull, SIGDN_FILESYSPATH, &pwszPath)))
672fa95a96eSWhindmar Saksit                         {
673fa95a96eSWhindmar Saksit                             if ((pSep = PathFindFileNameW(pwszPath)) > pwszPath)
674fa95a96eSWhindmar Saksit                             {
675fa95a96eSWhindmar Saksit                                 pSep[-1] = UNICODE_NULL;
676fa95a96eSWhindmar Saksit                                 pLink->SetWorkingDirectory(pwszPath);
677fa95a96eSWhindmar Saksit                             }
678fa95a96eSWhindmar Saksit                             SHFree(pwszPath);
679fa95a96eSWhindmar Saksit                         }
680fa95a96eSWhindmar Saksit                     }
681fa95a96eSWhindmar Saksit                 }
682fa95a96eSWhindmar Saksit                 if (SUCCEEDED(hr))
683fa95a96eSWhindmar Saksit                     hr = ppf->Save(wszNewLnk, !fSourceIsLink);
6840f5fb478SKatayama Hirofumi MZ                 if (FAILED_UNEXPECTEDLY(hr))
685fa95a96eSWhindmar Saksit                 {
686fa95a96eSWhindmar Saksit                     SHELL_ErrorBox(m_hwndSite, hr);
6870f5fb478SKatayama Hirofumi MZ                     break;
6880f5fb478SKatayama Hirofumi MZ                 }
689fa95a96eSWhindmar Saksit                 SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszNewLnk, NULL);
690c2c66affSColin Finck             }
691c2c66affSColin Finck         }
692c2c66affSColin Finck         else
693c2c66affSColin Finck         {
694fd209faaSGiannis Adamopoulos             hr = _CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
695c2c66affSColin Finck         }
696c2c66affSColin Finck 
697c2c66affSColin Finck         SHFree(pidl);
698c2c66affSColin Finck         _ILFreeaPidl(apidl, lpcida->cidl);
699c2c66affSColin Finck         ReleaseStgMedium(&medium);
700c2c66affSColin Finck     }
701c2c66affSColin Finck     else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
702c2c66affSColin Finck     {
703c2c66affSColin Finck         FORMATETC fmt2;
704c2c66affSColin Finck         InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
705c2c66affSColin Finck         if (SUCCEEDED(pDataObject->GetData(&fmt2, &medium)) /* && SUCCEEDED(pDataObject->GetData(&fmt2, &medium))*/)
706c2c66affSColin Finck         {
707c2c66affSColin Finck             WCHAR wszTargetPath[MAX_PATH + 1];
708c2c66affSColin Finck             LPWSTR pszSrcList;
709c2c66affSColin Finck 
710fd209faaSGiannis Adamopoulos             wcscpy(wszTargetPath, m_sPathTarget);
711c2c66affSColin Finck             //Double NULL terminate.
712c2c66affSColin Finck             wszTargetPath[wcslen(wszTargetPath) + 1] = '\0';
713c2c66affSColin Finck 
714c2c66affSColin Finck             LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal);
715c2c66affSColin Finck             if (!lpdf)
716c2c66affSColin Finck             {
717c2c66affSColin Finck                 ERR("Error locking global\n");
718c2c66affSColin Finck                 return E_FAIL;
719c2c66affSColin Finck             }
720c2c66affSColin Finck             pszSrcList = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);
721c2c66affSColin Finck             ERR("Source file (just the first) = %s, target path = %s, bCopy: %d\n", debugstr_w(pszSrcList), debugstr_w(wszTargetPath), bCopy);
722c2c66affSColin Finck 
723c2c66affSColin Finck             SHFILEOPSTRUCTW op;
724c2c66affSColin Finck             ZeroMemory(&op, sizeof(op));
725c2c66affSColin Finck             op.pFrom = pszSrcList;
726c2c66affSColin Finck             op.pTo = wszTargetPath;
7276d91269eSGiannis Adamopoulos             op.hwnd = m_hwndSite;
728c2c66affSColin Finck             op.wFunc = bCopy ? FO_COPY : FO_MOVE;
729c2c66affSColin Finck             op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
730a5a30fc2SKyle Katarn             int res = SHFileOperationW(&op);
731a5a30fc2SKyle Katarn             if (res)
732a5a30fc2SKyle Katarn             {
733a5a30fc2SKyle Katarn                 ERR("SHFileOperationW failed with 0x%x\n", res);
734a5a30fc2SKyle Katarn                 hr = E_FAIL;
735a5a30fc2SKyle Katarn             }
736a5a30fc2SKyle Katarn 
737c2c66affSColin Finck             return hr;
738c2c66affSColin Finck         }
739c2c66affSColin Finck         ERR("Error calling GetData\n");
740c2c66affSColin Finck         hr = E_FAIL;
741c2c66affSColin Finck     }
742c2c66affSColin Finck     else
743c2c66affSColin Finck     {
7446f91b6c0SJoachim Henze         ERR("No viable drop format\n");
745c2c66affSColin Finck         hr = E_FAIL;
746c2c66affSColin Finck     }
747c2c66affSColin Finck     return hr;
748c2c66affSColin Finck }
749c2c66affSColin Finck 
_DoDropThreadProc(LPVOID lpParameter)750c2c66affSColin Finck DWORD WINAPI CFSDropTarget::_DoDropThreadProc(LPVOID lpParameter)
751c2c66affSColin Finck {
752c2c66affSColin Finck     _DoDropData *data = static_cast<_DoDropData*>(lpParameter);
753c2c66affSColin Finck     CComPtr<IDataObject> pDataObject;
754c2c66affSColin Finck     HRESULT hr = CoGetInterfaceAndReleaseStream (data->pStream, IID_PPV_ARG(IDataObject, &pDataObject));
755c2c66affSColin Finck 
756c2c66affSColin Finck     if (SUCCEEDED(hr))
757c2c66affSColin Finck     {
758c2c66affSColin Finck         CComPtr<IAsyncOperation> pAsyncOperation;
759c2c66affSColin Finck         hr = data->This->_DoDrop(pDataObject, data->dwKeyState, data->pt, &data->pdwEffect);
760c2c66affSColin Finck         if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
761c2c66affSColin Finck         {
762c2c66affSColin Finck             pAsyncOperation->EndOperation(hr, NULL, data->pdwEffect);
763c2c66affSColin Finck         }
764c2c66affSColin Finck     }
765c2c66affSColin Finck     //Release the CFSFolder and data object holds in the copying thread.
766c2c66affSColin Finck     data->This->Release();
767c2c66affSColin Finck     //Release the parameter from the heap.
768c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, data);
769c2c66affSColin Finck     return 0;
770c2c66affSColin Finck }
771c2c66affSColin Finck 
CFSDropTarget_CreateInstance(LPWSTR sPathTarget,REFIID riid,LPVOID * ppvOut)772c2c66affSColin Finck HRESULT CFSDropTarget_CreateInstance(LPWSTR sPathTarget, REFIID riid, LPVOID * ppvOut)
773c2c66affSColin Finck {
774c2c66affSColin Finck     return ShellObjectCreatorInit<CFSDropTarget>(sPathTarget, riid, ppvOut);
775c2c66affSColin Finck }
776