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