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