Create the AHCI branch for Aman's work
[reactos.git] / dll / win32 / shell32 / folders / CControlPanelFolder.cpp
1 /*
2 * Control panel folder
3 *
4 * Copyright 2003 Martin Fuchs
5 * Copyright 2009 Andrew Hill
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <precomp.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL(shell);
25
26 /***********************************************************************
27 * control panel implementation in shell namespace
28 */
29
30 class CControlPanelEnum :
31 public CEnumIDListBase
32 {
33 public:
34 CControlPanelEnum();
35 ~CControlPanelEnum();
36 HRESULT WINAPI Initialize(DWORD dwFlags);
37 BOOL RegisterCPanelApp(LPCWSTR path);
38 int RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath);
39 int RegisterCPanelFolders(HKEY hkey_root, LPCWSTR szRepPath);
40 BOOL CreateCPanelEnumList(DWORD dwFlags);
41
42 BEGIN_COM_MAP(CControlPanelEnum)
43 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
44 END_COM_MAP()
45 };
46
47 /***********************************************************************
48 * IShellFolder [ControlPanel] implementation
49 */
50
51 static const shvheader ControlPanelSFHeader[] = {
52 {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},/*FIXME*/
53 {IDS_SHV_COLUMN9, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 80},/*FIXME*/
54 };
55
56 #define CONROLPANELSHELLVIEWCOLUMNS 2
57
58 CControlPanelEnum::CControlPanelEnum()
59 {
60 }
61
62 CControlPanelEnum::~CControlPanelEnum()
63 {
64 }
65
66 HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags)
67 {
68 if (CreateCPanelEnumList(dwFlags) == FALSE)
69 return E_FAIL;
70 return S_OK;
71 }
72
73 static LPITEMIDLIST _ILCreateCPanelApplet(LPCWSTR pszName, LPCWSTR pszDisplayName, LPCWSTR pszComment, int iIconIdx)
74 {
75 PIDLCPanelStruct *pCP;
76 LPITEMIDLIST pidl;
77 LPPIDLDATA pData;
78 int cchName, cchDisplayName, cchComment, cbData;
79
80 /* Calculate lengths of given strings */
81 cchName = wcslen(pszName);
82 cchDisplayName = wcslen(pszDisplayName);
83 cchComment = wcslen(pszComment);
84
85 /* Allocate PIDL */
86 cbData = sizeof(pidl->mkid.cb) + sizeof(pData->type) + sizeof(pData->u.cpanel) - sizeof(pData->u.cpanel.szName)
87 + (cchName + cchDisplayName + cchComment + 3) * sizeof(WCHAR);
88 pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD));
89 if (!pidl)
90 return NULL;
91
92 /* Copy data to allocated memory */
93 pidl->mkid.cb = cbData;
94 pData = (PIDLDATA *)pidl->mkid.abID;
95 pData->type = PT_CPLAPPLET;
96
97 pCP = &pData->u.cpanel;
98 pCP->dummy = 0;
99 pCP->iconIdx = iIconIdx;
100 wcscpy(pCP->szName, pszName);
101 pCP->offsDispName = cchName + 1;
102 wcscpy(pCP->szName + pCP->offsDispName, pszDisplayName);
103 pCP->offsComment = pCP->offsDispName + cchDisplayName + 1;
104 wcscpy(pCP->szName + pCP->offsComment, pszComment);
105
106 /* Add PIDL NULL terminator */
107 *(WORD*)(pCP->szName + pCP->offsComment + cchComment + 1) = 0;
108
109 pcheck(pidl);
110
111 return pidl;
112 }
113
114 /**************************************************************************
115 * _ILGetCPanelPointer()
116 * gets a pointer to the control panel struct stored in the pidl
117 */
118 static PIDLCPanelStruct *_ILGetCPanelPointer(LPCITEMIDLIST pidl)
119 {
120 LPPIDLDATA pdata = _ILGetDataPointer(pidl);
121
122 if (pdata && pdata->type == PT_CPLAPPLET)
123 return (PIDLCPanelStruct *) & (pdata->u.cpanel);
124
125 return NULL;
126 }
127
128 BOOL CControlPanelEnum::RegisterCPanelApp(LPCWSTR wpath)
129 {
130 CPlApplet* applet = Control_LoadApplet(0, wpath, NULL);
131 int iconIdx;
132
133 if (applet)
134 {
135 for (UINT i = 0; i < applet->count; ++i)
136 {
137 if (applet->info[i].idIcon > 0)
138 iconIdx = -applet->info[i].idIcon; /* negative icon index instead of icon number */
139 else
140 iconIdx = 0;
141
142 LPITEMIDLIST pidl = _ILCreateCPanelApplet(wpath,
143 applet->info[i].name,
144 applet->info[i].info,
145 iconIdx);
146
147 if (pidl)
148 AddToEnumList(pidl);
149 }
150 Control_UnloadApplet(applet);
151 }
152 return TRUE;
153 }
154
155 int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath)
156 {
157 WCHAR name[MAX_PATH];
158 WCHAR value[MAX_PATH];
159 HKEY hkey;
160
161 int cnt = 0;
162
163 if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
164 {
165 int idx = 0;
166
167 for(; ; idx++)
168 {
169 DWORD nameLen = MAX_PATH;
170 DWORD valueLen = MAX_PATH;
171 WCHAR buffer[MAX_PATH];
172
173 if (RegEnumValueW(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
174 break;
175
176 if (ExpandEnvironmentStringsW(value, buffer, MAX_PATH))
177 {
178 wcscpy(value, buffer);
179 }
180
181 if (RegisterCPanelApp(value))
182 ++cnt;
183 }
184 RegCloseKey(hkey);
185 }
186
187 return cnt;
188 }
189
190 int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root, LPCWSTR szRepPath)
191 {
192 WCHAR name[MAX_PATH];
193 HKEY hkey;
194
195 int cnt = 0;
196
197 if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
198 {
199 for (int idx = 0; ; idx++)
200 {
201 if (RegEnumKeyW(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
202 break;
203
204 if (*name == '{')
205 {
206 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name);
207
208 if (pidl && AddToEnumList(pidl))
209 ++cnt;
210 }
211 }
212
213 RegCloseKey(hkey);
214 }
215
216 return cnt;
217 }
218
219 /**************************************************************************
220 * CControlPanelEnum::CreateCPanelEnumList()
221 */
222 BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags)
223 {
224 WCHAR szPath[MAX_PATH];
225 WIN32_FIND_DATAW wfd;
226 HANDLE hFile;
227
228 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
229
230 /* enumerate control panel folders */
231 if (dwFlags & SHCONTF_FOLDERS)
232 RegisterCPanelFolders(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
233
234 /* enumerate the control panel applets */
235 if (dwFlags & SHCONTF_NONFOLDERS)
236 {
237 LPWSTR p;
238
239 GetSystemDirectoryW(szPath, MAX_PATH);
240 p = PathAddBackslashW(szPath);
241 wcscpy(p, L"*.cpl");
242
243 hFile = FindFirstFileW(szPath, &wfd);
244
245 if (hFile != INVALID_HANDLE_VALUE)
246 {
247 do
248 {
249 if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
250 continue;
251
252 if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
253 wcscpy(p, wfd.cFileName);
254 if (wcscmp(wfd.cFileName, L"ncpa.cpl"))
255 RegisterCPanelApp(szPath);
256 }
257 } while(FindNextFileW(hFile, &wfd));
258 FindClose(hFile);
259 }
260
261 RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
262 RegisterRegistryCPanelApps(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
263 }
264 return TRUE;
265 }
266
267 CControlPanelFolder::CControlPanelFolder()
268 {
269 pidlRoot = NULL; /* absolute pidl */
270 }
271
272 CControlPanelFolder::~CControlPanelFolder()
273 {
274 TRACE("-- destroying IShellFolder(%p)\n", this);
275 SHFree(pidlRoot);
276 }
277
278 HRESULT WINAPI CControlPanelFolder::FinalConstruct()
279 {
280 pidlRoot = _ILCreateControlPanel(); /* my qualified pidl */
281 if (pidlRoot == NULL)
282 return E_OUTOFMEMORY;
283 return S_OK;
284 }
285
286 /**************************************************************************
287 * CControlPanelFolder::ParseDisplayName
288 */
289 HRESULT WINAPI CControlPanelFolder::ParseDisplayName(
290 HWND hwndOwner,
291 LPBC pbc,
292 LPOLESTR lpszDisplayName,
293 DWORD *pchEaten,
294 PIDLIST_RELATIVE *ppidl,
295 DWORD *pdwAttributes)
296 {
297 /* We only support parsing guid names */
298 return SH_ParseGuidDisplayName(this, hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
299 }
300
301 /**************************************************************************
302 * CControlPanelFolder::EnumObjects
303 */
304 HRESULT WINAPI CControlPanelFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
305 {
306 return ShellObjectCreatorInit<CControlPanelEnum>(dwFlags, IID_IEnumIDList, ppEnumIDList);
307 }
308
309 /**************************************************************************
310 * CControlPanelFolder::BindToObject
311 */
312 HRESULT WINAPI CControlPanelFolder::BindToObject(
313 PCUIDLIST_RELATIVE pidl,
314 LPBC pbcReserved,
315 REFIID riid,
316 LPVOID *ppvOut)
317 {
318 return SHELL32_BindToGuidItem(pidlRoot, pidl, pbcReserved, riid, ppvOut);
319 }
320
321 /**************************************************************************
322 * CControlPanelFolder::BindToStorage
323 */
324 HRESULT WINAPI CControlPanelFolder::BindToStorage(
325 PCUIDLIST_RELATIVE pidl,
326 LPBC pbcReserved,
327 REFIID riid,
328 LPVOID *ppvOut)
329 {
330 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
331
332 *ppvOut = NULL;
333 return E_NOTIMPL;
334 }
335
336 /**************************************************************************
337 * CControlPanelFolder::CompareIDs
338 */
339 HRESULT WINAPI CControlPanelFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
340 {
341 /* Dont use SHELL32_CompareGuidItems because it would cause guid items to come first */
342 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
343 {
344 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
345 }
346 PIDLCPanelStruct *pData1 = _ILGetCPanelPointer(pidl1);
347 PIDLCPanelStruct *pData2 = _ILGetCPanelPointer(pidl2);
348
349 if (!pData1 || !pData2 || LOWORD(lParam)>= CONROLPANELSHELLVIEWCOLUMNS)
350 return E_INVALIDARG;
351
352 int result;
353 switch(LOWORD(lParam))
354 {
355 case 0: /* name */
356 result = wcsicmp(pData1->szName + pData1->offsDispName, pData2->szName + pData2->offsDispName);
357 break;
358 case 1: /* comment */
359 result = wcsicmp(pData1->szName + pData1->offsComment, pData2->szName + pData2->offsComment);
360 break;
361 default:
362 ERR("Got wrong lParam!\n");
363 return E_INVALIDARG;
364 }
365
366 return MAKE_COMPARE_HRESULT(result);
367 }
368
369 /**************************************************************************
370 * CControlPanelFolder::CreateViewObject
371 */
372 HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
373 {
374 CComPtr<IShellView> pShellView;
375 HRESULT hr = E_INVALIDARG;
376
377 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid(&riid), ppvOut);
378
379 if (ppvOut) {
380 *ppvOut = NULL;
381
382 if (IsEqualIID(riid, IID_IDropTarget)) {
383 WARN("IDropTarget not implemented\n");
384 hr = E_NOTIMPL;
385 } else if (IsEqualIID(riid, IID_IContextMenu)) {
386 WARN("IContextMenu not implemented\n");
387 hr = E_NOTIMPL;
388 } else if (IsEqualIID(riid, IID_IShellView)) {
389 hr = CDefView_Constructor(this, riid, ppvOut);
390 }
391 }
392 TRACE("--(%p)->(interface=%p)\n", this, ppvOut);
393 return hr;
394 }
395
396 /**************************************************************************
397 * CControlPanelFolder::GetAttributesOf
398 */
399 HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
400 {
401 HRESULT hr = S_OK;
402 static const DWORD dwControlPanelAttributes =
403 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
404
405 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
406 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
407
408 if (!rgfInOut)
409 return E_INVALIDARG;
410 if (cidl && !apidl)
411 return E_INVALIDARG;
412
413 if (*rgfInOut == 0)
414 *rgfInOut = ~0;
415
416 if (!cidl)
417 {
418 *rgfInOut &= dwControlPanelAttributes;
419 }
420 else
421 {
422 while(cidl > 0 && *apidl)
423 {
424 pdump(*apidl);
425 if (_ILIsCPanelStruct(*apidl))
426 *rgfInOut &= SFGAO_CANLINK;
427 else if (_ILIsSpecialFolder(*apidl))
428 SHELL32_GetGuidItemAttributes(this, *apidl, rgfInOut);
429 else
430 ERR("Got an unkown pidl here!\n");
431 apidl++;
432 cidl--;
433 }
434 }
435 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
436 *rgfInOut &= ~SFGAO_VALIDATE;
437
438 TRACE("-- result=0x%08x\n", *rgfInOut);
439 return hr;
440 }
441
442 /**************************************************************************
443 * CControlPanelFolder::GetUIObjectOf
444 *
445 * PARAMETERS
446 * HWND hwndOwner, //[in ] Parent window for any output
447 * UINT cidl, //[in ] array size
448 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
449 * REFIID riid, //[in ] Requested Interface
450 * UINT* prgfInOut, //[ ] reserved
451 * LPVOID* ppvObject) //[out] Resulting Interface
452 *
453 */
454 HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner,
455 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
456 {
457 LPITEMIDLIST pidl;
458 IUnknown *pObj = NULL;
459 HRESULT hr = E_INVALIDARG;
460
461 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
462 this, hwndOwner, cidl, apidl, shdebugstr_guid(&riid), prgfInOut, ppvOut);
463
464 if (ppvOut) {
465 *ppvOut = NULL;
466
467 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1)) {
468
469 /* HACK: We should use callbacks from CDefaultContextMenu instead of creating one on our own */
470 BOOL bHasCpl = FALSE;
471 for (UINT i = 0; i < cidl; i++)
472 {
473 if(_ILIsCPanelStruct(apidl[i]))
474 {
475 bHasCpl = TRUE;
476 }
477 }
478
479 if (bHasCpl)
480 hr = ShellObjectCreatorInit<CCPLItemMenu>(cidl, apidl, riid, &pObj);
481 else
482 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
483 } else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1)) {
484 hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
485 } else if (IsEqualIID(riid, IID_IExtractIconA) && (cidl == 1)) {
486 pidl = ILCombine(pidlRoot, apidl[0]);
487 pObj = IExtractIconA_Constructor(pidl);
488 SHFree(pidl);
489 hr = S_OK;
490 } else if (IsEqualIID(riid, IID_IExtractIconW) && (cidl == 1)) {
491 pidl = ILCombine(pidlRoot, apidl[0]);
492 pObj = IExtractIconW_Constructor(pidl);
493 SHFree(pidl);
494 hr = S_OK;
495 } else if ((IsEqualIID(riid, IID_IShellLinkW) || IsEqualIID(riid, IID_IShellLinkA))
496 && (cidl == 1)) {
497 pidl = ILCombine(pidlRoot, apidl[0]);
498 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
499 SHFree(pidl);
500 } else {
501 hr = E_NOINTERFACE;
502 }
503
504 if (SUCCEEDED(hr) && !pObj)
505 hr = E_OUTOFMEMORY;
506
507 *ppvOut = pObj;
508 }
509 TRACE("(%p)->hr=0x%08x\n", this, hr);
510 return hr;
511 }
512
513 /**************************************************************************
514 * CControlPanelFolder::GetDisplayNameOf
515 */
516 HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
517 {
518 if (!pidl)
519 return S_FALSE;
520
521 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl);
522
523 if (pCPanel)
524 {
525 return SHSetStrRet(strRet, pCPanel->szName + pCPanel->offsDispName);
526 }
527 else if (_ILIsSpecialFolder(pidl))
528 {
529 static const WCHAR* pszCPanelPath = L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}";
530 return SHELL32_GetDisplayNameOfGUIDItem(this, pszCPanelPath, pidl, dwFlags, strRet);
531 }
532
533 return S_OK;
534 }
535
536 /**************************************************************************
537 * CControlPanelFolder::SetNameOf
538 * Changes the name of a file object or subfolder, possibly changing its item
539 * identifier in the process.
540 *
541 * PARAMETERS
542 * HWND hwndOwner, //[in ] Owner window for output
543 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
544 * LPCOLESTR lpszName, //[in ] the items new display name
545 * DWORD dwFlags, //[in ] SHGNO formatting flags
546 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
547 */
548 HRESULT WINAPI CControlPanelFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
549 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
550 {
551 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut);
552 return E_FAIL;
553 }
554
555 HRESULT WINAPI CControlPanelFolder::GetDefaultSearchGUID(GUID *pguid)
556 {
557 FIXME("(%p)\n", this);
558 return E_NOTIMPL;
559 }
560
561 HRESULT WINAPI CControlPanelFolder::EnumSearches(IEnumExtraSearch **ppenum)
562 {
563 FIXME("(%p)\n", this);
564 return E_NOTIMPL;
565 }
566
567 HRESULT WINAPI CControlPanelFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
568 {
569 TRACE("(%p)\n", this);
570
571 if (pSort) *pSort = 0;
572 if (pDisplay) *pDisplay = 0;
573 return S_OK;
574 }
575
576 HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
577 {
578 TRACE("(%p)\n", this);
579
580 if (!pcsFlags || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) return E_INVALIDARG;
581 *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags;
582 return S_OK;
583 }
584
585 HRESULT WINAPI CControlPanelFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
586 {
587 FIXME("(%p)\n", this);
588 return E_NOTIMPL;
589 }
590
591 HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
592 {
593 if (!psd || iColumn >= CONROLPANELSHELLVIEWCOLUMNS)
594 return E_INVALIDARG;
595
596 if (!pidl)
597 {
598 psd->fmt = ControlPanelSFHeader[iColumn].fmt;
599 psd->cxChar = ControlPanelSFHeader[iColumn].cxChar;
600 return SHSetStrRet(&psd->str, shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid);
601 }
602 else if (_ILIsSpecialFolder(pidl))
603 {
604 return SHELL32_GetDetailsOfGuidItem(this, pidl, iColumn, psd);
605 }
606 else
607 {
608 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl);
609
610 if (!pCPanel)
611 return E_FAIL;
612
613 switch(iColumn)
614 {
615 case 0: /* name */
616 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsDispName);
617 case 1: /* comment */
618 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsComment);
619 }
620 }
621
622 return S_OK;
623 }
624
625 HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
626 {
627 FIXME("(%p)\n", this);
628 return E_NOTIMPL;
629 }
630
631 /************************************************************************
632 * CControlPanelFolder::GetClassID
633 */
634 HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId)
635 {
636 TRACE("(%p)\n", this);
637
638 if (!lpClassId)
639 return E_POINTER;
640 *lpClassId = CLSID_ControlPanel;
641
642 return S_OK;
643 }
644
645 /************************************************************************
646 * CControlPanelFolder::Initialize
647 *
648 * NOTES: it makes no sense to change the pidl
649 */
650 HRESULT WINAPI CControlPanelFolder::Initialize(LPCITEMIDLIST pidl)
651 {
652 if (pidlRoot)
653 SHFree((LPVOID)pidlRoot);
654
655 pidlRoot = ILClone(pidl);
656 return S_OK;
657 }
658
659 /**************************************************************************
660 * CControlPanelFolder::GetCurFolder
661 */
662 HRESULT WINAPI CControlPanelFolder::GetCurFolder(LPITEMIDLIST * pidl)
663 {
664 TRACE("(%p)->(%p)\n", this, pidl);
665
666 if (!pidl)
667 return E_POINTER;
668 *pidl = ILClone(pidlRoot);
669 return S_OK;
670 }
671
672 HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST pidl, LPWSTR szIconFile, UINT cchMax, int* piIndex)
673 {
674 PIDLCPanelStruct* pcpanel = _ILGetCPanelPointer(pidl);
675
676 if (!pcpanel)
677 return E_INVALIDARG;
678
679 wcsncpy(szIconFile, pcpanel->szName, cchMax);
680 *piIndex = (int)pcpanel->iconIdx != -1 ? pcpanel->iconIdx : 0;
681
682 return S_OK;
683 }
684
685
686 CCPLItemMenu::CCPLItemMenu()
687 {
688 m_apidl = NULL;
689 m_cidl = 0;
690 }
691
692 HRESULT WINAPI CCPLItemMenu::Initialize(UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
693 {
694 m_cidl = cidl;
695 m_apidl = _ILCopyaPidl(apidl, m_cidl);
696 if (m_cidl && !m_apidl)
697 return E_OUTOFMEMORY;
698
699 return S_OK;
700 }
701
702 CCPLItemMenu::~CCPLItemMenu()
703 {
704 _ILFreeaPidl(m_apidl, m_cidl);
705 }
706
707 HRESULT WINAPI CCPLItemMenu::QueryContextMenu(
708 HMENU hMenu,
709 UINT indexMenu,
710 UINT idCmdFirst,
711 UINT idCmdLast,
712 UINT uFlags)
713 {
714 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, MAKEINTRESOURCEW(IDS_OPEN), MFS_DEFAULT);
715 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + 1, MFT_SEPARATOR, NULL, MFS_ENABLED);
716 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
717
718 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 2);
719 }
720
721 EXTERN_C
722 void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
723
724 /**************************************************************************
725 * ICPanel_IContextMenu_InvokeCommand()
726 */
727 HRESULT WINAPI CCPLItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
728 {
729 HRESULT hResult;
730
731 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(m_apidl[0]);
732 if(!pCPanel)
733 return E_FAIL;
734
735 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
736
737 if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME
738 {
739 /* Hardcode the command here; Executing a cpl file would be fine but we also need to run things like console.dll */
740 WCHAR wszParams[MAX_PATH];
741 PCWSTR wszFile = L"rundll32.exe";
742 PCWSTR wszFormat = L"shell32.dll,Control_RunDLL %s,%s";
743
744 wsprintfW(wszParams, wszFormat, pCPanel->szName, pCPanel->szName + pCPanel->offsDispName);
745
746 /* Note: we pass the applet name to Control_RunDLL to distinguish between multiple applets in one .cpl file */
747 ShellExecuteW(NULL, NULL, wszFile, wszParams, NULL, 0);
748 }
749 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME
750 {
751 CComPtr<IDataObject> pDataObj;
752 LPITEMIDLIST pidl = _ILCreateControlPanel();
753
754 hResult = SHCreateDataObject(pidl, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj));
755 if (FAILED(hResult))
756 return hResult;
757
758 SHFree(pidl);
759
760 //FIXME: Use SHCreateLinks
761 CComPtr<IShellFolder> psf;
762 CComPtr<IDropTarget> pDT;
763
764 hResult = SHGetDesktopFolder(&psf);
765 if (FAILED(hResult))
766 return hResult;
767
768 hResult = psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pDT));
769 if (FAILED(hResult))
770 return hResult;
771
772 SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
773 }
774 return S_OK;
775 }
776
777 /**************************************************************************
778 * ICPanel_IContextMenu_GetCommandString()
779 *
780 */
781 HRESULT WINAPI CCPLItemMenu::GetCommandString(
782 UINT_PTR idCommand,
783 UINT uFlags,
784 UINT* lpReserved,
785 LPSTR lpszName,
786 UINT uMaxNameLen)
787 {
788 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
789
790 FIXME("unknown command string\n");
791 return E_FAIL;
792 }
793
794 /**************************************************************************
795 * ICPanel_IContextMenu_HandleMenuMsg()
796 */
797 HRESULT WINAPI CCPLItemMenu::HandleMenuMsg(
798 UINT uMsg,
799 WPARAM wParam,
800 LPARAM lParam)
801 {
802 TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam);
803
804 return E_NOTIMPL;
805 }