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 
27fa95a96eSWhindmar Saksit static void SHELL_StripIllegalFsNameCharacters(_Inout_ LPWSTR Buf)
28fa95a96eSWhindmar Saksit {
29fa95a96eSWhindmar Saksit     for (LPWSTR src = Buf, dst = src;;)
30fa95a96eSWhindmar Saksit     {
31fa95a96eSWhindmar Saksit         *dst = *src;
32fa95a96eSWhindmar Saksit         if (!*dst)
33fa95a96eSWhindmar Saksit             break;
34fa95a96eSWhindmar Saksit         else if (wcschr(INVALID_FILETITLE_CHARACTERSW, *dst))
35fa95a96eSWhindmar Saksit             src = CharNextW(src);
36fa95a96eSWhindmar Saksit         else
37fa95a96eSWhindmar Saksit             ++src, ++dst;
38fa95a96eSWhindmar Saksit     }
39fa95a96eSWhindmar Saksit }
40fa95a96eSWhindmar Saksit 
41fa95a96eSWhindmar Saksit static HRESULT
42fa95a96eSWhindmar Saksit SHELL_LimitDropEffectToItemAttributes(_In_ IDataObject *pDataObject, _Inout_ PDWORD pdwEffect)
43fa95a96eSWhindmar Saksit {
44fa95a96eSWhindmar Saksit     DWORD att = *pdwEffect & (SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK); // DROPEFFECT maps perfectly to these SFGAO bits
45fa95a96eSWhindmar Saksit     HRESULT hr = SHGetAttributesFromDataObject(pDataObject, att, &att, NULL);
46fa95a96eSWhindmar Saksit     if (FAILED(hr))
47fa95a96eSWhindmar Saksit         return S_FALSE;
48fa95a96eSWhindmar Saksit     *pdwEffect &= ~(SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK) | att;
49fa95a96eSWhindmar Saksit     return hr;
50fa95a96eSWhindmar Saksit }
51fa95a96eSWhindmar Saksit 
52fa95a96eSWhindmar Saksit static void GetDefaultCopyMoveEffect()
53fa95a96eSWhindmar Saksit {
54fa95a96eSWhindmar Saksit     // FIXME: When the source is on a different volume than the target, change default from move to copy
55fa95a96eSWhindmar Saksit }
56c2c66affSColin Finck 
57c2c66affSColin Finck /****************************************************************************
58fd209faaSGiannis Adamopoulos  * CFSDropTarget::_CopyItems
59c2c66affSColin Finck  *
601273bbe4SHuw Campbell  * copies or moves items to this folder
61c2c66affSColin Finck  */
62fd209faaSGiannis Adamopoulos HRESULT CFSDropTarget::_CopyItems(IShellFolder * pSFFrom, UINT cidl,
63c2c66affSColin Finck                                   LPCITEMIDLIST * apidl, BOOL bCopy)
64c2c66affSColin Finck {
651273bbe4SHuw Campbell     HRESULT ret;
661273bbe4SHuw Campbell     WCHAR wszDstPath[MAX_PATH + 1] = {0};
671273bbe4SHuw Campbell     PWCHAR pwszSrcPathsList = (PWCHAR) HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) * cidl + 1);
681273bbe4SHuw Campbell     if (!pwszSrcPathsList)
69c2c66affSColin Finck         return E_OUTOFMEMORY;
70c2c66affSColin Finck 
711273bbe4SHuw Campbell     PWCHAR pwszListPos = pwszSrcPathsList;
721273bbe4SHuw Campbell     STRRET strretFrom;
731273bbe4SHuw Campbell     SHFILEOPSTRUCTW fop;
74520577a8SKatayama Hirofumi MZ     BOOL bRenameOnCollision = FALSE;
75c2c66affSColin Finck 
761273bbe4SHuw Campbell     /* Build a double null terminated list of C strings from source paths */
771273bbe4SHuw Campbell     for (UINT i = 0; i < cidl; i++)
78a5a30fc2SKyle Katarn     {
791273bbe4SHuw Campbell         ret = pSFFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strretFrom);
801273bbe4SHuw Campbell         if (FAILED(ret))
811273bbe4SHuw Campbell             goto cleanup;
821273bbe4SHuw Campbell 
831273bbe4SHuw Campbell         ret = StrRetToBufW(&strretFrom, NULL, pwszListPos, MAX_PATH);
841273bbe4SHuw Campbell         if (FAILED(ret))
851273bbe4SHuw Campbell             goto cleanup;
861273bbe4SHuw Campbell 
871273bbe4SHuw Campbell         pwszListPos += lstrlenW(pwszListPos) + 1;
88a5a30fc2SKyle Katarn     }
891273bbe4SHuw Campbell     /* Append the final null. */
901273bbe4SHuw Campbell     *pwszListPos = L'\0';
911273bbe4SHuw Campbell 
921273bbe4SHuw Campbell     /* Build a double null terminated target (this path) */
931273bbe4SHuw Campbell     ret = StringCchCopyW(wszDstPath, MAX_PATH, m_sPathTarget);
941273bbe4SHuw Campbell     if (FAILED(ret))
951273bbe4SHuw Campbell         goto cleanup;
961273bbe4SHuw Campbell 
97520577a8SKatayama Hirofumi MZ     wszDstPath[lstrlenW(wszDstPath) + 1] = UNICODE_NULL;
98520577a8SKatayama Hirofumi MZ 
99520577a8SKatayama Hirofumi MZ     /* Set bRenameOnCollision to TRUE if necesssary */
100520577a8SKatayama Hirofumi MZ     if (bCopy)
101520577a8SKatayama Hirofumi MZ     {
102520577a8SKatayama Hirofumi MZ         WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
103520577a8SKatayama Hirofumi MZ         GetFullPathNameW(pwszSrcPathsList, _countof(szPath1), szPath1, NULL);
104520577a8SKatayama Hirofumi MZ         GetFullPathNameW(wszDstPath, _countof(szPath2), szPath2, NULL);
105520577a8SKatayama Hirofumi MZ         PathRemoveFileSpecW(szPath1);
106520577a8SKatayama Hirofumi MZ         if (_wcsicmp(szPath1, szPath2) == 0)
107520577a8SKatayama Hirofumi MZ             bRenameOnCollision = TRUE;
108520577a8SKatayama Hirofumi MZ     }
1091273bbe4SHuw Campbell 
1101273bbe4SHuw Campbell     ZeroMemory(&fop, sizeof(fop));
1111273bbe4SHuw Campbell     fop.hwnd = m_hwndSite;
1121273bbe4SHuw Campbell     fop.wFunc = bCopy ? FO_COPY : FO_MOVE;
1131273bbe4SHuw Campbell     fop.pFrom = pwszSrcPathsList;
1141273bbe4SHuw Campbell     fop.pTo = wszDstPath;
1151273bbe4SHuw Campbell     fop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
116520577a8SKatayama Hirofumi MZ     if (bRenameOnCollision)
117520577a8SKatayama Hirofumi MZ         fop.fFlags |= FOF_RENAMEONCOLLISION;
118520577a8SKatayama Hirofumi MZ 
1191273bbe4SHuw Campbell     ret = S_OK;
1201273bbe4SHuw Campbell 
1211273bbe4SHuw Campbell     if (SHFileOperationW(&fop))
1221273bbe4SHuw Campbell     {
1231273bbe4SHuw Campbell         ERR("SHFileOperationW failed\n");
1241273bbe4SHuw Campbell         ret = E_FAIL;
1251273bbe4SHuw Campbell     }
1261273bbe4SHuw Campbell 
1271273bbe4SHuw Campbell cleanup:
1281273bbe4SHuw Campbell     HeapFree(GetProcessHeap(), 0, pwszSrcPathsList);
1291273bbe4SHuw Campbell     return ret;
130c2c66affSColin Finck }
131c2c66affSColin Finck 
132c2c66affSColin Finck CFSDropTarget::CFSDropTarget():
133fd209faaSGiannis Adamopoulos     m_cfShellIDList(0),
134fd209faaSGiannis Adamopoulos     m_fAcceptFmt(FALSE),
135fd209faaSGiannis Adamopoulos     m_sPathTarget(NULL),
1366d91269eSGiannis Adamopoulos     m_hwndSite(NULL),
1376d91269eSGiannis Adamopoulos     m_grfKeyState(0)
138c2c66affSColin Finck {
139c2c66affSColin Finck }
140c2c66affSColin Finck 
141fd209faaSGiannis Adamopoulos HRESULT CFSDropTarget::Initialize(LPWSTR PathTarget)
142c2c66affSColin Finck {
143c2c66affSColin Finck     if (!PathTarget)
144c2c66affSColin Finck         return E_UNEXPECTED;
145c2c66affSColin Finck 
146fd209faaSGiannis Adamopoulos     m_cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
147fd209faaSGiannis Adamopoulos     if (!m_cfShellIDList)
148c2c66affSColin Finck         return E_FAIL;
149c2c66affSColin Finck 
150fd209faaSGiannis Adamopoulos     m_sPathTarget = (WCHAR *)SHAlloc((wcslen(PathTarget) + 1) * sizeof(WCHAR));
151fd209faaSGiannis Adamopoulos     if (!m_sPathTarget)
152c2c66affSColin Finck         return E_OUTOFMEMORY;
153c2c66affSColin Finck 
154fd209faaSGiannis Adamopoulos     wcscpy(m_sPathTarget, PathTarget);
155c2c66affSColin Finck 
156c2c66affSColin Finck     return S_OK;
157c2c66affSColin Finck }
158c2c66affSColin Finck 
159c2c66affSColin Finck CFSDropTarget::~CFSDropTarget()
160c2c66affSColin Finck {
161fd209faaSGiannis Adamopoulos     SHFree(m_sPathTarget);
162c2c66affSColin Finck }
163c2c66affSColin Finck 
164c2c66affSColin Finck BOOL
1650f5fb478SKatayama Hirofumi MZ CFSDropTarget::_GetUniqueFileName(LPCWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
166c2c66affSColin Finck {
167c2c66affSColin Finck     WCHAR wszLink[40];
168c2c66affSColin Finck 
169c2c66affSColin Finck     if (!bShortcut)
170c2c66affSColin Finck     {
171c2c66affSColin Finck         if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
172c2c66affSColin Finck             wszLink[0] = L'\0';
173c2c66affSColin Finck     }
174c2c66affSColin Finck 
175c2c66affSColin Finck     if (!bShortcut)
176c2c66affSColin Finck         swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
177c2c66affSColin Finck     else
178c2c66affSColin Finck         swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
179c2c66affSColin Finck 
180c2c66affSColin Finck     for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
181c2c66affSColin Finck     {
182c2c66affSColin Finck         if (!bShortcut)
183c2c66affSColin Finck             swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
184c2c66affSColin Finck         else
185c2c66affSColin Finck             swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
186c2c66affSColin Finck     }
187c2c66affSColin Finck 
188c2c66affSColin Finck     return TRUE;
189c2c66affSColin Finck }
190c2c66affSColin Finck 
191c2c66affSColin Finck /****************************************************************************
192c2c66affSColin Finck  * IDropTarget implementation
193c2c66affSColin Finck  */
194fd209faaSGiannis Adamopoulos BOOL CFSDropTarget::_QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
195c2c66affSColin Finck {
196c2c66affSColin Finck     /* TODO Windows does different drop effects if dragging across drives.
197c2c66affSColin Finck     i.e., it will copy instead of move if the directories are on different disks. */
198fa95a96eSWhindmar Saksit     GetDefaultCopyMoveEffect();
199c2c66affSColin Finck 
2006f25b42aSGiannis Adamopoulos     DWORD dwEffect = m_dwDefaultEffect;
201c2c66affSColin Finck 
202c2c66affSColin Finck     *pdwEffect = DROPEFFECT_NONE;
203c2c66affSColin Finck 
204fd209faaSGiannis Adamopoulos     if (m_fAcceptFmt) { /* Does our interpretation of the keystate ... */
205c2c66affSColin Finck         *pdwEffect = KeyStateToDropEffect (dwKeyState);
206c2c66affSColin Finck 
207c2c66affSColin Finck         if (*pdwEffect == DROPEFFECT_NONE)
208c2c66affSColin Finck             *pdwEffect = dwEffect;
209c2c66affSColin Finck 
210c2c66affSColin Finck         /* ... matches the desired effect ? */
211c2c66affSColin Finck         if (dwEffect & *pdwEffect) {
212c2c66affSColin Finck             return TRUE;
213c2c66affSColin Finck         }
214c2c66affSColin Finck     }
215c2c66affSColin Finck     return FALSE;
216c2c66affSColin Finck }
217c2c66affSColin Finck 
2186f25b42aSGiannis Adamopoulos HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, DWORD *pdwEffect, DWORD dwAvailableEffects)
2196d91269eSGiannis Adamopoulos {
2206d91269eSGiannis Adamopoulos     HMENU hmenu = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(IDM_DRAGFILE));
2216d91269eSGiannis Adamopoulos     if (!hmenu)
2226d91269eSGiannis Adamopoulos         return E_OUTOFMEMORY;
2236d91269eSGiannis Adamopoulos 
2246f25b42aSGiannis Adamopoulos     HMENU hpopupmenu = GetSubMenu(hmenu, 0);
2256f25b42aSGiannis Adamopoulos 
226fa95a96eSWhindmar Saksit     SHELL_LimitDropEffectToItemAttributes(pDataObject, &dwAvailableEffects);
2276f25b42aSGiannis Adamopoulos     if ((dwAvailableEffects & DROPEFFECT_COPY) == 0)
2286f25b42aSGiannis Adamopoulos         DeleteMenu(hpopupmenu, IDM_COPYHERE, MF_BYCOMMAND);
229fa95a96eSWhindmar Saksit     if ((dwAvailableEffects & DROPEFFECT_MOVE) == 0)
2306f25b42aSGiannis Adamopoulos         DeleteMenu(hpopupmenu, IDM_MOVEHERE, MF_BYCOMMAND);
231fa95a96eSWhindmar Saksit     if ((dwAvailableEffects & DROPEFFECT_LINK) == 0 && (dwAvailableEffects & (DROPEFFECT_COPY | DROPEFFECT_MOVE)))
2326f25b42aSGiannis Adamopoulos         DeleteMenu(hpopupmenu, IDM_LINKHERE, MF_BYCOMMAND);
2336f25b42aSGiannis Adamopoulos 
234fa95a96eSWhindmar Saksit     GetDefaultCopyMoveEffect();
235fa95a96eSWhindmar Saksit     if (*pdwEffect & dwAvailableEffects & DROPEFFECT_COPY)
2366f25b42aSGiannis Adamopoulos         SetMenuDefaultItem(hpopupmenu, IDM_COPYHERE, FALSE);
237fa95a96eSWhindmar Saksit     else if (*pdwEffect & dwAvailableEffects & DROPEFFECT_MOVE)
2386f25b42aSGiannis Adamopoulos         SetMenuDefaultItem(hpopupmenu, IDM_MOVEHERE, FALSE);
239fa95a96eSWhindmar Saksit     else if (dwAvailableEffects & DROPEFFECT_LINK)
2406f25b42aSGiannis Adamopoulos         SetMenuDefaultItem(hpopupmenu, IDM_LINKHERE, FALSE);
2416f25b42aSGiannis Adamopoulos 
2426d91269eSGiannis Adamopoulos     /* FIXME: We need to support shell extensions here */
2436d91269eSGiannis Adamopoulos 
2441d55f459SGiannis Adamopoulos     /* We shouldn't use the site window here because the menu should work even when we don't have a site */
2451d55f459SGiannis Adamopoulos     HWND hwndDummy = CreateWindowEx(0,
2461d55f459SGiannis Adamopoulos                               WC_STATIC,
2471d55f459SGiannis Adamopoulos                               NULL,
2481d55f459SGiannis Adamopoulos                               WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
2491d55f459SGiannis Adamopoulos                               pt.x,
2501d55f459SGiannis Adamopoulos                               pt.y,
2511d55f459SGiannis Adamopoulos                               1,
2521d55f459SGiannis Adamopoulos                               1,
2531d55f459SGiannis Adamopoulos                               NULL,
2541d55f459SGiannis Adamopoulos                               NULL,
2551d55f459SGiannis Adamopoulos                               NULL,
2561d55f459SGiannis Adamopoulos                               NULL);
2571d55f459SGiannis Adamopoulos 
258fa95a96eSWhindmar Saksit     SetForegroundWindow(hwndDummy); // Required for aborting by pressing Esc when dragging from Explorer to desktop
2596f25b42aSGiannis Adamopoulos     UINT uCommand = TrackPopupMenu(hpopupmenu,
2606f25b42aSGiannis Adamopoulos                                    TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY,
2611d55f459SGiannis Adamopoulos                                    pt.x, pt.y, 0, hwndDummy, NULL);
2621d55f459SGiannis Adamopoulos 
2631d55f459SGiannis Adamopoulos     DestroyWindow(hwndDummy);
2641d55f459SGiannis Adamopoulos 
2656d91269eSGiannis Adamopoulos     if (uCommand == 0)
2666d91269eSGiannis Adamopoulos         return S_FALSE;
2676d91269eSGiannis Adamopoulos     else if (uCommand == IDM_COPYHERE)
2686d91269eSGiannis Adamopoulos         *pdwEffect = DROPEFFECT_COPY;
2696d91269eSGiannis Adamopoulos     else if (uCommand == IDM_MOVEHERE)
2706d91269eSGiannis Adamopoulos         *pdwEffect = DROPEFFECT_MOVE;
2716d91269eSGiannis Adamopoulos     else if (uCommand == IDM_LINKHERE)
2726d91269eSGiannis Adamopoulos         *pdwEffect = DROPEFFECT_LINK;
2736d91269eSGiannis Adamopoulos 
2746d91269eSGiannis Adamopoulos     return S_OK;
2756d91269eSGiannis Adamopoulos }
2766d91269eSGiannis Adamopoulos 
2776d91269eSGiannis Adamopoulos HRESULT CFSDropTarget::_RepositionItems(IShellFolderView *psfv, IDataObject *pdtobj, POINTL pt)
2786d91269eSGiannis Adamopoulos {
2796d91269eSGiannis Adamopoulos     CComPtr<IFolderView> pfv;
2806d91269eSGiannis Adamopoulos     POINT ptDrag;
2816d91269eSGiannis Adamopoulos     HRESULT hr = psfv->QueryInterface(IID_PPV_ARG(IFolderView, &pfv));
2826d91269eSGiannis Adamopoulos     if (FAILED_UNEXPECTEDLY(hr))
2836d91269eSGiannis Adamopoulos         return hr;
2846d91269eSGiannis Adamopoulos 
2856d91269eSGiannis Adamopoulos     hr = psfv->GetDragPoint(&ptDrag);
2866d91269eSGiannis Adamopoulos     if (FAILED_UNEXPECTEDLY(hr))
2876d91269eSGiannis Adamopoulos         return hr;
2886d91269eSGiannis Adamopoulos 
2896d91269eSGiannis Adamopoulos     PIDLIST_ABSOLUTE pidlFolder;
2906d91269eSGiannis Adamopoulos     PUITEMID_CHILD *apidl;
2916d91269eSGiannis Adamopoulos     UINT cidl;
2926d91269eSGiannis Adamopoulos     hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
2936d91269eSGiannis Adamopoulos     if (FAILED_UNEXPECTEDLY(hr))
2946d91269eSGiannis Adamopoulos         return hr;
2956d91269eSGiannis Adamopoulos 
2966d91269eSGiannis Adamopoulos     CComHeapPtr<POINT> apt;
2976d91269eSGiannis Adamopoulos     if (!apt.Allocate(cidl))
2986d91269eSGiannis Adamopoulos     {
2996d91269eSGiannis Adamopoulos         SHFree(pidlFolder);
3006d91269eSGiannis Adamopoulos         _ILFreeaPidl(apidl, cidl);
3016d91269eSGiannis Adamopoulos         return E_OUTOFMEMORY;
3026d91269eSGiannis Adamopoulos     }
3036d91269eSGiannis Adamopoulos 
3046d91269eSGiannis Adamopoulos     for (UINT i = 0; i<cidl; i++)
3056d91269eSGiannis Adamopoulos     {
3066d91269eSGiannis Adamopoulos         pfv->GetItemPosition(apidl[i], &apt[i]);
3076d91269eSGiannis Adamopoulos         apt[i].x += pt.x - ptDrag.x;
3086d91269eSGiannis Adamopoulos         apt[i].y += pt.y - ptDrag.y;
3096d91269eSGiannis Adamopoulos     }
3106d91269eSGiannis Adamopoulos 
3116d91269eSGiannis Adamopoulos     pfv->SelectAndPositionItems(cidl, apidl, apt, SVSI_SELECT);
3126d91269eSGiannis Adamopoulos 
3136d91269eSGiannis Adamopoulos     SHFree(pidlFolder);
3146d91269eSGiannis Adamopoulos     _ILFreeaPidl(apidl, cidl);
3156d91269eSGiannis Adamopoulos     return S_OK;
3166d91269eSGiannis Adamopoulos }
3176d91269eSGiannis Adamopoulos 
318c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject *pDataObject,
319c2c66affSColin Finck                                         DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
320c2c66affSColin Finck {
321c2c66affSColin Finck     TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
3228f129932SKatayama Hirofumi MZ 
3238f129932SKatayama Hirofumi MZ     if (*pdwEffect == DROPEFFECT_NONE)
3248f129932SKatayama Hirofumi MZ         return S_OK;
3258f129932SKatayama Hirofumi MZ 
326c2c66affSColin Finck     FORMATETC fmt;
327c2c66affSColin Finck     FORMATETC fmt2;
328fd209faaSGiannis Adamopoulos     m_fAcceptFmt = FALSE;
329c2c66affSColin Finck 
330fd209faaSGiannis Adamopoulos     InitFormatEtc (fmt, m_cfShellIDList, TYMED_HGLOBAL);
331c2c66affSColin Finck     InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
332c2c66affSColin Finck 
333c2c66affSColin Finck     if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
334fd209faaSGiannis Adamopoulos         m_fAcceptFmt = TRUE;
335c2c66affSColin Finck     else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
336fd209faaSGiannis Adamopoulos         m_fAcceptFmt = TRUE;
337c2c66affSColin Finck 
3386d91269eSGiannis Adamopoulos     m_grfKeyState = dwKeyState;
339cd75a87cSKatayama Hirofumi MZ 
340cd75a87cSKatayama Hirofumi MZ #define D_NONE DROPEFFECT_NONE
341cd75a87cSKatayama Hirofumi MZ #define D_COPY DROPEFFECT_COPY
342cd75a87cSKatayama Hirofumi MZ #define D_MOVE DROPEFFECT_MOVE
343cd75a87cSKatayama Hirofumi MZ #define D_LINK DROPEFFECT_LINK
344cd75a87cSKatayama Hirofumi MZ     m_dwDefaultEffect = *pdwEffect;
345cd75a87cSKatayama Hirofumi MZ     switch (*pdwEffect & (D_COPY | D_MOVE | D_LINK))
346cd75a87cSKatayama Hirofumi MZ     {
347cd75a87cSKatayama Hirofumi MZ         case D_COPY | D_MOVE:
348cd75a87cSKatayama Hirofumi MZ             if (dwKeyState & MK_CONTROL)
349cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_COPY;
350cd75a87cSKatayama Hirofumi MZ             else
351cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_MOVE;
352cd75a87cSKatayama Hirofumi MZ             break;
353cd75a87cSKatayama Hirofumi MZ         case D_COPY | D_MOVE | D_LINK:
354cd75a87cSKatayama Hirofumi MZ             if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == (MK_SHIFT | MK_CONTROL))
355cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_LINK;
356cd75a87cSKatayama Hirofumi MZ             else if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == MK_CONTROL)
357cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_COPY;
358cd75a87cSKatayama Hirofumi MZ             else
359cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_MOVE;
360cd75a87cSKatayama Hirofumi MZ             break;
361cd75a87cSKatayama Hirofumi MZ         case D_COPY | D_LINK:
362cd75a87cSKatayama Hirofumi MZ             if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == (MK_SHIFT | MK_CONTROL))
363cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_LINK;
364cd75a87cSKatayama Hirofumi MZ             else
365cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_COPY;
366cd75a87cSKatayama Hirofumi MZ             break;
367cd75a87cSKatayama Hirofumi MZ         case D_MOVE | D_LINK:
368cd75a87cSKatayama Hirofumi MZ             if ((dwKeyState & (MK_SHIFT | MK_CONTROL)) == (MK_SHIFT | MK_CONTROL))
369cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_LINK;
370cd75a87cSKatayama Hirofumi MZ             else
371cd75a87cSKatayama Hirofumi MZ                 m_dwDefaultEffect = D_MOVE;
372cd75a87cSKatayama Hirofumi MZ             break;
373cd75a87cSKatayama Hirofumi MZ     }
3746f25b42aSGiannis Adamopoulos 
3756f25b42aSGiannis Adamopoulos     STGMEDIUM medium;
3766f25b42aSGiannis Adamopoulos     if (SUCCEEDED(pDataObject->GetData(&fmt2, &medium)))
3776f25b42aSGiannis Adamopoulos     {
3786f25b42aSGiannis Adamopoulos         WCHAR wstrFirstFile[MAX_PATH];
3796f25b42aSGiannis Adamopoulos         if (DragQueryFileW((HDROP)medium.hGlobal, 0, wstrFirstFile, _countof(wstrFirstFile)))
3806f25b42aSGiannis Adamopoulos         {
3816f25b42aSGiannis Adamopoulos             /* Check if the drive letter is different */
382fd209faaSGiannis Adamopoulos             if (wstrFirstFile[0] != m_sPathTarget[0])
3836f25b42aSGiannis Adamopoulos             {
3846f25b42aSGiannis Adamopoulos                 m_dwDefaultEffect = DROPEFFECT_COPY;
3856f25b42aSGiannis Adamopoulos             }
3866f25b42aSGiannis Adamopoulos         }
3876f25b42aSGiannis Adamopoulos         ReleaseStgMedium(&medium);
3886f25b42aSGiannis Adamopoulos     }
3896d91269eSGiannis Adamopoulos 
390cd75a87cSKatayama Hirofumi MZ     if (!m_fAcceptFmt)
391cd75a87cSKatayama Hirofumi MZ         *pdwEffect = DROPEFFECT_NONE;
392cd75a87cSKatayama Hirofumi MZ     else
393cd75a87cSKatayama Hirofumi MZ         *pdwEffect = m_dwDefaultEffect;
394cd75a87cSKatayama Hirofumi MZ 
395c2c66affSColin Finck     return S_OK;
396c2c66affSColin Finck }
397c2c66affSColin Finck 
398c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::DragOver(DWORD dwKeyState, POINTL pt,
399c2c66affSColin Finck                                        DWORD *pdwEffect)
400c2c66affSColin Finck {
401c2c66affSColin Finck     TRACE("(%p)\n", this);
402c2c66affSColin Finck 
403c2c66affSColin Finck     if (!pdwEffect)
404c2c66affSColin Finck         return E_INVALIDARG;
405c2c66affSColin Finck 
4066d91269eSGiannis Adamopoulos     m_grfKeyState = dwKeyState;
4076d91269eSGiannis Adamopoulos 
408fd209faaSGiannis Adamopoulos     _QueryDrop(dwKeyState, pdwEffect);
409c2c66affSColin Finck 
410c2c66affSColin Finck     return S_OK;
411c2c66affSColin Finck }
412c2c66affSColin Finck 
413c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::DragLeave()
414c2c66affSColin Finck {
415c2c66affSColin Finck     TRACE("(%p)\n", this);
416c2c66affSColin Finck 
417fd209faaSGiannis Adamopoulos     m_fAcceptFmt = FALSE;
418c2c66affSColin Finck 
419c2c66affSColin Finck     return S_OK;
420c2c66affSColin Finck }
421c2c66affSColin Finck 
422c2c66affSColin Finck HRESULT WINAPI CFSDropTarget::Drop(IDataObject *pDataObject,
423c2c66affSColin Finck                                    DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
424c2c66affSColin Finck {
425c2c66affSColin Finck     TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
426c2c66affSColin Finck 
427c2c66affSColin Finck     if (!pdwEffect)
428c2c66affSColin Finck         return E_INVALIDARG;
429c2c66affSColin Finck 
4306d91269eSGiannis Adamopoulos     IUnknown_GetWindow(m_site, &m_hwndSite);
4316d91269eSGiannis Adamopoulos 
4326f25b42aSGiannis Adamopoulos     DWORD dwAvailableEffects = *pdwEffect;
4336f25b42aSGiannis Adamopoulos 
434fd209faaSGiannis Adamopoulos     _QueryDrop(dwKeyState, pdwEffect);
435c2c66affSColin Finck 
4366f25b42aSGiannis Adamopoulos     TRACE("pdwEffect: 0x%x, m_dwDefaultEffect: 0x%x, dwAvailableEffects: 0x%x\n", *pdwEffect, m_dwDefaultEffect, dwAvailableEffects);
4376f25b42aSGiannis Adamopoulos 
4386d91269eSGiannis Adamopoulos     if (m_grfKeyState & MK_RBUTTON)
4396d91269eSGiannis Adamopoulos     {
4406f25b42aSGiannis Adamopoulos         HRESULT hr = _GetEffectFromMenu(pDataObject, pt, pdwEffect, dwAvailableEffects);
4416d91269eSGiannis Adamopoulos         if (FAILED_UNEXPECTEDLY(hr) || hr == S_FALSE)
4426d91269eSGiannis Adamopoulos             return hr;
4436d91269eSGiannis Adamopoulos     }
4446d91269eSGiannis Adamopoulos 
4456d91269eSGiannis Adamopoulos     if (*pdwEffect == DROPEFFECT_MOVE && m_site)
4466d91269eSGiannis Adamopoulos     {
4476d91269eSGiannis Adamopoulos         CComPtr<IShellFolderView> psfv;
4486d91269eSGiannis Adamopoulos         HRESULT hr = IUnknown_QueryService(m_site, SID_IFolderView, IID_PPV_ARG(IShellFolderView, &psfv));
4496d91269eSGiannis Adamopoulos         if (SUCCEEDED(hr) && psfv->IsDropOnSource(this) == S_OK)
4506d91269eSGiannis Adamopoulos         {
4516d91269eSGiannis Adamopoulos             _RepositionItems(psfv, pDataObject, pt);
4526d91269eSGiannis Adamopoulos             return S_OK;
4536d91269eSGiannis Adamopoulos         }
4546d91269eSGiannis Adamopoulos     }
4556d91269eSGiannis Adamopoulos 
456c2c66affSColin Finck     BOOL fIsOpAsync = FALSE;
457c2c66affSColin Finck     CComPtr<IAsyncOperation> pAsyncOperation;
458c2c66affSColin Finck 
459c2c66affSColin Finck     if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
460c2c66affSColin Finck     {
461c2c66affSColin Finck         if (SUCCEEDED(pAsyncOperation->GetAsyncMode(&fIsOpAsync)) && fIsOpAsync)
462c2c66affSColin Finck         {
463c2c66affSColin Finck             _DoDropData *data = static_cast<_DoDropData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData)));
464c2c66affSColin Finck             data->This = this;
465c2c66affSColin Finck             // Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
466c2c66affSColin Finck             pDataObject->AddRef();
467c2c66affSColin Finck             pAsyncOperation->StartOperation(NULL);
468c2c66affSColin Finck             CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &data->pStream);
469c2c66affSColin Finck             this->AddRef();
470c2c66affSColin Finck             data->dwKeyState = dwKeyState;
471c2c66affSColin Finck             data->pt = pt;
472c2c66affSColin Finck             // Need to dereference as pdweffect gets freed.
473c2c66affSColin Finck             data->pdwEffect = *pdwEffect;
474c2c66affSColin Finck             SHCreateThread(CFSDropTarget::_DoDropThreadProc, data, NULL, NULL);
475c2c66affSColin Finck             return S_OK;
476c2c66affSColin Finck         }
477c2c66affSColin Finck     }
478c2c66affSColin Finck     return this->_DoDrop(pDataObject, dwKeyState, pt, pdwEffect);
479c2c66affSColin Finck }
480c2c66affSColin Finck 
4816d91269eSGiannis Adamopoulos HRESULT
4826d91269eSGiannis Adamopoulos WINAPI
4836d91269eSGiannis Adamopoulos CFSDropTarget::SetSite(IUnknown *pUnkSite)
4846d91269eSGiannis Adamopoulos {
4856d91269eSGiannis Adamopoulos     m_site = pUnkSite;
4866d91269eSGiannis Adamopoulos     return S_OK;
4876d91269eSGiannis Adamopoulos }
4886d91269eSGiannis Adamopoulos 
4896d91269eSGiannis Adamopoulos HRESULT
4906d91269eSGiannis Adamopoulos WINAPI
4916d91269eSGiannis Adamopoulos CFSDropTarget::GetSite(REFIID riid, void **ppvSite)
4926d91269eSGiannis Adamopoulos {
4936d91269eSGiannis Adamopoulos     if (!m_site)
4946d91269eSGiannis Adamopoulos         return E_FAIL;
4956d91269eSGiannis Adamopoulos 
4966d91269eSGiannis Adamopoulos     return m_site->QueryInterface(riid, ppvSite);
4976d91269eSGiannis Adamopoulos }
4986d91269eSGiannis Adamopoulos 
499fd209faaSGiannis Adamopoulos HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
500c2c66affSColin Finck                                DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
501c2c66affSColin Finck {
502c2c66affSColin Finck     TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect);
503c2c66affSColin Finck     FORMATETC fmt;
504c2c66affSColin Finck     FORMATETC fmt2;
505c2c66affSColin Finck     STGMEDIUM medium;
506c2c66affSColin Finck 
507fd209faaSGiannis Adamopoulos     InitFormatEtc (fmt, m_cfShellIDList, TYMED_HGLOBAL);
508c2c66affSColin Finck     InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
509c2c66affSColin Finck 
510c2c66affSColin Finck     HRESULT hr;
511c2c66affSColin Finck     bool bCopy = TRUE;
512c2c66affSColin Finck     bool bLinking = FALSE;
513c2c66affSColin Finck 
514c2c66affSColin Finck     /* Figure out what drop operation we're doing */
515c2c66affSColin Finck     if (pdwEffect)
516c2c66affSColin Finck     {
517c2c66affSColin Finck         TRACE("Current drop effect flag %i\n", *pdwEffect);
518c2c66affSColin Finck         if ((*pdwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
519c2c66affSColin Finck             bCopy = FALSE;
520c2c66affSColin Finck         if ((*pdwEffect & DROPEFFECT_LINK) == DROPEFFECT_LINK)
521c2c66affSColin Finck             bLinking = TRUE;
522c2c66affSColin Finck     }
523c2c66affSColin Finck 
524c2c66affSColin Finck     if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
525c2c66affSColin Finck     {
526c2c66affSColin Finck         hr = pDataObject->GetData(&fmt, &medium);
5276f91b6c0SJoachim Henze         TRACE("CFSTR_SHELLIDLIST\n");
528a5a30fc2SKyle Katarn         if (FAILED(hr))
529a5a30fc2SKyle Katarn         {
530a5a30fc2SKyle Katarn             ERR("CFSTR_SHELLIDLIST failed\n");
531a5a30fc2SKyle Katarn         }
532c2c66affSColin Finck         /* lock the handle */
533c2c66affSColin Finck         LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
534c2c66affSColin Finck         if (!lpcida)
535c2c66affSColin Finck         {
536c2c66affSColin Finck             ReleaseStgMedium(&medium);
537c2c66affSColin Finck             return E_FAIL;
538c2c66affSColin Finck         }
539c2c66affSColin Finck 
540c2c66affSColin Finck         /* convert the data into pidl */
541c2c66affSColin Finck         LPITEMIDLIST pidl;
542c2c66affSColin Finck         LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
543c2c66affSColin Finck         if (!apidl)
544c2c66affSColin Finck         {
545c2c66affSColin Finck             ReleaseStgMedium(&medium);
546c2c66affSColin Finck             return E_FAIL;
547c2c66affSColin Finck         }
548c2c66affSColin Finck 
549c2c66affSColin Finck         CComPtr<IShellFolder> psfDesktop;
550c2c66affSColin Finck         CComPtr<IShellFolder> psfFrom = NULL;
551c2c66affSColin Finck 
552c2c66affSColin Finck         /* Grab the desktop shell folder */
553c2c66affSColin Finck         hr = SHGetDesktopFolder(&psfDesktop);
554c2c66affSColin Finck         if (FAILED(hr))
555c2c66affSColin Finck         {
556c2c66affSColin Finck             ERR("SHGetDesktopFolder failed\n");
557c2c66affSColin Finck             SHFree(pidl);
558c2c66affSColin Finck             _ILFreeaPidl(apidl, lpcida->cidl);
559c2c66affSColin Finck             ReleaseStgMedium(&medium);
560c2c66affSColin Finck             return E_FAIL;
561c2c66affSColin Finck         }
562c2c66affSColin Finck 
563c2c66affSColin Finck         /* Find source folder, this is where the clipboard data was copied from */
564c2c66affSColin Finck         if (_ILIsDesktop(pidl))
565c2c66affSColin Finck         {
566c2c66affSColin Finck             /* use desktop shell folder */
567c2c66affSColin Finck             psfFrom = psfDesktop;
568c2c66affSColin Finck         }
569c2c66affSColin Finck         else
570c2c66affSColin Finck         {
571c2c66affSColin Finck             hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
572c2c66affSColin Finck             if (FAILED(hr))
573c2c66affSColin Finck             {
574c2c66affSColin Finck                 ERR("no IShellFolder\n");
575c2c66affSColin Finck                 SHFree(pidl);
576c2c66affSColin Finck                 _ILFreeaPidl(apidl, lpcida->cidl);
577c2c66affSColin Finck                 ReleaseStgMedium(&medium);
578c2c66affSColin Finck                 return E_FAIL;
579c2c66affSColin Finck             }
580c2c66affSColin Finck         }
581c2c66affSColin Finck 
582c2c66affSColin Finck         if (bLinking)
583c2c66affSColin Finck         {
584fa95a96eSWhindmar Saksit             WCHAR wszNewLnk[MAX_PATH];
585c2c66affSColin Finck 
5860f5fb478SKatayama Hirofumi MZ             TRACE("target path = %s\n", debugstr_w(m_sPathTarget));
587c2c66affSColin Finck 
588c2c66affSColin Finck             /* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
589c2c66affSColin Finck             for (UINT i = 0; i < lpcida->cidl; i++)
590c2c66affSColin Finck             {
591cca9acfaSWhindmar Saksit                 SFGAOF att = SHGetAttributes(psfFrom, apidl[i], SFGAO_FOLDER | SFGAO_STREAM | SFGAO_FILESYSTEM);
592fa95a96eSWhindmar Saksit                 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlFull;
593fa95a96eSWhindmar Saksit                 hr = SHILCombine(pidl, apidl[i], &pidlFull);
594c2c66affSColin Finck 
595fa95a96eSWhindmar Saksit                 WCHAR targetName[MAX_PATH];
5960f5fb478SKatayama Hirofumi MZ                 if (SUCCEEDED(hr))
597cca9acfaSWhindmar Saksit                 {
598cca9acfaSWhindmar Saksit                     // If the target is a file, we use SHGDN_FORPARSING because "NeverShowExt" will hide the ".lnk" extension.
599cca9acfaSWhindmar Saksit                     // If the target is a virtual item, we ask for the friendly name because SHGDN_FORPARSING will return a GUID.
600cca9acfaSWhindmar Saksit                     BOOL UseParsing = (att & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) == SFGAO_FILESYSTEM;
601cca9acfaSWhindmar Saksit                     DWORD ShgdnFor = UseParsing ? SHGDN_FORPARSING : SHGDN_FOREDITING;
602cca9acfaSWhindmar Saksit                     hr = Shell_DisplayNameOf(psfFrom, apidl[i], ShgdnFor | SHGDN_INFOLDER, targetName, _countof(targetName));
603cca9acfaSWhindmar Saksit                 }
604fa95a96eSWhindmar Saksit                 if (FAILED_UNEXPECTEDLY(hr))
6050f5fb478SKatayama Hirofumi MZ                 {
606fa95a96eSWhindmar Saksit                     SHELL_ErrorBox(m_hwndSite, hr);
607fa95a96eSWhindmar Saksit                     break;
6080f5fb478SKatayama Hirofumi MZ                 }
609fa95a96eSWhindmar Saksit                 SHELL_StripIllegalFsNameCharacters(targetName);
6100f5fb478SKatayama Hirofumi MZ 
611fa95a96eSWhindmar Saksit                 WCHAR wszCombined[MAX_PATH + _countof(targetName)];
612fa95a96eSWhindmar Saksit                 PathCombineW(wszCombined, m_sPathTarget, targetName);
6130f5fb478SKatayama Hirofumi MZ 
6140f5fb478SKatayama Hirofumi MZ                 // Check to see if the source is a link
6150f5fb478SKatayama Hirofumi MZ                 BOOL fSourceIsLink = FALSE;
616*e4930be4STimo Kreuzer                 if (!_wcsicmp(PathFindExtensionW(targetName), L".lnk") && (att & (SFGAO_FOLDER | SFGAO_STREAM)) != SFGAO_FOLDER)
6170f5fb478SKatayama Hirofumi MZ                 {
6180f5fb478SKatayama Hirofumi MZ                     fSourceIsLink = TRUE;
6190f5fb478SKatayama Hirofumi MZ                     PathRemoveExtensionW(wszCombined);
6200f5fb478SKatayama Hirofumi MZ                 }
6210f5fb478SKatayama Hirofumi MZ 
6220f5fb478SKatayama Hirofumi MZ                 // Create a pathname to save the new link.
623fa95a96eSWhindmar Saksit                 _GetUniqueFileName(wszCombined, L".lnk", wszNewLnk, TRUE);
6240f5fb478SKatayama Hirofumi MZ 
625c2c66affSColin Finck                 CComPtr<IPersistFile> ppf;
6260f5fb478SKatayama Hirofumi MZ                 if (fSourceIsLink)
627c2c66affSColin Finck                 {
628fa95a96eSWhindmar Saksit                     PWSTR pwszTargetFull;
629fa95a96eSWhindmar Saksit                     hr = SHGetNameFromIDList(pidlFull, SIGDN_DESKTOPABSOLUTEPARSING, &pwszTargetFull);
630fa95a96eSWhindmar Saksit                     if (!FAILED_UNEXPECTEDLY(hr))
631fa95a96eSWhindmar Saksit                     {
632fa95a96eSWhindmar Saksit                         hr = IShellLink_ConstructFromPath(pwszTargetFull, IID_PPV_ARG(IPersistFile, &ppf));
633fa95a96eSWhindmar Saksit                         FAILED_UNEXPECTEDLY(hr);
634fa95a96eSWhindmar Saksit                         SHFree(pwszTargetFull);
635fa95a96eSWhindmar Saksit                     }
636c2c66affSColin Finck                 }
637c2c66affSColin Finck                 else
638c2c66affSColin Finck                 {
639c2c66affSColin Finck                     CComPtr<IShellLinkW> pLink;
640c2c66affSColin Finck                     hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
641fa95a96eSWhindmar Saksit                     if (!FAILED_UNEXPECTEDLY(hr))
642fa95a96eSWhindmar Saksit                     {
643fa95a96eSWhindmar Saksit                         hr = pLink->SetIDList(pidlFull);
644fa95a96eSWhindmar Saksit                         if (!FAILED_UNEXPECTEDLY(hr))
645c2c66affSColin Finck                             hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
646fa95a96eSWhindmar Saksit 
647fa95a96eSWhindmar Saksit                         PWSTR pwszPath, pSep;
648fa95a96eSWhindmar Saksit                         if ((att & SFGAO_FILESYSTEM) && SUCCEEDED(SHGetNameFromIDList(pidlFull, SIGDN_FILESYSPATH, &pwszPath)))
649fa95a96eSWhindmar Saksit                         {
650fa95a96eSWhindmar Saksit                             if ((pSep = PathFindFileNameW(pwszPath)) > pwszPath)
651fa95a96eSWhindmar Saksit                             {
652fa95a96eSWhindmar Saksit                                 pSep[-1] = UNICODE_NULL;
653fa95a96eSWhindmar Saksit                                 pLink->SetWorkingDirectory(pwszPath);
654fa95a96eSWhindmar Saksit                             }
655fa95a96eSWhindmar Saksit                             SHFree(pwszPath);
656fa95a96eSWhindmar Saksit                         }
657fa95a96eSWhindmar Saksit                     }
658fa95a96eSWhindmar Saksit                 }
659fa95a96eSWhindmar Saksit                 if (SUCCEEDED(hr))
660fa95a96eSWhindmar Saksit                     hr = ppf->Save(wszNewLnk, !fSourceIsLink);
6610f5fb478SKatayama Hirofumi MZ                 if (FAILED_UNEXPECTEDLY(hr))
662fa95a96eSWhindmar Saksit                 {
663fa95a96eSWhindmar Saksit                     SHELL_ErrorBox(m_hwndSite, hr);
6640f5fb478SKatayama Hirofumi MZ                     break;
6650f5fb478SKatayama Hirofumi MZ                 }
666fa95a96eSWhindmar Saksit                 SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszNewLnk, NULL);
667c2c66affSColin Finck             }
668c2c66affSColin Finck         }
669c2c66affSColin Finck         else
670c2c66affSColin Finck         {
671fd209faaSGiannis Adamopoulos             hr = _CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
672c2c66affSColin Finck         }
673c2c66affSColin Finck 
674c2c66affSColin Finck         SHFree(pidl);
675c2c66affSColin Finck         _ILFreeaPidl(apidl, lpcida->cidl);
676c2c66affSColin Finck         ReleaseStgMedium(&medium);
677c2c66affSColin Finck     }
678c2c66affSColin Finck     else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
679c2c66affSColin Finck     {
680c2c66affSColin Finck         FORMATETC fmt2;
681c2c66affSColin Finck         InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
682c2c66affSColin Finck         if (SUCCEEDED(pDataObject->GetData(&fmt2, &medium)) /* && SUCCEEDED(pDataObject->GetData(&fmt2, &medium))*/)
683c2c66affSColin Finck         {
684c2c66affSColin Finck             WCHAR wszTargetPath[MAX_PATH + 1];
685c2c66affSColin Finck             LPWSTR pszSrcList;
686c2c66affSColin Finck 
687fd209faaSGiannis Adamopoulos             wcscpy(wszTargetPath, m_sPathTarget);
688c2c66affSColin Finck             //Double NULL terminate.
689c2c66affSColin Finck             wszTargetPath[wcslen(wszTargetPath) + 1] = '\0';
690c2c66affSColin Finck 
691c2c66affSColin Finck             LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal);
692c2c66affSColin Finck             if (!lpdf)
693c2c66affSColin Finck             {
694c2c66affSColin Finck                 ERR("Error locking global\n");
695c2c66affSColin Finck                 return E_FAIL;
696c2c66affSColin Finck             }
697c2c66affSColin Finck             pszSrcList = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);
698c2c66affSColin Finck             ERR("Source file (just the first) = %s, target path = %s, bCopy: %d\n", debugstr_w(pszSrcList), debugstr_w(wszTargetPath), bCopy);
699c2c66affSColin Finck 
700c2c66affSColin Finck             SHFILEOPSTRUCTW op;
701c2c66affSColin Finck             ZeroMemory(&op, sizeof(op));
702c2c66affSColin Finck             op.pFrom = pszSrcList;
703c2c66affSColin Finck             op.pTo = wszTargetPath;
7046d91269eSGiannis Adamopoulos             op.hwnd = m_hwndSite;
705c2c66affSColin Finck             op.wFunc = bCopy ? FO_COPY : FO_MOVE;
706c2c66affSColin Finck             op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
707a5a30fc2SKyle Katarn             int res = SHFileOperationW(&op);
708a5a30fc2SKyle Katarn             if (res)
709a5a30fc2SKyle Katarn             {
710a5a30fc2SKyle Katarn                 ERR("SHFileOperationW failed with 0x%x\n", res);
711a5a30fc2SKyle Katarn                 hr = E_FAIL;
712a5a30fc2SKyle Katarn             }
713a5a30fc2SKyle Katarn 
714c2c66affSColin Finck             return hr;
715c2c66affSColin Finck         }
716c2c66affSColin Finck         ERR("Error calling GetData\n");
717c2c66affSColin Finck         hr = E_FAIL;
718c2c66affSColin Finck     }
719c2c66affSColin Finck     else
720c2c66affSColin Finck     {
7216f91b6c0SJoachim Henze         ERR("No viable drop format\n");
722c2c66affSColin Finck         hr = E_FAIL;
723c2c66affSColin Finck     }
724c2c66affSColin Finck     return hr;
725c2c66affSColin Finck }
726c2c66affSColin Finck 
727c2c66affSColin Finck DWORD WINAPI CFSDropTarget::_DoDropThreadProc(LPVOID lpParameter)
728c2c66affSColin Finck {
729c2c66affSColin Finck     CoInitialize(NULL);
730c2c66affSColin Finck     _DoDropData *data = static_cast<_DoDropData*>(lpParameter);
731c2c66affSColin Finck     CComPtr<IDataObject> pDataObject;
732c2c66affSColin Finck     HRESULT hr = CoGetInterfaceAndReleaseStream (data->pStream, IID_PPV_ARG(IDataObject, &pDataObject));
733c2c66affSColin Finck 
734c2c66affSColin Finck     if (SUCCEEDED(hr))
735c2c66affSColin Finck     {
736c2c66affSColin Finck         CComPtr<IAsyncOperation> pAsyncOperation;
737c2c66affSColin Finck         hr = data->This->_DoDrop(pDataObject, data->dwKeyState, data->pt, &data->pdwEffect);
738c2c66affSColin Finck         if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
739c2c66affSColin Finck         {
740c2c66affSColin Finck             pAsyncOperation->EndOperation(hr, NULL, data->pdwEffect);
741c2c66affSColin Finck         }
742c2c66affSColin Finck     }
743c2c66affSColin Finck     //Release the CFSFolder and data object holds in the copying thread.
744c2c66affSColin Finck     data->This->Release();
745c2c66affSColin Finck     //Release the parameter from the heap.
746c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, data);
747c2c66affSColin Finck     CoUninitialize();
748c2c66affSColin Finck     return 0;
749c2c66affSColin Finck }
750c2c66affSColin Finck 
751c2c66affSColin Finck HRESULT CFSDropTarget_CreateInstance(LPWSTR sPathTarget, REFIID riid, LPVOID * ppvOut)
752c2c66affSColin Finck {
753c2c66affSColin Finck     return ShellObjectCreatorInit<CFSDropTarget>(sPathTarget, riid, ppvOut);
754c2c66affSColin Finck }
755