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 class CNetFolderEnum
:
51 public CEnumIDListBase
56 HRESULT WINAPI
Initialize(HWND hwndOwner
, DWORD dwFlags
);
57 BOOL
CreateMyCompEnumList(DWORD dwFlags
);
58 BOOL
EnumerateRec(LPNETRESOURCE lpNet
);
60 BEGIN_COM_MAP(CNetFolderEnum
)
61 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
65 static shvheader NetworkPlacesSFHeader
[] = {
66 {IDS_SHV_COLUMN8
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},
67 {IDS_SHV_COLUMN13
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
68 {IDS_SHV_COLUMN_WORKGROUP
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},
69 {IDS_SHV_NETWORKLOCATION
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15}
73 #define COLUMN_CATEGORY 1
74 #define COLUMN_WORKGROUP 2
75 #define COLUMN_NETLOCATION 3
77 #define NETWORKPLACESSHELLVIEWCOLUMNS 4
79 CNetFolderEnum::CNetFolderEnum()
83 CNetFolderEnum::~CNetFolderEnum()
87 HRESULT WINAPI
CNetFolderEnum::Initialize(HWND hwndOwner
, DWORD dwFlags
)
89 if (CreateMyCompEnumList(dwFlags
) == FALSE
)
95 /**************************************************************************
96 * CDrivesFolderEnum::CreateMyCompEnumList()
99 BOOL
CNetFolderEnum::EnumerateRec(LPNETRESOURCE lpNet
)
105 DWORD dSize
= 0x1000;
109 dRet
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
, 0, lpNet
, &hEnum
);
110 if (dRet
!= WN_SUCCESS
)
112 ERR("WNetOpenEnum() failed: %x\n", dRet
);
116 lpRes
= (LPNETRESOURCE
)CoTaskMemAlloc(dSize
);
119 ERR("CoTaskMemAlloc() failed\n");
120 WNetCloseEnum(hEnum
);
129 memset(lpRes
, 0, dSize
);
130 dRet
= WNetEnumResource(hEnum
, &dCount
, lpRes
, &dSize
);
131 if (dRet
== WN_SUCCESS
|| dRet
== WN_MORE_DATA
)
134 for (; dCount
; dCount
--)
136 TRACE("lpRemoteName: %S\n", lpCur
->lpRemoteName
);
138 if ((lpCur
->dwUsage
& RESOURCEUSAGE_CONTAINER
) == RESOURCEUSAGE_CONTAINER
)
140 TRACE("Found provider: %S\n", lpCur
->lpProvider
);
141 /* Sounds like a WTF hack.... Is Wine doing correct? */
142 if (!wcscmp(lpCur
->lpRemoteName
, lpCur
->lpProvider
))
144 lpCur
->lpRemoteName
= NULL
;
152 #ifdef HACKY_UNC_PATHS
153 pidl
= ILCreateFromNetworkPlaceW(lpCur
->lpRemoteName
);
156 bRet
= AddToEnumList(pidl
);
159 ERR("ILCreateFromPathW() failed\n");
168 } while (dRet
!= WN_NO_MORE_ENTRIES
);
170 CoTaskMemFree(lpRes
);
171 WNetCloseEnum(hEnum
);
173 TRACE("Done: %u\n", bRet
);
178 BOOL
CNetFolderEnum::CreateMyCompEnumList(DWORD dwFlags
)
182 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags
);
184 /* enumerate the folders */
185 if (dwFlags
& SHCONTF_FOLDERS
)
187 bRet
= EnumerateRec(NULL
);
193 CNetFolder::CNetFolder()
198 CNetFolder::~CNetFolder()
200 TRACE("-- destroying IShellFolder(%p)\n", this);
204 HRESULT WINAPI
CNetFolder::FinalConstruct()
206 pidlRoot
= _ILCreateGuid(PT_GUID
, CLSID_NetworkPlaces
); /* my qualified pidl */
207 if (pidlRoot
== NULL
)
208 return E_OUTOFMEMORY
;
212 /**************************************************************************
213 * CNetFolder::ParseDisplayName
215 HRESULT WINAPI
CNetFolder::ParseDisplayName(HWND hwndOwner
, LPBC pbcReserved
, LPOLESTR lpszDisplayName
,
216 DWORD
*pchEaten
, PIDLIST_RELATIVE
*ppidl
, DWORD
*pdwAttributes
)
218 HRESULT hr
= E_UNEXPECTED
;
219 #ifdef HACKY_UNC_PATHS
220 /* FIXME: the code below is an ugly hack */
222 /* Can we use a CFSFolder on that path? */
223 DWORD attrs
= GetFileAttributes(lpszDisplayName
);
224 if ((attrs
& FILE_ATTRIBUTE_DIRECTORY
))
227 *pchEaten
= 0; /* strange but like the original */
231 /* Create our hacky pidl */
232 LPITEMIDLIST pidl
= ILCreateFromNetworkPlaceW(lpszDisplayName
);
236 *pdwAttributes
= SFGAO_FILESYSTEM
| SFGAO_CANLINK
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
;
241 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
242 hwndOwner
, pbcReserved
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
243 pchEaten
, ppidl
, pdwAttributes
);
247 *pchEaten
= 0; /* strange but like the original */
249 TRACE("(%p)->(-- ret=0x%08x)\n", this, hr
);
254 /**************************************************************************
255 * CNetFolder::EnumObjects
257 HRESULT WINAPI
CNetFolder::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
259 return ShellObjectCreatorInit
<CNetFolderEnum
>(hwndOwner
, dwFlags
, IID_IEnumIDList
, ppEnumIDList
);
262 /**************************************************************************
263 * CNetFolder::BindToObject
265 HRESULT WINAPI
CNetFolder::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
267 #ifdef HACKY_UNC_PATHS
269 CComPtr
<IPersistFolder3
> ppf3
;
270 hr
= SHCoCreateInstance(NULL
, &CLSID_ShellFSFolder
, NULL
, IID_PPV_ARG(IPersistFolder3
, &ppf3
));
274 PERSIST_FOLDER_TARGET_INFO pfti
= {0};
276 wcscpy(pfti
.szTargetParsingName
, (WCHAR
*)pidl
->mkid
.abID
);
278 PCUIDLIST_RELATIVE pidlChild
= ILCloneFirst (pidl
);
280 hr
= ppf3
->InitializeEx(NULL
, ILCombine(pidlRoot
,pidlChild
), &pfti
);
284 if (_ILIsPidlSimple (pidl
))
286 return ppf3
->QueryInterface(riid
, ppvOut
);
290 CComPtr
<IShellFolder
> psf
;
291 hr
= ppf3
->QueryInterface(IID_PPV_ARG(IShellFolder
, &psf
));
295 return psf
->BindToObject(ILGetNext (pidl
), pbcReserved
, riid
, ppvOut
);
303 /**************************************************************************
304 * CNetFolder::BindToStorage
306 HRESULT WINAPI
CNetFolder::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
308 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
309 pidl
, pbcReserved
, shdebugstr_guid (&riid
), ppvOut
);
315 /**************************************************************************
316 * CNetFolder::CompareIDs
319 HRESULT WINAPI
CNetFolder::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
324 /**************************************************************************
325 * CNetFolder::CreateViewObject
327 HRESULT WINAPI
CNetFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
*ppvOut
)
329 CComPtr
<IShellView
> pShellView
;
330 HRESULT hr
= E_INVALIDARG
;
332 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
333 hwndOwner
, shdebugstr_guid (&riid
), ppvOut
);
340 if (IsEqualIID(riid
, IID_IDropTarget
))
342 WARN("IDropTarget not implemented\n");
345 else if (IsEqualIID(riid
, IID_IContextMenu
))
347 WARN("IContextMenu not implemented\n");
350 else if (IsEqualIID(riid
, IID_IShellView
))
352 hr
= CDefView_Constructor(this, riid
, ppvOut
);
354 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut
);
358 /**************************************************************************
359 * CNetFolder::GetAttributesOf
361 HRESULT WINAPI
CNetFolder::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
*rgfInOut
)
363 static const DWORD dwNethoodAttributes
=
364 SFGAO_STORAGE
| SFGAO_HASPROPSHEET
| SFGAO_STORAGEANCESTOR
|
365 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
| SFGAO_CANRENAME
| SFGAO_CANDELETE
;
368 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this,
369 cidl
, apidl
, rgfInOut
, rgfInOut
? *rgfInOut
: 0);
380 *rgfInOut
= dwNethoodAttributes
;
383 /* FIXME: Implement when enumerating items is implemented */
384 #ifdef HACKY_UNC_PATHS
385 *rgfInOut
= SFGAO_FILESYSTEM
| SFGAO_CANLINK
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
;
389 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
390 *rgfInOut
&= ~SFGAO_VALIDATE
;
392 TRACE("-- result=0x%08x\n", *rgfInOut
);
396 /**************************************************************************
397 * CNetFolder::GetUIObjectOf
400 * hwndOwner [in] Parent window for any output
401 * cidl [in] array size
402 * apidl [in] simple pidl array
403 * riid [in] Requested Interface
404 * prgfInOut [ ] reserved
405 * ppvObject [out] Resulting Interface
408 HRESULT WINAPI
CNetFolder::GetUIObjectOf(HWND hwndOwner
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, REFIID riid
,
409 UINT
* prgfInOut
, LPVOID
* ppvOut
)
412 IUnknown
*pObj
= NULL
;
413 HRESULT hr
= E_INVALIDARG
;
415 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
416 hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
423 if (IsEqualIID(riid
, IID_IContextMenu
) && (cidl
>= 1))
425 IContextMenu
* pCm
= NULL
;
426 hr
= CDefFolderMenu_Create2(pidlRoot
, hwndOwner
, cidl
, apidl
, static_cast<IShellFolder
*>(this), NULL
, 0, NULL
, &pCm
);
429 else if (IsEqualIID(riid
, IID_IDataObject
) && (cidl
>= 1))
431 IDataObject
* pDo
= NULL
;
432 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, apidl
, cidl
, &pDo
);
435 else if (IsEqualIID(riid
, IID_IExtractIconA
) && (cidl
== 1))
437 pidl
= ILCombine (pidlRoot
, apidl
[0]);
438 pObj
= IExtractIconA_Constructor (pidl
);
442 else if (IsEqualIID(riid
, IID_IExtractIconW
) && (cidl
== 1))
444 pidl
= ILCombine (pidlRoot
, apidl
[0]);
445 pObj
= IExtractIconW_Constructor (pidl
);
449 else if (IsEqualIID(riid
, IID_IDropTarget
) && (cidl
>= 1))
451 IDropTarget
* pDt
= NULL
;
452 hr
= this->QueryInterface(IID_PPV_ARG(IDropTarget
, &pDt
));
458 if (SUCCEEDED(hr
) && !pObj
)
462 TRACE("(%p)->hr=0x%08x\n", this, hr
);
466 /**************************************************************************
467 * CNetFolder::GetDisplayNameOf
470 HRESULT WINAPI
CNetFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET strRet
)
474 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", this, pidl
, dwFlags
, strRet
);
482 pszName
= (LPWSTR
)CoTaskMemAlloc(MAX_PATH
* sizeof(WCHAR
));
484 return E_OUTOFMEMORY
;
486 if (LoadStringW(shell32_hInstance
, IDS_NETWORKPLACE
, pszName
, MAX_PATH
))
488 pszName
[MAX_PATH
-1] = L
'\0';
489 strRet
->uType
= STRRET_WSTR
;
490 strRet
->pOleStr
= pszName
;
493 CoTaskMemFree(pszName
);
496 #ifdef HACKY_UNC_PATHS
499 LPCWSTR pstr
= (LPCWSTR
)pidl
->mkid
.abID
;
500 pszName
= (LPWSTR
)CoTaskMemAlloc(MAX_PATH
* sizeof(WCHAR
));
502 return E_OUTOFMEMORY
;
504 wcscpy(pszName
, pstr
);
505 strRet
->pOleStr
= pszName
;
506 strRet
->uType
= STRRET_WSTR
;
513 /**************************************************************************
514 * CNetFolder::SetNameOf
515 * Changes the name of a file object or subfolder, possibly changing its item
516 * identifier in the process.
519 * hwndOwner [in] Owner window for output
520 * pidl [in] simple pidl of item to change
521 * lpszName [in] the items new display name
522 * dwFlags [in] SHGNO formatting flags
523 * ppidlOut [out] simple pidl returned
525 HRESULT WINAPI
CNetFolder::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
, /*simple pidl */
526 LPCOLESTR lpName
, DWORD dwFlags
, PITEMID_CHILD
*pPidlOut
)
528 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
529 hwndOwner
, pidl
, debugstr_w (lpName
), dwFlags
, pPidlOut
);
533 HRESULT WINAPI
CNetFolder::GetDefaultSearchGUID(GUID
*pguid
)
535 FIXME("(%p)\n", this);
539 HRESULT WINAPI
CNetFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
541 FIXME("(%p)\n", this);
545 HRESULT WINAPI
CNetFolder::GetDefaultColumn (DWORD dwRes
, ULONG
*pSort
, ULONG
*pDisplay
)
547 TRACE("(%p)\n", this);
557 HRESULT WINAPI
CNetFolder::GetDefaultColumnState(UINT iColumn
, DWORD
*pcsFlags
)
559 TRACE("(%p)\n", this);
561 if (!pcsFlags
|| iColumn
>= NETWORKPLACESSHELLVIEWCOLUMNS
)
563 *pcsFlags
= NetworkPlacesSFHeader
[iColumn
].pcsFlags
;
567 HRESULT WINAPI
CNetFolder::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
569 FIXME("(%p)\n", this);
573 HRESULT WINAPI
CNetFolder::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*psd
)
575 WCHAR buffer
[MAX_PATH
] = {0};
578 if (iColumn
>= NETWORKPLACESSHELLVIEWCOLUMNS
)
581 psd
->fmt
= NetworkPlacesSFHeader
[iColumn
].fmt
;
582 psd
->cxChar
= NetworkPlacesSFHeader
[iColumn
].cxChar
;
585 psd
->str
.uType
= STRRET_WSTR
;
586 if (LoadStringW(shell32_hInstance
, NetworkPlacesSFHeader
[iColumn
].colnameid
, buffer
, _countof(buffer
)))
587 hr
= SHStrDupW(buffer
, &psd
->str
.pOleStr
);
592 if (iColumn
== COLUMN_NAME
)
593 return GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &psd
->str
);
595 FIXME("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
600 HRESULT WINAPI
CNetFolder::MapColumnToSCID(UINT column
, SHCOLUMNID
*pscid
)
602 FIXME("(%p)\n", this);
607 /************************************************************************
608 * CNetFolder::GetClassID
610 HRESULT WINAPI
CNetFolder::GetClassID(CLSID
*lpClassId
)
612 TRACE("(%p)\n", this);
617 *lpClassId
= CLSID_NetworkPlaces
;
622 /************************************************************************
623 * CNetFolder::Initialize
625 * NOTES: it makes no sense to change the pidl
627 HRESULT WINAPI
CNetFolder::Initialize(LPCITEMIDLIST pidl
)
629 TRACE("(%p)->(%p)\n", this, pidl
);
634 /**************************************************************************
635 * CNetFolder::GetCurFolder
637 HRESULT WINAPI
CNetFolder::GetCurFolder(LPITEMIDLIST
*pidl
)
639 TRACE("(%p)->(%p)\n", this, pidl
);
644 *pidl
= ILClone(pidlRoot
);