2 * Network Places (Neighbourhood) folder
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2003 Mike McCormack for Codeweavers
7 * Copyright 2009 Andrew Hill
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
28 #define HACKY_UNC_PATHS
30 #ifdef HACKY_UNC_PATHS
31 LPITEMIDLIST
ILCreateFromNetworkPlaceW(LPCWSTR lpNetworkPlace
)
33 int cbData
= sizeof(WORD
) + sizeof(WCHAR
) * (wcslen(lpNetworkPlace
)+1);
34 LPITEMIDLIST pidl
= (LPITEMIDLIST
)SHAlloc(cbData
+ sizeof(WORD
));
38 pidl
->mkid
.cb
= cbData
;
39 wcscpy((WCHAR
*)&pidl
->mkid
.abID
[0], lpNetworkPlace
);
40 *(WORD
*)((char*)pidl
+ cbData
) = 0;
46 /***********************************************************************
47 * IShellFolder implementation
50 HRESULT
CNetFolderExtractIcon_CreateInstance(LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
* ppvOut
)
52 CComPtr
<IDefaultExtractIconInit
> initIcon
;
53 HRESULT hr
= SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit
, &initIcon
));
54 if (FAILED_UNEXPECTEDLY(hr
))
57 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_NETWORK_FOLDER
);
59 return initIcon
->QueryInterface(riid
, ppvOut
);
62 HRESULT CALLBACK
NetFolderMenuCallback(IShellFolder
*psf
,
71 case DFM_MERGECONTEXTMENU
:
73 case DFM_INVOKECOMMAND
:
74 case DFM_INVOKECOMMANDEX
:
75 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default
81 class CNetFolderEnum
:
82 public CEnumIDListBase
87 HRESULT WINAPI
Initialize(HWND hwndOwner
, DWORD dwFlags
);
88 BOOL
CreateMyCompEnumList(DWORD dwFlags
);
89 BOOL
EnumerateRec(LPNETRESOURCE lpNet
);
91 BEGIN_COM_MAP(CNetFolderEnum
)
92 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
96 static shvheader NetworkPlacesSFHeader
[] = {
97 {IDS_SHV_COLUMN_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},
98 {IDS_SHV_COLUMN_CATEGORY
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
99 {IDS_SHV_COLUMN_WORKGROUP
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},
100 {IDS_SHV_COLUMN_NETLOCATION
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15}
103 #define COLUMN_NAME 0
104 #define COLUMN_CATEGORY 1
105 #define COLUMN_WORKGROUP 2
106 #define COLUMN_NETLOCATION 3
108 #define NETWORKPLACESSHELLVIEWCOLUMNS 4
110 CNetFolderEnum::CNetFolderEnum()
114 CNetFolderEnum::~CNetFolderEnum()
118 HRESULT WINAPI
CNetFolderEnum::Initialize(HWND hwndOwner
, DWORD dwFlags
)
120 if (CreateMyCompEnumList(dwFlags
) == FALSE
)
126 /**************************************************************************
127 * CDrivesFolderEnum::CreateMyCompEnumList()
130 BOOL
CNetFolderEnum::EnumerateRec(LPNETRESOURCE lpNet
)
136 DWORD dSize
= 0x1000;
140 dRet
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
, 0, lpNet
, &hEnum
);
141 if (dRet
!= WN_SUCCESS
)
143 ERR("WNetOpenEnum() failed: %x\n", dRet
);
147 lpRes
= (LPNETRESOURCE
)CoTaskMemAlloc(dSize
);
150 ERR("CoTaskMemAlloc() failed\n");
151 WNetCloseEnum(hEnum
);
160 memset(lpRes
, 0, dSize
);
161 dRet
= WNetEnumResource(hEnum
, &dCount
, lpRes
, &dSize
);
162 if (dRet
== WN_SUCCESS
|| dRet
== WN_MORE_DATA
)
165 for (; dCount
; dCount
--)
167 TRACE("lpRemoteName: %S\n", lpCur
->lpRemoteName
);
169 if ((lpCur
->dwUsage
& RESOURCEUSAGE_CONTAINER
) == RESOURCEUSAGE_CONTAINER
)
171 TRACE("Found provider: %S\n", lpCur
->lpProvider
);
178 #ifdef HACKY_UNC_PATHS
179 pidl
= ILCreateFromNetworkPlaceW(lpCur
->lpRemoteName
);
182 bRet
= AddToEnumList(pidl
);
185 ERR("ILCreateFromPathW() failed\n");
194 } while (dRet
!= WN_NO_MORE_ENTRIES
);
196 CoTaskMemFree(lpRes
);
197 WNetCloseEnum(hEnum
);
199 TRACE("Done: %u\n", bRet
);
204 BOOL
CNetFolderEnum::CreateMyCompEnumList(DWORD dwFlags
)
208 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags
);
210 /* enumerate the folders */
211 if (dwFlags
& SHCONTF_FOLDERS
)
213 bRet
= EnumerateRec(NULL
);
219 CNetFolder::CNetFolder()
224 CNetFolder::~CNetFolder()
230 /**************************************************************************
231 * CNetFolder::ParseDisplayName
233 HRESULT WINAPI
CNetFolder::ParseDisplayName(HWND hwndOwner
, LPBC pbcReserved
, LPOLESTR lpszDisplayName
,
234 DWORD
*pchEaten
, PIDLIST_RELATIVE
*ppidl
, DWORD
*pdwAttributes
)
236 HRESULT hr
= E_UNEXPECTED
;
237 #ifdef HACKY_UNC_PATHS
238 /* FIXME: the code below is an ugly hack */
240 /* Can we use a CFSFolder on that path? */
241 DWORD attrs
= GetFileAttributes(lpszDisplayName
);
242 if ((attrs
& FILE_ATTRIBUTE_DIRECTORY
))
245 *pchEaten
= 0; /* strange but like the original */
249 /* Create our hacky pidl */
250 LPITEMIDLIST pidl
= ILCreateFromNetworkPlaceW(lpszDisplayName
);
254 *pdwAttributes
= SFGAO_FILESYSTEM
| SFGAO_CANLINK
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
;
259 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
260 hwndOwner
, pbcReserved
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
261 pchEaten
, ppidl
, pdwAttributes
);
265 *pchEaten
= 0; /* strange but like the original */
267 TRACE("(%p)->(-- ret=0x%08x)\n", this, hr
);
272 /**************************************************************************
273 * CNetFolder::EnumObjects
275 HRESULT WINAPI
CNetFolder::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
277 return ShellObjectCreatorInit
<CNetFolderEnum
>(hwndOwner
, dwFlags
, IID_PPV_ARG(IEnumIDList
, ppEnumIDList
));
280 /**************************************************************************
281 * CNetFolder::BindToObject
283 HRESULT WINAPI
CNetFolder::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
285 #ifdef HACKY_UNC_PATHS
286 /* Create the target folder info */
287 PERSIST_FOLDER_TARGET_INFO pfti
= {0};
288 pfti
.dwAttributes
= -1;
290 StringCchCopyW(pfti
.szTargetParsingName
, MAX_PATH
, (WCHAR
*)pidl
->mkid
.abID
);
292 return SHELL32_BindToSF(pidlRoot
, &pfti
, pidl
, &CLSID_ShellFSFolder
, riid
, ppvOut
);
298 /**************************************************************************
299 * CNetFolder::BindToStorage
301 HRESULT WINAPI
CNetFolder::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
303 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
304 pidl
, pbcReserved
, shdebugstr_guid (&riid
), ppvOut
);
310 /**************************************************************************
311 * CNetFolder::CompareIDs
314 HRESULT WINAPI
CNetFolder::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
319 /**************************************************************************
320 * CNetFolder::CreateViewObject
322 HRESULT WINAPI
CNetFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
*ppvOut
)
324 CComPtr
<IShellView
> pShellView
;
325 HRESULT hr
= E_INVALIDARG
;
327 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
328 hwndOwner
, shdebugstr_guid (&riid
), ppvOut
);
335 if (IsEqualIID(riid
, IID_IDropTarget
))
337 WARN("IDropTarget not implemented\n");
340 else if (IsEqualIID(riid
, IID_IContextMenu
))
342 WARN("IContextMenu not implemented\n");
345 else if (IsEqualIID(riid
, IID_IShellView
))
347 SFV_CREATE sfvparams
= {sizeof(SFV_CREATE
), this};
348 hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**)ppvOut
);
350 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut
);
354 /**************************************************************************
355 * CNetFolder::GetAttributesOf
357 HRESULT WINAPI
CNetFolder::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
*rgfInOut
)
359 static const DWORD dwNethoodAttributes
=
360 SFGAO_STORAGE
| SFGAO_HASPROPSHEET
| SFGAO_STORAGEANCESTOR
|
361 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
| SFGAO_CANRENAME
| SFGAO_CANDELETE
;
364 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this,
365 cidl
, apidl
, rgfInOut
, rgfInOut
? *rgfInOut
: 0);
376 *rgfInOut
= dwNethoodAttributes
;
379 /* FIXME: Implement when enumerating items is implemented */
380 #ifdef HACKY_UNC_PATHS
381 *rgfInOut
= SFGAO_FILESYSTEM
| SFGAO_CANLINK
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
;
385 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
386 *rgfInOut
&= ~SFGAO_VALIDATE
;
388 TRACE("-- result=0x%08x\n", *rgfInOut
);
392 /**************************************************************************
393 * CNetFolder::GetUIObjectOf
396 * hwndOwner [in] Parent window for any output
397 * cidl [in] array size
398 * apidl [in] simple pidl array
399 * riid [in] Requested Interface
400 * prgfInOut [ ] reserved
401 * ppvObject [out] Resulting Interface
404 HRESULT WINAPI
CNetFolder::GetUIObjectOf(HWND hwndOwner
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, REFIID riid
,
405 UINT
* prgfInOut
, LPVOID
* ppvOut
)
408 HRESULT hr
= E_INVALIDARG
;
410 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
411 hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
418 if (IsEqualIID(riid
, IID_IContextMenu
) && (cidl
>= 1))
420 IContextMenu
* pCm
= NULL
;
423 AddClassKeyToArray(L
"Folder", &hkey
, &cKeys
);
424 hr
= CDefFolderMenu_Create2(pidlRoot
, hwndOwner
, cidl
, apidl
, this, NetFolderMenuCallback
, cKeys
, &hkey
, &pCm
);
427 else if (IsEqualIID(riid
, IID_IDataObject
) && (cidl
>= 1))
429 IDataObject
* pDo
= NULL
;
430 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, apidl
, cidl
, &pDo
);
433 else if ((IsEqualIID(riid
, IID_IExtractIconA
) || IsEqualIID(riid
, IID_IExtractIconW
)) && (cidl
== 1))
435 hr
= CNetFolderExtractIcon_CreateInstance(apidl
[0], riid
, &pObj
);
437 else if (IsEqualIID(riid
, IID_IDropTarget
) && (cidl
>= 1))
439 IDropTarget
* pDt
= NULL
;
440 hr
= this->QueryInterface(IID_PPV_ARG(IDropTarget
, &pDt
));
446 if (SUCCEEDED(hr
) && !pObj
)
450 TRACE("(%p)->hr=0x%08x\n", this, hr
);
454 /**************************************************************************
455 * CNetFolder::GetDisplayNameOf
458 HRESULT WINAPI
CNetFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET strRet
)
460 if (!strRet
|| !pidl
|| !pidl
->mkid
.cb
)
463 #ifdef HACKY_UNC_PATHS
464 return SHSetStrRet(strRet
, (LPCWSTR
)pidl
->mkid
.abID
);
469 /**************************************************************************
470 * CNetFolder::SetNameOf
471 * Changes the name of a file object or subfolder, possibly changing its item
472 * identifier in the process.
475 * hwndOwner [in] Owner window for output
476 * pidl [in] simple pidl of item to change
477 * lpszName [in] the items new display name
478 * dwFlags [in] SHGNO formatting flags
479 * ppidlOut [out] simple pidl returned
481 HRESULT WINAPI
CNetFolder::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
, /*simple pidl */
482 LPCOLESTR lpName
, DWORD dwFlags
, PITEMID_CHILD
*pPidlOut
)
484 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
485 hwndOwner
, pidl
, debugstr_w (lpName
), dwFlags
, pPidlOut
);
489 HRESULT WINAPI
CNetFolder::GetDefaultSearchGUID(GUID
*pguid
)
491 FIXME("(%p)\n", this);
495 HRESULT WINAPI
CNetFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
497 FIXME("(%p)\n", this);
501 HRESULT WINAPI
CNetFolder::GetDefaultColumn (DWORD dwRes
, ULONG
*pSort
, ULONG
*pDisplay
)
503 TRACE("(%p)\n", this);
513 HRESULT WINAPI
CNetFolder::GetDefaultColumnState(UINT iColumn
, DWORD
*pcsFlags
)
515 TRACE("(%p)\n", this);
517 if (!pcsFlags
|| iColumn
>= NETWORKPLACESSHELLVIEWCOLUMNS
)
519 *pcsFlags
= NetworkPlacesSFHeader
[iColumn
].pcsFlags
;
523 HRESULT WINAPI
CNetFolder::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
525 FIXME("(%p)\n", this);
529 HRESULT WINAPI
CNetFolder::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*psd
)
531 if (iColumn
>= NETWORKPLACESSHELLVIEWCOLUMNS
)
534 psd
->fmt
= NetworkPlacesSFHeader
[iColumn
].fmt
;
535 psd
->cxChar
= NetworkPlacesSFHeader
[iColumn
].cxChar
;
537 return SHSetStrRet(&psd
->str
, NetworkPlacesSFHeader
[iColumn
].colnameid
);
539 if (iColumn
== COLUMN_NAME
)
540 return GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &psd
->str
);
542 FIXME("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
547 HRESULT WINAPI
CNetFolder::MapColumnToSCID(UINT column
, SHCOLUMNID
*pscid
)
549 FIXME("(%p)\n", this);
554 /************************************************************************
555 * CNetFolder::GetClassID
557 HRESULT WINAPI
CNetFolder::GetClassID(CLSID
*lpClassId
)
559 TRACE("(%p)\n", this);
564 *lpClassId
= CLSID_NetworkPlaces
;
569 /************************************************************************
570 * CNetFolder::Initialize
572 * NOTES: it makes no sense to change the pidl
574 HRESULT WINAPI
CNetFolder::Initialize(PCIDLIST_ABSOLUTE pidl
)
577 SHFree((LPVOID
)pidlRoot
);
579 pidlRoot
= ILClone(pidl
);
583 /**************************************************************************
584 * CNetFolder::GetCurFolder
586 HRESULT WINAPI
CNetFolder::GetCurFolder(PIDLIST_ABSOLUTE
*pidl
)
588 TRACE("(%p)->(%p)\n", this, pidl
);
593 *pidl
= ILClone(pidlRoot
);