5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998, 1999, 2002 Juergen Schmied
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
28 CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is
29 returned by Next. When the enumerator is created, it can do numerous additional operations
30 including formatting a drive, reconnecting a network share drive, and requesting a disk
31 be inserted in a removable drive.
34 /***********************************************************************
35 * IShellFolder implementation
39 public IEnumIDListImpl
45 HRESULT WINAPI
Initialize(LPWSTR sPathTarget
, DWORD dwFlags
);
47 BEGIN_COM_MAP(CFileSysEnum
)
48 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
52 CFileSysEnum::CFileSysEnum()
56 CFileSysEnum::~CFileSysEnum()
60 HRESULT WINAPI
CFileSysEnum::Initialize(LPWSTR sPathTarget
, DWORD dwFlags
)
62 return CreateFolderEnumList(sPathTarget
, dwFlags
);
65 /**************************************************************************
66 * registers clipboardformat once
68 void CFSFolder::SF_RegisterClipFmt()
70 TRACE ("(%p)\n", this);
73 cfShellIDList
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
76 CFSFolder::CFSFolder()
78 pclsid
= (CLSID
*)&CLSID_ShellFSFolder
;
86 CFSFolder::~CFSFolder()
88 TRACE("-- destroying IShellFolder(%p)\n", this);
95 static const shvheader GenericSFHeader
[] = {
96 {IDS_SHV_COLUMN1
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},
97 {IDS_SHV_COLUMN2
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
98 {IDS_SHV_COLUMN3
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
99 {IDS_SHV_COLUMN4
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 12},
100 {IDS_SHV_COLUMN5
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 5}
103 #define GENERICSHELLVIEWCOLUMNS 5
105 /**************************************************************************
106 * SHELL32_CreatePidlFromBindCtx [internal]
108 * If the caller bound File System Bind Data, assume it is the
109 * find data for the path.
110 * This allows binding of paths that don't exist.
112 LPITEMIDLIST
SHELL32_CreatePidlFromBindCtx(IBindCtx
*pbc
, LPCWSTR path
)
114 IFileSystemBindData
*fsbd
= NULL
;
115 LPITEMIDLIST pidl
= NULL
;
116 IUnknown
*param
= NULL
;
117 WIN32_FIND_DATAW wfd
;
120 TRACE("%p %s\n", pbc
, debugstr_w(path
));
125 /* see if the caller bound File System Bind Data */
126 r
= pbc
->GetObjectParam((LPOLESTR
)STR_FILE_SYS_BIND_DATA
, ¶m
);
130 r
= param
->QueryInterface(IID_PPV_ARG(IFileSystemBindData
,&fsbd
));
133 r
= fsbd
->GetFindData(&wfd
);
136 lstrcpynW(&wfd
.cFileName
[0], path
, MAX_PATH
);
137 pidl
= _ILCreateFromFindDataW(&wfd
);
145 /**************************************************************************
146 * CFSFolder::ParseDisplayName {SHELL32}
148 * Parse a display name.
151 * hwndOwner [in] Parent window for any message's
152 * pbc [in] optional FileSystemBindData context
153 * lpszDisplayName [in] Unicode displayname.
154 * pchEaten [out] (unicode) characters processed
155 * ppidl [out] complex pidl to item
156 * pdwAttributes [out] items attributes
159 * Every folder tries to parse only its own (the leftmost) pidl and creates a
160 * subfolder to evaluate the remaining parts.
161 * Now we can parse into namespaces implemented by shell extensions
163 * Behaviour on win98: lpszDisplayName=NULL -> crash
164 * lpszDisplayName="" -> returns mycoputer-pidl
167 * pdwAttributes is not set
168 * pchEaten is not set like in windows
170 HRESULT WINAPI
CFSFolder::ParseDisplayName(HWND hwndOwner
,
172 LPOLESTR lpszDisplayName
,
173 DWORD
*pchEaten
, LPITEMIDLIST
*ppidl
,
174 DWORD
*pdwAttributes
)
176 HRESULT hr
= E_INVALIDARG
;
177 LPCWSTR szNext
= NULL
;
178 WCHAR szElement
[MAX_PATH
];
179 WCHAR szPath
[MAX_PATH
];
180 LPITEMIDLIST pidlTemp
= NULL
;
183 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
184 this, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
185 pchEaten
, ppidl
, pdwAttributes
);
190 if (!lpszDisplayName
)
199 *pchEaten
= 0; /* strange but like the original */
201 if (*lpszDisplayName
)
203 /* get the next element */
204 szNext
= GetNextElementW (lpszDisplayName
, szElement
, MAX_PATH
);
206 pidlTemp
= SHELL32_CreatePidlFromBindCtx(pbc
, szElement
);
207 if (pidlTemp
!= NULL
)
213 /* build the full pathname to the element */
214 lstrcpynW(szPath
, sPathTarget
, MAX_PATH
- 1);
215 PathAddBackslashW(szPath
);
216 len
= wcslen(szPath
);
217 lstrcpynW(szPath
+ len
, szElement
, MAX_PATH
- len
);
220 hr
= _ILCreateFromPathW(szPath
, &pidlTemp
);
225 if (szNext
&& *szNext
)
227 /* try to analyse the next element */
228 hr
= SHELL32_ParseNextElement(this, hwndOwner
, pbc
,
229 &pidlTemp
, (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
233 /* it's the last element */
234 if (pdwAttributes
&& *pdwAttributes
)
235 hr
= SHELL32_GetItemAttributes(this, pidlTemp
, pdwAttributes
);
245 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl
? *ppidl
: 0, hr
);
250 /**************************************************************************
251 * CFSFolder::EnumObjects
253 * HWND hwndOwner, //[in ] Parent Window
254 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
255 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
257 HRESULT WINAPI
CFSFolder::EnumObjects(
260 LPENUMIDLIST
*ppEnumIDList
)
262 CComObject
<CFileSysEnum
> *theEnumerator
;
263 CComPtr
<IEnumIDList
> result
;
266 TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner
, dwFlags
, ppEnumIDList
);
268 if (ppEnumIDList
== NULL
)
270 *ppEnumIDList
= NULL
;
271 ATLTRY (theEnumerator
= new CComObject
<CFileSysEnum
>);
272 if (theEnumerator
== NULL
)
273 return E_OUTOFMEMORY
;
274 hResult
= theEnumerator
->QueryInterface(IID_PPV_ARG(IEnumIDList
, &result
));
277 delete theEnumerator
;
280 hResult
= theEnumerator
->Initialize (sPathTarget
, dwFlags
);
281 if (FAILED (hResult
))
283 *ppEnumIDList
= result
.Detach();
285 TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList
);
290 /**************************************************************************
291 * CFSFolder::BindToObject
293 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
294 * LPBC pbc, //[in ] optional FileSystemBindData context
295 * REFIID riid, //[in ] Initial Interface
296 * LPVOID* ppvObject //[out] Interface*
298 HRESULT WINAPI
CFSFolder::BindToObject(
304 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl
, pbc
,
305 shdebugstr_guid(&riid
), ppvOut
);
307 return SHELL32_BindToChild(pidlRoot
, sPathTarget
, pidl
, riid
, ppvOut
);
310 /**************************************************************************
311 * CFSFolder::BindToStorage
313 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
314 * LPBC pbc, //[in ] reserved
315 * REFIID riid, //[in ] Initial storage interface
316 * LPVOID* ppvObject //[out] Interface* returned
318 HRESULT WINAPI
CFSFolder::BindToStorage(
324 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl
, pbcReserved
,
325 shdebugstr_guid (&riid
), ppvOut
);
331 /**************************************************************************
332 * CFSFolder::CompareIDs
335 HRESULT WINAPI
CFSFolder::CompareIDs(LPARAM lParam
,
336 LPCITEMIDLIST pidl1
, LPCITEMIDLIST pidl2
)
340 TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam
, pidl1
, pidl2
);
341 nReturn
= SHELL32_CompareIDs(this, lParam
, pidl1
, pidl2
);
342 TRACE("-- %i\n", nReturn
);
346 /**************************************************************************
347 * CFSFolder::CreateViewObject
349 HRESULT WINAPI
CFSFolder::CreateViewObject(HWND hwndOwner
,
350 REFIID riid
, LPVOID
* ppvOut
)
352 LPSHELLVIEW pShellView
;
353 HRESULT hr
= E_INVALIDARG
;
355 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner
, shdebugstr_guid (&riid
),
362 if (IsEqualIID (riid
, IID_IDropTarget
))
363 hr
= this->QueryInterface (IID_IDropTarget
, ppvOut
);
364 else if (IsEqualIID (riid
, IID_IContextMenu
))
366 FIXME ("IContextMenu not implemented\n");
369 else if (IsEqualIID (riid
, IID_IShellView
))
371 hr
= IShellView_Constructor ((IShellFolder
*)this, &pShellView
);
374 hr
= pShellView
->QueryInterface(riid
, ppvOut
);
375 pShellView
->Release();
379 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut
);
383 /**************************************************************************
384 * CFSFolder::GetAttributesOf
387 * UINT cidl, //[in ] num elements in pidl array
388 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
389 * ULONG* rgfInOut) //[out] result array
392 HRESULT WINAPI
CFSFolder::GetAttributesOf(UINT cidl
,
393 LPCITEMIDLIST
* apidl
, DWORD
* rgfInOut
)
397 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this, cidl
, apidl
,
398 rgfInOut
, rgfInOut
? *rgfInOut
: 0);
410 IShellFolder
*psfParent
= NULL
;
411 LPCITEMIDLIST rpidl
= NULL
;
413 hr
= SHBindToParent(pidlRoot
, IID_PPV_ARG(IShellFolder
, &psfParent
), &rpidl
);
416 SHELL32_GetItemAttributes (psfParent
, rpidl
, rgfInOut
);
417 psfParent
->Release();
422 while (cidl
> 0 && *apidl
)
425 SHELL32_GetItemAttributes(this, *apidl
, rgfInOut
);
430 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
431 *rgfInOut
&= ~SFGAO_VALIDATE
;
433 TRACE("-- result=0x%08x\n", *rgfInOut
);
438 /**************************************************************************
439 * CFSFolder::GetUIObjectOf
442 * HWND hwndOwner, //[in ] Parent window for any output
443 * UINT cidl, //[in ] array size
444 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
445 * REFIID riid, //[in ] Requested Interface
446 * UINT* prgfInOut, //[ ] reserved
447 * LPVOID* ppvObject) //[out] Resulting Interface
450 * This function gets asked to return "view objects" for one or more (multiple
452 * The viewobject typically is an COM object with one of the following
454 * IExtractIcon,IDataObject,IContextMenu
455 * In order to support icon positions in the default Listview your DataObject
456 * must implement the SetData method (in addition to GetData :) - the shell
457 * passes a barely documented "Icon positions" structure to SetData when the
458 * drag starts, and GetData's it if the drop is in another explorer window that
459 * needs the positions.
461 HRESULT WINAPI
CFSFolder::GetUIObjectOf(HWND hwndOwner
,
462 UINT cidl
, LPCITEMIDLIST
* apidl
, REFIID riid
,
463 UINT
* prgfInOut
, LPVOID
* ppvOut
)
466 IUnknown
*pObj
= NULL
;
467 HRESULT hr
= E_INVALIDARG
;
469 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
470 this, hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
476 if (IsEqualIID (riid
, IID_IContextMenu
) && (cidl
>= 1))
477 hr
= CDefFolderMenu_Create2(pidlRoot
, hwndOwner
, cidl
, apidl
, (IShellFolder
*)this, NULL
, 0, NULL
, (IContextMenu
**)&pObj
);
478 else if (IsEqualIID (riid
, IID_IDataObject
))
481 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
485 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, (LPCITEMIDLIST
*)&pidlRoot
, 1, (IDataObject
**)&pObj
);
488 else if (IsEqualIID (riid
, IID_IExtractIconA
) && (cidl
== 1))
490 pidl
= ILCombine (pidlRoot
, apidl
[0]);
491 pObj
= (LPUNKNOWN
) IExtractIconA_Constructor (pidl
);
495 else if (IsEqualIID (riid
, IID_IExtractIconW
) && (cidl
== 1))
497 pidl
= ILCombine (pidlRoot
, apidl
[0]);
498 pObj
= (LPUNKNOWN
) IExtractIconW_Constructor (pidl
);
502 else if (IsEqualIID (riid
, IID_IDropTarget
))
504 /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
505 if (cidl
== 1 && SUCCEEDED(hr
= this->BindToObject(apidl
[0], NULL
, IID_IDropTarget
, (LPVOID
*)&pObj
)));
507 hr
= this->QueryInterface(IID_IDropTarget
, (LPVOID
*)&pObj
);
509 else if ((IsEqualIID(riid
, IID_IShellLinkW
) ||
510 IsEqualIID(riid
, IID_IShellLinkA
)) && (cidl
== 1))
512 pidl
= ILCombine (pidlRoot
, apidl
[0]);
513 hr
= IShellLink_ConstructFromFile(NULL
, riid
, pidl
, (LPVOID
*)&pObj
);
519 if (SUCCEEDED(hr
) && !pObj
)
524 TRACE("(%p)->hr=0x%08x\n", this, hr
);
528 static const WCHAR AdvancedW
[] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
529 static const WCHAR HideFileExtW
[] = L
"HideFileExt";
530 static const WCHAR NeverShowExtW
[] = L
"NeverShowExt";
532 /******************************************************************************
533 * SHELL_FS_HideExtension [Internal]
535 * Query the registry if the filename extension of a given path should be
539 * szPath [I] Relative or absolute path of a file
542 * TRUE, if the filename's extension should be hidden
545 BOOL
SHELL_FS_HideExtension(LPWSTR szPath
)
549 DWORD dwDataSize
= sizeof (DWORD
);
550 BOOL doHide
= FALSE
; /* The default value is FALSE (win98 at least) */
552 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, AdvancedW
, 0, 0, 0, KEY_ALL_ACCESS
, 0, &hKey
, 0)) {
553 if (!RegQueryValueExW(hKey
, HideFileExtW
, 0, 0, (LPBYTE
) &dwData
, &dwDataSize
))
559 LPWSTR ext
= PathFindExtensionW(szPath
);
562 WCHAR classname
[MAX_PATH
];
563 LONG classlen
= sizeof(classname
);
565 if (!RegQueryValueW(HKEY_CLASSES_ROOT
, ext
, classname
, &classlen
))
566 if (!RegOpenKeyW(HKEY_CLASSES_ROOT
, classname
, &hKey
)) {
567 if (!RegQueryValueExW(hKey
, NeverShowExtW
, 0, NULL
, NULL
, NULL
))
576 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath
, DWORD dwFlags
)
578 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
579 if (!(dwFlags
& SHGDN_FORPARSING
) &&
580 ((dwFlags
& SHGDN_INFOLDER
) || (dwFlags
== SHGDN_NORMAL
))) {
581 if (SHELL_FS_HideExtension(szPath
) && szPath
[0] != '.')
582 PathRemoveExtensionW(szPath
);
586 /**************************************************************************
587 * CFSFolder::GetDisplayNameOf
588 * Retrieves the display name for the specified file object or subfolder
591 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
592 * DWORD dwFlags, //[in ] SHGNO formatting flags
593 * LPSTRRET lpName) //[out] Returned display name
596 * if the name is in the pidl the ret value should be a STRRET_OFFSET
599 HRESULT WINAPI
CFSFolder::GetDisplayNameOf(LPCITEMIDLIST pidl
,
600 DWORD dwFlags
, LPSTRRET strRet
)
607 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl
, dwFlags
, strRet
);
610 if (!pidl
|| !strRet
)
613 pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
615 return E_OUTOFMEMORY
;
617 if (_ILIsDesktop(pidl
)) /* empty pidl */
619 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
620 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
))
623 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
);
626 hr
= E_INVALIDARG
; /* pidl has to contain exactly one non null SHITEMID */
628 else if (_ILIsPidlSimple(pidl
))
630 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
631 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
634 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
);
635 PathAddBackslashW(pszPath
);
636 len
= wcslen(pszPath
);
638 _ILSimpleGetTextW(pidl
, pszPath
+ len
, MAX_PATH
+ 1 - len
);
639 if (!_ILIsFolder(pidl
)) SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
641 hr
= SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, pszPath
, MAX_PATH
);
644 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
645 if (GetVersion() & 0x80000000)
647 strRet
->uType
= STRRET_CSTR
;
648 if (!WideCharToMultiByte(CP_ACP
, 0, pszPath
, -1, strRet
->cStr
, MAX_PATH
,
650 strRet
->cStr
[0] = '\0';
651 CoTaskMemFree(pszPath
);
655 strRet
->uType
= STRRET_WSTR
;
656 strRet
->pOleStr
= pszPath
;
659 CoTaskMemFree(pszPath
);
661 TRACE ("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
665 /**************************************************************************
666 * CFSFolder::SetNameOf
667 * Changes the name of a file object or subfolder, possibly changing its item
668 * identifier in the process.
671 * HWND hwndOwner, //[in ] Owner window for output
672 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
673 * LPCOLESTR lpszName, //[in ] the items new display name
674 * DWORD dwFlags, //[in ] SHGNO formatting flags
675 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
677 HRESULT WINAPI
CFSFolder::SetNameOf(
682 LPITEMIDLIST
* pPidlOut
)
684 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
686 BOOL bIsFolder
= _ILIsFolder (ILFindLastID (pidl
));
688 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner
, pidl
,
689 debugstr_w (lpName
), dwFlags
, pPidlOut
);
691 /* build source path */
692 lstrcpynW(szSrc
, sPathTarget
, MAX_PATH
);
693 ptr
= PathAddBackslashW (szSrc
);
695 _ILSimpleGetTextW (pidl
, ptr
, MAX_PATH
+ 1 - (ptr
- szSrc
));
697 /* build destination path */
698 if (dwFlags
== SHGDN_NORMAL
|| dwFlags
& SHGDN_INFOLDER
) {
699 lstrcpynW(szDest
, sPathTarget
, MAX_PATH
);
700 ptr
= PathAddBackslashW (szDest
);
702 lstrcpynW(ptr
, lpName
, MAX_PATH
+ 1 - (ptr
- szDest
));
704 lstrcpynW(szDest
, lpName
, MAX_PATH
);
706 if(!(dwFlags
& SHGDN_FORPARSING
) && SHELL_FS_HideExtension(szSrc
)) {
707 WCHAR
*ext
= PathFindExtensionW(szSrc
);
709 INT len
= wcslen(szDest
);
710 lstrcpynW(szDest
+ len
, ext
, MAX_PATH
- len
);
714 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc
), debugstr_w(szDest
));
715 if (!memcmp(szSrc
, szDest
, (wcslen(szDest
) + 1) * sizeof(WCHAR
)))
717 /* src and destination is the same */
720 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
726 if (MoveFileW (szSrc
, szDest
))
731 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
733 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
734 SHCNF_PATHW
, szSrc
, szDest
);
742 HRESULT WINAPI
CFSFolder::GetDefaultSearchGUID(GUID
* pguid
)
744 FIXME ("(%p)\n", this);
748 HRESULT WINAPI
CFSFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
750 FIXME ("(%p)\n", this);
754 HRESULT WINAPI
CFSFolder::GetDefaultColumn(DWORD dwRes
,
755 ULONG
* pSort
, ULONG
* pDisplay
)
757 TRACE ("(%p)\n", this);
767 HRESULT WINAPI
CFSFolder::GetDefaultColumnState(UINT iColumn
,
770 TRACE ("(%p)\n", this);
772 if (!pcsFlags
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
775 *pcsFlags
= GenericSFHeader
[iColumn
].pcsFlags
;
780 HRESULT WINAPI
CFSFolder::GetDetailsEx(LPCITEMIDLIST pidl
,
781 const SHCOLUMNID
* pscid
, VARIANT
* pv
)
783 FIXME ("(%p)\n", this);
788 HRESULT WINAPI
CFSFolder::GetDetailsOf(LPCITEMIDLIST pidl
,
789 UINT iColumn
, SHELLDETAILS
* psd
)
793 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
795 if (!psd
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
800 /* the header titles */
801 psd
->fmt
= GenericSFHeader
[iColumn
].fmt
;
802 psd
->cxChar
= GenericSFHeader
[iColumn
].cxChar
;
803 psd
->str
.uType
= STRRET_CSTR
;
804 LoadStringA(shell32_hInstance
, GenericSFHeader
[iColumn
].colnameid
,
805 psd
->str
.cStr
, MAX_PATH
);
811 psd
->str
.uType
= STRRET_CSTR
;
812 /* the data from the pidl */
816 hr
= GetDisplayNameOf (pidl
,
817 SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
820 _ILGetFileSize(pidl
, psd
->str
.cStr
, MAX_PATH
);
823 _ILGetFileType(pidl
, psd
->str
.cStr
, MAX_PATH
);
826 _ILGetFileDate(pidl
, psd
->str
.cStr
, MAX_PATH
);
828 case 4: /* attributes */
829 _ILGetFileAttributes(pidl
, psd
->str
.cStr
, MAX_PATH
);
837 HRESULT WINAPI
CFSFolder::MapColumnToSCID (UINT column
,
840 FIXME ("(%p)\n", this);
844 /****************************************************************************
845 * ISFHelper for IShellFolder implementation
848 /****************************************************************************
849 * CFSFolder::GetUniqueName
851 * creates a unique folder name
854 HRESULT WINAPI
CFSFolder::GetUniqueName(LPWSTR pwszName
, UINT uLen
)
858 WCHAR wszText
[MAX_PATH
];
859 WCHAR wszNewFolder
[25];
860 const WCHAR wszFormat
[] = L
"%s %d";
862 LoadStringW(shell32_hInstance
, IDS_NEWFOLDER
, wszNewFolder
, _countof(wszNewFolder
));
864 TRACE ("(%p)(%p %u)\n", this, pwszName
, uLen
);
866 if (uLen
< _countof(wszNewFolder
) + 3)
869 lstrcpynW (pwszName
, wszNewFolder
, uLen
);
871 hr
= EnumObjects(0, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &penum
);
880 while (S_OK
== penum
->Next(1, &pidl
, &dwFetched
) && dwFetched
)
882 _ILSimpleGetTextW(pidl
, wszText
, MAX_PATH
);
883 if (0 == lstrcmpiW(wszText
, pwszName
))
885 _snwprintf(pwszName
, uLen
, wszFormat
, wszNewFolder
, i
++);
900 /****************************************************************************
901 * CFSFolder::AddFolder
906 HRESULT WINAPI
CFSFolder::AddFolder(HWND hwnd
, LPCWSTR pwszName
,
907 LPITEMIDLIST
* ppidlOut
)
909 WCHAR wszNewDir
[MAX_PATH
];
911 HRESULT hres
= E_FAIL
;
913 TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName
), ppidlOut
);
917 lstrcpynW(wszNewDir
, sPathTarget
, MAX_PATH
);
918 PathAppendW(wszNewDir
, pwszName
);
920 bRes
= CreateDirectoryW(wszNewDir
, NULL
);
923 SHChangeNotify(SHCNE_MKDIR
, SHCNF_PATHW
, wszNewDir
, NULL
);
928 hres
= _ILCreateFromPathW(wszNewDir
, ppidlOut
);
932 WCHAR wszText
[128 + MAX_PATH
];
933 WCHAR wszTempText
[128];
934 WCHAR wszCaption
[256];
936 /* Cannot Create folder because of permissions */
937 LoadStringW(shell32_hInstance
, IDS_CREATEFOLDER_DENIED
, wszTempText
,
938 _countof(wszTempText
));
939 LoadStringW(shell32_hInstance
, IDS_CREATEFOLDER_CAPTION
, wszCaption
,
940 _countof(wszCaption
));
941 swprintf(wszText
, wszTempText
, wszNewDir
);
942 MessageBoxW(hwnd
, wszText
, wszCaption
, MB_OK
| MB_ICONEXCLAMATION
);
948 /****************************************************************************
951 * Builds a list of paths like the one used in SHFileOperation from a table of
952 * PIDLs relative to the given base folder
955 BuildPathsList(LPCWSTR wszBasePath
, int cidl
, LPCITEMIDLIST
*pidls
)
957 WCHAR
*pwszPathsList
;
961 iPathLen
= wcslen(wszBasePath
);
962 pwszPathsList
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
) * cidl
+ 1);
963 pwszListPos
= pwszPathsList
;
965 for (i
= 0; i
< cidl
; i
++)
967 if (!_ILIsFolder(pidls
[i
]) && !_ILIsValue(pidls
[i
]))
970 wcscpy(pwszListPos
, wszBasePath
);
971 pwszListPos
+= iPathLen
;
972 /* FIXME: abort if path too long */
973 _ILSimpleGetTextW(pidls
[i
], pwszListPos
, MAX_PATH
- iPathLen
);
974 pwszListPos
+= wcslen(pwszListPos
) + 1;
977 return pwszPathsList
;
980 /****************************************************************************
981 * CFSFolder::DeleteItems
983 * deletes items in folder
985 HRESULT WINAPI
CFSFolder::DeleteItems(UINT cidl
, LPCITEMIDLIST
*apidl
)
989 WCHAR wszPath
[MAX_PATH
];
992 WCHAR
*wszCurrentPath
;
994 TRACE ("(%p)(%u %p)\n", this, cidl
, apidl
);
995 if (cidl
== 0) return S_OK
;
998 lstrcpynW(wszPath
, sPathTarget
, MAX_PATH
);
1001 PathAddBackslashW(wszPath
);
1002 wszPathsList
= BuildPathsList(wszPath
, cidl
, apidl
);
1004 ZeroMemory(&op
, sizeof(op
));
1005 op
.hwnd
= GetActiveWindow();
1006 op
.wFunc
= FO_DELETE
;
1007 op
.pFrom
= wszPathsList
;
1008 op
.fFlags
= FOF_ALLOWUNDO
;
1009 if (SHFileOperationW(&op
))
1011 WARN("SHFileOperation failed\n");
1017 /* we currently need to manually send the notifies */
1018 wszCurrentPath
= wszPathsList
;
1019 for (i
= 0; i
< cidl
; i
++)
1023 if (_ILIsFolder(apidl
[i
]))
1024 wEventId
= SHCNE_RMDIR
;
1025 else if (_ILIsValue(apidl
[i
]))
1026 wEventId
= SHCNE_DELETE
;
1030 /* check if file exists */
1031 if (GetFileAttributesW(wszCurrentPath
) == INVALID_FILE_ATTRIBUTES
)
1033 LPITEMIDLIST pidl
= ILCombine(pidlRoot
, apidl
[i
]);
1034 SHChangeNotify(wEventId
, SHCNF_IDLIST
, pidl
, NULL
);
1038 wszCurrentPath
+= wcslen(wszCurrentPath
) + 1;
1040 HeapFree(GetProcessHeap(), 0, wszPathsList
);
1044 /****************************************************************************
1045 * CFSFolder::CopyItems
1047 * copies items to this folder
1049 HRESULT WINAPI
CFSFolder::CopyItems(IShellFolder
* pSFFrom
, UINT cidl
,
1050 LPCITEMIDLIST
* apidl
, bool bCopy
)
1052 IPersistFolder2
*ppf2
= NULL
;
1053 WCHAR szSrcPath
[MAX_PATH
];
1054 WCHAR szTargetPath
[MAX_PATH
];
1057 LPWSTR pszSrc
, pszTarget
, pszSrcList
, pszTargetList
, pszFileName
;
1062 TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom
, cidl
, apidl
);
1064 hr
= pSFFrom
->QueryInterface (IID_PPV_ARG(IPersistFolder2
, &ppf2
));
1067 hr
= ppf2
->GetCurFolder(&pidl
);
1075 hr
= pSFFrom
->GetDisplayNameOf(pidl
, SHGDN_FORPARSING
, &strRet
);
1082 hr
= StrRetToBufW(&strRet
, pidl
, szSrcPath
, MAX_PATH
);
1090 pszSrc
= PathAddBackslashW(szSrcPath
);
1092 wcscpy(szTargetPath
, sPathTarget
);
1093 pszTarget
= PathAddBackslashW(szTargetPath
);
1095 pszSrcList
= BuildPathsList(szSrcPath
, cidl
, apidl
);
1096 pszTargetList
= BuildPathsList(szTargetPath
, cidl
, apidl
);
1098 if (!pszSrcList
|| !pszTargetList
)
1101 HeapFree(GetProcessHeap(), 0, pszSrcList
);
1104 HeapFree(GetProcessHeap(), 0, pszTargetList
);
1108 return E_OUTOFMEMORY
;
1111 ZeroMemory(&op
, sizeof(op
));
1114 /* remove trailing backslash */
1117 op
.pFrom
= szSrcPath
;
1121 op
.pFrom
= pszSrcList
;
1124 if (!pszTargetList
[0])
1126 /* remove trailing backslash */
1127 if (pszTarget
- szTargetPath
> 3)
1130 pszTarget
[0] = L
'\0';
1134 pszTarget
[1] = L
'\0';
1137 op
.pTo
= szTargetPath
;
1142 op
.pTo
= pszTargetList
;
1143 op
.fFlags
= FOF_MULTIDESTFILES
;
1145 op
.hwnd
= GetActiveWindow();
1146 op
.wFunc
= bCopy
? FO_COPY
: FO_MOVE
;
1147 op
.fFlags
|= FOF_ALLOWUNDO
| FOF_NOCONFIRMMKDIR
;
1149 res
= SHFileOperationW(&op
);
1151 if (res
== DE_SAMEFILE
)
1153 length
= wcslen(szTargetPath
);
1155 pszFileName
= wcsrchr(pszSrcList
, '\\');
1158 if (LoadStringW(shell32_hInstance
, IDS_COPY_OF
, pszTarget
, MAX_PATH
- length
))
1160 wcscat(szTargetPath
, L
" ");
1163 wcscat(szTargetPath
, pszFileName
);
1164 op
.pTo
= szTargetPath
;
1166 res
= SHFileOperationW(&op
);
1169 HeapFree(GetProcessHeap(), 0, pszSrcList
);
1170 HeapFree(GetProcessHeap(), 0, pszTargetList
);
1180 /************************************************************************
1181 * CFSFolder::GetClassID
1183 HRESULT WINAPI
CFSFolder::GetClassID(CLSID
* lpClassId
)
1185 TRACE ("(%p)\n", this);
1190 *lpClassId
= *pclsid
;
1195 /************************************************************************
1196 * CFSFolder::Initialize
1199 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1201 HRESULT WINAPI
CFSFolder::Initialize(LPCITEMIDLIST pidl
)
1203 WCHAR wszTemp
[MAX_PATH
];
1205 TRACE ("(%p)->(%p)\n", this, pidl
);
1207 SHFree (pidlRoot
); /* free the old pidl */
1208 pidlRoot
= ILClone (pidl
); /* set my pidl */
1210 SHFree (sPathTarget
);
1214 if (SHGetPathFromIDListW (pidl
, wszTemp
))
1216 int len
= wcslen(wszTemp
);
1217 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1219 return E_OUTOFMEMORY
;
1220 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1223 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget
));
1227 /**************************************************************************
1228 * CFSFolder::GetCurFolder
1230 HRESULT WINAPI
CFSFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1232 TRACE ("(%p)->(%p)\n", this, pidl
);
1237 *pidl
= ILClone(pidlRoot
);
1241 /**************************************************************************
1242 * CFSFolder::InitializeEx
1244 * FIXME: error handling
1246 HRESULT WINAPI
CFSFolder::InitializeEx(IBindCtx
* pbc
, LPCITEMIDLIST pidlRootx
,
1247 const PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1249 WCHAR wszTemp
[MAX_PATH
];
1251 TRACE("(%p)->(%p,%p,%p)\n", this, pbc
, pidlRootx
, ppfti
);
1253 TRACE("--%p %s %s 0x%08x 0x%08x\n",
1254 ppfti
->pidlTargetFolder
, debugstr_w (ppfti
->szTargetParsingName
),
1255 debugstr_w (ppfti
->szNetworkProvider
), ppfti
->dwAttributes
,
1259 if (ppfti
&& ppfti
->pidlTargetFolder
)
1260 pdump(ppfti
->pidlTargetFolder
);
1263 __SHFreeAndNil(&pidlRoot
); /* free the old */
1265 __SHFreeAndNil(&sPathTarget
);
1268 * Root path and pidl
1270 pidlRoot
= ILClone(pidlRootx
);
1273 * the target folder is spezified in csidl OR pidlTargetFolder OR
1274 * szTargetParsingName
1278 if (ppfti
->csidl
!= -1)
1280 if (SHGetSpecialFolderPathW(0, wszTemp
, ppfti
->csidl
,
1281 ppfti
->csidl
& CSIDL_FLAG_CREATE
)) {
1282 int len
= wcslen(wszTemp
);
1283 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1285 return E_OUTOFMEMORY
;
1286 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1289 else if (ppfti
->szTargetParsingName
[0])
1291 int len
= wcslen(ppfti
->szTargetParsingName
);
1292 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1294 return E_OUTOFMEMORY
;
1295 memcpy(sPathTarget
, ppfti
->szTargetParsingName
,
1296 (len
+ 1) * sizeof(WCHAR
));
1298 else if (ppfti
->pidlTargetFolder
)
1300 if (SHGetPathFromIDListW(ppfti
->pidlTargetFolder
, wszTemp
))
1302 int len
= wcslen(wszTemp
);
1303 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1305 return E_OUTOFMEMORY
;
1306 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1311 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget
));
1313 return (sPathTarget
) ? S_OK
: E_FAIL
;
1316 HRESULT WINAPI
CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1318 FIXME("(%p)->(%p)\n", this, ppfti
);
1319 ZeroMemory(ppfti
, sizeof (*ppfti
));
1324 CFSFolder::GetUniqueFileName(LPWSTR pwszBasePath
, LPCWSTR pwszExt
, LPWSTR pwszTarget
, BOOL bShortcut
)
1330 if (!LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, wszLink
, _countof(wszLink
)))
1335 swprintf(pwszTarget
, L
"%s%s%s", wszLink
, pwszBasePath
, pwszExt
);
1337 swprintf(pwszTarget
, L
"%s%s", pwszBasePath
, pwszExt
);
1339 for (UINT i
= 2; PathFileExistsW(pwszTarget
); ++i
)
1342 swprintf(pwszTarget
, L
"%s%s (%u)%s", wszLink
, pwszBasePath
, i
, pwszExt
);
1344 swprintf(pwszTarget
, L
"%s (%u)%s", pwszBasePath
, i
, pwszExt
);
1350 /****************************************************************************
1351 * IDropTarget implementation
1353 BOOL
CFSFolder::QueryDrop(DWORD dwKeyState
, LPDWORD pdwEffect
)
1355 /* TODO Windows does different drop effects if dragging across drives.
1356 i.e., it will copy instead of move if the directories are on different disks. */
1358 DWORD dwEffect
= DROPEFFECT_MOVE
;
1360 *pdwEffect
= DROPEFFECT_NONE
;
1362 if (fAcceptFmt
) { /* Does our interpretation of the keystate ... */
1363 *pdwEffect
= KeyStateToDropEffect (dwKeyState
);
1365 if (*pdwEffect
== DROPEFFECT_NONE
)
1366 *pdwEffect
= dwEffect
;
1368 /* ... matches the desired effect ? */
1369 if (dwEffect
& *pdwEffect
) {
1376 HRESULT WINAPI
CFSFolder::DragEnter(IDataObject
*pDataObject
,
1377 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1379 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject
);
1384 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
1385 InitFormatEtc (fmt2
, CF_HDROP
, TYMED_HGLOBAL
);
1387 if (SUCCEEDED(pDataObject
->QueryGetData(&fmt
)))
1389 else if (SUCCEEDED(pDataObject
->QueryGetData(&fmt2
)))
1392 QueryDrop(dwKeyState
, pdwEffect
);
1396 HRESULT WINAPI
CFSFolder::DragOver(DWORD dwKeyState
, POINTL pt
,
1399 TRACE("(%p)\n", this);
1402 return E_INVALIDARG
;
1404 QueryDrop(dwKeyState
, pdwEffect
);
1409 HRESULT WINAPI
CFSFolder::DragLeave()
1411 TRACE("(%p)\n", this);
1418 HRESULT WINAPI
CFSFolder::Drop(IDataObject
*pDataObject
,
1419 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1421 TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect
);
1423 BOOL fIsOpAsync
= FALSE
;
1424 CComPtr
<IAsyncOperation
> pAsyncOperation
;
1426 if (SUCCEEDED(pDataObject
->QueryInterface(IID_PPV_ARG(IAsyncOperation
, &pAsyncOperation
))))
1428 if (SUCCEEDED(pAsyncOperation
->GetAsyncMode(&fIsOpAsync
)) && fIsOpAsync
)
1430 _DoDropData
*data
= reinterpret_cast<_DoDropData
*> (HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData
)));
1432 // Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
1434 data
->pDataObject
= pDataObject
;
1435 data
->pAsyncOperation
= pAsyncOperation
;
1436 data
->dwKeyState
= dwKeyState
;
1438 // Need to dereference as pdweffect gets freed.
1439 data
->pdwEffect
= *pdwEffect
;
1440 data
->pDataObject
->AddRef();
1441 data
->pAsyncOperation
->StartOperation(NULL
);
1442 SHCreateThread(reinterpret_cast<LPTHREAD_START_ROUTINE
> (CFSFolder::_DoDropThreadProc
), reinterpret_cast<void *> (data
), NULL
, NULL
);
1446 pAsyncOperation
->Release();
1448 return this->_DoDrop(pDataObject
, dwKeyState
, pt
, pdwEffect
);
1451 HRESULT WINAPI
CFSFolder::_DoDrop(IDataObject
*pDataObject
,
1452 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1454 TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect
);
1459 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
1460 InitFormatEtc (fmt2
, CF_HDROP
, TYMED_HGLOBAL
);
1464 bool bLinking
= FALSE
;
1466 /* Figure out what drop operation we're doing */
1469 TRACE("Current drop effect flag %i\n", *pdwEffect
);
1470 if ((*pdwEffect
& DROPEFFECT_MOVE
) == DROPEFFECT_MOVE
)
1472 if ((*pdwEffect
& DROPEFFECT_LINK
) == DROPEFFECT_LINK
)
1476 if (SUCCEEDED(pDataObject
->QueryGetData(&fmt
)))
1478 hr
= pDataObject
->GetData(&fmt
, &medium
);
1479 TRACE("CFSTR_SHELLIDLIST.\n");
1481 /* lock the handle */
1482 LPIDA lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
1485 ReleaseStgMedium(&medium
);
1489 /* convert the data into pidl */
1491 LPITEMIDLIST
*apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1494 ReleaseStgMedium(&medium
);
1498 CComPtr
<IShellFolder
> psfDesktop
;
1499 CComPtr
<IShellFolder
> psfFrom
= NULL
;
1500 CComPtr
<IShellFolder
> psfTarget
= NULL
;
1502 hr
= this->QueryInterface(IID_PPV_ARG(IShellFolder
, &psfTarget
));
1505 ERR("psfTarget setting failed\n");
1507 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1508 ReleaseStgMedium(&medium
);
1512 /* Grab the desktop shell folder */
1513 hr
= SHGetDesktopFolder(&psfDesktop
);
1516 ERR("SHGetDesktopFolder failed\n");
1518 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1519 ReleaseStgMedium(&medium
);
1523 /* Find source folder, this is where the clipboard data was copied from */
1524 if (_ILIsDesktop(pidl
))
1526 /* use desktop shell folder */
1527 psfFrom
= psfDesktop
;
1531 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_IShellFolder
, (LPVOID
*)&psfFrom
);
1534 ERR("no IShellFolder\n");
1536 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1537 ReleaseStgMedium(&medium
);
1544 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
1546 WCHAR wszTargetPath
[MAX_PATH
];
1547 LPITEMIDLIST targetpidl
;
1548 WCHAR wszPath
[MAX_PATH
];
1549 WCHAR wszTarget
[MAX_PATH
];
1551 hr
= this->QueryInterface(IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1554 hr
= ppf2
->GetCurFolder(&targetpidl
);
1557 hr
= psfDesktop
->GetDisplayNameOf(targetpidl
, SHGDN_FORPARSING
, &strFile
);
1561 hr
= StrRetToBufW(&strFile
, NULL
, wszTargetPath
, _countof(wszTargetPath
));
1568 ERR("Error obtaining target path");
1571 TRACE("target path = %s", debugstr_w(wszTargetPath
));
1573 /* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
1574 for (UINT i
= 0; i
< lpcida
->cidl
; i
++)
1576 //Find out which file we're copying
1578 hr
= psfFrom
->GetDisplayNameOf(apidl
[i
], SHGDN_FORPARSING
, &strFile
);
1581 ERR("Error source obtaining path");
1585 hr
= StrRetToBufW(&strFile
, apidl
[i
], wszPath
, _countof(wszPath
));
1588 ERR("Error putting source path into buffer");
1591 TRACE("source path = %s", debugstr_w(wszPath
));
1593 // Creating a buffer to hold the combined path
1594 WCHAR buffer_1
[MAX_PATH
] = L
"";
1598 LPWSTR pwszFileName
= PathFindFileNameW(wszPath
);
1599 LPWSTR pwszExt
= PathFindExtensionW(wszPath
);
1600 LPWSTR placementPath
= PathCombineW(lpStr1
, wszTargetPath
, pwszFileName
);
1601 CComPtr
<IPersistFile
> ppf
;
1603 //Check to see if it's already a link.
1604 if (!wcsicmp(pwszExt
, L
".lnk"))
1606 //It's a link so, we create a new one which copies the old.
1607 if(!GetUniqueFileName(placementPath
, pwszExt
, wszTarget
, TRUE
))
1609 ERR("Error getting unique file name");
1613 hr
= IShellLink_ConstructFromFile(NULL
, IID_IPersistFile
, ILCombine(pidl
, apidl
[i
]), (LPVOID
*)&ppf
);
1615 ERR("Error constructing link from file");
1619 hr
= ppf
->Save(wszTarget
, FALSE
);
1623 //It's not a link, so build a new link using the creator class and fill it in.
1624 //Create a file name for the link
1625 if (!GetUniqueFileName(placementPath
, L
".lnk", wszTarget
, TRUE
))
1627 ERR("Error creating unique file name");
1632 CComPtr
<IShellLinkW
> pLink
;
1633 hr
= CShellLink::_CreatorClass::CreateInstance(NULL
, IID_PPV_ARG(IShellLinkW
, &pLink
));
1635 ERR("Error instantiating IShellLinkW");
1639 WCHAR szDirPath
[MAX_PATH
], *pwszFile
;
1640 GetFullPathName(wszPath
, MAX_PATH
, szDirPath
, &pwszFile
);
1641 if (pwszFile
) pwszFile
[0] = 0;
1643 hr
= pLink
->SetPath(wszPath
);
1647 hr
= pLink
->SetWorkingDirectory(szDirPath
);
1651 hr
= pLink
->QueryInterface(IID_PPV_ARG(IPersistFile
, &ppf
));
1655 hr
= ppf
->Save(wszTarget
, TRUE
);
1661 hr
= this->CopyItems(psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
, bCopy
);
1665 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1666 ReleaseStgMedium(&medium
);
1668 else if (SUCCEEDED(pDataObject
->QueryGetData(&fmt2
)))
1671 InitFormatEtc (fmt2
, CF_HDROP
, TYMED_HGLOBAL
);
1672 if (SUCCEEDED(pDataObject
->GetData(&fmt2
, &medium
)) /* && SUCCEEDED(pDataObject->GetData(&fmt2, &medium))*/)
1674 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
1676 WCHAR wszTargetPath
[MAX_PATH
+ 1];
1678 LPITEMIDLIST targetpidl
;
1679 CComPtr
<IShellFolder
> psfDesktop
= NULL
;
1680 hr
= SHGetDesktopFolder(&psfDesktop
);
1683 ERR("SHGetDesktopFolder failed\n");
1687 hr
= this->QueryInterface(IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1690 hr
= ppf2
->GetCurFolder(&targetpidl
);
1693 hr
= psfDesktop
->GetDisplayNameOf(targetpidl
, SHGDN_FORPARSING
, &strFile
);
1697 hr
= StrRetToBufW(&strFile
, NULL
, wszTargetPath
, _countof(wszTargetPath
));
1698 //Double NULL terminate.
1699 wszTargetPath
[wcslen(wszTargetPath
) + 1] = '\0';
1705 ERR("Error obtaining target path");
1709 LPDROPFILES lpdf
= (LPDROPFILES
) GlobalLock(medium
.hGlobal
);
1712 ERR("Error locking global\n");
1715 pszSrcList
= (LPWSTR
) (((byte
*) lpdf
) + lpdf
->pFiles
);
1716 TRACE("Source file (just the first) = %s\n", debugstr_w(pszSrcList
));
1717 TRACE("Target path = %s\n", debugstr_w(wszTargetPath
));
1720 ZeroMemory(&op
, sizeof(op
));
1721 op
.pFrom
= pszSrcList
;
1722 op
.pTo
= wszTargetPath
;
1723 op
.hwnd
= GetActiveWindow();
1724 op
.wFunc
= bCopy
? FO_COPY
: FO_MOVE
;
1725 op
.fFlags
= FOF_ALLOWUNDO
| FOF_NOCONFIRMMKDIR
;
1726 hr
= SHFileOperationW(&op
);
1729 ERR("Error calling GetData\n");
1734 ERR("No viable drop format.\n");
1740 DWORD
CFSFolder::_DoDropThreadProc(LPVOID lpParameter
) {
1741 _DoDropData
*data
= reinterpret_cast<_DoDropData
*>(lpParameter
);
1742 HRESULT hr
= data
->This
->_DoDrop(data
->pDataObject
, data
->dwKeyState
, data
->pt
, &data
->pdwEffect
);
1743 //Release the CFSFolder and data object holds in the copying thread.
1744 data
->pAsyncOperation
->EndOperation(hr
, NULL
, data
->pdwEffect
);
1745 data
->pAsyncOperation
->Release();
1746 data
->pDataObject
->Release();
1747 data
->This
->Release();
1748 //Release the parameter from the heap.
1749 HeapFree(GetProcessHeap(), 0, data
);