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 CEnumIDListBase
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 CFSFolder::CFSFolder()
67 pclsid
= (CLSID
*)&CLSID_ShellFSFolder
;
70 m_bGroupPolicyActive
= 0;
73 CFSFolder::~CFSFolder()
75 TRACE("-- destroying IShellFolder(%p)\n", this);
82 static const shvheader GenericSFHeader
[] = {
83 {IDS_SHV_COLUMN1
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 15},
84 {IDS_SHV_COLUMN2
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
85 {IDS_SHV_COLUMN3
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10},
86 {IDS_SHV_COLUMN4
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 12},
87 {IDS_SHV_COLUMN5
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10}
90 #define GENERICSHELLVIEWCOLUMNS 5
92 /**************************************************************************
93 * SHELL32_CreatePidlFromBindCtx [internal]
95 * If the caller bound File System Bind Data, assume it is the
96 * find data for the path.
97 * This allows binding of paths that don't exist.
99 LPITEMIDLIST
SHELL32_CreatePidlFromBindCtx(IBindCtx
*pbc
, LPCWSTR path
)
101 IFileSystemBindData
*fsbd
= NULL
;
102 LPITEMIDLIST pidl
= NULL
;
103 IUnknown
*param
= NULL
;
104 WIN32_FIND_DATAW wfd
;
107 TRACE("%p %s\n", pbc
, debugstr_w(path
));
112 /* see if the caller bound File System Bind Data */
113 r
= pbc
->GetObjectParam((LPOLESTR
)STR_FILE_SYS_BIND_DATA
, ¶m
);
117 r
= param
->QueryInterface(IID_PPV_ARG(IFileSystemBindData
,&fsbd
));
120 r
= fsbd
->GetFindData(&wfd
);
123 lstrcpynW(&wfd
.cFileName
[0], path
, MAX_PATH
);
124 pidl
= _ILCreateFromFindDataW(&wfd
);
132 /**************************************************************************
133 * CFSFolder::ParseDisplayName {SHELL32}
135 * Parse a display name.
138 * hwndOwner [in] Parent window for any message's
139 * pbc [in] optional FileSystemBindData context
140 * lpszDisplayName [in] Unicode displayname.
141 * pchEaten [out] (unicode) characters processed
142 * ppidl [out] complex pidl to item
143 * pdwAttributes [out] items attributes
146 * Every folder tries to parse only its own (the leftmost) pidl and creates a
147 * subfolder to evaluate the remaining parts.
148 * Now we can parse into namespaces implemented by shell extensions
150 * Behaviour on win98: lpszDisplayName=NULL -> crash
151 * lpszDisplayName="" -> returns mycoputer-pidl
154 * pdwAttributes is not set
155 * pchEaten is not set like in windows
157 HRESULT WINAPI
CFSFolder::ParseDisplayName(HWND hwndOwner
,
159 LPOLESTR lpszDisplayName
,
160 DWORD
*pchEaten
, PIDLIST_RELATIVE
*ppidl
,
161 DWORD
*pdwAttributes
)
163 HRESULT hr
= E_INVALIDARG
;
164 LPCWSTR szNext
= NULL
;
165 WCHAR szElement
[MAX_PATH
];
166 WCHAR szPath
[MAX_PATH
];
167 LPITEMIDLIST pidlTemp
= NULL
;
170 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
171 this, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
172 pchEaten
, ppidl
, pdwAttributes
);
177 if (!lpszDisplayName
)
186 *pchEaten
= 0; /* strange but like the original */
188 if (*lpszDisplayName
)
190 /* get the next element */
191 szNext
= GetNextElementW (lpszDisplayName
, szElement
, MAX_PATH
);
193 pidlTemp
= SHELL32_CreatePidlFromBindCtx(pbc
, szElement
);
194 if (pidlTemp
!= NULL
)
196 /* We are creating an id list without ensuring that the items exist.
197 If we have a remaining path, this must be a folder.
198 We have to do it now because it is set as a file by default */
201 pidlTemp
->mkid
.abID
[0] = PT_FOLDER
;
207 /* build the full pathname to the element */
208 lstrcpynW(szPath
, sPathTarget
, MAX_PATH
- 1);
209 PathAddBackslashW(szPath
);
210 len
= wcslen(szPath
);
211 lstrcpynW(szPath
+ len
, szElement
, MAX_PATH
- len
);
214 hr
= _ILCreateFromPathW(szPath
, &pidlTemp
);
219 if (szNext
&& *szNext
)
221 /* try to analyse the next element */
222 hr
= SHELL32_ParseNextElement(this, hwndOwner
, pbc
,
223 &pidlTemp
, (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
227 /* it's the last element */
228 if (pdwAttributes
&& *pdwAttributes
)
229 hr
= SHELL32_GetFSItemAttributes(this, pidlTemp
, pdwAttributes
);
239 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl
? *ppidl
: 0, hr
);
244 /**************************************************************************
245 * CFSFolder::EnumObjects
247 * HWND hwndOwner, //[in ] Parent Window
248 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
249 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
251 HRESULT WINAPI
CFSFolder::EnumObjects(
254 LPENUMIDLIST
*ppEnumIDList
)
256 return ShellObjectCreatorInit
<CFileSysEnum
>(sPathTarget
, dwFlags
, IID_IEnumIDList
, ppEnumIDList
);
259 /**************************************************************************
260 * CFSFolder::BindToObject
262 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
263 * LPBC pbc, //[in ] optional FileSystemBindData context
264 * REFIID riid, //[in ] Initial Interface
265 * LPVOID* ppvObject //[out] Interface*
267 HRESULT WINAPI
CFSFolder::BindToObject(
268 PCUIDLIST_RELATIVE pidl
,
273 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl
, pbc
,
274 shdebugstr_guid(&riid
), ppvOut
);
276 return SHELL32_BindToFS(pidlRoot
, sPathTarget
, pidl
, riid
, ppvOut
);
279 /**************************************************************************
280 * CFSFolder::BindToStorage
282 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
283 * LPBC pbc, //[in ] reserved
284 * REFIID riid, //[in ] Initial storage interface
285 * LPVOID* ppvObject //[out] Interface* returned
287 HRESULT WINAPI
CFSFolder::BindToStorage(
288 PCUIDLIST_RELATIVE pidl
,
293 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl
, pbcReserved
,
294 shdebugstr_guid (&riid
), ppvOut
);
300 /**************************************************************************
301 * CFSFolder::CompareIDs
304 HRESULT WINAPI
CFSFolder::CompareIDs(LPARAM lParam
,
305 PCUIDLIST_RELATIVE pidl1
,
306 PCUIDLIST_RELATIVE pidl2
)
308 LPPIDLDATA pData1
= _ILGetDataPointer(pidl1
);
309 LPPIDLDATA pData2
= _ILGetDataPointer(pidl2
);
310 FileStructW
* pDataW1
= _ILGetFileStructW(pidl1
);
311 FileStructW
* pDataW2
= _ILGetFileStructW(pidl2
);
312 BOOL bIsFolder1
= _ILIsFolder(pidl1
);
313 BOOL bIsFolder2
= _ILIsFolder(pidl2
);
314 LPWSTR pExtension1
, pExtension2
;
316 if (!pDataW1
|| !pDataW2
|| LOWORD(lParam
) >= GENERICSHELLVIEWCOLUMNS
)
319 /* When sorting between a File and a Folder, the Folder gets sorted first */
320 if (bIsFolder1
!= bIsFolder2
)
322 return MAKE_COMPARE_HRESULT(bIsFolder1
? -1 : 1);
326 switch (LOWORD(lParam
))
329 result
= wcsicmp(pDataW1
->wszName
, pDataW2
->wszName
);
332 pExtension1
= PathFindExtensionW(pDataW1
->wszName
);
333 pExtension2
= PathFindExtensionW(pDataW2
->wszName
);
334 result
= wcsicmp(pExtension1
, pExtension2
);
337 result
= pData1
->u
.file
.dwFileSize
- pData2
->u
.file
.dwFileSize
;
339 case 3: /* Modified */
340 result
= pData1
->u
.file
.uFileDate
- pData2
->u
.file
.uFileDate
;
342 result
= pData1
->u
.file
.uFileTime
- pData2
->u
.file
.uFileTime
;
344 case 4: /* Attributes */
345 return SHELL32_CompareDetails(this, lParam
, pidl1
, pidl2
);
347 return MAKE_COMPARE_HRESULT(result
);
350 /**************************************************************************
351 * CFSFolder::CreateViewObject
353 HRESULT WINAPI
CFSFolder::CreateViewObject(HWND hwndOwner
,
354 REFIID riid
, LPVOID
* ppvOut
)
356 CComPtr
<IShellView
> pShellView
;
357 HRESULT hr
= E_INVALIDARG
;
359 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner
, shdebugstr_guid (&riid
),
366 if (IsEqualIID (riid
, IID_IDropTarget
))
367 hr
= ShellObjectCreatorInit
<CFSDropTarget
>(sPathTarget
, riid
, ppvOut
);
368 else if (IsEqualIID (riid
, IID_IContextMenu
))
370 FIXME ("IContextMenu not implemented\n");
373 else if (IsEqualIID (riid
, IID_IShellView
))
375 hr
= CDefView_Constructor(this, riid
, ppvOut
);
378 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut
);
382 /**************************************************************************
383 * CFSFolder::GetAttributesOf
386 * UINT cidl, //[in ] num elements in pidl array
387 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
388 * ULONG* rgfInOut) //[out] result array
391 HRESULT WINAPI
CFSFolder::GetAttributesOf(UINT cidl
,
392 PCUITEMID_CHILD_ARRAY apidl
, DWORD
* rgfInOut
)
406 LPCITEMIDLIST rpidl
= ILFindLastID(pidlRoot
);
408 if (_ILIsFolder(rpidl
) || _ILIsValue(rpidl
))
410 SHELL32_GetFSItemAttributes(this, rpidl
, rgfInOut
);
412 else if (_ILIsDrive(rpidl
))
414 IShellFolder
*psfParent
= NULL
;
415 hr
= SHBindToParent(pidlRoot
, IID_PPV_ARG(IShellFolder
, &psfParent
), NULL
);
418 hr
= psfParent
->GetAttributesOf(1, &rpidl
, (SFGAOF
*)rgfInOut
);
419 psfParent
->Release();
424 ERR("Got and unknown pidl!\n");
429 while (cidl
> 0 && *apidl
)
432 if(_ILIsFolder(*apidl
) || _ILIsValue(*apidl
))
433 SHELL32_GetFSItemAttributes(this, *apidl
, rgfInOut
);
435 ERR("Got an unknown type of pidl!!!\n");
440 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
441 *rgfInOut
&= ~SFGAO_VALIDATE
;
443 TRACE("-- result=0x%08x\n", *rgfInOut
);
448 /**************************************************************************
449 * CFSFolder::GetUIObjectOf
452 * HWND hwndOwner, //[in ] Parent window for any output
453 * UINT cidl, //[in ] array size
454 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
455 * REFIID riid, //[in ] Requested Interface
456 * UINT* prgfInOut, //[ ] reserved
457 * LPVOID* ppvObject) //[out] Resulting Interface
460 * This function gets asked to return "view objects" for one or more (multiple
462 * The viewobject typically is an COM object with one of the following
464 * IExtractIcon,IDataObject,IContextMenu
465 * In order to support icon positions in the default Listview your DataObject
466 * must implement the SetData method (in addition to GetData :) - the shell
467 * passes a barely documented "Icon positions" structure to SetData when the
468 * drag starts, and GetData's it if the drop is in another explorer window that
469 * needs the positions.
471 HRESULT WINAPI
CFSFolder::GetUIObjectOf(HWND hwndOwner
,
472 UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
473 REFIID riid
, UINT
* prgfInOut
,
477 HRESULT hr
= E_INVALIDARG
;
479 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
480 this, hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
486 if (IsEqualIID(riid
, IID_IContextMenu
) && (cidl
>= 1))
488 IContextMenu
* pCm
= NULL
;
489 hr
= CDefFolderMenu_Create2(pidlRoot
, hwndOwner
, cidl
, apidl
, static_cast<IShellFolder
*>(this), NULL
, 0, NULL
, &pCm
);
492 else if (IsEqualIID (riid
, IID_IDataObject
))
496 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
500 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, (LPCITEMIDLIST
*)&pidlRoot
, 1, (IDataObject
**)&pObj
);
503 else if ((IsEqualIID (riid
, IID_IExtractIconA
) || IsEqualIID (riid
, IID_IExtractIconW
)) && (cidl
== 1))
505 hr
= CFSExtractIcon_CreateInstance(this, apidl
[0], riid
, &pObj
);
507 else if (IsEqualIID (riid
, IID_IDropTarget
))
509 /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
510 if (cidl
!= 1 || FAILED(hr
= this->_GetDropTarget(apidl
[0], (LPVOID
*) &pObj
)))
512 IDropTarget
* pDt
= NULL
;
513 hr
= ShellObjectCreatorInit
<CFSDropTarget
>(sPathTarget
, riid
, ppvOut
);
517 else if ((IsEqualIID(riid
, IID_IShellLinkW
) ||
518 IsEqualIID(riid
, IID_IShellLinkA
)) && (cidl
== 1))
520 hr
= IShellLink_ConstructFromFile(this, apidl
[0], riid
, &pObj
);
525 if (SUCCEEDED(hr
) && !pObj
)
530 TRACE("(%p)->hr=0x%08x\n", this, hr
);
534 static const WCHAR AdvancedW
[] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
535 static const WCHAR HideFileExtW
[] = L
"HideFileExt";
536 static const WCHAR NeverShowExtW
[] = L
"NeverShowExt";
538 /******************************************************************************
539 * SHELL_FS_HideExtension [Internal]
541 * Query the registry if the filename extension of a given path should be
545 * szPath [I] Relative or absolute path of a file
548 * TRUE, if the filename's extension should be hidden
551 BOOL
SHELL_FS_HideExtension(LPWSTR szPath
)
555 DWORD dwDataSize
= sizeof (DWORD
);
556 BOOL doHide
= FALSE
; /* The default value is FALSE (win98 at least) */
558 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, AdvancedW
, 0, 0, 0, KEY_ALL_ACCESS
, 0, &hKey
, 0)) {
559 if (!RegQueryValueExW(hKey
, HideFileExtW
, 0, 0, (LPBYTE
) &dwData
, &dwDataSize
))
565 LPWSTR ext
= PathFindExtensionW(szPath
);
568 WCHAR classname
[MAX_PATH
];
569 LONG classlen
= sizeof(classname
);
571 if (!RegQueryValueW(HKEY_CLASSES_ROOT
, ext
, classname
, &classlen
))
572 if (!RegOpenKeyW(HKEY_CLASSES_ROOT
, classname
, &hKey
)) {
573 if (!RegQueryValueExW(hKey
, NeverShowExtW
, 0, NULL
, NULL
, NULL
))
582 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath
, DWORD dwFlags
)
584 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
585 if (!(dwFlags
& SHGDN_FORPARSING
) &&
586 ((dwFlags
& SHGDN_INFOLDER
) || (dwFlags
== SHGDN_NORMAL
))) {
587 if (SHELL_FS_HideExtension(szPath
) && szPath
[0] != '.')
588 PathRemoveExtensionW(szPath
);
592 /**************************************************************************
593 * CFSFolder::GetDisplayNameOf
594 * Retrieves the display name for the specified file object or subfolder
597 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
598 * DWORD dwFlags, //[in ] SHGNO formatting flags
599 * LPSTRRET lpName) //[out] Returned display name
602 * if the name is in the pidl the ret value should be a STRRET_OFFSET
605 HRESULT WINAPI
CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
,
606 DWORD dwFlags
, LPSTRRET strRet
)
608 if (!pidl
|| !strRet
)
611 /* If it is a complex pidl, let the child handle it */
612 if (!_ILIsPidlSimple (pidl
)) /* complex pidl */
614 return SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, strRet
);
616 else if (!pidl
->mkid
.cb
) /* empty pidl */
618 /* If it is an empty pidl return only the path of the folder */
619 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
620 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
623 return SHSetStrRet(strRet
, sPathTarget
);
629 LPWSTR pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
631 return E_OUTOFMEMORY
;
633 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
634 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
637 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
);
638 PathAddBackslashW(pszPath
);
639 len
= wcslen(pszPath
);
641 _ILSimpleGetTextW(pidl
, pszPath
+ len
, MAX_PATH
+ 1 - len
);
642 if (!_ILIsFolder(pidl
)) SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
644 strRet
->uType
= STRRET_WSTR
;
645 strRet
->pOleStr
= pszPath
;
647 TRACE ("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
651 /**************************************************************************
652 * CFSFolder::SetNameOf
653 * Changes the name of a file object or subfolder, possibly changing its item
654 * identifier in the process.
657 * HWND hwndOwner, //[in ] Owner window for output
658 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
659 * LPCOLESTR lpszName, //[in ] the items new display name
660 * DWORD dwFlags, //[in ] SHGNO formatting flags
661 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
663 HRESULT WINAPI
CFSFolder::SetNameOf(
665 PCUITEMID_CHILD pidl
,
668 PITEMID_CHILD
*pPidlOut
)
670 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
672 BOOL bIsFolder
= _ILIsFolder (ILFindLastID (pidl
));
674 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner
, pidl
,
675 debugstr_w (lpName
), dwFlags
, pPidlOut
);
677 /* build source path */
678 lstrcpynW(szSrc
, sPathTarget
, MAX_PATH
);
679 ptr
= PathAddBackslashW (szSrc
);
681 _ILSimpleGetTextW (pidl
, ptr
, MAX_PATH
+ 1 - (ptr
- szSrc
));
683 /* build destination path */
684 if (dwFlags
== SHGDN_NORMAL
|| dwFlags
& SHGDN_INFOLDER
) {
685 lstrcpynW(szDest
, sPathTarget
, MAX_PATH
);
686 ptr
= PathAddBackslashW (szDest
);
688 lstrcpynW(ptr
, lpName
, MAX_PATH
+ 1 - (ptr
- szDest
));
690 lstrcpynW(szDest
, lpName
, MAX_PATH
);
692 if(!(dwFlags
& SHGDN_FORPARSING
) && SHELL_FS_HideExtension(szSrc
)) {
693 WCHAR
*ext
= PathFindExtensionW(szSrc
);
695 INT len
= wcslen(szDest
);
696 lstrcpynW(szDest
+ len
, ext
, MAX_PATH
- len
);
700 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc
), debugstr_w(szDest
));
701 if (!memcmp(szSrc
, szDest
, (wcslen(szDest
) + 1) * sizeof(WCHAR
)))
703 /* src and destination is the same */
706 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
712 if (MoveFileW (szSrc
, szDest
))
717 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
719 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
720 SHCNF_PATHW
, szSrc
, szDest
);
728 HRESULT WINAPI
CFSFolder::GetDefaultSearchGUID(GUID
* pguid
)
730 FIXME ("(%p)\n", this);
734 HRESULT WINAPI
CFSFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
736 FIXME ("(%p)\n", this);
740 HRESULT WINAPI
CFSFolder::GetDefaultColumn(DWORD dwRes
,
741 ULONG
* pSort
, ULONG
* pDisplay
)
743 TRACE ("(%p)\n", this);
753 HRESULT WINAPI
CFSFolder::GetDefaultColumnState(UINT iColumn
,
756 TRACE ("(%p)\n", this);
758 if (!pcsFlags
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
761 *pcsFlags
= GenericSFHeader
[iColumn
].pcsFlags
;
766 HRESULT WINAPI
CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl
,
767 const SHCOLUMNID
* pscid
, VARIANT
* pv
)
769 FIXME ("(%p)\n", this);
774 HRESULT WINAPI
CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl
,
775 UINT iColumn
, SHELLDETAILS
* psd
)
779 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
781 if (!psd
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
786 /* the header titles */
787 psd
->fmt
= GenericSFHeader
[iColumn
].fmt
;
788 psd
->cxChar
= GenericSFHeader
[iColumn
].cxChar
;
789 return SHSetStrRet(&psd
->str
, GenericSFHeader
[iColumn
].colnameid
);
794 psd
->str
.uType
= STRRET_CSTR
;
795 /* the data from the pidl */
799 hr
= GetDisplayNameOf (pidl
,
800 SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
803 _ILGetFileSize(pidl
, psd
->str
.cStr
, MAX_PATH
);
806 _ILGetFileType(pidl
, psd
->str
.cStr
, MAX_PATH
);
809 _ILGetFileDate(pidl
, psd
->str
.cStr
, MAX_PATH
);
811 case 4: /* attributes */
812 _ILGetFileAttributes(pidl
, psd
->str
.cStr
, MAX_PATH
);
820 HRESULT WINAPI
CFSFolder::MapColumnToSCID (UINT column
,
823 FIXME ("(%p)\n", this);
827 /****************************************************************************
830 * Builds a list of paths like the one used in SHFileOperation from a table of
831 * PIDLs relative to the given base folder
834 BuildPathsList(LPCWSTR wszBasePath
, int cidl
, LPCITEMIDLIST
*pidls
)
836 WCHAR
*pwszPathsList
;
840 iPathLen
= wcslen(wszBasePath
);
841 pwszPathsList
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
) * cidl
+ 1);
842 pwszListPos
= pwszPathsList
;
844 for (i
= 0; i
< cidl
; i
++)
846 if (!_ILIsFolder(pidls
[i
]) && !_ILIsValue(pidls
[i
]))
849 wcscpy(pwszListPos
, wszBasePath
);
850 pwszListPos
+= iPathLen
;
851 /* FIXME: abort if path too long */
852 _ILSimpleGetTextW(pidls
[i
], pwszListPos
, MAX_PATH
- iPathLen
);
853 pwszListPos
+= wcslen(pwszListPos
) + 1;
856 return pwszPathsList
;
859 /****************************************************************************
860 * CFSDropTarget::CopyItems
862 * copies items to this folder
864 HRESULT WINAPI
CFSDropTarget::CopyItems(IShellFolder
* pSFFrom
, UINT cidl
,
865 LPCITEMIDLIST
* apidl
, BOOL bCopy
)
867 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
868 WCHAR szSrcPath
[MAX_PATH
];
869 WCHAR szTargetPath
[MAX_PATH
];
872 LPWSTR pszSrc
, pszTarget
, pszSrcList
, pszTargetList
, pszFileName
;
876 TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom
, cidl
, apidl
);
878 hr
= pSFFrom
->QueryInterface (IID_PPV_ARG(IPersistFolder2
, &ppf2
));
881 hr
= ppf2
->GetCurFolder(&pidl
);
887 hr
= SHGetPathFromIDListW(pidl
, szSrcPath
);
893 pszSrc
= PathAddBackslashW(szSrcPath
);
895 wcscpy(szTargetPath
, sPathTarget
);
896 pszTarget
= PathAddBackslashW(szTargetPath
);
898 pszSrcList
= BuildPathsList(szSrcPath
, cidl
, apidl
);
899 pszTargetList
= BuildPathsList(szTargetPath
, cidl
, apidl
);
901 if (!pszSrcList
|| !pszTargetList
)
904 HeapFree(GetProcessHeap(), 0, pszSrcList
);
907 HeapFree(GetProcessHeap(), 0, pszTargetList
);
910 return E_OUTOFMEMORY
;
913 ZeroMemory(&op
, sizeof(op
));
916 /* remove trailing backslash */
919 op
.pFrom
= szSrcPath
;
923 op
.pFrom
= pszSrcList
;
926 if (!pszTargetList
[0])
928 /* remove trailing backslash */
929 if (pszTarget
- szTargetPath
> 3)
932 pszTarget
[0] = L
'\0';
936 pszTarget
[1] = L
'\0';
939 op
.pTo
= szTargetPath
;
944 op
.pTo
= pszTargetList
;
945 op
.fFlags
= FOF_MULTIDESTFILES
;
947 op
.hwnd
= GetActiveWindow();
948 op
.wFunc
= bCopy
? FO_COPY
: FO_MOVE
;
949 op
.fFlags
|= FOF_ALLOWUNDO
| FOF_NOCONFIRMMKDIR
;
951 res
= SHFileOperationW(&op
);
953 if (res
== DE_SAMEFILE
)
955 length
= wcslen(szTargetPath
);
957 pszFileName
= wcsrchr(pszSrcList
, '\\');
960 if (LoadStringW(shell32_hInstance
, IDS_COPY_OF
, pszTarget
, MAX_PATH
- length
))
962 wcscat(szTargetPath
, L
" ");
965 wcscat(szTargetPath
, pszFileName
);
966 op
.pTo
= szTargetPath
;
968 res
= SHFileOperationW(&op
);
971 HeapFree(GetProcessHeap(), 0, pszSrcList
);
972 HeapFree(GetProcessHeap(), 0, pszTargetList
);
982 /************************************************************************
983 * CFSFolder::GetClassID
985 HRESULT WINAPI
CFSFolder::GetClassID(CLSID
* lpClassId
)
987 TRACE ("(%p)\n", this);
992 *lpClassId
= *pclsid
;
997 /************************************************************************
998 * CFSFolder::Initialize
1001 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1003 HRESULT WINAPI
CFSFolder::Initialize(LPCITEMIDLIST pidl
)
1005 WCHAR wszTemp
[MAX_PATH
];
1007 TRACE ("(%p)->(%p)\n", this, pidl
);
1009 SHFree (pidlRoot
); /* free the old pidl */
1010 pidlRoot
= ILClone (pidl
); /* set my pidl */
1012 SHFree (sPathTarget
);
1016 if (SHGetPathFromIDListW (pidl
, wszTemp
))
1018 int len
= wcslen(wszTemp
);
1019 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1021 return E_OUTOFMEMORY
;
1022 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1025 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget
));
1029 /**************************************************************************
1030 * CFSFolder::GetCurFolder
1032 HRESULT WINAPI
CFSFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1034 TRACE ("(%p)->(%p)\n", this, pidl
);
1039 *pidl
= ILClone(pidlRoot
);
1043 /**************************************************************************
1044 * CFSFolder::InitializeEx
1046 * FIXME: error handling
1048 HRESULT WINAPI
CFSFolder::InitializeEx(IBindCtx
* pbc
, LPCITEMIDLIST pidlRootx
,
1049 const PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1051 WCHAR wszTemp
[MAX_PATH
];
1053 TRACE("(%p)->(%p,%p,%p)\n", this, pbc
, pidlRootx
, ppfti
);
1055 TRACE("--%p %s %s 0x%08x 0x%08x\n",
1056 ppfti
->pidlTargetFolder
, debugstr_w (ppfti
->szTargetParsingName
),
1057 debugstr_w (ppfti
->szNetworkProvider
), ppfti
->dwAttributes
,
1061 if (ppfti
&& ppfti
->pidlTargetFolder
)
1062 pdump(ppfti
->pidlTargetFolder
);
1065 __SHFreeAndNil(&pidlRoot
); /* free the old */
1067 __SHFreeAndNil(&sPathTarget
);
1070 * Root path and pidl
1072 pidlRoot
= ILClone(pidlRootx
);
1075 * the target folder is spezified in csidl OR pidlTargetFolder OR
1076 * szTargetParsingName
1080 if (ppfti
->csidl
!= -1)
1082 if (SHGetSpecialFolderPathW(0, wszTemp
, ppfti
->csidl
,
1083 ppfti
->csidl
& CSIDL_FLAG_CREATE
)) {
1084 int len
= wcslen(wszTemp
);
1085 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1087 return E_OUTOFMEMORY
;
1088 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1091 else if (ppfti
->szTargetParsingName
[0])
1093 int len
= wcslen(ppfti
->szTargetParsingName
);
1094 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1096 return E_OUTOFMEMORY
;
1097 memcpy(sPathTarget
, ppfti
->szTargetParsingName
,
1098 (len
+ 1) * sizeof(WCHAR
));
1100 else if (ppfti
->pidlTargetFolder
)
1102 if (SHGetPathFromIDListW(ppfti
->pidlTargetFolder
, wszTemp
))
1104 int len
= wcslen(wszTemp
);
1105 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1107 return E_OUTOFMEMORY
;
1108 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1113 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget
));
1115 return (sPathTarget
) ? S_OK
: E_FAIL
;
1118 HRESULT WINAPI
CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1120 FIXME("(%p)->(%p)\n", this, ppfti
);
1121 ZeroMemory(ppfti
, sizeof (*ppfti
));
1125 CFSDropTarget::CFSDropTarget():
1132 HRESULT WINAPI
CFSDropTarget::Initialize(LPWSTR PathTarget
)
1134 cfShellIDList
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
1138 sPathTarget
= (WCHAR
*)SHAlloc((wcslen(PathTarget
) + 1) * sizeof(WCHAR
));
1140 return E_OUTOFMEMORY
;
1141 wcscpy(sPathTarget
, PathTarget
);
1146 CFSDropTarget::~CFSDropTarget()
1148 SHFree(sPathTarget
);
1152 CFSDropTarget::GetUniqueFileName(LPWSTR pwszBasePath
, LPCWSTR pwszExt
, LPWSTR pwszTarget
, BOOL bShortcut
)
1158 if (!LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, wszLink
, _countof(wszLink
)))
1163 swprintf(pwszTarget
, L
"%s%s%s", wszLink
, pwszBasePath
, pwszExt
);
1165 swprintf(pwszTarget
, L
"%s%s", pwszBasePath
, pwszExt
);
1167 for (UINT i
= 2; PathFileExistsW(pwszTarget
); ++i
)
1170 swprintf(pwszTarget
, L
"%s%s (%u)%s", wszLink
, pwszBasePath
, i
, pwszExt
);
1172 swprintf(pwszTarget
, L
"%s (%u)%s", pwszBasePath
, i
, pwszExt
);
1178 /****************************************************************************
1179 * IDropTarget implementation
1181 BOOL
CFSDropTarget::QueryDrop(DWORD dwKeyState
, LPDWORD pdwEffect
)
1183 /* TODO Windows does different drop effects if dragging across drives.
1184 i.e., it will copy instead of move if the directories are on different disks. */
1186 DWORD dwEffect
= DROPEFFECT_MOVE
;
1188 *pdwEffect
= DROPEFFECT_NONE
;
1190 if (fAcceptFmt
) { /* Does our interpretation of the keystate ... */
1191 *pdwEffect
= KeyStateToDropEffect (dwKeyState
);
1193 if (*pdwEffect
== DROPEFFECT_NONE
)
1194 *pdwEffect
= dwEffect
;
1196 /* ... matches the desired effect ? */
1197 if (dwEffect
& *pdwEffect
) {
1204 HRESULT WINAPI
CFSDropTarget::DragEnter(IDataObject
*pDataObject
,
1205 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1207 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject
);
1212 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
1213 InitFormatEtc (fmt2
, CF_HDROP
, TYMED_HGLOBAL
);
1215 if (SUCCEEDED(pDataObject
->QueryGetData(&fmt
)))
1217 else if (SUCCEEDED(pDataObject
->QueryGetData(&fmt2
)))
1220 QueryDrop(dwKeyState
, pdwEffect
);
1224 HRESULT WINAPI
CFSDropTarget::DragOver(DWORD dwKeyState
, POINTL pt
,
1227 TRACE("(%p)\n", this);
1230 return E_INVALIDARG
;
1232 QueryDrop(dwKeyState
, pdwEffect
);
1237 HRESULT WINAPI
CFSDropTarget::DragLeave()
1239 TRACE("(%p)\n", this);
1246 HRESULT WINAPI
CFSDropTarget::Drop(IDataObject
*pDataObject
,
1247 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1249 TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect
);
1252 return E_INVALIDARG
;
1254 QueryDrop(dwKeyState
, pdwEffect
);
1256 BOOL fIsOpAsync
= FALSE
;
1257 CComPtr
<IAsyncOperation
> pAsyncOperation
;
1259 if (SUCCEEDED(pDataObject
->QueryInterface(IID_PPV_ARG(IAsyncOperation
, &pAsyncOperation
))))
1261 if (SUCCEEDED(pAsyncOperation
->GetAsyncMode(&fIsOpAsync
)) && fIsOpAsync
)
1263 _DoDropData
*data
= static_cast<_DoDropData
*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData
)));
1265 // Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
1266 pDataObject
->AddRef();
1267 pAsyncOperation
->StartOperation(NULL
);
1268 CoMarshalInterThreadInterfaceInStream(IID_IDataObject
, pDataObject
, &data
->pStream
);
1270 data
->dwKeyState
= dwKeyState
;
1272 // Need to dereference as pdweffect gets freed.
1273 data
->pdwEffect
= *pdwEffect
;
1274 SHCreateThread(CFSDropTarget::_DoDropThreadProc
, data
, NULL
, NULL
);
1278 return this->_DoDrop(pDataObject
, dwKeyState
, pt
, pdwEffect
);
1281 HRESULT WINAPI
CFSDropTarget::_DoDrop(IDataObject
*pDataObject
,
1282 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1284 TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect
);
1289 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
1290 InitFormatEtc (fmt2
, CF_HDROP
, TYMED_HGLOBAL
);
1294 bool bLinking
= FALSE
;
1296 /* Figure out what drop operation we're doing */
1299 TRACE("Current drop effect flag %i\n", *pdwEffect
);
1300 if ((*pdwEffect
& DROPEFFECT_MOVE
) == DROPEFFECT_MOVE
)
1302 if ((*pdwEffect
& DROPEFFECT_LINK
) == DROPEFFECT_LINK
)
1306 if (SUCCEEDED(pDataObject
->QueryGetData(&fmt
)))
1308 hr
= pDataObject
->GetData(&fmt
, &medium
);
1309 TRACE("CFSTR_SHELLIDLIST.\n");
1311 /* lock the handle */
1312 LPIDA lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
1315 ReleaseStgMedium(&medium
);
1319 /* convert the data into pidl */
1321 LPITEMIDLIST
*apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1324 ReleaseStgMedium(&medium
);
1328 CComPtr
<IShellFolder
> psfDesktop
;
1329 CComPtr
<IShellFolder
> psfFrom
= NULL
;
1331 /* Grab the desktop shell folder */
1332 hr
= SHGetDesktopFolder(&psfDesktop
);
1335 ERR("SHGetDesktopFolder failed\n");
1337 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1338 ReleaseStgMedium(&medium
);
1342 /* Find source folder, this is where the clipboard data was copied from */
1343 if (_ILIsDesktop(pidl
))
1345 /* use desktop shell folder */
1346 psfFrom
= psfDesktop
;
1350 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfFrom
));
1353 ERR("no IShellFolder\n");
1355 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1356 ReleaseStgMedium(&medium
);
1363 WCHAR wszTargetPath
[MAX_PATH
];
1364 WCHAR wszPath
[MAX_PATH
];
1365 WCHAR wszTarget
[MAX_PATH
];
1367 wcscpy(wszTargetPath
, sPathTarget
);
1369 TRACE("target path = %s", debugstr_w(wszTargetPath
));
1371 /* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
1372 for (UINT i
= 0; i
< lpcida
->cidl
; i
++)
1374 //Find out which file we're copying
1376 hr
= psfFrom
->GetDisplayNameOf(apidl
[i
], SHGDN_FORPARSING
, &strFile
);
1379 ERR("Error source obtaining path");
1383 hr
= StrRetToBufW(&strFile
, apidl
[i
], wszPath
, _countof(wszPath
));
1386 ERR("Error putting source path into buffer");
1389 TRACE("source path = %s", debugstr_w(wszPath
));
1391 // Creating a buffer to hold the combined path
1392 WCHAR buffer_1
[MAX_PATH
] = L
"";
1396 LPWSTR pwszFileName
= PathFindFileNameW(wszPath
);
1397 LPWSTR pwszExt
= PathFindExtensionW(wszPath
);
1398 LPWSTR placementPath
= PathCombineW(lpStr1
, sPathTarget
, pwszFileName
);
1399 CComPtr
<IPersistFile
> ppf
;
1401 //Check to see if it's already a link.
1402 if (!wcsicmp(pwszExt
, L
".lnk"))
1404 //It's a link so, we create a new one which copies the old.
1405 if(!GetUniqueFileName(placementPath
, pwszExt
, wszTarget
, TRUE
))
1407 ERR("Error getting unique file name");
1411 hr
= IShellLink_ConstructFromPath(wszPath
, IID_PPV_ARG(IPersistFile
, &ppf
));
1413 ERR("Error constructing link from file");
1417 hr
= ppf
->Save(wszTarget
, FALSE
);
1420 SHChangeNotify(SHCNE_CREATE
, SHCNF_PATHW
, wszTarget
, NULL
);
1424 //It's not a link, so build a new link using the creator class and fill it in.
1425 //Create a file name for the link
1426 if (!GetUniqueFileName(placementPath
, L
".lnk", wszTarget
, TRUE
))
1428 ERR("Error creating unique file name");
1433 CComPtr
<IShellLinkW
> pLink
;
1434 hr
= CShellLink::_CreatorClass::CreateInstance(NULL
, IID_PPV_ARG(IShellLinkW
, &pLink
));
1436 ERR("Error instantiating IShellLinkW");
1440 WCHAR szDirPath
[MAX_PATH
], *pwszFile
;
1441 GetFullPathName(wszPath
, MAX_PATH
, szDirPath
, &pwszFile
);
1442 if (pwszFile
) pwszFile
[0] = 0;
1444 hr
= pLink
->SetPath(wszPath
);
1448 hr
= pLink
->SetWorkingDirectory(szDirPath
);
1452 hr
= pLink
->QueryInterface(IID_PPV_ARG(IPersistFile
, &ppf
));
1456 hr
= ppf
->Save(wszTarget
, TRUE
);
1459 SHChangeNotify(SHCNE_CREATE
, SHCNF_PATHW
, wszTarget
, NULL
);
1465 hr
= this->CopyItems(psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
, bCopy
);
1469 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1470 ReleaseStgMedium(&medium
);
1472 else if (SUCCEEDED(pDataObject
->QueryGetData(&fmt2
)))
1475 InitFormatEtc (fmt2
, CF_HDROP
, TYMED_HGLOBAL
);
1476 if (SUCCEEDED(pDataObject
->GetData(&fmt2
, &medium
)) /* && SUCCEEDED(pDataObject->GetData(&fmt2, &medium))*/)
1478 WCHAR wszTargetPath
[MAX_PATH
+ 1];
1481 wcscpy(wszTargetPath
, sPathTarget
);
1482 //Double NULL terminate.
1483 wszTargetPath
[wcslen(wszTargetPath
) + 1] = '\0';
1485 LPDROPFILES lpdf
= (LPDROPFILES
) GlobalLock(medium
.hGlobal
);
1488 ERR("Error locking global\n");
1491 pszSrcList
= (LPWSTR
) (((byte
*) lpdf
) + lpdf
->pFiles
);
1492 TRACE("Source file (just the first) = %s\n", debugstr_w(pszSrcList
));
1493 TRACE("Target path = %s\n", debugstr_w(wszTargetPath
));
1496 ZeroMemory(&op
, sizeof(op
));
1497 op
.pFrom
= pszSrcList
;
1498 op
.pTo
= wszTargetPath
;
1499 op
.hwnd
= GetActiveWindow();
1500 op
.wFunc
= bCopy
? FO_COPY
: FO_MOVE
;
1501 op
.fFlags
= FOF_ALLOWUNDO
| FOF_NOCONFIRMMKDIR
;
1502 hr
= SHFileOperationW(&op
);
1505 ERR("Error calling GetData\n");
1510 ERR("No viable drop format.\n");
1516 DWORD WINAPI
CFSDropTarget::_DoDropThreadProc(LPVOID lpParameter
)
1519 _DoDropData
*data
= static_cast<_DoDropData
*>(lpParameter
);
1520 CComPtr
<IDataObject
> pDataObject
;
1521 HRESULT hr
= CoGetInterfaceAndReleaseStream (data
->pStream
, IID_PPV_ARG(IDataObject
, &pDataObject
));
1525 CComPtr
<IAsyncOperation
> pAsyncOperation
;
1526 hr
= data
->This
->_DoDrop(pDataObject
, data
->dwKeyState
, data
->pt
, &data
->pdwEffect
);
1527 if (SUCCEEDED(pDataObject
->QueryInterface(IID_PPV_ARG(IAsyncOperation
, &pAsyncOperation
))))
1529 pAsyncOperation
->EndOperation(hr
, NULL
, data
->pdwEffect
);
1532 //Release the CFSFolder and data object holds in the copying thread.
1533 data
->This
->Release();
1534 //Release the parameter from the heap.
1535 HeapFree(GetProcessHeap(), 0, data
);
1540 HRESULT WINAPI
CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl
, LPVOID
*ppvOut
) {
1544 TRACE("CFSFolder::_GetDropTarget entered\n");
1546 if (_ILIsFolder (pidl
))
1548 CComPtr
<IShellFolder
> psfChild
;
1549 hr
= this->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
1550 if (FAILED_UNEXPECTEDLY(hr
))
1553 return psfChild
->CreateViewObject(NULL
, IID_IDropTarget
, ppvOut
);
1557 hr
= this->GetDisplayNameOf(pidl
, SHGDN_FORPARSING
, &strFile
);
1560 WCHAR wszPath
[MAX_PATH
];
1561 hr
= StrRetToBufW(&strFile
, pidl
, wszPath
, _countof(wszPath
));
1565 LPCWSTR pwszExt
= PathFindExtensionW(wszPath
);
1568 /* enumerate dynamic/static for a given file class */
1569 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pwszExt
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
1571 /* load dynamic extensions from file extension key, for example .jpg */
1572 _LoadDynamicDropTargetHandlerForKey(hKey
, wszPath
, ppvOut
);
1577 DWORD dwSize
= sizeof(wszTemp
);
1578 if (RegGetValueW(HKEY_CLASSES_ROOT
, pwszExt
, NULL
, RRF_RT_REG_SZ
, NULL
, wszTemp
, &dwSize
) == ERROR_SUCCESS
)
1580 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
1582 /* load dynamic extensions from progid key, for example jpegfile */
1583 _LoadDynamicDropTargetHandlerForKey(hKey
, wszPath
, ppvOut
);
1591 ERR("GetDisplayNameOf failed: %x\n", hr
);
1596 HRESULT WINAPI
CFSFolder::_LoadDynamicDropTargetHandlerForKey(HKEY hRootKey
, LPCWSTR pwcsname
, LPVOID
*ppvOut
)
1598 TRACE("CFSFolder::_LoadDynamicDropTargetHandlerForKey entered\n");
1600 WCHAR wszName
[MAX_PATH
], *pwszClsid
;
1601 DWORD dwSize
= sizeof(wszName
);
1604 if (RegGetValueW(hRootKey
, L
"shellex\\DropHandler", NULL
, RRF_RT_REG_SZ
, NULL
, wszName
, &dwSize
) == ERROR_SUCCESS
)
1607 hr
= CLSIDFromString(wszName
, &clsid
);
1609 pwszClsid
= wszName
;
1611 if (m_bGroupPolicyActive
)
1613 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
1614 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1619 NULL
) == ERROR_SUCCESS
)
1621 hr
= _LoadDynamicDropTargetHandler(&clsid
, pwcsname
, ppvOut
);
1626 hr
= _LoadDynamicDropTargetHandler(&clsid
, pwcsname
, ppvOut
);
1634 HRESULT WINAPI
CFSFolder::_LoadDynamicDropTargetHandler(const CLSID
*pclsid
, LPCWSTR pwcsname
, LPVOID
*ppvOut
)
1636 TRACE("CFSFolder::_LoadDynamicDropTargetHandler entered\n");
1639 CComPtr
<IPersistFile
> pp
;
1640 hr
= SHCoCreateInstance(NULL
, pclsid
, NULL
, IID_PPV_ARG(IPersistFile
, &pp
));
1643 ERR("SHCoCreateInstance failed %x\n", GetLastError());
1645 pp
->Load(pwcsname
, 0);
1647 hr
= pp
->QueryInterface(IID_PPV_ARG(IDropTarget
, (IDropTarget
**) ppvOut
));
1650 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr
, wine_dbgstr_guid(pclsid
));