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
29 #define NONAMELESSUNION
42 #include "shell32_main.h"
45 #include "shellfolder.h"
46 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
52 /***********************************************************************
53 * IShellFolder implementation
57 IUnknown IUnknown_inner
;
59 IShellFolder2 IShellFolder2_iface
;
60 IPersistFolder3 IPersistFolder3_iface
;
61 IPersistPropertyBag IPersistPropertyBag_iface
;
62 IDropTarget IDropTarget_iface
;
63 ISFHelper ISFHelper_iface
;
68 /* both paths are parsible from the desktop */
69 LPWSTR sPathTarget
; /* complete path to target used for enumeration and ChangeNotify */
71 LPITEMIDLIST pidlRoot
; /* absolute pidl */
72 DWORD drop_effects_mask
;
75 static UINT cfShellIDList
;
77 static inline IGenericSFImpl
*impl_from_IUnknown(IUnknown
*iface
)
79 return CONTAINING_RECORD(iface
, IGenericSFImpl
, IUnknown_inner
);
82 static inline IGenericSFImpl
*impl_from_IShellFolder2(IShellFolder2
*iface
)
84 return CONTAINING_RECORD(iface
, IGenericSFImpl
, IShellFolder2_iface
);
87 static inline IGenericSFImpl
*impl_from_IPersistFolder3(IPersistFolder3
*iface
)
89 return CONTAINING_RECORD(iface
, IGenericSFImpl
, IPersistFolder3_iface
);
92 static inline IGenericSFImpl
*impl_from_IPersistPropertyBag(IPersistPropertyBag
*iface
)
94 return CONTAINING_RECORD(iface
, IGenericSFImpl
, IPersistPropertyBag_iface
);
97 static inline IGenericSFImpl
*impl_from_IDropTarget(IDropTarget
*iface
)
99 return CONTAINING_RECORD(iface
, IGenericSFImpl
, IDropTarget_iface
);
102 static inline IGenericSFImpl
*impl_from_ISFHelper(ISFHelper
*iface
)
104 return CONTAINING_RECORD(iface
, IGenericSFImpl
, ISFHelper_iface
);
107 /**************************************************************************
110 static HRESULT WINAPI
IUnknown_fnQueryInterface(IUnknown
*iface
, REFIID riid
, void **ppvObj
)
112 IGenericSFImpl
*This
= impl_from_IUnknown(iface
);
114 TRACE("(%p)->(%s,%p)\n", This
, shdebugstr_guid(riid
), ppvObj
);
118 if (IsEqualIID (riid
, &IID_IUnknown
))
119 *ppvObj
= &This
->IUnknown_inner
;
120 else if (IsEqualIID(riid
, &IID_IShellFolder
) || IsEqualIID(riid
, &IID_IShellFolder2
))
121 *ppvObj
= &This
->IShellFolder2_iface
;
122 else if (IsEqualIID(riid
, &IID_IPersist
) || IsEqualIID(riid
, &IID_IPersistFolder
) ||
123 IsEqualIID(riid
, &IID_IPersistFolder2
) || IsEqualIID(riid
, &IID_IPersistFolder3
))
124 *ppvObj
= &This
->IPersistFolder3_iface
;
125 else if (IsEqualIID(&IID_IPersistPropertyBag
, riid
))
126 *ppvObj
= &This
->IPersistPropertyBag_iface
;
127 else if (IsEqualIID (riid
, &IID_ISFHelper
))
128 *ppvObj
= &This
->ISFHelper_iface
;
129 else if (IsEqualIID (riid
, &IID_IDropTarget
)) {
130 *ppvObj
= &This
->IDropTarget_iface
;
131 if (!cfShellIDList
) cfShellIDList
= RegisterClipboardFormatW(CFSTR_SHELLIDLISTW
);
135 IUnknown_AddRef((IUnknown
*)*ppvObj
);
136 TRACE ("-- Interface = %p\n", *ppvObj
);
139 TRACE ("-- Interface: E_NOINTERFACE\n");
140 return E_NOINTERFACE
;
143 static ULONG WINAPI
IUnknown_fnAddRef(IUnknown
*iface
)
145 IGenericSFImpl
*This
= impl_from_IUnknown(iface
);
146 ULONG ref
= InterlockedIncrement(&This
->ref
);
148 TRACE("(%p) ref=%ld\n", This
, ref
);
153 static ULONG WINAPI
IUnknown_fnRelease(IUnknown
*iface
)
155 IGenericSFImpl
*This
= impl_from_IUnknown(iface
);
156 ULONG ref
= InterlockedDecrement(&This
->ref
);
158 TRACE("(%p) ref=%ld\n", This
, ref
);
161 TRACE("-- destroying IShellFolder(%p)\n", This
);
163 SHFree(This
->pidlRoot
);
164 SHFree(This
->sPathTarget
);
170 static const IUnknownVtbl unkvt
=
172 IUnknown_fnQueryInterface
,
177 static const shvheader GenericSFHeader
[] =
179 { &FMTID_Storage
, PID_STG_NAME
, IDS_SHV_COLUMN1
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15 },
180 { &FMTID_Storage
, PID_STG_SIZE
, IDS_SHV_COLUMN2
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10 },
181 { &FMTID_Storage
, PID_STG_STORAGETYPE
, IDS_SHV_COLUMN3
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10 },
182 { &FMTID_Storage
, PID_STG_WRITETIME
, IDS_SHV_COLUMN4
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 12 },
183 { &FMTID_Storage
, PID_STG_ATTRIBUTES
, IDS_SHV_COLUMN5
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 5 },
186 #define GENERICSHELLVIEWCOLUMNS 5
188 /**************************************************************************
189 * IShellFolder_fnQueryInterface
191 static HRESULT WINAPI
IShellFolder_fnQueryInterface(IShellFolder2
*iface
, REFIID riid
,
194 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
196 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppvObj
);
199 /**************************************************************************
200 * IShellFolder_AddRef
202 static ULONG WINAPI
IShellFolder_fnAddRef(IShellFolder2
*iface
)
204 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
206 return IUnknown_AddRef(This
->outer_unk
);
209 /**************************************************************************
210 * IShellFolder_fnRelease
212 static ULONG WINAPI
IShellFolder_fnRelease(IShellFolder2
*iface
)
214 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
216 return IUnknown_Release(This
->outer_unk
);
219 /**************************************************************************
220 * SHELL32_CreatePidlFromBindCtx [internal]
222 * If the caller bound File System Bind Data, assume it is the
223 * find data for the path.
224 * This allows binding of paths that don't exist.
226 LPITEMIDLIST
SHELL32_CreatePidlFromBindCtx(IBindCtx
*pbc
, LPCWSTR path
)
228 IFileSystemBindData
*fsbd
= NULL
;
229 LPITEMIDLIST pidl
= NULL
;
230 IUnknown
*unk
= NULL
;
233 TRACE("%p %s\n", pbc
, debugstr_w(path
));
238 /* see if the caller bound File System Bind Data */
239 r
= IBindCtx_GetObjectParam( pbc
, (WCHAR
*)L
"File System Bind Data", &unk
);
243 r
= IUnknown_QueryInterface( unk
, &IID_IFileSystemBindData
, (void**)&fsbd
);
246 WIN32_FIND_DATAW wfd
;
248 r
= IFileSystemBindData_GetFindData( fsbd
, &wfd
);
251 lstrcpynW( &wfd
.cFileName
[0], path
, MAX_PATH
);
252 pidl
= _ILCreateFromFindDataW( &wfd
);
254 IFileSystemBindData_Release( fsbd
);
256 IUnknown_Release( unk
);
261 /**************************************************************************
262 * IShellFolder_ParseDisplayName {SHELL32}
264 * Parse a display name.
267 * hwndOwner [in] Parent window for any message's
268 * pbc [in] optional FileSystemBindData context
269 * lpszDisplayName [in] Unicode displayname.
270 * pchEaten [out] (unicode) characters processed
271 * ppidl [out] complex pidl to item
272 * pdwAttributes [out] items attributes
275 * Every folder tries to parse only its own (the leftmost) pidl and creates a
276 * subfolder to evaluate the remaining parts.
277 * Now we can parse into namespaces implemented by shell extensions
279 * Behaviour on win98: lpszDisplayName=NULL -> crash
280 * lpszDisplayName="" -> returns mycomputer-pidl
283 * pdwAttributes is not set
284 * pchEaten is not set like in windows
286 static HRESULT WINAPI
287 IShellFolder_fnParseDisplayName (IShellFolder2
* iface
,
290 LPOLESTR lpszDisplayName
,
291 DWORD
* pchEaten
, LPITEMIDLIST
* ppidl
,
292 DWORD
* pdwAttributes
)
294 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
297 LPCWSTR szNext
= NULL
;
298 WCHAR
*p
, szPath
[MAX_PATH
];
299 WIN32_FIND_DATAW find_data
= { 0 };
300 IFileSystemBindData
*fsbd
= NULL
;
301 LPITEMIDLIST pidlTemp
= NULL
;
304 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
305 This
, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
306 pchEaten
, ppidl
, pdwAttributes
);
308 if (!lpszDisplayName
|| !lpszDisplayName
[0] || !ppidl
) return E_INVALIDARG
;
311 *pchEaten
= 0; /* strange but like the original */
317 /* see if the caller bound File System Bind Data */
318 if (SUCCEEDED( IBindCtx_GetObjectParam( pbc
, (WCHAR
*)L
"File System Bind Data", &unk
)))
320 IUnknown_QueryInterface( unk
, &IID_IFileSystemBindData
, (void**)&fsbd
);
321 IUnknown_Release( unk
);
325 if (*lpszDisplayName
)
327 /* build the full pathname to the element */
328 lstrcpynW(szPath
, This
->sPathTarget
, MAX_PATH
- 1);
329 PathAddBackslashW(szPath
);
330 len
= lstrlenW(szPath
);
331 /* get the next element */
332 szNext
= GetNextElementW( lpszDisplayName
, szPath
+ len
, MAX_PATH
- len
);
334 if (IsEqualCLSID( This
->pclsid
, &CLSID_UnixFolder
) && lpszDisplayName
[0] == '/')
336 lstrcpynW( szPath
+ len
, lpszDisplayName
+ 1, MAX_PATH
- len
);
337 for (p
= szPath
+ len
; *p
; p
++) if (*p
== '/') *p
= '\\';
339 else if (!wcsnicmp( lpszDisplayName
, L
"\\\\?\\unix\\", 9 ))
341 lstrcpynW( szPath
+ len
, lpszDisplayName
+ 9, MAX_PATH
- len
);
342 if ((p
= wcschr( szPath
+ len
, '\\' )))
343 while (*p
== '\\') *p
++ = 0;
347 /* Special case for the root folder. */
348 if (!wcsicmp( szPath
, L
"\\\\?\\unix\\" ))
350 *ppidl
= SHAlloc(sizeof(USHORT
));
351 if (!*ppidl
) return E_FAIL
;
352 (*ppidl
)->mkid
.cb
= 0; /* Terminate the ITEMIDLIST */
356 PathRemoveBackslashW( szPath
);
358 if (szNext
&& *szNext
)
360 hr
= _ILCreateFromPathW( szPath
, &pidlTemp
);
361 if (hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
) && fsbd
)
363 find_data
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
364 lstrcpyW( find_data
.cFileName
, szPath
+ len
);
365 pidlTemp
= _ILCreateFromFindDataW( &find_data
);
367 if (pidlTemp
) /* try to analyse the next element */
368 hr
= SHELL32_ParseNextElement( iface
, hwndOwner
, pbc
, &pidlTemp
,
369 (WCHAR
*)szNext
, pchEaten
, pdwAttributes
);
371 else /* it's the last element */
375 if (FAILED( IFileSystemBindData_GetFindData( fsbd
, &find_data
)))
376 find_data
.dwFileAttributes
= FILE_ATTRIBUTE_NORMAL
;
377 lstrcpyW( find_data
.cFileName
, szPath
+ len
);
378 pidlTemp
= _ILCreateFromFindDataW( &find_data
);
380 else hr
= _ILCreateFromPathW(szPath
, &pidlTemp
);
382 if (pidlTemp
&& pdwAttributes
&& *pdwAttributes
)
383 hr
= SHELL32_GetItemAttributes(&This
->IShellFolder2_iface
, pidlTemp
, pdwAttributes
);
392 TRACE ("(%p)->(-- pidl=%p ret=0x%08lx)\n", This
, *ppidl
, hr
);
394 if (fsbd
) IFileSystemBindData_Release( fsbd
);
398 /**************************************************************************
399 * IShellFolder_fnEnumObjects
401 * HWND hwndOwner, //[in ] Parent Window
402 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
403 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
405 static HRESULT WINAPI
406 IShellFolder_fnEnumObjects (IShellFolder2
* iface
, HWND hwndOwner
,
407 DWORD dwFlags
, LPENUMIDLIST
* ppEnumIDList
)
409 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
410 IEnumIDListImpl
*list
;
412 TRACE ("(%p)->(HWND=%p flags=0x%08lx pplist=%p)\n", This
, hwndOwner
,
413 dwFlags
, ppEnumIDList
);
415 if (!(list
= IEnumIDList_Constructor()))
416 return E_OUTOFMEMORY
;
417 CreateFolderEnumList(list
, This
->sPathTarget
, dwFlags
);
418 *ppEnumIDList
= &list
->IEnumIDList_iface
;
420 TRACE ("-- (%p)->(new ID List: %p)\n", This
, *ppEnumIDList
);
425 /**************************************************************************
426 * IShellFolder_fnBindToObject
428 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
429 * LPBC pbc, //[in ] optional FileSystemBindData context
430 * REFIID riid, //[in ] Initial Interface
431 * LPVOID* ppvObject //[out] Interface*
433 static HRESULT WINAPI
434 IShellFolder_fnBindToObject (IShellFolder2
* iface
, LPCITEMIDLIST pidl
,
435 LPBC pbc
, REFIID riid
, LPVOID
* ppvOut
)
437 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
438 const CLSID
*clsid
= This
->pclsid
;
440 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This
, pidl
, pbc
,
441 shdebugstr_guid (riid
), ppvOut
);
443 if (!IsEqualCLSID( clsid
, &CLSID_UnixFolder
) && !IsEqualCLSID( clsid
, &CLSID_UnixDosFolder
))
444 clsid
= &CLSID_ShellFSFolder
;
446 return SHELL32_BindToChild (This
->pidlRoot
, clsid
, This
->sPathTarget
, pidl
, riid
, ppvOut
);
449 /**************************************************************************
450 * IShellFolder_fnBindToStorage
452 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
453 * LPBC pbc, //[in ] reserved
454 * REFIID riid, //[in ] Initial storage interface
455 * LPVOID* ppvObject //[out] Interface* returned
457 static HRESULT WINAPI
458 IShellFolder_fnBindToStorage (IShellFolder2
* iface
, LPCITEMIDLIST pidl
,
459 LPBC pbcReserved
, REFIID riid
, LPVOID
* ppvOut
)
461 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
463 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This
, pidl
, pbcReserved
,
464 shdebugstr_guid (riid
), ppvOut
);
470 /**************************************************************************
471 * IShellFolder_fnCompareIDs
474 static HRESULT WINAPI
475 IShellFolder_fnCompareIDs (IShellFolder2
* iface
, LPARAM lParam
,
476 LPCITEMIDLIST pidl1
, LPCITEMIDLIST pidl2
)
478 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
482 TRACE ("(%p)->(0x%08Ix,pidl1=%p,pidl2=%p)\n", This
, lParam
, pidl1
, pidl2
);
483 nReturn
= SHELL32_CompareIDs(&This
->IShellFolder2_iface
, lParam
, pidl1
, pidl2
);
484 TRACE ("-- %i\n", nReturn
);
488 /**************************************************************************
489 * IShellFolder_fnCreateViewObject
491 static HRESULT WINAPI
492 IShellFolder_fnCreateViewObject (IShellFolder2
* iface
, HWND hwndOwner
,
493 REFIID riid
, LPVOID
* ppvOut
)
495 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
497 LPSHELLVIEW pShellView
;
498 HRESULT hr
= E_INVALIDARG
;
500 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This
, hwndOwner
, shdebugstr_guid (riid
),
506 if (IsEqualIID (riid
, &IID_IDropTarget
)) {
507 hr
= IShellFolder2_QueryInterface (iface
, &IID_IDropTarget
, ppvOut
);
508 } else if (IsEqualIID (riid
, &IID_IContextMenu
)) {
509 hr
= BackgroundMenu_Constructor((IShellFolder
*)iface
, FALSE
, riid
, ppvOut
);
510 } else if (IsEqualIID (riid
, &IID_IShellView
)) {
511 pShellView
= IShellView_Constructor ((IShellFolder
*) iface
);
513 hr
= IShellView_QueryInterface (pShellView
, riid
, ppvOut
);
514 IShellView_Release (pShellView
);
518 TRACE ("-- (%p)->(interface=%p)\n", This
, ppvOut
);
522 /**************************************************************************
523 * IShellFolder_fnGetAttributesOf
526 * UINT cidl, //[in ] num elements in pidl array
527 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
528 * ULONG* rgfInOut) //[out] result array
531 static HRESULT WINAPI
532 IShellFolder_fnGetAttributesOf (IShellFolder2
* iface
, UINT cidl
,
533 LPCITEMIDLIST
* apidl
, DWORD
* rgfInOut
)
535 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
539 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n", This
, cidl
, apidl
,
540 rgfInOut
, rgfInOut
? *rgfInOut
: 0);
551 IShellFolder2
*parent
= NULL
;
552 LPCITEMIDLIST rpidl
= NULL
;
554 if (_ILIsSpecialFolder(This
->pidlRoot
))
556 *rgfInOut
&= (SFGAO_HASSUBFOLDER
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
|
557 SFGAO_DROPTARGET
| SFGAO_HASPROPSHEET
| SFGAO_CANRENAME
);
561 hr
= SHBindToParent(This
->pidlRoot
, &IID_IShellFolder2
, (void **)&parent
, &rpidl
);
563 SHELL32_GetItemAttributes(parent
, rpidl
, rgfInOut
);
564 IShellFolder2_Release(parent
);
569 while (cidl
> 0 && *apidl
) {
571 SHELL32_GetItemAttributes(&This
->IShellFolder2_iface
, *apidl
, rgfInOut
);
576 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
577 *rgfInOut
&= ~SFGAO_VALIDATE
;
579 TRACE ("-- result=0x%08lx\n", *rgfInOut
);
584 /**************************************************************************
585 * SHELL32_CreateExtensionUIObject (internal)
587 static HRESULT
SHELL32_CreateExtensionUIObject(IShellFolder2
*iface
,
588 LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
*ppvOut
)
590 IPersistFile
*persist_file
;
592 WCHAR extensionW
[20], buf
[MAX_PATH
];
593 DWORD size
= MAX_PATH
;
601 if(!_ILGetExtension(pidl
, extensionA
, 20))
604 MultiByteToWideChar(CP_ACP
, 0, extensionA
, -1, extensionW
, 20);
606 swprintf(buf
, ARRAY_SIZE(buf
), L
".%s\\ShellEx\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
607 extensionW
, riid
->Data1
, riid
->Data2
, riid
->Data3
,
608 riid
->Data4
[0], riid
->Data4
[1], riid
->Data4
[2], riid
->Data4
[3],
609 riid
->Data4
[4], riid
->Data4
[5], riid
->Data4
[6], riid
->Data4
[7]);
611 if(RegGetValueW(HKEY_CLASSES_ROOT
, buf
, NULL
, RRF_RT_REG_SZ
,
612 NULL
, buf
, &size
) != ERROR_SUCCESS
)
615 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Blocked", 0, 0, 0,
616 KEY_READ
, NULL
, &key
, NULL
) != ERROR_SUCCESS
)
618 if(RegQueryValueExW(key
, buf
, 0, NULL
, NULL
, NULL
)
619 != ERROR_FILE_NOT_FOUND
)
620 return E_ACCESSDENIED
;
623 if(RegCreateKeyExW(HKEY_CURRENT_USER
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Blocked", 0, 0, 0,
624 KEY_READ
, NULL
, &key
, NULL
) != ERROR_SUCCESS
)
626 if(RegQueryValueExW(key
, buf
, 0, NULL
, NULL
, NULL
)
627 != ERROR_FILE_NOT_FOUND
)
628 return E_ACCESSDENIED
;
631 if(!GUIDFromStringW(buf
, &guid
))
634 hr
= CoCreateInstance(&guid
, NULL
, CLSCTX_INPROC_SERVER
,
635 &IID_IPersistFile
, (void**)&persist_file
);
639 hr
= IShellFolder2_GetDisplayNameOf(iface
, pidl
, SHGDN_FORPARSING
, &path
);
641 hr
= StrRetToStrW(&path
, NULL
, &file
);
643 IPersistFile_Release(persist_file
);
647 hr
= IPersistFile_Load(persist_file
, file
, STGM_READ
);
650 IPersistFile_Release(persist_file
);
654 hr
= IPersistFile_QueryInterface(persist_file
, riid
, ppvOut
);
655 IPersistFile_Release(persist_file
);
659 /**************************************************************************
660 * IShellFolder_fnGetUIObjectOf
663 * HWND hwndOwner, //[in ] Parent window for any output
664 * UINT cidl, //[in ] array size
665 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
666 * REFIID riid, //[in ] Requested Interface
667 * UINT* prgfInOut, //[ ] reserved
668 * LPVOID* ppvObject) //[out] Resulting Interface
671 * This function gets asked to return "view objects" for one or more (multiple
673 * The viewobject typically is an COM object with one of the following
675 * IExtractIcon,IDataObject,IContextMenu
676 * In order to support icon positions in the default Listview your DataObject
677 * must implement the SetData method (in addition to GetData :) - the shell
678 * passes a barely documented "Icon positions" structure to SetData when the
679 * drag starts, and GetData's it if the drop is in another explorer window that
680 * needs the positions.
682 static HRESULT WINAPI
683 IShellFolder_fnGetUIObjectOf (IShellFolder2
* iface
,
685 UINT cidl
, LPCITEMIDLIST
* apidl
, REFIID riid
,
686 UINT
* prgfInOut
, LPVOID
* ppvOut
)
688 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
691 IUnknown
*pObj
= NULL
;
692 HRESULT hr
= E_INVALIDARG
;
694 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
695 This
, hwndOwner
, cidl
, apidl
, shdebugstr_guid (riid
), prgfInOut
, ppvOut
);
701 hr
= SHELL32_CreateExtensionUIObject(iface
, *apidl
, riid
, ppvOut
);
706 if (IsEqualIID (riid
, &IID_IContextMenu
) && (cidl
>= 1)) {
707 return ItemMenu_Constructor((IShellFolder
*)iface
, This
->pidlRoot
, apidl
, cidl
, riid
, ppvOut
);
708 } else if (IsEqualIID (riid
, &IID_IDataObject
) && (cidl
>= 1)) {
709 pObj
= (LPUNKNOWN
) IDataObject_Constructor (hwndOwner
,
710 This
->pidlRoot
, apidl
, cidl
);
712 } else if (IsEqualIID (riid
, &IID_IExtractIconA
) && (cidl
== 1)) {
713 pidl
= ILCombine (This
->pidlRoot
, apidl
[0]);
714 pObj
= (LPUNKNOWN
) IExtractIconA_Constructor (pidl
);
717 } else if (IsEqualIID (riid
, &IID_IExtractIconW
) && (cidl
== 1)) {
718 pidl
= ILCombine (This
->pidlRoot
, apidl
[0]);
719 pObj
= (LPUNKNOWN
) IExtractIconW_Constructor (pidl
);
722 } else if (IsEqualIID (riid
, &IID_IDropTarget
) && (cidl
>= 1)) {
723 hr
= IShellFolder2_QueryInterface (iface
, &IID_IDropTarget
,
725 } else if ((IsEqualIID(riid
,&IID_IShellLinkW
) ||
726 IsEqualIID(riid
,&IID_IShellLinkA
)) && (cidl
== 1)) {
727 pidl
= ILCombine (This
->pidlRoot
, apidl
[0]);
728 hr
= IShellLink_ConstructFromFile(NULL
, riid
, pidl
, &pObj
);
734 if (SUCCEEDED(hr
) && !pObj
)
739 TRACE ("(%p)->hr=0x%08lx\n", This
, hr
);
743 /******************************************************************************
744 * SHELL_FS_HideExtension [Internal]
746 * Query the registry if the filename extension of a given path should be
750 * szPath [I] Relative or absolute path of a file
753 * TRUE, if the filename's extension should be hidden
756 static BOOL
SHELL_FS_HideExtension(LPCWSTR szPath
)
760 DWORD dwDataSize
= sizeof (DWORD
);
761 BOOL doHide
= FALSE
; /* The default value is FALSE (win98 at least) */
763 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
764 0, 0, 0, KEY_ALL_ACCESS
, 0, &hKey
, 0)) {
765 if (!RegQueryValueExW(hKey
, L
"HideFileExt", 0, 0, (LPBYTE
) &dwData
, &dwDataSize
))
771 LPWSTR ext
= PathFindExtensionW(szPath
);
774 WCHAR classname
[MAX_PATH
];
775 LONG classlen
= sizeof(classname
);
777 if (!RegQueryValueW(HKEY_CLASSES_ROOT
, ext
, classname
, &classlen
))
778 if (!RegOpenKeyW(HKEY_CLASSES_ROOT
, classname
, &hKey
)) {
779 if (!RegQueryValueExW(hKey
, L
"NeverShowExt", 0, NULL
, NULL
, NULL
))
788 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath
, DWORD dwFlags
)
790 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
791 if (!(dwFlags
& SHGDN_FORPARSING
) &&
792 ((dwFlags
& SHGDN_INFOLDER
) || (dwFlags
== SHGDN_NORMAL
))) {
793 if (SHELL_FS_HideExtension(szPath
) && szPath
[0] != '.')
794 PathRemoveExtensionW(szPath
);
798 static void get_display_name( WCHAR dest
[MAX_PATH
], const WCHAR
*path
, LPCITEMIDLIST pidl
, BOOL is_unix
)
804 lstrcpynW( dest
, path
, MAX_PATH
);
806 /* try to get a better path than the \\?\unix one */
807 if (!wcsnicmp( path
, L
"\\\\?\\unix\\", 9 ))
811 len
= WideCharToMultiByte( CP_UNIXCP
, 0, path
+ 8, -1, NULL
, 0, NULL
, NULL
);
812 buffer
= heap_alloc( len
);
813 len
= WideCharToMultiByte( CP_UNIXCP
, 0, path
+ 8, -1, buffer
, len
, NULL
, NULL
);
814 for (i
= 0; i
< len
; i
++) if (buffer
[i
] == '\\') buffer
[i
] = '/';
815 if ((res
= wine_get_dos_file_name( buffer
)))
817 lstrcpynW( dest
, res
, MAX_PATH
);
821 else lstrcpynW( dest
, path
+ 8, MAX_PATH
);
824 if (!_ILIsDesktop(pidl
))
826 PathAddBackslashW( dest
);
827 len
= lstrlenW( dest
);
828 _ILSimpleGetTextW( pidl
, dest
+ len
, MAX_PATH
- len
);
830 if (is_unix
) for (i
= 0; dest
[i
]; i
++) if (dest
[i
] == '\\') dest
[i
] = '/';
833 /**************************************************************************
834 * IShellFolder_fnGetDisplayNameOf
835 * Retrieves the display name for the specified file object or subfolder
838 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
839 * DWORD dwFlags, //[in ] SHGNO formatting flags
840 * LPSTRRET lpName) //[out] Returned display name
843 * if the name is in the pidl the ret value should be a STRRET_OFFSET
846 static HRESULT WINAPI
847 IShellFolder_fnGetDisplayNameOf (IShellFolder2
* iface
, LPCITEMIDLIST pidl
,
848 DWORD dwFlags
, LPSTRRET strRet
)
850 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
855 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This
, pidl
, dwFlags
, strRet
);
861 pszPath
= CoTaskMemAlloc((MAX_PATH
+1) * sizeof(WCHAR
));
863 return E_OUTOFMEMORY
;
865 if (_ILIsDesktop(pidl
)) { /* empty pidl */
866 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
867 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
))
869 if (This
->sPathTarget
)
870 get_display_name( pszPath
, This
->sPathTarget
, pidl
,
871 IsEqualCLSID( This
->pclsid
, &CLSID_UnixFolder
));
873 /* pidl has to contain exactly one non null SHITEMID */
876 } else if (_ILIsPidlSimple(pidl
)) {
877 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
878 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
881 get_display_name( pszPath
, This
->sPathTarget
, pidl
,
882 IsEqualCLSID( This
->pclsid
, &CLSID_UnixFolder
));
884 else _ILSimpleGetTextW(pidl
, pszPath
, MAX_PATH
);
885 if (!_ILIsFolder(pidl
)) SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
887 hr
= SHELL32_GetDisplayNameOfChild(iface
, pidl
, dwFlags
, pszPath
, MAX_PATH
);
891 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
892 if (GetVersion() & 0x80000000) {
893 strRet
->uType
= STRRET_CSTR
;
894 if (!WideCharToMultiByte(CP_ACP
, 0, pszPath
, -1, strRet
->u
.cStr
, MAX_PATH
,
896 strRet
->u
.cStr
[0] = '\0';
897 CoTaskMemFree(pszPath
);
899 strRet
->uType
= STRRET_WSTR
;
900 strRet
->u
.pOleStr
= pszPath
;
903 CoTaskMemFree(pszPath
);
905 TRACE ("-- (%p)->(%s)\n", This
, strRet
->uType
== STRRET_CSTR
? strRet
->u
.cStr
: debugstr_w(strRet
->u
.pOleStr
));
909 /**************************************************************************
910 * IShellFolder_fnSetNameOf
911 * Changes the name of a file object or subfolder, possibly changing its item
912 * identifier in the process.
915 * HWND hwndOwner, //[in ] Owner window for output
916 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
917 * LPCOLESTR lpszName, //[in ] the items new display name
918 * DWORD dwFlags, //[in ] SHGNO formatting flags
919 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
921 static HRESULT WINAPI
IShellFolder_fnSetNameOf (IShellFolder2
* iface
,
926 LPITEMIDLIST
* pPidlOut
)
928 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
929 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
931 BOOL bIsFolder
= _ILIsFolder (ILFindLastID (pidl
));
933 TRACE ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", This
, hwndOwner
, pidl
,
934 debugstr_w (lpName
), dwFlags
, pPidlOut
);
936 /* pidl has to contain a single non-empty SHITEMID */
937 if (_ILIsDesktop(pidl
) || !_ILIsPidlSimple(pidl
) || !_ILGetTextPointer(pidl
)) return E_INVALIDARG
;
939 if (wcspbrk( lpName
, L
"\\/:*?\"<>|" )) return HRESULT_FROM_WIN32(ERROR_CANCELLED
);
941 /* build source path */
942 lstrcpynW(szSrc
, This
->sPathTarget
, MAX_PATH
);
943 ptr
= PathAddBackslashW (szSrc
);
944 _ILSimpleGetTextW (pidl
, ptr
, MAX_PATH
+ 1 - (ptr
- szSrc
));
946 /* build destination path */
947 lstrcpynW(szDest
, This
->sPathTarget
, MAX_PATH
);
948 ptr
= PathAddBackslashW (szDest
);
949 lstrcpynW(ptr
, lpName
, MAX_PATH
+ 1 - (ptr
- szDest
));
951 if(!(dwFlags
& SHGDN_FORPARSING
) && SHELL_FS_HideExtension(szSrc
)) {
952 WCHAR
*ext
= PathFindExtensionW(szSrc
);
954 INT len
= lstrlenW(szDest
);
955 lstrcpynW(szDest
+ len
, ext
, MAX_PATH
- len
);
959 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc
), debugstr_w(szDest
));
961 if (MoveFileW (szSrc
, szDest
)) {
965 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
967 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
968 SHCNF_PATHW
, szSrc
, szDest
);
976 static HRESULT WINAPI
IShellFolder_fnGetDefaultSearchGUID(IShellFolder2
*iface
, GUID
*guid
)
978 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
979 TRACE("(%p)->(%p)\n", This
, guid
);
983 static HRESULT WINAPI
IShellFolder_fnEnumSearches (IShellFolder2
* iface
,
984 IEnumExtraSearch
** ppenum
)
986 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
987 FIXME ("(%p)\n", This
);
991 static HRESULT WINAPI
992 IShellFolder_fnGetDefaultColumn(IShellFolder2
*iface
, DWORD reserved
, ULONG
*sort
, ULONG
*display
)
994 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
996 TRACE("(%p)->(%#lx, %p, %p)\n", This
, reserved
, sort
, display
);
1001 static HRESULT WINAPI
1002 IShellFolder_fnGetDefaultColumnState (IShellFolder2
* iface
, UINT iColumn
,
1005 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
1007 TRACE ("(%p)\n", This
);
1009 if (!pcsFlags
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
1010 return E_INVALIDARG
;
1012 *pcsFlags
= GenericSFHeader
[iColumn
].pcsFlags
;
1017 static HRESULT WINAPI
1018 IShellFolder_fnGetDetailsEx (IShellFolder2
* iface
, LPCITEMIDLIST pidl
,
1019 const SHCOLUMNID
* pscid
, VARIANT
* pv
)
1021 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
1022 FIXME ("(%p)\n", This
);
1027 static HRESULT WINAPI
1028 IShellFolder_fnGetDetailsOf (IShellFolder2
* iface
, LPCITEMIDLIST pidl
,
1029 UINT iColumn
, SHELLDETAILS
* psd
)
1031 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
1033 TRACE ("(%p)->(%p %i %p)\n", This
, pidl
, iColumn
, psd
);
1035 if (!psd
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
1036 return E_INVALIDARG
;
1038 if (!pidl
) return SHELL32_GetColumnDetails(GenericSFHeader
, iColumn
, psd
);
1040 return shellfolder_get_file_details( iface
, pidl
, GenericSFHeader
, iColumn
, psd
);
1043 static HRESULT WINAPI
1044 IShellFolder_fnMapColumnToSCID (IShellFolder2
*iface
, UINT column
, SHCOLUMNID
*scid
)
1046 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
1048 TRACE("(%p)->(%u %p)\n", This
, column
, scid
);
1050 if (column
>= GENERICSHELLVIEWCOLUMNS
)
1051 return E_INVALIDARG
;
1053 return shellfolder_map_column_to_scid(GenericSFHeader
, column
, scid
);
1056 static const IShellFolder2Vtbl sfvt
=
1058 IShellFolder_fnQueryInterface
,
1059 IShellFolder_fnAddRef
,
1060 IShellFolder_fnRelease
,
1061 IShellFolder_fnParseDisplayName
,
1062 IShellFolder_fnEnumObjects
,
1063 IShellFolder_fnBindToObject
,
1064 IShellFolder_fnBindToStorage
,
1065 IShellFolder_fnCompareIDs
,
1066 IShellFolder_fnCreateViewObject
,
1067 IShellFolder_fnGetAttributesOf
,
1068 IShellFolder_fnGetUIObjectOf
,
1069 IShellFolder_fnGetDisplayNameOf
,
1070 IShellFolder_fnSetNameOf
,
1072 IShellFolder_fnGetDefaultSearchGUID
,
1073 IShellFolder_fnEnumSearches
,
1074 IShellFolder_fnGetDefaultColumn
,
1075 IShellFolder_fnGetDefaultColumnState
,
1076 IShellFolder_fnGetDetailsEx
,
1077 IShellFolder_fnGetDetailsOf
,
1078 IShellFolder_fnMapColumnToSCID
1081 /****************************************************************************
1082 * ISFHelper for IShellFolder implementation
1085 static HRESULT WINAPI
ISFHelper_fnQueryInterface(ISFHelper
*iface
, REFIID riid
, void **ppvObj
)
1087 IGenericSFImpl
*This
= impl_from_ISFHelper(iface
);
1089 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppvObj
);
1092 static ULONG WINAPI
ISFHelper_fnAddRef(ISFHelper
*iface
)
1094 IGenericSFImpl
*This
= impl_from_ISFHelper(iface
);
1096 return IUnknown_AddRef(This
->outer_unk
);
1099 static ULONG WINAPI
ISFHelper_fnRelease(ISFHelper
*iface
)
1101 IGenericSFImpl
*This
= impl_from_ISFHelper(iface
);
1103 return IUnknown_Release(This
->outer_unk
);
1106 /****************************************************************************
1107 * ISFHelper_fnGetUniqueName
1109 * creates a unique folder name
1112 static HRESULT WINAPI
1113 ISFHelper_fnGetUniqueName (ISFHelper
* iface
, LPWSTR pwszName
, UINT uLen
)
1115 IGenericSFImpl
*This
= impl_from_ISFHelper(iface
);
1118 WCHAR wszText
[MAX_PATH
];
1119 WCHAR wszNewFolder
[25];
1121 TRACE ("(%p)(%p %u)\n", This
, pwszName
, uLen
);
1123 LoadStringW(shell32_hInstance
, IDS_NEWFOLDER
, wszNewFolder
, ARRAY_SIZE(wszNewFolder
));
1124 if (uLen
< ARRAY_SIZE(wszNewFolder
) + 3)
1127 lstrcpynW (pwszName
, wszNewFolder
, uLen
);
1129 hr
= IShellFolder2_EnumObjects(&This
->IShellFolder2_iface
, 0,
1130 SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &penum
);
1137 IEnumIDList_Reset (penum
);
1138 while (S_OK
== IEnumIDList_Next (penum
, 1, &pidl
, &dwFetched
) &&
1140 _ILSimpleGetTextW (pidl
, wszText
, MAX_PATH
);
1141 if (0 == lstrcmpiW (wszText
, pwszName
)) {
1142 swprintf (pwszName
, uLen
, L
"%s %d", wszNewFolder
, i
++);
1151 IEnumIDList_Release (penum
);
1156 /****************************************************************************
1157 * ISFHelper_fnAddFolder
1159 * adds a new folder.
1162 static HRESULT WINAPI
1163 ISFHelper_fnAddFolder (ISFHelper
* iface
, HWND hwnd
, LPCWSTR pwszName
,
1164 LPITEMIDLIST
* ppidlOut
)
1166 IGenericSFImpl
*This
= impl_from_ISFHelper(iface
);
1167 WCHAR wszNewDir
[MAX_PATH
];
1169 HRESULT hres
= E_FAIL
;
1171 TRACE ("(%p)(%s %p)\n", This
, debugstr_w(pwszName
), ppidlOut
);
1174 if (This
->sPathTarget
)
1175 lstrcpynW(wszNewDir
, This
->sPathTarget
, MAX_PATH
);
1176 PathAppendW(wszNewDir
, pwszName
);
1178 bRes
= CreateDirectoryW (wszNewDir
, NULL
);
1180 LPITEMIDLIST relPidl
;
1182 lstrcpyW(wszNewDir
, pwszName
);
1184 hres
= IShellFolder2_ParseDisplayName(&This
->IShellFolder2_iface
, hwnd
, NULL
, wszNewDir
,
1185 NULL
, &relPidl
, NULL
);
1187 if (SUCCEEDED(hres
)) {
1188 LPITEMIDLIST fullPidl
;
1190 fullPidl
= ILCombine(This
->pidlRoot
, relPidl
);
1193 SHChangeNotify(SHCNE_MKDIR
, SHCNF_IDLIST
, fullPidl
, NULL
);
1197 *ppidlOut
= relPidl
;
1201 WARN("failed to combine %s into a full PIDL\n", wine_dbgstr_w(pwszName
));
1206 WARN("failed to parse %s into a PIDL\n", wine_dbgstr_w(pwszName
));
1209 WCHAR wszText
[128 + MAX_PATH
];
1210 WCHAR wszTempText
[128];
1211 WCHAR wszCaption
[256];
1213 /* Cannot Create folder because of permissions */
1214 LoadStringW (shell32_hInstance
, IDS_CREATEFOLDER_DENIED
, wszTempText
, ARRAY_SIZE(wszTempText
));
1215 LoadStringW (shell32_hInstance
, IDS_CREATEFOLDER_CAPTION
, wszCaption
, ARRAY_SIZE(wszCaption
));
1216 swprintf (wszText
, ARRAY_SIZE(wszText
), wszTempText
, wszNewDir
);
1217 MessageBoxW (hwnd
, wszText
, wszCaption
, MB_OK
| MB_ICONEXCLAMATION
);
1223 /****************************************************************************
1226 * Builds a list of paths like the one used in SHFileOperation from a table of
1227 * PIDLs relative to the given base folder
1229 static WCHAR
*build_paths_list(LPCWSTR wszBasePath
, int cidl
, const LPCITEMIDLIST
*pidls
)
1231 WCHAR
*wszPathsList
;
1236 iPathLen
= lstrlenW(wszBasePath
);
1237 wszPathsList
= heap_alloc(MAX_PATH
*sizeof(WCHAR
)*cidl
+1);
1238 wszListPos
= wszPathsList
;
1240 for (i
= 0; i
< cidl
; i
++) {
1241 if (!_ILIsFolder(pidls
[i
]) && !_ILIsValue(pidls
[i
]))
1244 lstrcpynW(wszListPos
, wszBasePath
, MAX_PATH
);
1245 /* FIXME: abort if path too long */
1246 _ILSimpleGetTextW(pidls
[i
], wszListPos
+iPathLen
, MAX_PATH
-iPathLen
);
1247 wszListPos
+= lstrlenW(wszListPos
)+1;
1250 return wszPathsList
;
1253 /****************************************************************************
1254 * ISFHelper_fnDeleteItems
1256 * deletes items in folder
1258 static HRESULT WINAPI
1259 ISFHelper_fnDeleteItems (ISFHelper
* iface
, UINT cidl
, LPCITEMIDLIST
* apidl
)
1261 IGenericSFImpl
*This
= impl_from_ISFHelper(iface
);
1264 WCHAR wszPath
[MAX_PATH
];
1265 WCHAR
*wszPathsList
;
1267 WCHAR
*wszCurrentPath
;
1269 TRACE ("(%p)(%u %p)\n", This
, cidl
, apidl
);
1270 if (cidl
==0) return S_OK
;
1272 if (This
->sPathTarget
)
1273 lstrcpynW(wszPath
, This
->sPathTarget
, MAX_PATH
);
1276 PathAddBackslashW(wszPath
);
1277 wszPathsList
= build_paths_list(wszPath
, cidl
, apidl
);
1279 ZeroMemory(&op
, sizeof(op
));
1280 op
.hwnd
= GetActiveWindow();
1281 op
.wFunc
= FO_DELETE
;
1282 op
.pFrom
= wszPathsList
;
1283 op
.fFlags
= FOF_ALLOWUNDO
;
1284 if (SHFileOperationW(&op
))
1286 WARN("SHFileOperation failed\n");
1292 /* we currently need to manually send the notifies */
1293 wszCurrentPath
= wszPathsList
;
1294 for (i
= 0; i
< cidl
; i
++)
1298 if (_ILIsFolder(apidl
[i
]))
1299 wEventId
= SHCNE_RMDIR
;
1300 else if (_ILIsValue(apidl
[i
]))
1301 wEventId
= SHCNE_DELETE
;
1305 /* check if file exists */
1306 if (GetFileAttributesW(wszCurrentPath
) == INVALID_FILE_ATTRIBUTES
)
1308 LPITEMIDLIST pidl
= ILCombine(This
->pidlRoot
, apidl
[i
]);
1309 SHChangeNotify(wEventId
, SHCNF_IDLIST
, pidl
, NULL
);
1313 wszCurrentPath
+= lstrlenW(wszCurrentPath
)+1;
1315 heap_free(wszPathsList
);
1319 /****************************************************************************
1320 * ISFHelper_fnCopyItems
1322 * copies items to this folder
1324 static HRESULT WINAPI
1325 ISFHelper_fnCopyItems (ISFHelper
* iface
, IShellFolder
* pSFFrom
, UINT cidl
,
1326 LPCITEMIDLIST
* apidl
)
1329 IPersistFolder2
*ppf2
= NULL
;
1330 WCHAR wszSrcPathRoot
[MAX_PATH
],
1331 wszDstPath
[MAX_PATH
+1];
1332 WCHAR
*wszSrcPathsList
;
1333 IGenericSFImpl
*This
= impl_from_ISFHelper(iface
);
1335 SHFILEOPSTRUCTW fop
;
1337 TRACE ("(%p)->(%p,%u,%p)\n", This
, pSFFrom
, cidl
, apidl
);
1339 IShellFolder_QueryInterface (pSFFrom
, &IID_IPersistFolder2
,
1344 if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2
, &pidl
))) {
1345 SHGetPathFromIDListW (pidl
, wszSrcPathRoot
);
1346 if (This
->sPathTarget
)
1347 lstrcpynW(wszDstPath
, This
->sPathTarget
, MAX_PATH
);
1350 PathAddBackslashW(wszSrcPathRoot
);
1351 PathAddBackslashW(wszDstPath
);
1352 wszSrcPathsList
= build_paths_list(wszSrcPathRoot
, cidl
, apidl
);
1353 ZeroMemory(&fop
, sizeof(fop
));
1354 fop
.hwnd
= GetActiveWindow();
1355 fop
.wFunc
= FO_COPY
;
1356 fop
.pFrom
= wszSrcPathsList
;
1357 fop
.pTo
= wszDstPath
;
1358 fop
.fFlags
= FOF_ALLOWUNDO
;
1360 if(SHFileOperationW(&fop
))
1362 WARN("Copy failed\n");
1365 heap_free(wszSrcPathsList
);
1368 IPersistFolder2_Release(ppf2
);
1373 static const ISFHelperVtbl shvt
=
1375 ISFHelper_fnQueryInterface
,
1377 ISFHelper_fnRelease
,
1378 ISFHelper_fnGetUniqueName
,
1379 ISFHelper_fnAddFolder
,
1380 ISFHelper_fnDeleteItems
,
1381 ISFHelper_fnCopyItems
1384 /************************************************************************
1385 * IFSFldr_PersistFolder3_QueryInterface
1388 static HRESULT WINAPI
IFSFldr_PersistFolder3_QueryInterface(IPersistFolder3
*iface
, REFIID iid
,
1391 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1393 return IUnknown_QueryInterface(This
->outer_unk
, iid
, ppv
);
1396 /************************************************************************
1397 * IFSFldr_PersistFolder3_AddRef
1400 static ULONG WINAPI
IFSFldr_PersistFolder3_AddRef(IPersistFolder3
*iface
)
1402 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1404 return IUnknown_AddRef(This
->outer_unk
);
1407 /************************************************************************
1408 * IFSFldr_PersistFolder3_Release
1411 static ULONG WINAPI
IFSFldr_PersistFolder3_Release(IPersistFolder3
*iface
)
1413 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1415 return IUnknown_Release(This
->outer_unk
);
1418 /************************************************************************
1419 * IFSFldr_PersistFolder3_GetClassID
1421 static HRESULT WINAPI
1422 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3
* iface
, CLSID
* lpClassId
)
1424 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1426 TRACE ("(%p)\n", This
);
1430 *lpClassId
= *This
->pclsid
;
1435 /************************************************************************
1436 * IFSFldr_PersistFolder3_Initialize
1439 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1441 static HRESULT WINAPI
1442 IFSFldr_PersistFolder3_Initialize (IPersistFolder3
* iface
, LPCITEMIDLIST pidl
)
1444 WCHAR wszTemp
[MAX_PATH
];
1446 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1448 TRACE ("(%p)->(%p)\n", This
, pidl
);
1452 SHFree (This
->pidlRoot
); /* free the old pidl */
1453 This
->pidlRoot
= ILClone (pidl
); /* set my pidl */
1455 /* FolderShortcuts' Initialize method only sets the ITEMIDLIST, which
1456 * specifies the location in the shell namespace, but leaves the
1457 * target folder alone */
1458 if (IsEqualCLSID( This
->pclsid
, &CLSID_FolderShortcut
)) return S_OK
;
1460 SHFree (This
->sPathTarget
);
1461 This
->sPathTarget
= NULL
;
1464 if (_ILIsSpecialFolder(pidl
) && IsEqualCLSID( This
->pclsid
, _ILGetGUIDPointer(pidl
) ))
1466 if (IsEqualCLSID( This
->pclsid
, &CLSID_MyDocuments
))
1468 if (!SHGetSpecialFolderPathW( 0, wszTemp
, CSIDL_PERSONAL
, FALSE
)) return E_FAIL
;
1469 PathAddBackslashW( wszTemp
);
1471 else lstrcpyW( wszTemp
, L
"\\\\?\\unix\\" );
1473 else SHGetPathFromIDListW( pidl
, wszTemp
);
1475 if ((len
= lstrlenW(wszTemp
)))
1477 This
->sPathTarget
= SHAlloc((len
+ 1) * sizeof(WCHAR
));
1478 if (!This
->sPathTarget
) return E_OUTOFMEMORY
;
1479 memcpy(This
->sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1482 TRACE ("--(%p)->(%s)\n", This
, debugstr_w(This
->sPathTarget
));
1486 /**************************************************************************
1487 * IFSFldr_PersistFolder3_GetCurFolder
1489 static HRESULT WINAPI
1490 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3
* iface
,
1491 LPITEMIDLIST
* pidl
)
1493 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1495 TRACE ("(%p)->(%p)\n", This
, pidl
);
1497 if (!pidl
) return E_POINTER
;
1498 *pidl
= ILClone (This
->pidlRoot
);
1502 /**************************************************************************
1503 * IFSFldr_PersistFolder3_InitializeEx
1505 * FIXME: error handling
1507 static HRESULT WINAPI
1508 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3
* iface
,
1509 IBindCtx
* pbc
, LPCITEMIDLIST pidlRoot
,
1510 const PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1512 WCHAR wszTemp
[MAX_PATH
];
1514 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1516 TRACE ("(%p)->(%p,%p,%p)\n", This
, pbc
, pidlRoot
, ppfti
);
1518 TRACE ("--%p %s %s 0x%08lx 0x%08x\n",
1519 ppfti
->pidlTargetFolder
, debugstr_w (ppfti
->szTargetParsingName
),
1520 debugstr_w (ppfti
->szNetworkProvider
), ppfti
->dwAttributes
,
1524 if (ppfti
&& ppfti
->pidlTargetFolder
)
1525 pdump (ppfti
->pidlTargetFolder
);
1529 SHFree(This
->pidlRoot
);
1530 This
->pidlRoot
= NULL
;
1532 if (This
->sPathTarget
)
1534 SHFree(This
->sPathTarget
);
1535 This
->sPathTarget
= NULL
;
1539 * Root path and pidl
1541 This
->pidlRoot
= ILClone (pidlRoot
);
1544 * the target folder is specified in csidl OR pidlTargetFolder OR
1545 * szTargetParsingName
1548 if (ppfti
->csidl
!= -1) {
1549 if (SHGetSpecialFolderPathW (0, wszTemp
, ppfti
->csidl
,
1550 ppfti
->csidl
& CSIDL_FLAG_CREATE
)) {
1551 int len
= lstrlenW(wszTemp
);
1552 This
->sPathTarget
= SHAlloc((len
+ 1) * sizeof(WCHAR
));
1553 if (!This
->sPathTarget
)
1554 return E_OUTOFMEMORY
;
1555 memcpy(This
->sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1557 } else if (ppfti
->szTargetParsingName
[0]) {
1558 int len
= lstrlenW(ppfti
->szTargetParsingName
);
1559 This
->sPathTarget
= SHAlloc((len
+ 1) * sizeof(WCHAR
));
1560 if (!This
->sPathTarget
)
1561 return E_OUTOFMEMORY
;
1562 memcpy(This
->sPathTarget
, ppfti
->szTargetParsingName
,
1563 (len
+ 1) * sizeof(WCHAR
));
1564 } else if (ppfti
->pidlTargetFolder
) {
1565 if (SHGetPathFromIDListW(ppfti
->pidlTargetFolder
, wszTemp
)) {
1566 int len
= lstrlenW(wszTemp
);
1567 This
->sPathTarget
= SHAlloc((len
+ 1) * sizeof(WCHAR
));
1568 if (!This
->sPathTarget
)
1569 return E_OUTOFMEMORY
;
1570 memcpy(This
->sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1575 TRACE ("--(%p)->(target=%s)\n", This
, debugstr_w(This
->sPathTarget
));
1576 pdump (This
->pidlRoot
);
1577 return (This
->sPathTarget
) ? S_OK
: E_FAIL
;
1580 static HRESULT WINAPI
1581 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3
* iface
,
1582 PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1584 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1585 FIXME ("(%p)->(%p)\n", This
, ppfti
);
1586 ZeroMemory (ppfti
, sizeof (*ppfti
));
1590 static const IPersistFolder3Vtbl pfvt
=
1592 IFSFldr_PersistFolder3_QueryInterface
,
1593 IFSFldr_PersistFolder3_AddRef
,
1594 IFSFldr_PersistFolder3_Release
,
1595 IFSFldr_PersistFolder3_GetClassID
,
1596 IFSFldr_PersistFolder3_Initialize
,
1597 IFSFldr_PersistFolder3_fnGetCurFolder
,
1598 IFSFldr_PersistFolder3_InitializeEx
,
1599 IFSFldr_PersistFolder3_GetFolderTargetInfo
1602 /****************************************************************************
1603 * IPersistPropertyBag implementation
1605 static HRESULT WINAPI
PersistPropertyBag_QueryInterface(IPersistPropertyBag
* iface
,
1606 REFIID riid
, void** ppv
)
1608 IGenericSFImpl
*This
= impl_from_IPersistPropertyBag(iface
);
1609 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
1612 static ULONG WINAPI
PersistPropertyBag_AddRef(IPersistPropertyBag
* iface
)
1614 IGenericSFImpl
*This
= impl_from_IPersistPropertyBag(iface
);
1615 return IUnknown_AddRef(This
->outer_unk
);
1618 static ULONG WINAPI
PersistPropertyBag_Release(IPersistPropertyBag
* iface
)
1620 IGenericSFImpl
*This
= impl_from_IPersistPropertyBag(iface
);
1621 return IUnknown_Release(This
->outer_unk
);
1624 static HRESULT WINAPI
PersistPropertyBag_GetClassID(IPersistPropertyBag
* iface
, CLSID
* pClassID
)
1626 IGenericSFImpl
*This
= impl_from_IPersistPropertyBag(iface
);
1627 return IPersistFolder3_GetClassID(&This
->IPersistFolder3_iface
, pClassID
);
1630 static HRESULT WINAPI
PersistPropertyBag_InitNew(IPersistPropertyBag
* iface
)
1632 IGenericSFImpl
*This
= impl_from_IPersistPropertyBag(iface
);
1633 FIXME("(%p): stub\n", This
);
1637 static HRESULT WINAPI
PersistPropertyBag_Load(IPersistPropertyBag
*iface
,
1638 IPropertyBag
*pPropertyBag
, IErrorLog
*pErrorLog
)
1640 IGenericSFImpl
*This
= impl_from_IPersistPropertyBag(iface
);
1641 PERSIST_FOLDER_TARGET_INFO pftiTarget
;
1645 TRACE("(%p)->(%p %p)\n", This
, pPropertyBag
, pErrorLog
);
1650 /* Get 'Target' property from the property bag. */
1651 V_VT(&var
) = VT_BSTR
;
1652 hr
= IPropertyBag_Read(pPropertyBag
, L
"Target", &var
, NULL
);
1655 lstrcpyW(pftiTarget
.szTargetParsingName
, V_BSTR(&var
));
1656 SysFreeString(V_BSTR(&var
));
1658 pftiTarget
.pidlTargetFolder
= NULL
;
1659 pftiTarget
.szNetworkProvider
[0] = 0;
1660 pftiTarget
.dwAttributes
= -1;
1661 pftiTarget
.csidl
= -1;
1663 return IPersistFolder3_InitializeEx(&This
->IPersistFolder3_iface
, NULL
, NULL
, &pftiTarget
);
1666 static HRESULT WINAPI
PersistPropertyBag_Save(IPersistPropertyBag
*iface
,
1667 IPropertyBag
*pPropertyBag
, BOOL fClearDirty
, BOOL fSaveAllProperties
)
1669 IGenericSFImpl
*This
= impl_from_IPersistPropertyBag(iface
);
1670 FIXME("(%p): stub\n", This
);
1674 static const IPersistPropertyBagVtbl ppbvt
= {
1675 PersistPropertyBag_QueryInterface
,
1676 PersistPropertyBag_AddRef
,
1677 PersistPropertyBag_Release
,
1678 PersistPropertyBag_GetClassID
,
1679 PersistPropertyBag_InitNew
,
1680 PersistPropertyBag_Load
,
1681 PersistPropertyBag_Save
1684 /****************************************************************************
1685 * ISFDropTarget implementation
1687 static HRESULT WINAPI
ISFDropTarget_QueryInterface(IDropTarget
*iface
, REFIID riid
, void **ppv
)
1689 IGenericSFImpl
*This
= impl_from_IDropTarget(iface
);
1691 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
1694 static ULONG WINAPI
ISFDropTarget_AddRef(IDropTarget
*iface
)
1696 IGenericSFImpl
*This
= impl_from_IDropTarget(iface
);
1698 return IUnknown_AddRef(This
->outer_unk
);
1701 static ULONG WINAPI
ISFDropTarget_Release(IDropTarget
*iface
)
1703 IGenericSFImpl
*This
= impl_from_IDropTarget(iface
);
1705 return IUnknown_Release(This
->outer_unk
);
1708 #define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
1709 #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
1711 static HRESULT WINAPI
1712 ISFDropTarget_DragEnter (IDropTarget
* iface
, IDataObject
* pDataObject
,
1713 DWORD dwKeyState
, POINTL pt
, DWORD
* pdwEffect
)
1715 IGenericSFImpl
*This
= impl_from_IDropTarget(iface
);
1719 TRACE("(%p)->(%p 0x%08lx {.x=%ld, .y=%ld} %p)\n", This
, pDataObject
, dwKeyState
, pt
.x
, pt
.y
, pdwEffect
);
1721 if (!pdwEffect
|| !pDataObject
)
1722 return E_INVALIDARG
;
1724 /* Compute a mask of supported drop-effects for this shellfolder object and the given data
1725 * object. Dropping is only supported on folders, which represent filesystem locations. One
1726 * can't drop on file objects. And the 'move' drop effect is only supported, if the source
1727 * folder is not identical to the target folder. */
1728 This
->drop_effects_mask
= DROPEFFECT_NONE
;
1729 InitFormatEtc(format
, cfShellIDList
, TYMED_HGLOBAL
);
1730 if (_ILIsFolder(ILFindLastID(This
->pidlRoot
)) && /* Only drop to folders, not to files */
1731 SUCCEEDED(IDataObject_GetData(pDataObject
, &format
, &medium
))) /* Only ShellIDList format */
1733 LPIDA pidaShellIDList
= GlobalLock(medium
.u
.hGlobal
);
1734 This
->drop_effects_mask
|= DROPEFFECT_COPY
|DROPEFFECT_LINK
;
1736 if (pidaShellIDList
) { /* Files can only be moved between two different folders */
1737 if (!ILIsEqual(HIDA_GetPIDLFolder(pidaShellIDList
), This
->pidlRoot
))
1738 This
->drop_effects_mask
|= DROPEFFECT_MOVE
;
1739 GlobalUnlock(medium
.u
.hGlobal
);
1743 *pdwEffect
= KeyStateToDropEffect(dwKeyState
) & This
->drop_effects_mask
;
1748 static HRESULT WINAPI
1749 ISFDropTarget_DragOver (IDropTarget
* iface
, DWORD dwKeyState
, POINTL pt
,
1752 IGenericSFImpl
*This
= impl_from_IDropTarget(iface
);
1754 TRACE("(%p)->(0x%08lx {.x=%ld, .y=%ld} %p)\n", This
, dwKeyState
, pt
.x
, pt
.y
, pdwEffect
);
1757 return E_INVALIDARG
;
1759 *pdwEffect
= KeyStateToDropEffect(dwKeyState
) & This
->drop_effects_mask
;
1764 static HRESULT WINAPI
ISFDropTarget_DragLeave (IDropTarget
* iface
)
1766 IGenericSFImpl
*This
= impl_from_IDropTarget(iface
);
1768 TRACE("(%p)\n", This
);
1770 This
->drop_effects_mask
= DROPEFFECT_NONE
;
1774 static HRESULT WINAPI
1775 ISFDropTarget_Drop (IDropTarget
* iface
, IDataObject
* pDataObject
,
1776 DWORD dwKeyState
, POINTL pt
, DWORD
* pdwEffect
)
1778 IGenericSFImpl
*This
= impl_from_IDropTarget(iface
);
1783 TRACE("(%p)->(%p %ld {.x=%ld, .y=%ld} %p) semi-stub\n",
1784 This
, pDataObject
, dwKeyState
, pt
.x
, pt
.y
, pdwEffect
);
1786 InitFormatEtc(format
, cfShellIDList
, TYMED_HGLOBAL
);
1787 hr
= IDataObject_GetData(pDataObject
, &format
, &medium
);
1791 if (medium
.tymed
== TYMED_HGLOBAL
) {
1792 IShellFolder
*psfSourceFolder
, *psfDesktopFolder
;
1793 LPIDA pidaShellIDList
= GlobalLock(medium
.u
.hGlobal
);
1797 if (!pidaShellIDList
)
1798 return HRESULT_FROM_WIN32(GetLastError());
1800 hr
= SHGetDesktopFolder(&psfDesktopFolder
);
1802 GlobalUnlock(medium
.u
.hGlobal
);
1806 hr
= IShellFolder_BindToObject(psfDesktopFolder
, HIDA_GetPIDLFolder(pidaShellIDList
), NULL
,
1807 &IID_IShellFolder
, (LPVOID
*)&psfSourceFolder
);
1808 IShellFolder_Release(psfDesktopFolder
);
1810 GlobalUnlock(medium
.u
.hGlobal
);
1814 for (i
= 0; i
< pidaShellIDList
->cidl
; i
++) {
1815 WCHAR wszSourcePath
[MAX_PATH
];
1817 hr
= IShellFolder_GetDisplayNameOf(psfSourceFolder
, HIDA_GetPIDLItem(pidaShellIDList
, i
),
1818 SHGDN_FORPARSING
, &strret
);
1822 hr
= StrRetToBufW(&strret
, NULL
, wszSourcePath
, MAX_PATH
);
1826 switch (*pdwEffect
) {
1827 case DROPEFFECT_MOVE
:
1828 FIXME("Move %s to %s!\n", debugstr_w(wszSourcePath
), debugstr_w(This
->sPathTarget
));
1830 case DROPEFFECT_COPY
:
1831 FIXME("Copy %s to %s!\n", debugstr_w(wszSourcePath
), debugstr_w(This
->sPathTarget
));
1833 case DROPEFFECT_LINK
:
1834 FIXME("Link %s from %s!\n", debugstr_w(wszSourcePath
), debugstr_w(This
->sPathTarget
));
1839 IShellFolder_Release(psfSourceFolder
);
1840 GlobalUnlock(medium
.u
.hGlobal
);
1847 static const IDropTargetVtbl dtvt
= {
1848 ISFDropTarget_QueryInterface
,
1849 ISFDropTarget_AddRef
,
1850 ISFDropTarget_Release
,
1851 ISFDropTarget_DragEnter
,
1852 ISFDropTarget_DragOver
,
1853 ISFDropTarget_DragLeave
,
1857 static HRESULT
create_fs( IUnknown
*outer_unk
, REFIID riid
, void **ppv
, const CLSID
*clsid
)
1862 TRACE("outer_unk=%p %s\n", outer_unk
, shdebugstr_guid(riid
));
1864 if (outer_unk
&& !IsEqualIID(riid
, &IID_IUnknown
))
1865 return CLASS_E_NOAGGREGATION
;
1867 sf
= LocalAlloc(LMEM_ZEROINIT
, sizeof(*sf
));
1869 return E_OUTOFMEMORY
;
1872 sf
->IUnknown_inner
.lpVtbl
= &unkvt
;
1873 sf
->IShellFolder2_iface
.lpVtbl
= &sfvt
;
1874 sf
->IPersistFolder3_iface
.lpVtbl
= &pfvt
;
1875 sf
->IPersistPropertyBag_iface
.lpVtbl
= &ppbvt
;
1876 sf
->IDropTarget_iface
.lpVtbl
= &dtvt
;
1877 sf
->ISFHelper_iface
.lpVtbl
= &shvt
;
1879 sf
->outer_unk
= outer_unk
? outer_unk
: &sf
->IUnknown_inner
;
1881 hr
= IUnknown_QueryInterface(&sf
->IUnknown_inner
, riid
, ppv
);
1882 IUnknown_Release(&sf
->IUnknown_inner
);
1884 TRACE ("--%p\n", *ppv
);
1888 HRESULT WINAPI
IFSFolder_Constructor(IUnknown
*outer_unk
, REFIID riid
, void **ppv
)
1890 return create_fs( outer_unk
, riid
, ppv
, &CLSID_ShellFSFolder
);
1893 HRESULT WINAPI
UnixFolder_Constructor(IUnknown
*outer_unk
, REFIID riid
, void **ppv
)
1895 return create_fs( outer_unk
, riid
, ppv
, &CLSID_UnixFolder
);
1898 HRESULT WINAPI
UnixDosFolder_Constructor(IUnknown
*outer_unk
, REFIID riid
, void **ppv
)
1900 return create_fs( outer_unk
, riid
, ppv
, &CLSID_UnixDosFolder
);
1903 HRESULT WINAPI
FolderShortcut_Constructor(IUnknown
*outer_unk
, REFIID riid
, void **ppv
)
1905 return create_fs( outer_unk
, riid
, ppv
, &CLSID_FolderShortcut
);
1908 HRESULT WINAPI
MyDocuments_Constructor(IUnknown
*outer_unk
, REFIID riid
, void **ppv
)
1910 return create_fs( outer_unk
, riid
, ppv
, &CLSID_MyDocuments
);