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