Create a branch for working on csrss and co.
[reactos.git] / dll / win32 / shell32 / folders / cpanel.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 /*
23 TODO:
24 1. The selected items list should not be stored in CControlPanelFolder, it should
25 be a result returned by an internal method.
26 */
27
28 #include <precomp.h>
29
30 WINE_DEFAULT_DEBUG_CHANNEL(shell);
31
32 /***********************************************************************
33 * control panel implementation in shell namespace
34 */
35
36 class CControlPanelEnum :
37 public IEnumIDListImpl
38 {
39 public:
40 CControlPanelEnum();
41 ~CControlPanelEnum();
42 HRESULT WINAPI Initialize(DWORD dwFlags);
43 BOOL RegisterCPanelApp(LPCSTR path);
44 int RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath);
45 int RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath);
46 BOOL CreateCPanelEnumList(DWORD dwFlags);
47
48 BEGIN_COM_MAP(CControlPanelEnum)
49 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
50 END_COM_MAP()
51 };
52
53 /***********************************************************************
54 * IShellFolder [ControlPanel] implementation
55 */
56
57 static const shvheader ControlPanelSFHeader[] = {
58 {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},/*FIXME*/
59 {IDS_SHV_COLUMN9, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 200},/*FIXME*/
60 };
61
62 #define CONROLPANELSHELLVIEWCOLUMNS 2
63
64 CControlPanelEnum::CControlPanelEnum()
65 {
66 }
67
68 CControlPanelEnum::~CControlPanelEnum()
69 {
70 }
71
72 HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags)
73 {
74 if (CreateCPanelEnumList(dwFlags) == FALSE)
75 return E_FAIL;
76 return S_OK;
77 }
78
79 static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName, LPCSTR pszComment, int iIconIdx)
80 {
81 PIDLCPanelStruct *pCP;
82 LPITEMIDLIST pidl;
83 LPPIDLDATA pData;
84 int cchName, cchDisplayName, cchComment, cbData;
85
86 /* Calculate lengths of given strings */
87 cchName = strlen(pszName);
88 cchDisplayName = strlen(pszDisplayName);
89 cchComment = strlen(pszComment);
90
91 /* Allocate PIDL */
92 cbData = sizeof(pidl->mkid.cb) + sizeof(pData->type) + sizeof(pData->u.cpanel) - sizeof(pData->u.cpanel.szName)
93 + cchName + cchDisplayName + cchComment + 3;
94 pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD));
95 if (!pidl)
96 return NULL;
97
98 /* Copy data to allocated memory */
99 pidl->mkid.cb = cbData;
100 pData = (PIDLDATA *)pidl->mkid.abID;
101 pData->type = PT_CPLAPPLET;
102
103 pCP = &pData->u.cpanel;
104 pCP->dummy = 0;
105 pCP->iconIdx = iIconIdx;
106 strcpy(pCP->szName, pszName);
107 pCP->offsDispName = cchName + 1;
108 strcpy(pCP->szName + pCP->offsDispName, pszDisplayName);
109 pCP->offsComment = pCP->offsDispName + cchDisplayName + 1;
110 strcpy(pCP->szName + pCP->offsComment, pszComment);
111
112 /* Add PIDL NULL terminator */
113 *(WORD*)(pCP->szName + pCP->offsComment + cchComment + 1) = 0;
114
115 pcheck(pidl);
116
117 return pidl;
118 }
119
120 /**************************************************************************
121 * _ILGetCPanelPointer()
122 * gets a pointer to the control panel struct stored in the pidl
123 */
124 static PIDLCPanelStruct *_ILGetCPanelPointer(LPCITEMIDLIST pidl)
125 {
126 LPPIDLDATA pdata = _ILGetDataPointer(pidl);
127
128 if (pdata && pdata->type == PT_CPLAPPLET)
129 return (PIDLCPanelStruct *) & (pdata->u.cpanel);
130
131 return NULL;
132 }
133
134 BOOL CControlPanelEnum::RegisterCPanelApp(LPCSTR path)
135 {
136 LPITEMIDLIST pidl;
137 CPlApplet* applet;
138 CPanel panel;
139 CPLINFO info;
140 unsigned i;
141 int iconIdx;
142
143 char displayName[MAX_PATH];
144 char comment[MAX_PATH];
145
146 WCHAR wpath[MAX_PATH];
147
148 MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH);
149
150 panel.first = NULL;
151 applet = Control_LoadApplet(0, wpath, &panel);
152
153 if (applet)
154 {
155 for (i = 0; i < applet->count; ++i)
156 {
157 WideCharToMultiByte(CP_ACP, 0, applet->info[i].szName, -1, displayName, MAX_PATH, 0, 0);
158 WideCharToMultiByte(CP_ACP, 0, applet->info[i].szInfo, -1, comment, MAX_PATH, 0, 0);
159
160 applet->proc(0, CPL_INQUIRE, i, (LPARAM)&info);
161
162 if (info.idIcon > 0)
163 iconIdx = -info.idIcon; /* negative icon index instead of icon number */
164 else
165 iconIdx = 0;
166
167 pidl = _ILCreateCPanelApplet(path, displayName, comment, iconIdx);
168
169 if (pidl)
170 AddToEnumList(pidl);
171 }
172 Control_UnloadApplet(applet);
173 }
174 return TRUE;
175 }
176
177 int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath)
178 {
179 char name[MAX_PATH];
180 char value[MAX_PATH];
181 HKEY hkey;
182
183 int cnt = 0;
184
185 if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
186 {
187 int idx = 0;
188
189 for(; ; idx++)
190 {
191 DWORD nameLen = MAX_PATH;
192 DWORD valueLen = MAX_PATH;
193
194 if (RegEnumValueA(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
195 break;
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, LPCSTR szRepPath)
207 {
208 char name[MAX_PATH];
209 HKEY hkey;
210
211 int cnt = 0;
212
213 if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
214 {
215 int idx = 0;
216 for (; ; idx++)
217 {
218 if (RegEnumKeyA(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
219 break;
220
221 if (*name == '{')
222 {
223 LPITEMIDLIST pidl = _ILCreateGuidFromStrA(name);
224
225 if (pidl && AddToEnumList(pidl))
226 ++cnt;
227 }
228 }
229
230 RegCloseKey(hkey);
231 }
232
233 return cnt;
234 }
235
236 /**************************************************************************
237 * CControlPanelEnum::CreateCPanelEnumList()
238 */
239 BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags)
240 {
241 CHAR szPath[MAX_PATH];
242 WIN32_FIND_DATAA wfd;
243 HANDLE hFile;
244
245 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
246
247 /* enumerate control panel folders */
248 if (dwFlags & SHCONTF_FOLDERS)
249 RegisterCPanelFolders(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
250
251 /* enumerate the control panel applets */
252 if (dwFlags & SHCONTF_NONFOLDERS)
253 {
254 LPSTR p;
255
256 GetSystemDirectoryA(szPath, MAX_PATH);
257 p = PathAddBackslashA(szPath);
258 strcpy(p, "*.cpl");
259
260 TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n", this, debugstr_a(szPath));
261 hFile = FindFirstFileA(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 strcpy(p, wfd.cFileName);
272 if (strcmp(wfd.cFileName, "ncpa.cpl"))
273 RegisterCPanelApp(szPath);
274 }
275 } while(FindNextFileA(hFile, &wfd));
276 FindClose(hFile);
277 }
278
279 RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
280 RegisterRegistryCPanelApps(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
281 }
282 return TRUE;
283 }
284
285 CControlPanelFolder::CControlPanelFolder()
286 {
287 pidlRoot = NULL; /* absolute pidl */
288 dwAttributes = 0; /* attributes returned by GetAttributesOf FIXME: use it */
289 apidl = NULL;
290 cidl = 0;
291 }
292
293 CControlPanelFolder::~CControlPanelFolder()
294 {
295 TRACE("-- destroying IShellFolder(%p)\n", this);
296 SHFree(pidlRoot);
297 }
298
299 HRESULT WINAPI CControlPanelFolder::FinalConstruct()
300 {
301 pidlRoot = _ILCreateControlPanel(); /* my qualified pidl */
302 if (pidlRoot == NULL)
303 return E_OUTOFMEMORY;
304 return S_OK;
305 }
306
307 /**************************************************************************
308 * CControlPanelFolder::ParseDisplayName
309 */
310 HRESULT WINAPI CControlPanelFolder::ParseDisplayName(
311 HWND hwndOwner,
312 LPBC pbc,
313 LPOLESTR lpszDisplayName,
314 DWORD *pchEaten,
315 LPITEMIDLIST *ppidl,
316 DWORD *pdwAttributes)
317 {
318 WCHAR szElement[MAX_PATH];
319 LPCWSTR szNext = NULL;
320 LPITEMIDLIST pidlTemp = NULL;
321 HRESULT hr = S_OK;
322 CLSID clsid;
323
324 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
325 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
326 pchEaten, ppidl, pdwAttributes);
327
328 if (!lpszDisplayName || !ppidl)
329 return E_INVALIDARG;
330
331 *ppidl = 0;
332
333 if (pchEaten)
334 *pchEaten = 0; /* strange but like the original */
335
336 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
337 {
338 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
339 TRACE ("-- element: %s\n", debugstr_w (szElement));
340 CLSIDFromString (szElement + 2, &clsid);
341 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
342 }
343 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
344 {
345 *ppidl = pidlTemp;
346 return S_OK;
347 }
348
349 if (SUCCEEDED(hr) && pidlTemp)
350 {
351 if (szNext && *szNext)
352 {
353 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
354 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
355 }
356 else
357 {
358 if (pdwAttributes && *pdwAttributes)
359 hr = SHELL32_GetItemAttributes(this,
360 pidlTemp, pdwAttributes);
361 }
362 }
363
364 *ppidl = pidlTemp;
365
366 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
367
368 return hr;
369 }
370
371 /**************************************************************************
372 * CControlPanelFolder::EnumObjects
373 */
374 HRESULT WINAPI CControlPanelFolder::EnumObjects(
375 HWND hwndOwner,
376 DWORD dwFlags,
377 LPENUMIDLIST *ppEnumIDList)
378 {
379 CComObject<CControlPanelEnum> *theEnumerator;
380 CComPtr<IEnumIDList> result;
381 HRESULT hResult;
382
383 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
384
385 if (ppEnumIDList == NULL)
386 return E_POINTER;
387 *ppEnumIDList = NULL;
388 ATLTRY (theEnumerator = new CComObject<CControlPanelEnum>);
389 if (theEnumerator == NULL)
390 return E_OUTOFMEMORY;
391 hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result);
392 if (FAILED (hResult))
393 {
394 delete theEnumerator;
395 return hResult;
396 }
397 hResult = theEnumerator->Initialize (dwFlags);
398 if (FAILED (hResult))
399 return hResult;
400 *ppEnumIDList = result.Detach ();
401
402 TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
403
404 return S_OK;
405 }
406
407 /**************************************************************************
408 * CControlPanelFolder::BindToObject
409 */
410 HRESULT WINAPI CControlPanelFolder::BindToObject(
411 LPCITEMIDLIST pidl,
412 LPBC pbcReserved,
413 REFIID riid,
414 LPVOID *ppvOut)
415 {
416 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
417
418 return SHELL32_BindToChild(pidlRoot, NULL, pidl, riid, ppvOut);
419 }
420
421 /**************************************************************************
422 * CControlPanelFolder::BindToStorage
423 */
424 HRESULT WINAPI CControlPanelFolder::BindToStorage(
425 LPCITEMIDLIST pidl,
426 LPBC pbcReserved,
427 REFIID riid,
428 LPVOID *ppvOut)
429 {
430 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
431
432 *ppvOut = NULL;
433 return E_NOTIMPL;
434 }
435
436 /**************************************************************************
437 * CControlPanelFolder::CompareIDs
438 */
439
440 HRESULT WINAPI CControlPanelFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
441 {
442 int nReturn;
443
444 TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
445 nReturn = SHELL32_CompareIDs(this, lParam, pidl1, pidl2);
446 TRACE("-- %i\n", nReturn);
447 return nReturn;
448 }
449
450 /**************************************************************************
451 * CControlPanelFolder::CreateViewObject
452 */
453 HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
454 {
455 CComPtr<IShellView> pShellView;
456 HRESULT hr = E_INVALIDARG;
457
458 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid(&riid), ppvOut);
459
460 if (ppvOut) {
461 *ppvOut = NULL;
462
463 if (IsEqualIID(riid, IID_IDropTarget)) {
464 WARN("IDropTarget not implemented\n");
465 hr = E_NOTIMPL;
466 } else if (IsEqualIID(riid, IID_IContextMenu)) {
467 WARN("IContextMenu not implemented\n");
468 hr = E_NOTIMPL;
469 } else if (IsEqualIID(riid, IID_IShellView)) {
470 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
471 if (pShellView) {
472 hr = pShellView->QueryInterface(riid, ppvOut);
473 }
474 }
475 }
476 TRACE("--(%p)->(interface=%p)\n", this, ppvOut);
477 return hr;
478 }
479
480 /**************************************************************************
481 * CControlPanelFolder::GetAttributesOf
482 */
483 HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
484 {
485 HRESULT hr = S_OK;
486
487 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
488 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
489
490 if (!rgfInOut)
491 return E_INVALIDARG;
492 if (cidl && !apidl)
493 return E_INVALIDARG;
494
495 if (*rgfInOut == 0)
496 *rgfInOut = ~0;
497
498 while(cidl > 0 && *apidl)
499 {
500 pdump(*apidl);
501 SHELL32_GetItemAttributes(this, *apidl, rgfInOut);
502 apidl++;
503 cidl--;
504 }
505 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
506 *rgfInOut &= ~SFGAO_VALIDATE;
507
508 TRACE("-- result=0x%08x\n", *rgfInOut);
509 return hr;
510 }
511
512 /**************************************************************************
513 * CControlPanelFolder::GetUIObjectOf
514 *
515 * PARAMETERS
516 * HWND hwndOwner, //[in ] Parent window for any output
517 * UINT cidl, //[in ] array size
518 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
519 * REFIID riid, //[in ] Requested Interface
520 * UINT* prgfInOut, //[ ] reserved
521 * LPVOID* ppvObject) //[out] Resulting Interface
522 *
523 */
524 HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner,
525 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
526 {
527 LPITEMIDLIST pidl;
528 IUnknown *pObj = NULL;
529 HRESULT hr = E_INVALIDARG;
530
531 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
532 this, hwndOwner, cidl, apidl, shdebugstr_guid(&riid), prgfInOut, ppvOut);
533
534 if (ppvOut) {
535 *ppvOut = NULL;
536
537 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1)) {
538 // TODO
539 // create a seperate item struct
540 //
541 pObj = (IContextMenu *)this;
542 this->apidl = apidl;
543 this->cidl = cidl;
544 pObj->AddRef();
545 hr = S_OK;
546 } else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1)) {
547 hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
548 } else if (IsEqualIID(riid, IID_IExtractIconA) && (cidl == 1)) {
549 pidl = ILCombine(pidlRoot, apidl[0]);
550 pObj = (LPUNKNOWN) IExtractIconA_Constructor(pidl);
551 SHFree(pidl);
552 hr = S_OK;
553 } else if (IsEqualIID(riid, IID_IExtractIconW) && (cidl == 1)) {
554 pidl = ILCombine(pidlRoot, apidl[0]);
555 pObj = (LPUNKNOWN) IExtractIconW_Constructor(pidl);
556 SHFree(pidl);
557 hr = S_OK;
558 } else if ((IsEqualIID(riid, IID_IShellLinkW) || IsEqualIID(riid, IID_IShellLinkA))
559 && (cidl == 1)) {
560 pidl = ILCombine(pidlRoot, apidl[0]);
561 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
562 SHFree(pidl);
563 } else {
564 hr = E_NOINTERFACE;
565 }
566
567 if (SUCCEEDED(hr) && !pObj)
568 hr = E_OUTOFMEMORY;
569
570 *ppvOut = pObj;
571 }
572 TRACE("(%p)->hr=0x%08x\n", this, hr);
573 return hr;
574 }
575
576 /**************************************************************************
577 * CControlPanelFolder::GetDisplayNameOf
578 */
579 HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
580 {
581 CHAR szName[MAX_PATH];
582 WCHAR wszName[MAX_PATH+1]; /* +1 for potential backslash */
583 PIDLCPanelStruct *pCPanel;
584 HRESULT hr;
585
586 *szName = '\0';
587
588 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
589 pdump(pidl);
590
591 if (!pidl)
592 return S_FALSE;
593
594 pCPanel = _ILGetCPanelPointer(pidl);
595
596 if (pCPanel)
597 {
598 /* copy display name from pidl - it was retrived from applet before;
599 SHGDN_FORPARSING does not need special handling */
600 lstrcpyA(szName, pCPanel->szName + pCPanel->offsDispName);
601 }
602 /* take names of special folders only if it's only this folder */
603 else if (_ILIsSpecialFolder(pidl))
604 {
605 BOOL bSimplePidl = _ILIsPidlSimple(pidl);
606 SFGAOF Attr = SFGAO_FILESYSTEM;
607
608 SHELL32_GetItemAttributes(this, pidl, &Attr);
609 if (Attr & SFGAO_FILESYSTEM)
610 {
611 hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, wszName, sizeof(wszName));
612 if (FAILED(hr))
613 return hr;
614 }
615 else if (bSimplePidl)
616 {
617 _ILSimpleGetTextW(pidl, wszName, MAX_PATH); /* append my own path */
618 }
619 else
620 {
621 FIXME("special pidl\n");
622 if (dwFlags & SHGDN_FORPARSING)
623 {
624 /* go deeper if needed */
625 int cchName;
626
627 PathAddBackslashW(wszName);
628 cchName = wcslen(wszName);
629
630 hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, wszName + cchName, MAX_PATH + 1 - cchName);
631 if (FAILED(hr))
632 return hr;
633 }
634 }
635
636 if (!WideCharToMultiByte(CP_ACP, 0, wszName, -1, szName, MAX_PATH, NULL, NULL))
637 szName[0] = '\0';
638 }
639
640 strRet->uType = STRRET_CSTR;
641 lstrcpynA(strRet->cStr, szName, MAX_PATH);
642
643 TRACE("--(%p)->(%s)\n", this, szName);
644 return S_OK;
645 }
646
647 /**************************************************************************
648 * CControlPanelFolder::SetNameOf
649 * Changes the name of a file object or subfolder, possibly changing its item
650 * identifier in the process.
651 *
652 * PARAMETERS
653 * HWND hwndOwner, //[in ] Owner window for output
654 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
655 * LPCOLESTR lpszName, //[in ] the items new display name
656 * DWORD dwFlags, //[in ] SHGNO formatting flags
657 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
658 */
659 HRESULT WINAPI CControlPanelFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */
660 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
661 {
662 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut);
663 return E_FAIL;
664 }
665
666 HRESULT WINAPI CControlPanelFolder::GetDefaultSearchGUID(GUID *pguid)
667 {
668 FIXME("(%p)\n", this);
669 return E_NOTIMPL;
670 }
671
672 HRESULT WINAPI CControlPanelFolder::EnumSearches(IEnumExtraSearch **ppenum)
673 {
674 FIXME("(%p)\n", this);
675 return E_NOTIMPL;
676 }
677
678 HRESULT WINAPI CControlPanelFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
679 {
680 TRACE("(%p)\n", this);
681
682 if (pSort) *pSort = 0;
683 if (pDisplay) *pDisplay = 0;
684 return S_OK;
685 }
686
687 HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
688 {
689 TRACE("(%p)\n", this);
690
691 if (!pcsFlags || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) return E_INVALIDARG;
692 *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags;
693 return S_OK;
694 }
695
696 HRESULT WINAPI CControlPanelFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
697 {
698 FIXME("(%p)\n", this);
699 return E_NOTIMPL;
700 }
701
702 HRESULT WINAPI CControlPanelFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
703 {
704 HRESULT hr;
705
706 TRACE("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
707
708 if (!psd || iColumn >= CONROLPANELSHELLVIEWCOLUMNS)
709 return E_INVALIDARG;
710
711 if (!pidl) {
712 psd->fmt = ControlPanelSFHeader[iColumn].fmt;
713 psd->cxChar = ControlPanelSFHeader[iColumn].cxChar;
714 psd->str.uType = STRRET_CSTR;
715 LoadStringA(shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid, psd->str.cStr, MAX_PATH);
716 return S_OK;
717 } else {
718 psd->str.cStr[0] = 0x00;
719 psd->str.uType = STRRET_CSTR;
720 switch(iColumn) {
721 case 0: /* name */
722 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
723 break;
724 case 1: /* comment */
725 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
726 break;
727 }
728 hr = S_OK;
729 }
730
731 return hr;
732 }
733
734 HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
735 {
736 FIXME("(%p)\n", this);
737 return E_NOTIMPL;
738 }
739
740 /************************************************************************
741 * CControlPanelFolder::GetClassID
742 */
743 HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId)
744 {
745 TRACE("(%p)\n", this);
746
747 if (!lpClassId)
748 return E_POINTER;
749 *lpClassId = CLSID_ControlPanel;
750
751 return S_OK;
752 }
753
754 /************************************************************************
755 * CControlPanelFolder::Initialize
756 *
757 * NOTES: it makes no sense to change the pidl
758 */
759 HRESULT WINAPI CControlPanelFolder::Initialize(LPCITEMIDLIST pidl)
760 {
761 if (pidlRoot)
762 SHFree((LPVOID)pidlRoot);
763
764 pidlRoot = ILClone(pidl);
765 return S_OK;
766 }
767
768 /**************************************************************************
769 * CControlPanelFolder::GetCurFolder
770 */
771 HRESULT WINAPI CControlPanelFolder::GetCurFolder(LPITEMIDLIST * pidl)
772 {
773 TRACE("(%p)->(%p)\n", this, pidl);
774
775 if (!pidl)
776 return E_POINTER;
777 *pidl = ILClone(pidlRoot);
778 return S_OK;
779 }
780
781 HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST pidl, LPWSTR szIconFile, UINT cchMax, int* piIndex)
782 {
783 PIDLCPanelStruct* pcpanel = _ILGetCPanelPointer(pidl);
784
785 if (!pcpanel)
786 return E_INVALIDARG;
787
788 MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, szIconFile, cchMax);
789 *piIndex = (int)pcpanel->iconIdx != -1 ? pcpanel->iconIdx : 0;
790
791 return S_OK;
792 }
793
794
795 /**************************************************************************
796 * IShellExecuteHookW Implementation
797 */
798
799 static HRESULT
800 ExecuteAppletFromCLSID(LPOLESTR pOleStr)
801 {
802 WCHAR wszBuf[128], wszCmd[MAX_PATH];
803 DWORD cbCmd = sizeof(wszCmd);
804
805 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"CLSID\\%s\\shell\\open\\command", pOleStr);
806
807 if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, NULL, RRF_RT_REG_SZ, NULL, (PVOID)wszCmd, &cbCmd) != ERROR_SUCCESS)
808 {
809 ERR("RegGetValueW(%ls) failed with %u\n", wszBuf, GetLastError());
810 return E_FAIL;
811 }
812
813 if (!ExpandEnvironmentStringsW(wszCmd, wszBuf, _countof(wszBuf)))
814 return E_FAIL;
815
816 PROCESS_INFORMATION pi;
817 STARTUPINFOW si;
818 ZeroMemory(&si, sizeof(si));
819 si.cb = sizeof(si);
820 if (!CreateProcessW(NULL, wszBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
821 return E_FAIL;
822
823 CloseHandle(pi.hProcess);
824 CloseHandle(pi.hThread);
825 return S_OK;
826 }
827
828 EXTERN_C void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
829
830 HRESULT WINAPI CControlPanelFolder::ExecuteFromIdList(LPCITEMIDLIST pidl)
831 {
832 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(ILFindLastID(pidl));
833
834 if (!pCPanel)
835 {
836 /* Is it GUID to control panel applet? */
837 IID *piid = _ILGetGUIDPointer(ILFindLastID(pidl));
838 if (!piid)
839 return E_INVALIDARG;
840
841 /* Start it */
842 LPOLESTR pOleStr;
843 if (StringFromCLSID(*piid, &pOleStr) == S_OK)
844 {
845 HRESULT hr = ExecuteAppletFromCLSID(pOleStr);
846 CoTaskMemFree(pOleStr);
847 return hr;
848 }
849
850 ERR("Cannot open cpanel applet\n");
851 return E_INVALIDARG;
852 }
853
854 /* Build control panel applet cmd
855 Note: we passes applet name to Control_RunDLL to distinguish between applets in one .cpl file */
856 WCHAR wszCmd[2*MAX_PATH];
857 StringCbPrintfW(wszCmd, sizeof(wszCmd), L"rundll32 shell32.dll,Control_RunDLL \"%hs\",\"%hs\"", pCPanel->szName, pCPanel->szName + pCPanel->offsDispName);
858
859 /* Start the applet */
860 TRACE("Run cpl %ls\n", wszCmd);
861 STARTUPINFO si;
862 PROCESS_INFORMATION pi;
863 ZeroMemory(&si, sizeof(si));
864 si.cb = sizeof(si);
865 if (!CreateProcessW(NULL, wszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
866 return E_FAIL;
867
868 CloseHandle(pi.hProcess);
869 CloseHandle(pi.hThread);
870 return S_OK;
871 }
872
873 HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOW psei)
874 {
875 TRACE("(%p)->execute(%p)\n", this, psei);
876
877 if (!psei)
878 return E_INVALIDARG;
879
880 if (!(psei->fMask & SEE_MASK_IDLIST))
881 {
882 FIXME("no idlist given!\n");
883 return E_FAIL;
884 }
885
886 return ExecuteFromIdList((LPCITEMIDLIST)psei->lpIDList);
887 }
888
889 /**************************************************************************
890 * IShellExecuteHookA Implementation
891 */
892
893 HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOA psei)
894 {
895 TRACE("(%p)->execute(%p)\n", this, psei);
896
897 if (!psei)
898 return E_INVALIDARG;
899
900 if (!(psei->fMask & SEE_MASK_IDLIST))
901 {
902 FIXME("no idlist given!\n");
903 return E_FAIL;
904 }
905
906 return ExecuteFromIdList((LPCITEMIDLIST)psei->lpIDList);
907 }
908
909 /**************************************************************************
910 * IContextMenu2 Implementation
911 */
912
913 /**************************************************************************
914 * ICPanel_IContextMenu_QueryContextMenu()
915 */
916 HRESULT WINAPI CControlPanelFolder::QueryContextMenu(
917 HMENU hMenu,
918 UINT indexMenu,
919 UINT idCmdFirst,
920 UINT idCmdLast,
921 UINT uFlags)
922 {
923 WCHAR szBuffer[30] = {0};
924 ULONG Count = 1;
925
926 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
927 this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
928
929 if (LoadStringW(shell32_hInstance, IDS_OPEN, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
930 {
931 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
932 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, szBuffer, MFS_DEFAULT); //FIXME identifier
933 Count++;
934 }
935
936 if (LoadStringW(shell32_hInstance, IDS_CREATELINK, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
937 {
938 if (Count)
939 {
940 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_SEPARATOR, NULL, MFS_ENABLED);
941 }
942 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
943
944 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, szBuffer, MFS_ENABLED); //FIXME identifier
945 Count++;
946 }
947 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
948 }
949
950 /**************************************************************************
951 * ICPanel_IContextMenu_InvokeCommand()
952 */
953 HRESULT WINAPI CControlPanelFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
954 {
955 SHELLEXECUTEINFOW sei;
956 WCHAR szPath[MAX_PATH];
957 char szTarget[MAX_PATH];
958 STRRET strret;
959 WCHAR* pszPath;
960 INT Length, cLength;
961 PIDLCPanelStruct *pcpanel;
962 CComPtr<IPersistFile> ppf;
963 CComPtr<IShellLinkA> isl;
964 HRESULT hResult;
965
966 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
967
968 if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME
969 {
970 ZeroMemory(&sei, sizeof(sei));
971 sei.cbSize = sizeof(sei);
972 sei.fMask = SEE_MASK_INVOKEIDLIST;
973 sei.lpIDList = ILCombine(pidlRoot, apidl[0]);
974 sei.hwnd = lpcmi->hwnd;
975 sei.nShow = SW_SHOWNORMAL;
976 sei.lpVerb = L"open";
977 ERR("here\n");
978 return Execute(&sei);
979 }
980 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME
981 {
982 if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE))
983 return E_FAIL;
984
985 pszPath = PathAddBackslashW(szPath);
986 if (!pszPath)
987 return E_FAIL;
988
989 if (GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strret) != S_OK)
990 return E_FAIL;
991
992 Length = MAX_PATH - (pszPath - szPath);
993 cLength = strlen(strret.cStr);
994 if (Length < cLength + 5)
995 {
996 FIXME("\n");
997 return E_FAIL;
998 }
999
1000 if (MultiByteToWideChar(CP_ACP, 0, strret.cStr, cLength + 1, pszPath, Length))
1001 {
1002 pszPath += cLength;
1003 Length -= cLength;
1004 }
1005
1006 if (Length > 10)
1007 {
1008 wcscpy(pszPath, L" - ");
1009 cLength = LoadStringW(shell32_hInstance, IDS_LNK_FILE, &pszPath[3], Length - 4) + 3;
1010 if (cLength + 5 > Length)
1011 cLength = Length - 5;
1012 Length -= cLength;
1013 pszPath += cLength;
1014 }
1015 wcscpy(pszPath, L".lnk");
1016
1017 pcpanel = _ILGetCPanelPointer(ILFindLastID(apidl[0]));
1018 if (pcpanel)
1019 {
1020 strncpy(szTarget, pcpanel->szName, MAX_PATH);
1021 }
1022 else
1023 {
1024 FIXME("Couldn't retrieve pointer to cpl structure\n");
1025 return E_FAIL;
1026 }
1027 hResult = CShellLink::_CreatorClass::CreateInstance(NULL, IID_IShellLinkA, (void **)&isl);
1028 if (SUCCEEDED(hResult))
1029 {
1030 isl->SetPath(szTarget);
1031 if (SUCCEEDED(isl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
1032 ppf->Save(szPath, TRUE);
1033 }
1034 return NOERROR;
1035 }
1036 return S_OK;
1037 }
1038
1039 /**************************************************************************
1040 * ICPanel_IContextMenu_GetCommandString()
1041 *
1042 */
1043 HRESULT WINAPI CControlPanelFolder::GetCommandString(
1044 UINT_PTR idCommand,
1045 UINT uFlags,
1046 UINT* lpReserved,
1047 LPSTR lpszName,
1048 UINT uMaxNameLen)
1049 {
1050 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
1051
1052 FIXME("unknown command string\n");
1053 return E_FAIL;
1054 }
1055
1056 /**************************************************************************
1057 * ICPanel_IContextMenu_HandleMenuMsg()
1058 */
1059 HRESULT WINAPI CControlPanelFolder::HandleMenuMsg(
1060 UINT uMsg,
1061 WPARAM wParam,
1062 LPARAM lParam)
1063 {
1064 TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam);
1065
1066 return E_NOTIMPL;
1067 }