73962e7394adadc9f941fca7c9384e02e60eab5f
[reactos.git] / reactos / 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 HRESULT CCPLExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
129 {
130 PIDLCPanelStruct *pData = _ILGetCPanelPointer(pidl);
131 if (!pData)
132 {
133 return GenericExtractIcon_CreateInstance(psf, pidl, riid, ppvOut);
134 }
135
136 CComPtr<IDefaultExtractIconInit> initIcon;
137 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
138 if (FAILED(hr))
139 return NULL;
140
141 initIcon->SetNormalIcon(pData->szName, (int)pData->iconIdx != -1 ? pData->iconIdx : 0);
142
143 return initIcon->QueryInterface(riid, ppvOut);
144 }
145
146 BOOL CControlPanelEnum::RegisterCPanelApp(LPCWSTR wpath)
147 {
148 CPlApplet* applet = Control_LoadApplet(0, wpath, NULL);
149 int iconIdx;
150
151 if (applet)
152 {
153 for (UINT i = 0; i < applet->count; ++i)
154 {
155 if (applet->info[i].idIcon > 0)
156 iconIdx = -applet->info[i].idIcon; /* negative icon index instead of icon number */
157 else
158 iconIdx = 0;
159
160 LPITEMIDLIST pidl = _ILCreateCPanelApplet(wpath,
161 applet->info[i].name,
162 applet->info[i].info,
163 iconIdx);
164
165 if (pidl)
166 AddToEnumList(pidl);
167 }
168 Control_UnloadApplet(applet);
169 }
170 return TRUE;
171 }
172
173 int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath)
174 {
175 WCHAR name[MAX_PATH];
176 WCHAR value[MAX_PATH];
177 HKEY hkey;
178
179 int cnt = 0;
180
181 if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
182 {
183 int idx = 0;
184
185 for(; ; idx++)
186 {
187 DWORD nameLen = MAX_PATH;
188 DWORD valueLen = MAX_PATH;
189 WCHAR buffer[MAX_PATH];
190
191 if (RegEnumValueW(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
192 break;
193
194 if (ExpandEnvironmentStringsW(value, buffer, MAX_PATH))
195 {
196 wcscpy(value, buffer);
197 }
198
199 if (RegisterCPanelApp(value))
200 ++cnt;
201 }
202 RegCloseKey(hkey);
203 }
204
205 return cnt;
206 }
207
208 int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root, LPCWSTR szRepPath)
209 {
210 WCHAR name[MAX_PATH];
211 HKEY hkey;
212
213 int cnt = 0;
214
215 if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
216 {
217 for (int idx = 0; ; idx++)
218 {
219 if (RegEnumKeyW(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
220 break;
221
222 if (*name == '{')
223 {
224 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name);
225
226 if (pidl && AddToEnumList(pidl))
227 ++cnt;
228 }
229 }
230
231 RegCloseKey(hkey);
232 }
233
234 return cnt;
235 }
236
237 /**************************************************************************
238 * CControlPanelEnum::CreateCPanelEnumList()
239 */
240 BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags)
241 {
242 WCHAR szPath[MAX_PATH];
243 WIN32_FIND_DATAW wfd;
244 HANDLE hFile;
245
246 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
247
248 /* enumerate control panel folders */
249 if (dwFlags & SHCONTF_FOLDERS)
250 RegisterCPanelFolders(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
251
252 /* enumerate the control panel applets */
253 if (dwFlags & SHCONTF_NONFOLDERS)
254 {
255 LPWSTR p;
256
257 GetSystemDirectoryW(szPath, MAX_PATH);
258 p = PathAddBackslashW(szPath);
259 wcscpy(p, L"*.cpl");
260
261 hFile = FindFirstFileW(szPath, &wfd);
262
263 if (hFile != INVALID_HANDLE_VALUE)
264 {
265 do
266 {
267 if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
268 continue;
269
270 if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
271 wcscpy(p, wfd.cFileName);
272 if (wcscmp(wfd.cFileName, L"ncpa.cpl"))
273 RegisterCPanelApp(szPath);
274 }
275 } while(FindNextFileW(hFile, &wfd));
276 FindClose(hFile);
277 }
278
279 RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
280 RegisterRegistryCPanelApps(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
281 }
282 return TRUE;
283 }
284
285 CControlPanelFolder::CControlPanelFolder()
286 {
287 pidlRoot = NULL; /* absolute pidl */
288 }
289
290 CControlPanelFolder::~CControlPanelFolder()
291 {
292 TRACE("-- destroying IShellFolder(%p)\n", this);
293 SHFree(pidlRoot);
294 }
295
296 HRESULT WINAPI CControlPanelFolder::FinalConstruct()
297 {
298 pidlRoot = _ILCreateControlPanel(); /* my qualified pidl */
299 if (pidlRoot == NULL)
300 return E_OUTOFMEMORY;
301 return S_OK;
302 }
303
304 /**************************************************************************
305 * CControlPanelFolder::ParseDisplayName
306 */
307 HRESULT WINAPI CControlPanelFolder::ParseDisplayName(
308 HWND hwndOwner,
309 LPBC pbc,
310 LPOLESTR lpszDisplayName,
311 DWORD *pchEaten,
312 PIDLIST_RELATIVE *ppidl,
313 DWORD *pdwAttributes)
314 {
315 /* We only support parsing guid names */
316 return SH_ParseGuidDisplayName(this, hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
317 }
318
319 /**************************************************************************
320 * CControlPanelFolder::EnumObjects
321 */
322 HRESULT WINAPI CControlPanelFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
323 {
324 return ShellObjectCreatorInit<CControlPanelEnum>(dwFlags, IID_IEnumIDList, ppEnumIDList);
325 }
326
327 /**************************************************************************
328 * CControlPanelFolder::BindToObject
329 */
330 HRESULT WINAPI CControlPanelFolder::BindToObject(
331 PCUIDLIST_RELATIVE pidl,
332 LPBC pbcReserved,
333 REFIID riid,
334 LPVOID *ppvOut)
335 {
336 return SHELL32_BindToGuidItem(pidlRoot, pidl, pbcReserved, riid, ppvOut);
337 }
338
339 /**************************************************************************
340 * CControlPanelFolder::BindToStorage
341 */
342 HRESULT WINAPI CControlPanelFolder::BindToStorage(
343 PCUIDLIST_RELATIVE pidl,
344 LPBC pbcReserved,
345 REFIID riid,
346 LPVOID *ppvOut)
347 {
348 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
349
350 *ppvOut = NULL;
351 return E_NOTIMPL;
352 }
353
354 /**************************************************************************
355 * CControlPanelFolder::CompareIDs
356 */
357 HRESULT WINAPI CControlPanelFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
358 {
359 /* Dont use SHELL32_CompareGuidItems because it would cause guid items to come first */
360 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
361 {
362 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
363 }
364 PIDLCPanelStruct *pData1 = _ILGetCPanelPointer(pidl1);
365 PIDLCPanelStruct *pData2 = _ILGetCPanelPointer(pidl2);
366
367 if (!pData1 || !pData2 || LOWORD(lParam)>= CONROLPANELSHELLVIEWCOLUMNS)
368 return E_INVALIDARG;
369
370 int result;
371 switch(LOWORD(lParam))
372 {
373 case 0: /* name */
374 result = wcsicmp(pData1->szName + pData1->offsDispName, pData2->szName + pData2->offsDispName);
375 break;
376 case 1: /* comment */
377 result = wcsicmp(pData1->szName + pData1->offsComment, pData2->szName + pData2->offsComment);
378 break;
379 default:
380 ERR("Got wrong lParam!\n");
381 return E_INVALIDARG;
382 }
383
384 return MAKE_COMPARE_HRESULT(result);
385 }
386
387 /**************************************************************************
388 * CControlPanelFolder::CreateViewObject
389 */
390 HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
391 {
392 CComPtr<IShellView> pShellView;
393 HRESULT hr = E_INVALIDARG;
394
395 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid(&riid), ppvOut);
396
397 if (ppvOut) {
398 *ppvOut = NULL;
399
400 if (IsEqualIID(riid, IID_IDropTarget)) {
401 WARN("IDropTarget not implemented\n");
402 hr = E_NOTIMPL;
403 } else if (IsEqualIID(riid, IID_IContextMenu)) {
404 WARN("IContextMenu not implemented\n");
405 hr = E_NOTIMPL;
406 } else if (IsEqualIID(riid, IID_IShellView)) {
407 hr = CDefView_Constructor(this, riid, ppvOut);
408 }
409 }
410 TRACE("--(%p)->(interface=%p)\n", this, ppvOut);
411 return hr;
412 }
413
414 /**************************************************************************
415 * CControlPanelFolder::GetAttributesOf
416 */
417 HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
418 {
419 HRESULT hr = S_OK;
420 static const DWORD dwControlPanelAttributes =
421 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
422
423 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
424 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
425
426 if (!rgfInOut)
427 return E_INVALIDARG;
428 if (cidl && !apidl)
429 return E_INVALIDARG;
430
431 if (*rgfInOut == 0)
432 *rgfInOut = ~0;
433
434 if (!cidl)
435 {
436 *rgfInOut &= dwControlPanelAttributes;
437 }
438 else
439 {
440 while(cidl > 0 && *apidl)
441 {
442 pdump(*apidl);
443 if (_ILIsCPanelStruct(*apidl))
444 *rgfInOut &= SFGAO_CANLINK;
445 else if (_ILIsSpecialFolder(*apidl))
446 SHELL32_GetGuidItemAttributes(this, *apidl, rgfInOut);
447 else
448 ERR("Got an unkown pidl here!\n");
449 apidl++;
450 cidl--;
451 }
452 }
453 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
454 *rgfInOut &= ~SFGAO_VALIDATE;
455
456 TRACE("-- result=0x%08x\n", *rgfInOut);
457 return hr;
458 }
459
460 /**************************************************************************
461 * CControlPanelFolder::GetUIObjectOf
462 *
463 * PARAMETERS
464 * HWND hwndOwner, //[in ] Parent window for any output
465 * UINT cidl, //[in ] array size
466 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
467 * REFIID riid, //[in ] Requested Interface
468 * UINT* prgfInOut, //[ ] reserved
469 * LPVOID* ppvObject) //[out] Resulting Interface
470 *
471 */
472 HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner,
473 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
474 {
475 LPVOID pObj = NULL;
476 HRESULT hr = E_INVALIDARG;
477
478 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
479 this, hwndOwner, cidl, apidl, shdebugstr_guid(&riid), prgfInOut, ppvOut);
480
481 if (ppvOut) {
482 *ppvOut = NULL;
483
484 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1)) {
485
486 /* HACK: We should use callbacks from CDefaultContextMenu instead of creating one on our own */
487 BOOL bHasCpl = FALSE;
488 for (UINT i = 0; i < cidl; i++)
489 {
490 if(_ILIsCPanelStruct(apidl[i]))
491 {
492 bHasCpl = TRUE;
493 }
494 }
495
496 if (bHasCpl)
497 hr = ShellObjectCreatorInit<CCPLItemMenu>(cidl, apidl, riid, &pObj);
498 else
499 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
500 } else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1)) {
501 hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
502 } else if ((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) {
503 hr = CCPLExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
504 } else {
505 hr = E_NOINTERFACE;
506 }
507
508 if (SUCCEEDED(hr) && !pObj)
509 hr = E_OUTOFMEMORY;
510
511 *ppvOut = pObj;
512 }
513 TRACE("(%p)->hr=0x%08x\n", this, hr);
514 return hr;
515 }
516
517 /**************************************************************************
518 * CControlPanelFolder::GetDisplayNameOf
519 */
520 HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
521 {
522 if (!pidl)
523 return S_FALSE;
524
525 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl);
526
527 if (pCPanel)
528 {
529 return SHSetStrRet(strRet, pCPanel->szName + pCPanel->offsDispName);
530 }
531 else if (_ILIsSpecialFolder(pidl))
532 {
533 static const WCHAR* pszCPanelPath = L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}";
534 return SHELL32_GetDisplayNameOfGUIDItem(this, pszCPanelPath, pidl, dwFlags, strRet);
535 }
536
537 return S_OK;
538 }
539
540 /**************************************************************************
541 * CControlPanelFolder::SetNameOf
542 * Changes the name of a file object or subfolder, possibly changing its item
543 * identifier in the process.
544 *
545 * PARAMETERS
546 * HWND hwndOwner, //[in ] Owner window for output
547 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
548 * LPCOLESTR lpszName, //[in ] the items new display name
549 * DWORD dwFlags, //[in ] SHGNO formatting flags
550 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
551 */
552 HRESULT WINAPI CControlPanelFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
553 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
554 {
555 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut);
556 return E_FAIL;
557 }
558
559 HRESULT WINAPI CControlPanelFolder::GetDefaultSearchGUID(GUID *pguid)
560 {
561 FIXME("(%p)\n", this);
562 return E_NOTIMPL;
563 }
564
565 HRESULT WINAPI CControlPanelFolder::EnumSearches(IEnumExtraSearch **ppenum)
566 {
567 FIXME("(%p)\n", this);
568 return E_NOTIMPL;
569 }
570
571 HRESULT WINAPI CControlPanelFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
572 {
573 TRACE("(%p)\n", this);
574
575 if (pSort) *pSort = 0;
576 if (pDisplay) *pDisplay = 0;
577 return S_OK;
578 }
579
580 HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
581 {
582 TRACE("(%p)\n", this);
583
584 if (!pcsFlags || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) return E_INVALIDARG;
585 *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags;
586 return S_OK;
587 }
588
589 HRESULT WINAPI CControlPanelFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
590 {
591 FIXME("(%p)\n", this);
592 return E_NOTIMPL;
593 }
594
595 HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
596 {
597 if (!psd || iColumn >= CONROLPANELSHELLVIEWCOLUMNS)
598 return E_INVALIDARG;
599
600 if (!pidl)
601 {
602 psd->fmt = ControlPanelSFHeader[iColumn].fmt;
603 psd->cxChar = ControlPanelSFHeader[iColumn].cxChar;
604 return SHSetStrRet(&psd->str, shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid);
605 }
606 else if (_ILIsSpecialFolder(pidl))
607 {
608 return SHELL32_GetDetailsOfGuidItem(this, pidl, iColumn, psd);
609 }
610 else
611 {
612 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl);
613
614 if (!pCPanel)
615 return E_FAIL;
616
617 switch(iColumn)
618 {
619 case 0: /* name */
620 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsDispName);
621 case 1: /* comment */
622 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsComment);
623 }
624 }
625
626 return S_OK;
627 }
628
629 HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
630 {
631 FIXME("(%p)\n", this);
632 return E_NOTIMPL;
633 }
634
635 /************************************************************************
636 * CControlPanelFolder::GetClassID
637 */
638 HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId)
639 {
640 TRACE("(%p)\n", this);
641
642 if (!lpClassId)
643 return E_POINTER;
644 *lpClassId = CLSID_ControlPanel;
645
646 return S_OK;
647 }
648
649 /************************************************************************
650 * CControlPanelFolder::Initialize
651 *
652 * NOTES: it makes no sense to change the pidl
653 */
654 HRESULT WINAPI CControlPanelFolder::Initialize(LPCITEMIDLIST pidl)
655 {
656 if (pidlRoot)
657 SHFree((LPVOID)pidlRoot);
658
659 pidlRoot = ILClone(pidl);
660 return S_OK;
661 }
662
663 /**************************************************************************
664 * CControlPanelFolder::GetCurFolder
665 */
666 HRESULT WINAPI CControlPanelFolder::GetCurFolder(LPITEMIDLIST * pidl)
667 {
668 TRACE("(%p)->(%p)\n", this, pidl);
669
670 if (!pidl)
671 return E_POINTER;
672 *pidl = ILClone(pidlRoot);
673 return S_OK;
674 }
675
676 CCPLItemMenu::CCPLItemMenu()
677 {
678 m_apidl = NULL;
679 m_cidl = 0;
680 }
681
682 HRESULT WINAPI CCPLItemMenu::Initialize(UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
683 {
684 m_cidl = cidl;
685 m_apidl = _ILCopyaPidl(apidl, m_cidl);
686 if (m_cidl && !m_apidl)
687 return E_OUTOFMEMORY;
688
689 return S_OK;
690 }
691
692 CCPLItemMenu::~CCPLItemMenu()
693 {
694 _ILFreeaPidl(m_apidl, m_cidl);
695 }
696
697 HRESULT WINAPI CCPLItemMenu::QueryContextMenu(
698 HMENU hMenu,
699 UINT indexMenu,
700 UINT idCmdFirst,
701 UINT idCmdLast,
702 UINT uFlags)
703 {
704 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, MAKEINTRESOURCEW(IDS_OPEN), MFS_DEFAULT);
705 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + 1, MFT_SEPARATOR, NULL, MFS_ENABLED);
706 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
707
708 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 2);
709 }
710
711 EXTERN_C
712 void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
713
714 /**************************************************************************
715 * ICPanel_IContextMenu_InvokeCommand()
716 */
717 HRESULT WINAPI CCPLItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
718 {
719 HRESULT hResult;
720
721 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(m_apidl[0]);
722 if(!pCPanel)
723 return E_FAIL;
724
725 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
726
727 if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME
728 {
729 /* Hardcode the command here; Executing a cpl file would be fine but we also need to run things like console.dll */
730 WCHAR wszParams[MAX_PATH];
731 PCWSTR wszFile = L"rundll32.exe";
732 PCWSTR wszFormat = L"shell32.dll,Control_RunDLL %s,%s";
733
734 wsprintfW(wszParams, wszFormat, pCPanel->szName, pCPanel->szName + pCPanel->offsDispName);
735
736 /* Note: we pass the applet name to Control_RunDLL to distinguish between multiple applets in one .cpl file */
737 ShellExecuteW(NULL, NULL, wszFile, wszParams, NULL, 0);
738 }
739 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME
740 {
741 CComPtr<IDataObject> pDataObj;
742 LPITEMIDLIST pidl = _ILCreateControlPanel();
743
744 hResult = SHCreateDataObject(pidl, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj));
745 if (FAILED(hResult))
746 return hResult;
747
748 SHFree(pidl);
749
750 //FIXME: Use SHCreateLinks
751 CComPtr<IShellFolder> psf;
752 CComPtr<IDropTarget> pDT;
753
754 hResult = SHGetDesktopFolder(&psf);
755 if (FAILED(hResult))
756 return hResult;
757
758 hResult = psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pDT));
759 if (FAILED(hResult))
760 return hResult;
761
762 SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
763 }
764 return S_OK;
765 }
766
767 /**************************************************************************
768 * ICPanel_IContextMenu_GetCommandString()
769 *
770 */
771 HRESULT WINAPI CCPLItemMenu::GetCommandString(
772 UINT_PTR idCommand,
773 UINT uFlags,
774 UINT* lpReserved,
775 LPSTR lpszName,
776 UINT uMaxNameLen)
777 {
778 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
779
780 FIXME("unknown command string\n");
781 return E_FAIL;
782 }
783
784 /**************************************************************************
785 * ICPanel_IContextMenu_HandleMenuMsg()
786 */
787 HRESULT WINAPI CCPLItemMenu::HandleMenuMsg(
788 UINT uMsg,
789 WPARAM wParam,
790 LPARAM lParam)
791 {
792 TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam);
793
794 return E_NOTIMPL;
795 }