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