[SHELL32]
[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 /***********************************************************************
31 * IShellFolder implementation
32 */
33
34 static shvheader NetworkPlacesSFHeader[] = {
35 {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
36 {IDS_SHV_COLUMN13, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
37 {IDS_SHV_COLUMN_WORKGROUP, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
38 {IDS_SHV_NETWORKLOCATION, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}
39 };
40
41 #define COLUMN_NAME 0
42 #define COLUMN_CATEGORY 1
43 #define COLUMN_WORKGROUP 2
44 #define COLUMN_NETLOCATION 3
45
46 #define NETWORKPLACESSHELLVIEWCOLUMNS 4
47
48 CNetFolder::CNetFolder()
49 {
50 pidlRoot = NULL;
51 }
52
53 CNetFolder::~CNetFolder()
54 {
55 TRACE("-- destroying IShellFolder(%p)\n", this);
56 SHFree(pidlRoot);
57 }
58
59 HRESULT WINAPI CNetFolder::FinalConstruct()
60 {
61 pidlRoot = _ILCreateGuid(PT_GUID, CLSID_NetworkPlaces); /* my qualified pidl */
62 if (pidlRoot == NULL)
63 return E_OUTOFMEMORY;
64 return S_OK;
65 }
66
67 /**************************************************************************
68 * CNetFolder::ParseDisplayName
69 */
70 HRESULT WINAPI CNetFolder::ParseDisplayName(HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpszDisplayName,
71 DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
72 {
73 HRESULT hr = E_UNEXPECTED;
74 #ifdef HACKY_UNC_PATHS
75 /* FIXME: the code below is an ugly hack */
76
77 /* Can we use a CFSFolder on that path? */
78 DWORD attrs = GetFileAttributes(lpszDisplayName);
79 if ((attrs & FILE_ATTRIBUTE_DIRECTORY))
80 {
81 /* YES WE CAN */
82
83 /* Create our hacky pidl */
84 int cbData = sizeof(WORD) + sizeof(WCHAR) * (wcslen(lpszDisplayName)+1);
85 LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD));
86 if (!pidl)
87 return NULL;
88
89 pidl->mkid.cb = cbData;
90 wcscpy((WCHAR*)&pidl->mkid.abID[0], lpszDisplayName);
91 *(WORD*)((char*)pidl + cbData) = 0;
92
93 *ppidl = pidl;
94 if (pdwAttributes)
95 *pdwAttributes = SFGAO_FILESYSTEM | SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR;
96 return S_OK;
97 }
98 #endif
99
100 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
101 hwndOwner, pbcReserved, lpszDisplayName, debugstr_w (lpszDisplayName),
102 pchEaten, ppidl, pdwAttributes);
103
104 *ppidl = 0;
105 if (pchEaten)
106 *pchEaten = 0; /* strange but like the original */
107
108 TRACE("(%p)->(-- ret=0x%08x)\n", this, hr);
109
110 return hr;
111 }
112
113 /**************************************************************************
114 * CNetFolder::EnumObjects
115 */
116 HRESULT WINAPI CNetFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
117 {
118 TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this,
119 hwndOwner, dwFlags, ppEnumIDList);
120
121 *ppEnumIDList = NULL; //IEnumIDList_Constructor();
122
123 TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
124 return S_FALSE;
125 // return (*ppEnumIDList) ? S_OK : E_OUTOFMEMORY;
126 }
127
128 /**************************************************************************
129 * CNetFolder::BindToObject
130 */
131 HRESULT WINAPI CNetFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
132 {
133 #ifdef HACKY_UNC_PATHS
134 HRESULT hr;
135 CComPtr<IPersistFolder3> ppf3;
136 hr = SHCoCreateInstance(NULL, &CLSID_ShellFSFolder, NULL, IID_PPV_ARG(IPersistFolder3, &ppf3));
137 if (FAILED(hr))
138 return hr;
139
140 PERSIST_FOLDER_TARGET_INFO pfti = {0};
141 pfti.csidl = -1;
142 wcscpy(pfti.szTargetParsingName, (WCHAR*)pidl->mkid.abID);
143
144 PCUIDLIST_RELATIVE pidlChild = ILCloneFirst (pidl);
145
146 hr = ppf3->InitializeEx(NULL, ILCombine(pidlRoot,pidlChild), &pfti);
147 if (FAILED(hr))
148 return hr;
149
150 if (_ILIsPidlSimple (pidl))
151 {
152 return ppf3->QueryInterface(riid, ppvOut);
153 }
154 else
155 {
156 CComPtr<IShellFolder> psf;
157 hr = ppf3->QueryInterface(IID_PPV_ARG(IShellFolder, &psf));
158 if (FAILED(hr))
159 return hr;
160
161 return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut);
162 }
163
164 #else
165 return E_NOTIMPL;
166 #endif
167 }
168
169 /**************************************************************************
170 * CNetFolder::BindToStorage
171 */
172 HRESULT WINAPI CNetFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
173 {
174 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
175 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
176
177 *ppvOut = NULL;
178 return E_NOTIMPL;
179 }
180
181 /**************************************************************************
182 * CNetFolder::CompareIDs
183 */
184
185 HRESULT WINAPI CNetFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
186 {
187 return E_NOTIMPL;
188 }
189
190 /**************************************************************************
191 * CNetFolder::CreateViewObject
192 */
193 HRESULT WINAPI CNetFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
194 {
195 CComPtr<IShellView> pShellView;
196 HRESULT hr = E_INVALIDARG;
197
198 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
199 hwndOwner, shdebugstr_guid (&riid), ppvOut);
200
201 if (!ppvOut)
202 return hr;
203
204 *ppvOut = NULL;
205
206 if (IsEqualIID(riid, IID_IDropTarget))
207 {
208 WARN("IDropTarget not implemented\n");
209 hr = E_NOTIMPL;
210 }
211 else if (IsEqualIID(riid, IID_IContextMenu))
212 {
213 WARN("IContextMenu not implemented\n");
214 hr = E_NOTIMPL;
215 }
216 else if (IsEqualIID(riid, IID_IShellView))
217 {
218 hr = CDefView_Constructor(this, riid, ppvOut);
219 }
220 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
221 return hr;
222 }
223
224 /**************************************************************************
225 * CNetFolder::GetAttributesOf
226 */
227 HRESULT WINAPI CNetFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
228 {
229 static const DWORD dwNethoodAttributes =
230 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
231 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
232 HRESULT hr = S_OK;
233
234 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this,
235 cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
236
237 if (!rgfInOut)
238 return E_INVALIDARG;
239 if (cidl && !apidl)
240 return E_INVALIDARG;
241
242 if (*rgfInOut == 0)
243 *rgfInOut = ~0;
244
245 if(cidl == 0)
246 *rgfInOut = dwNethoodAttributes;
247 else
248 {
249 /* FIXME: Implement when enumerating items is implemented */
250 #ifdef HACKY_UNC_PATHS
251 *rgfInOut = SFGAO_FILESYSTEM | SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR;
252 #endif
253 }
254
255 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
256 *rgfInOut &= ~SFGAO_VALIDATE;
257
258 TRACE("-- result=0x%08x\n", *rgfInOut);
259 return hr;
260 }
261
262 /**************************************************************************
263 * CNetFolder::GetUIObjectOf
264 *
265 * PARAMETERS
266 * hwndOwner [in] Parent window for any output
267 * cidl [in] array size
268 * apidl [in] simple pidl array
269 * riid [in] Requested Interface
270 * prgfInOut [ ] reserved
271 * ppvObject [out] Resulting Interface
272 *
273 */
274 HRESULT WINAPI CNetFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
275 UINT * prgfInOut, LPVOID * ppvOut)
276 {
277 LPITEMIDLIST pidl;
278 IUnknown *pObj = NULL;
279 HRESULT hr = E_INVALIDARG;
280
281 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
282 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
283
284 if (!ppvOut)
285 return hr;
286
287 *ppvOut = NULL;
288
289 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
290 {
291 IContextMenu * pCm = NULL;
292 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), NULL, 0, NULL, &pCm);
293 pObj = pCm;
294 }
295 else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1))
296 {
297 IDataObject * pDo = NULL;
298 hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, &pDo);
299 pObj = pDo;
300 }
301 else if (IsEqualIID(riid, IID_IExtractIconA) && (cidl == 1))
302 {
303 pidl = ILCombine (pidlRoot, apidl[0]);
304 pObj = IExtractIconA_Constructor (pidl);
305 SHFree (pidl);
306 hr = S_OK;
307 }
308 else if (IsEqualIID(riid, IID_IExtractIconW) && (cidl == 1))
309 {
310 pidl = ILCombine (pidlRoot, apidl[0]);
311 pObj = IExtractIconW_Constructor (pidl);
312 SHFree (pidl);
313 hr = S_OK;
314 }
315 else if (IsEqualIID(riid, IID_IDropTarget) && (cidl >= 1))
316 {
317 IDropTarget * pDt = NULL;
318 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
319 pObj = pDt;
320 }
321 else
322 hr = E_NOINTERFACE;
323
324 if (SUCCEEDED(hr) && !pObj)
325 hr = E_OUTOFMEMORY;
326
327 *ppvOut = pObj;
328 TRACE("(%p)->hr=0x%08x\n", this, hr);
329 return hr;
330 }
331
332 /**************************************************************************
333 * CNetFolder::GetDisplayNameOf
334 *
335 */
336 HRESULT WINAPI CNetFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
337 {
338 LPWSTR pszName;
339
340 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", this, pidl, dwFlags, strRet);
341 pdump (pidl);
342
343 if (!strRet)
344 return E_INVALIDARG;
345
346 if (!pidl->mkid.cb)
347 {
348 pszName = (LPWSTR)CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
349 if (!pszName)
350 return E_OUTOFMEMORY;
351
352 if (LoadStringW(shell32_hInstance, IDS_NETWORKPLACE, pszName, MAX_PATH))
353 {
354 pszName[MAX_PATH-1] = L'\0';
355 strRet->uType = STRRET_WSTR;
356 strRet->pOleStr = pszName;
357 return S_OK;
358 }
359 CoTaskMemFree(pszName);
360 return E_FAIL;
361 }
362 #ifdef HACKY_UNC_PATHS
363 else
364 {
365 LPCWSTR pstr = (LPCWSTR)pidl->mkid.abID;
366 pszName = (LPWSTR)CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
367 if (!pszName)
368 return E_OUTOFMEMORY;
369
370 wcscpy(pszName, pstr);
371 strRet->pOleStr = pszName;
372 strRet->uType = STRRET_WSTR;
373 return S_OK;
374 }
375 #endif
376 return E_NOTIMPL;
377 }
378
379 /**************************************************************************
380 * CNetFolder::SetNameOf
381 * Changes the name of a file object or subfolder, possibly changing its item
382 * identifier in the process.
383 *
384 * PARAMETERS
385 * hwndOwner [in] Owner window for output
386 * pidl [in] simple pidl of item to change
387 * lpszName [in] the items new display name
388 * dwFlags [in] SHGNO formatting flags
389 * ppidlOut [out] simple pidl returned
390 */
391 HRESULT WINAPI CNetFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
392 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
393 {
394 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
395 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
396 return E_FAIL;
397 }
398
399 HRESULT WINAPI CNetFolder::GetDefaultSearchGUID(GUID *pguid)
400 {
401 FIXME("(%p)\n", this);
402 return E_NOTIMPL;
403 }
404
405 HRESULT WINAPI CNetFolder::EnumSearches(IEnumExtraSearch ** ppenum)
406 {
407 FIXME("(%p)\n", this);
408 return E_NOTIMPL;
409 }
410
411 HRESULT WINAPI CNetFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
412 {
413 TRACE("(%p)\n", this);
414
415 if (pSort)
416 *pSort = 0;
417 if (pDisplay)
418 *pDisplay = 0;
419
420 return S_OK;
421 }
422
423 HRESULT WINAPI CNetFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
424 {
425 TRACE("(%p)\n", this);
426
427 if (!pcsFlags || iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS)
428 return E_INVALIDARG;
429 *pcsFlags = NetworkPlacesSFHeader[iColumn].pcsFlags;
430 return S_OK;
431 }
432
433 HRESULT WINAPI CNetFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
434 {
435 FIXME("(%p)\n", this);
436 return E_NOTIMPL;
437 }
438
439 HRESULT WINAPI CNetFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
440 {
441 WCHAR buffer[MAX_PATH] = {0};
442 HRESULT hr = E_FAIL;
443
444 if (iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS)
445 return E_FAIL;
446
447 psd->fmt = NetworkPlacesSFHeader[iColumn].fmt;
448 psd->cxChar = NetworkPlacesSFHeader[iColumn].cxChar;
449 if (pidl == NULL)
450 {
451 psd->str.uType = STRRET_WSTR;
452 if (LoadStringW(shell32_hInstance, NetworkPlacesSFHeader[iColumn].colnameid, buffer, _countof(buffer)))
453 hr = SHStrDupW(buffer, &psd->str.pOleStr);
454
455 return hr;
456 }
457
458 if (iColumn == COLUMN_NAME)
459 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
460
461 FIXME("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
462
463 return E_NOTIMPL;
464 }
465
466 HRESULT WINAPI CNetFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
467 {
468 FIXME("(%p)\n", this);
469
470 return E_NOTIMPL;
471 }
472
473 /************************************************************************
474 * CNetFolder::GetClassID
475 */
476 HRESULT WINAPI CNetFolder::GetClassID(CLSID *lpClassId)
477 {
478 TRACE("(%p)\n", this);
479
480 if (!lpClassId)
481 return E_POINTER;
482
483 *lpClassId = CLSID_NetworkPlaces;
484
485 return S_OK;
486 }
487
488 /************************************************************************
489 * CNetFolder::Initialize
490 *
491 * NOTES: it makes no sense to change the pidl
492 */
493 HRESULT WINAPI CNetFolder::Initialize(LPCITEMIDLIST pidl)
494 {
495 TRACE("(%p)->(%p)\n", this, pidl);
496
497 return S_OK;
498 }
499
500 /**************************************************************************
501 * CNetFolder::GetCurFolder
502 */
503 HRESULT WINAPI CNetFolder::GetCurFolder(LPITEMIDLIST *pidl)
504 {
505 TRACE("(%p)->(%p)\n", this, pidl);
506
507 if (!pidl)
508 return E_POINTER;
509
510 *pidl = ILClone(pidlRoot);
511
512 return S_OK;
513 }