[SHELLUTILS.H]
[reactos.git] / reactos / dll / win32 / shell32 / folders / CNetFolder.cpp
1 /*
2 * Network Places (Neighbourhood) folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2003 Mike McCormack for Codeweavers
7 * Copyright 2009 Andrew Hill
8 *
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.
13 *
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.
18 *
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
22 */
23
24 #include <precomp.h>
25
26 WINE_DEFAULT_DEBUG_CHANNEL (shell);
27
28 #define HACKY_UNC_PATHS
29
30 #ifdef HACKY_UNC_PATHS
31 LPITEMIDLIST ILCreateFromNetworkPlaceW(LPCWSTR lpNetworkPlace)
32 {
33 int cbData = sizeof(WORD) + sizeof(WCHAR) * (wcslen(lpNetworkPlace)+1);
34 LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD));
35 if (!pidl)
36 return NULL;
37
38 pidl->mkid.cb = cbData;
39 wcscpy((WCHAR*)&pidl->mkid.abID[0], lpNetworkPlace);
40 *(WORD*)((char*)pidl + cbData) = 0;
41
42 return pidl;
43 }
44 #endif
45
46 /***********************************************************************
47 * IShellFolder implementation
48 */
49
50 HRESULT CNetFolderExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
51 {
52 CComPtr<IDefaultExtractIconInit> initIcon;
53 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
54 if (FAILED_UNEXPECTEDLY(hr))
55 return hr;
56
57 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_NETWORK_FOLDER);
58
59 return initIcon->QueryInterface(riid, ppvOut);
60 }
61
62 HRESULT CALLBACK NetFolderMenuCallback(IShellFolder *psf,
63 HWND hwnd,
64 IDataObject *pdtobj,
65 UINT uMsg,
66 WPARAM wParam,
67 LPARAM lParam)
68 {
69 switch (uMsg)
70 {
71 case DFM_MERGECONTEXTMENU:
72 return S_OK;
73 case DFM_INVOKECOMMAND:
74 case DFM_INVOKECOMMANDEX:
75 case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
76 return S_FALSE;
77 }
78 return E_NOTIMPL;
79 }
80
81 class CNetFolderEnum :
82 public CEnumIDListBase
83 {
84 public:
85 CNetFolderEnum();
86 ~CNetFolderEnum();
87 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
88 BOOL CreateMyCompEnumList(DWORD dwFlags);
89 BOOL EnumerateRec(LPNETRESOURCE lpNet);
90
91 BEGIN_COM_MAP(CNetFolderEnum)
92 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
93 END_COM_MAP()
94 };
95
96 static shvheader NetworkPlacesSFHeader[] = {
97 {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
98 {IDS_SHV_COLUMN13, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
99 {IDS_SHV_COLUMN_WORKGROUP, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
100 {IDS_SHV_NETWORKLOCATION, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}
101 };
102
103 #define COLUMN_NAME 0
104 #define COLUMN_CATEGORY 1
105 #define COLUMN_WORKGROUP 2
106 #define COLUMN_NETLOCATION 3
107
108 #define NETWORKPLACESSHELLVIEWCOLUMNS 4
109
110 CNetFolderEnum::CNetFolderEnum()
111 {
112 }
113
114 CNetFolderEnum::~CNetFolderEnum()
115 {
116 }
117
118 HRESULT WINAPI CNetFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
119 {
120 if (CreateMyCompEnumList(dwFlags) == FALSE)
121 return E_FAIL;
122
123 return S_OK;
124 }
125
126 /**************************************************************************
127 * CDrivesFolderEnum::CreateMyCompEnumList()
128 */
129
130 BOOL CNetFolderEnum::EnumerateRec(LPNETRESOURCE lpNet)
131 {
132 BOOL bRet = TRUE;
133 DWORD dRet;
134 HANDLE hEnum;
135 LPNETRESOURCE lpRes;
136 DWORD dSize = 0x1000;
137 DWORD dCount = -1;
138 LPNETRESOURCE lpCur;
139
140 dRet = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, lpNet, &hEnum);
141 if (dRet != WN_SUCCESS)
142 {
143 ERR("WNetOpenEnum() failed: %x\n", dRet);
144 return FALSE;
145 }
146
147 lpRes = (LPNETRESOURCE)CoTaskMemAlloc(dSize);
148 if (!lpRes)
149 {
150 ERR("CoTaskMemAlloc() failed\n");
151 WNetCloseEnum(hEnum);
152 return FALSE;
153 }
154
155 do
156 {
157 dSize = 0x1000;
158 dCount = -1;
159
160 memset(lpRes, 0, dSize);
161 dRet = WNetEnumResource(hEnum, &dCount, lpRes, &dSize);
162 if (dRet == WN_SUCCESS || dRet == WN_MORE_DATA)
163 {
164 lpCur = lpRes;
165 for (; dCount; dCount--)
166 {
167 TRACE("lpRemoteName: %S\n", lpCur->lpRemoteName);
168
169 if ((lpCur->dwUsage & RESOURCEUSAGE_CONTAINER) == RESOURCEUSAGE_CONTAINER)
170 {
171 TRACE("Found provider: %S\n", lpCur->lpProvider);
172 EnumerateRec(lpCur);
173 }
174 else
175 {
176 LPITEMIDLIST pidl;
177
178 #ifdef HACKY_UNC_PATHS
179 pidl = ILCreateFromNetworkPlaceW(lpCur->lpRemoteName);
180 #endif
181 if (pidl != NULL)
182 bRet = AddToEnumList(pidl);
183 else
184 {
185 ERR("ILCreateFromPathW() failed\n");
186 bRet = FALSE;
187 break;
188 }
189 }
190
191 lpCur++;
192 }
193 }
194 } while (dRet != WN_NO_MORE_ENTRIES);
195
196 CoTaskMemFree(lpRes);
197 WNetCloseEnum(hEnum);
198
199 TRACE("Done: %u\n", bRet);
200
201 return bRet;
202 }
203
204 BOOL CNetFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
205 {
206 BOOL bRet = TRUE;
207
208 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
209
210 /* enumerate the folders */
211 if (dwFlags & SHCONTF_FOLDERS)
212 {
213 bRet = EnumerateRec(NULL);
214 }
215
216 return bRet;
217 }
218
219 CNetFolder::CNetFolder()
220 {
221 pidlRoot = NULL;
222 }
223
224 CNetFolder::~CNetFolder()
225 {
226 if (pidlRoot)
227 SHFree(pidlRoot);
228 }
229
230 /**************************************************************************
231 * CNetFolder::ParseDisplayName
232 */
233 HRESULT WINAPI CNetFolder::ParseDisplayName(HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpszDisplayName,
234 DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
235 {
236 HRESULT hr = E_UNEXPECTED;
237 #ifdef HACKY_UNC_PATHS
238 /* FIXME: the code below is an ugly hack */
239
240 /* Can we use a CFSFolder on that path? */
241 DWORD attrs = GetFileAttributes(lpszDisplayName);
242 if ((attrs & FILE_ATTRIBUTE_DIRECTORY))
243 {
244 if (pchEaten)
245 *pchEaten = 0; /* strange but like the original */
246
247 /* YES WE CAN */
248
249 /* Create our hacky pidl */
250 LPITEMIDLIST pidl = ILCreateFromNetworkPlaceW(lpszDisplayName);
251
252 *ppidl = pidl;
253 if (pdwAttributes)
254 *pdwAttributes = SFGAO_FILESYSTEM | SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR;
255 return S_OK;
256 }
257 #endif
258
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);
262
263 *ppidl = 0;
264 if (pchEaten)
265 *pchEaten = 0; /* strange but like the original */
266
267 TRACE("(%p)->(-- ret=0x%08x)\n", this, hr);
268
269 return hr;
270 }
271
272 /**************************************************************************
273 * CNetFolder::EnumObjects
274 */
275 HRESULT WINAPI CNetFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
276 {
277 return ShellObjectCreatorInit<CNetFolderEnum>(hwndOwner, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
278 }
279
280 /**************************************************************************
281 * CNetFolder::BindToObject
282 */
283 HRESULT WINAPI CNetFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
284 {
285 #ifdef HACKY_UNC_PATHS
286 PITEMID_CHILD pidlChild = ILCloneFirst (pidl);
287 if (!pidlChild)
288 return E_FAIL;
289
290 PIDLIST_ABSOLUTE pidlAbsolute = ILCombine(pidlRoot,pidlChild);
291 if (!pidlAbsolute)
292 return E_FAIL;
293
294 CComPtr<IShellFolder> psf;
295 HRESULT hr = SHELL32_CoCreateInitSF(pidlAbsolute,
296 (WCHAR*)pidl->mkid.abID,
297 NULL,
298 &CLSID_ShellFSFolder,
299 -1,
300 IID_PPV_ARG(IShellFolder, &psf));
301 ILFree(pidlChild);
302 ILFree(pidlAbsolute);
303
304 if (FAILED_UNEXPECTEDLY(hr))
305 return hr;
306
307 if (_ILIsPidlSimple (pidl))
308 return psf->QueryInterface(riid, ppvOut);
309 else
310 return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut);
311 #else
312 return E_NOTIMPL;
313 #endif
314 }
315
316 /**************************************************************************
317 * CNetFolder::BindToStorage
318 */
319 HRESULT WINAPI CNetFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
320 {
321 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
322 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
323
324 *ppvOut = NULL;
325 return E_NOTIMPL;
326 }
327
328 /**************************************************************************
329 * CNetFolder::CompareIDs
330 */
331
332 HRESULT WINAPI CNetFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
333 {
334 return E_NOTIMPL;
335 }
336
337 /**************************************************************************
338 * CNetFolder::CreateViewObject
339 */
340 HRESULT WINAPI CNetFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
341 {
342 CComPtr<IShellView> pShellView;
343 HRESULT hr = E_INVALIDARG;
344
345 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
346 hwndOwner, shdebugstr_guid (&riid), ppvOut);
347
348 if (!ppvOut)
349 return hr;
350
351 *ppvOut = NULL;
352
353 if (IsEqualIID(riid, IID_IDropTarget))
354 {
355 WARN("IDropTarget not implemented\n");
356 hr = E_NOTIMPL;
357 }
358 else if (IsEqualIID(riid, IID_IContextMenu))
359 {
360 WARN("IContextMenu not implemented\n");
361 hr = E_NOTIMPL;
362 }
363 else if (IsEqualIID(riid, IID_IShellView))
364 {
365 hr = CDefView_Constructor(this, riid, ppvOut);
366 }
367 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
368 return hr;
369 }
370
371 /**************************************************************************
372 * CNetFolder::GetAttributesOf
373 */
374 HRESULT WINAPI CNetFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
375 {
376 static const DWORD dwNethoodAttributes =
377 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
378 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
379 HRESULT hr = S_OK;
380
381 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this,
382 cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
383
384 if (!rgfInOut)
385 return E_INVALIDARG;
386 if (cidl && !apidl)
387 return E_INVALIDARG;
388
389 if (*rgfInOut == 0)
390 *rgfInOut = ~0;
391
392 if(cidl == 0)
393 *rgfInOut = dwNethoodAttributes;
394 else
395 {
396 /* FIXME: Implement when enumerating items is implemented */
397 #ifdef HACKY_UNC_PATHS
398 *rgfInOut = SFGAO_FILESYSTEM | SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR;
399 #endif
400 }
401
402 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
403 *rgfInOut &= ~SFGAO_VALIDATE;
404
405 TRACE("-- result=0x%08x\n", *rgfInOut);
406 return hr;
407 }
408
409 /**************************************************************************
410 * CNetFolder::GetUIObjectOf
411 *
412 * PARAMETERS
413 * hwndOwner [in] Parent window for any output
414 * cidl [in] array size
415 * apidl [in] simple pidl array
416 * riid [in] Requested Interface
417 * prgfInOut [ ] reserved
418 * ppvObject [out] Resulting Interface
419 *
420 */
421 HRESULT WINAPI CNetFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
422 UINT * prgfInOut, LPVOID * ppvOut)
423 {
424 LPVOID pObj = NULL;
425 HRESULT hr = E_INVALIDARG;
426
427 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
428 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
429
430 if (!ppvOut)
431 return hr;
432
433 *ppvOut = NULL;
434
435 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
436 {
437 IContextMenu * pCm = NULL;
438 HKEY hkey;
439 UINT cKeys = 0;
440 AddClassKeyToArray(L"Folder", &hkey, &cKeys);
441 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, this, NetFolderMenuCallback, cKeys, &hkey, &pCm);
442 pObj = pCm;
443 }
444 else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1))
445 {
446 IDataObject * pDo = NULL;
447 hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, &pDo);
448 pObj = pDo;
449 }
450 else if ((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1))
451 {
452 hr = CNetFolderExtractIcon_CreateInstance(apidl[0], riid, &pObj);
453 }
454 else if (IsEqualIID(riid, IID_IDropTarget) && (cidl >= 1))
455 {
456 IDropTarget * pDt = NULL;
457 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
458 pObj = pDt;
459 }
460 else
461 hr = E_NOINTERFACE;
462
463 if (SUCCEEDED(hr) && !pObj)
464 hr = E_OUTOFMEMORY;
465
466 *ppvOut = pObj;
467 TRACE("(%p)->hr=0x%08x\n", this, hr);
468 return hr;
469 }
470
471 /**************************************************************************
472 * CNetFolder::GetDisplayNameOf
473 *
474 */
475 HRESULT WINAPI CNetFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
476 {
477 if (!strRet || !pidl || !pidl->mkid.cb)
478 return E_INVALIDARG;
479
480 #ifdef HACKY_UNC_PATHS
481 return SHSetStrRet(strRet, (LPCWSTR)pidl->mkid.abID);
482 #endif
483 return E_NOTIMPL;
484 }
485
486 /**************************************************************************
487 * CNetFolder::SetNameOf
488 * Changes the name of a file object or subfolder, possibly changing its item
489 * identifier in the process.
490 *
491 * PARAMETERS
492 * hwndOwner [in] Owner window for output
493 * pidl [in] simple pidl of item to change
494 * lpszName [in] the items new display name
495 * dwFlags [in] SHGNO formatting flags
496 * ppidlOut [out] simple pidl returned
497 */
498 HRESULT WINAPI CNetFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
499 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
500 {
501 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
502 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
503 return E_FAIL;
504 }
505
506 HRESULT WINAPI CNetFolder::GetDefaultSearchGUID(GUID *pguid)
507 {
508 FIXME("(%p)\n", this);
509 return E_NOTIMPL;
510 }
511
512 HRESULT WINAPI CNetFolder::EnumSearches(IEnumExtraSearch ** ppenum)
513 {
514 FIXME("(%p)\n", this);
515 return E_NOTIMPL;
516 }
517
518 HRESULT WINAPI CNetFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
519 {
520 TRACE("(%p)\n", this);
521
522 if (pSort)
523 *pSort = 0;
524 if (pDisplay)
525 *pDisplay = 0;
526
527 return S_OK;
528 }
529
530 HRESULT WINAPI CNetFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
531 {
532 TRACE("(%p)\n", this);
533
534 if (!pcsFlags || iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS)
535 return E_INVALIDARG;
536 *pcsFlags = NetworkPlacesSFHeader[iColumn].pcsFlags;
537 return S_OK;
538 }
539
540 HRESULT WINAPI CNetFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
541 {
542 FIXME("(%p)\n", this);
543 return E_NOTIMPL;
544 }
545
546 HRESULT WINAPI CNetFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
547 {
548 if (iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS)
549 return E_FAIL;
550
551 psd->fmt = NetworkPlacesSFHeader[iColumn].fmt;
552 psd->cxChar = NetworkPlacesSFHeader[iColumn].cxChar;
553 if (pidl == NULL)
554 return SHSetStrRet(&psd->str, NetworkPlacesSFHeader[iColumn].colnameid);
555
556 if (iColumn == COLUMN_NAME)
557 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
558
559 FIXME("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
560
561 return E_NOTIMPL;
562 }
563
564 HRESULT WINAPI CNetFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
565 {
566 FIXME("(%p)\n", this);
567
568 return E_NOTIMPL;
569 }
570
571 /************************************************************************
572 * CNetFolder::GetClassID
573 */
574 HRESULT WINAPI CNetFolder::GetClassID(CLSID *lpClassId)
575 {
576 TRACE("(%p)\n", this);
577
578 if (!lpClassId)
579 return E_POINTER;
580
581 *lpClassId = CLSID_NetworkPlaces;
582
583 return S_OK;
584 }
585
586 /************************************************************************
587 * CNetFolder::Initialize
588 *
589 * NOTES: it makes no sense to change the pidl
590 */
591 HRESULT WINAPI CNetFolder::Initialize(LPCITEMIDLIST pidl)
592 {
593 if (pidlRoot)
594 SHFree((LPVOID)pidlRoot);
595
596 pidlRoot = ILClone(pidl);
597 return S_OK;
598 }
599
600 /**************************************************************************
601 * CNetFolder::GetCurFolder
602 */
603 HRESULT WINAPI CNetFolder::GetCurFolder(LPITEMIDLIST *pidl)
604 {
605 TRACE("(%p)->(%p)\n", this, pidl);
606
607 if (!pidl)
608 return E_POINTER;
609
610 *pidl = ILClone(pidlRoot);
611
612 return S_OK;
613 }