riched20: Fix crash undoing a paste.
[wine] / dlls / shell32 / cpanelfolder.c
1 /*
2  * Control panel folder
3  *
4  * Copyright 2003 Martin Fuchs
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or(at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #define COBJMACROS
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32
33 #include "winerror.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winreg.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39
40 #include "ole2.h"
41 #include "shlguid.h"
42
43 #include "cpanel.h"
44 #include "enumidlist.h"
45 #include "pidl.h"
46 #include "undocshell.h"
47 #include "shell32_main.h"
48 #include "shresdef.h"
49 #include "shlwapi.h"
50 #include "wine/debug.h"
51 #include "debughlp.h"
52 #include "shfldr.h"
53
54 WINE_DEFAULT_DEBUG_CHANNEL(shell);
55
56 /***********************************************************************
57 *   control panel implementation in shell namespace
58 */
59
60 typedef struct {
61     const IShellFolder2Vtbl      *lpVtbl;
62     LONG                   ref;
63     const IPersistFolder2Vtbl    *lpVtblPersistFolder2;
64     const IShellExecuteHookWVtbl *lpVtblShellExecuteHookW;
65     const IShellExecuteHookAVtbl *lpVtblShellExecuteHookA;
66
67     IUnknown *pUnkOuter;        /* used for aggregation */
68
69     /* both paths are parsible from the desktop */
70     LPITEMIDLIST pidlRoot;      /* absolute pidl */
71     int dwAttributes;           /* attributes returned by GetAttributesOf FIXME: use it */
72 } ICPanelImpl;
73
74 static const IShellFolder2Vtbl vt_ShellFolder2;
75 static const IPersistFolder2Vtbl vt_PersistFolder2;
76 static const IShellExecuteHookWVtbl vt_ShellExecuteHookW;
77 static const IShellExecuteHookAVtbl vt_ShellExecuteHookA;
78
79 static inline ICPanelImpl *impl_from_IPersistFolder2( IPersistFolder2 *iface )
80 {
81     return (ICPanelImpl *)((char*)iface - FIELD_OFFSET(ICPanelImpl, lpVtblPersistFolder2));
82 }
83
84 static inline ICPanelImpl *impl_from_IShellExecuteHookW( IShellExecuteHookW *iface )
85 {
86     return (ICPanelImpl *)((char*)iface - FIELD_OFFSET(ICPanelImpl, lpVtblShellExecuteHookW));
87 }
88
89 static inline ICPanelImpl *impl_from_IShellExecuteHookA( IShellExecuteHookA *iface )
90 {
91     return (ICPanelImpl *)((char*)iface - FIELD_OFFSET(ICPanelImpl, lpVtblShellExecuteHookA));
92 }
93
94
95 /*
96   converts This to an interface pointer
97 */
98 #define _IUnknown_(This)           (IUnknown*)&(This->lpVtbl)
99 #define _IShellFolder_(This)       (IShellFolder*)&(This->lpVtbl)
100 #define _IShellFolder2_(This)      (IShellFolder2*)&(This->lpVtbl)
101
102 #define _IPersist_(This)           (IPersist*)&(This->lpVtblPersistFolder2)
103 #define _IPersistFolder_(This)     (IPersistFolder*)&(This->lpVtblPersistFolder2)
104 #define _IPersistFolder2_(This)    (IPersistFolder2*)&(This->lpVtblPersistFolder2)
105 #define _IShellExecuteHookW_(This) (IShellExecuteHookW*)&(This->lpVtblShellExecuteHookW)
106 #define _IShellExecuteHookA_(This) (IShellExecuteHookA*)&(This->lpVtblShellExecuteHookA)
107
108 /***********************************************************************
109 *   IShellFolder [ControlPanel] implementation
110 */
111
112 static const shvheader ControlPanelSFHeader[] = {
113     {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},/*FIXME*/
114     {IDS_SHV_COLUMN9, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 200},/*FIXME*/
115 };
116
117 #define CONROLPANELSHELLVIEWCOLUMNS 2
118
119 /**************************************************************************
120 *       IControlPanel_Constructor
121 */
122 HRESULT WINAPI IControlPanel_Constructor(IUnknown* pUnkOuter, REFIID riid, LPVOID * ppv)
123 {
124     ICPanelImpl *sf;
125
126     TRACE("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid(riid));
127
128     if (!ppv)
129         return E_POINTER;
130     if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
131         return CLASS_E_NOAGGREGATION;
132
133     sf = (ICPanelImpl *) LocalAlloc(LMEM_ZEROINIT, sizeof(ICPanelImpl));
134     if (!sf)
135         return E_OUTOFMEMORY;
136
137     sf->ref = 0;
138     sf->lpVtbl = &vt_ShellFolder2;
139     sf->lpVtblPersistFolder2 = &vt_PersistFolder2;
140     sf->lpVtblShellExecuteHookW = &vt_ShellExecuteHookW;
141     sf->lpVtblShellExecuteHookA = &vt_ShellExecuteHookA;
142     sf->pidlRoot = _ILCreateControlPanel();     /* my qualified pidl */
143     sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf);
144
145     if (!SUCCEEDED(IUnknown_QueryInterface(_IUnknown_(sf), riid, ppv))) {
146         IUnknown_Release(_IUnknown_(sf));
147         return E_NOINTERFACE;
148     }
149
150     TRACE("--(%p)\n", sf);
151     return S_OK;
152 }
153
154 /**************************************************************************
155  *      ISF_ControlPanel_fnQueryInterface
156  *
157  * NOTES supports not IPersist/IPersistFolder
158  */
159 static HRESULT WINAPI ISF_ControlPanel_fnQueryInterface(IShellFolder2 * iface, REFIID riid, LPVOID * ppvObject)
160 {
161     ICPanelImpl *This = (ICPanelImpl *)iface;
162
163     TRACE("(%p)->(%s,%p)\n", This, shdebugstr_guid(riid), ppvObject);
164
165     *ppvObject = NULL;
166
167     if (IsEqualIID(riid, &IID_IUnknown) ||
168         IsEqualIID(riid, &IID_IShellFolder) || IsEqualIID(riid, &IID_IShellFolder2))
169         *ppvObject = This;
170     else if (IsEqualIID(riid, &IID_IPersist) ||
171                IsEqualIID(riid, &IID_IPersistFolder) || IsEqualIID(riid, &IID_IPersistFolder2))
172         *ppvObject = _IPersistFolder2_(This);
173     else if (IsEqualIID(riid, &IID_IShellExecuteHookW))
174         *ppvObject = _IShellExecuteHookW_(This);
175     else if (IsEqualIID(riid, &IID_IShellExecuteHookA))
176         *ppvObject = _IShellExecuteHookA_(This);
177
178     if (*ppvObject) {
179         IUnknown_AddRef((IUnknown *)(*ppvObject));
180         TRACE("-- Interface:(%p)->(%p)\n", ppvObject, *ppvObject);
181         return S_OK;
182     }
183     TRACE("-- Interface: E_NOINTERFACE\n");
184     return E_NOINTERFACE;
185 }
186
187 static ULONG WINAPI ISF_ControlPanel_fnAddRef(IShellFolder2 * iface)
188 {
189     ICPanelImpl *This = (ICPanelImpl *)iface;
190     ULONG refCount = InterlockedIncrement(&This->ref);
191
192     TRACE("(%p)->(count=%u)\n", This, refCount - 1);
193
194     return refCount;
195 }
196
197 static ULONG WINAPI ISF_ControlPanel_fnRelease(IShellFolder2 * iface)
198 {
199     ICPanelImpl *This = (ICPanelImpl *)iface;
200     ULONG refCount = InterlockedDecrement(&This->ref);
201
202     TRACE("(%p)->(count=%u)\n", This, refCount + 1);
203
204     if (!refCount) {
205         TRACE("-- destroying IShellFolder(%p)\n", This);
206         SHFree(This->pidlRoot);
207         LocalFree((HLOCAL) This);
208     }
209     return refCount;
210 }
211
212 /**************************************************************************
213 *       ISF_ControlPanel_fnParseDisplayName
214 */
215 static HRESULT WINAPI
216 ISF_ControlPanel_fnParseDisplayName(IShellFolder2 * iface,
217                                    HWND hwndOwner,
218                                    LPBC pbc,
219                                    LPOLESTR lpszDisplayName,
220                                    DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
221 {
222     ICPanelImpl *This = (ICPanelImpl *)iface;
223
224     HRESULT hr = E_INVALIDARG;
225
226     FIXME("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
227            This, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName), pchEaten, ppidl, pdwAttributes);
228
229     *ppidl = 0;
230     if (pchEaten)
231         *pchEaten = 0;
232
233     TRACE("(%p)->(-- ret=0x%08x)\n", This, hr);
234
235     return hr;
236 }
237
238 static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR name, LPCSTR displayName,
239  LPCSTR comment, int iconIdx)
240 {
241     PIDLCPanelStruct *p;
242     LPITEMIDLIST pidl;
243     PIDLDATA tmp;
244     int size0 = (char*)&tmp.u.cpanel.szName-(char*)&tmp.u.cpanel;
245     int size = size0;
246     int l;
247
248     tmp.type = PT_CPLAPPLET;
249     tmp.u.cpanel.dummy = 0;
250     tmp.u.cpanel.iconIdx = iconIdx;
251
252     l = strlen(name);
253     size += l+1;
254
255     tmp.u.cpanel.offsDispName = l+1;
256     l = strlen(displayName);
257     size += l+1;
258
259     tmp.u.cpanel.offsComment = tmp.u.cpanel.offsDispName+1+l;
260     l = strlen(comment);
261     size += l+1;
262
263     pidl = SHAlloc(size+4);
264     if (!pidl)
265         return NULL;
266
267     pidl->mkid.cb = size+2;
268     memcpy(pidl->mkid.abID, &tmp, 2+size0);
269
270     p = &((PIDLDATA*)pidl->mkid.abID)->u.cpanel;
271     strcpy(p->szName, name);
272     strcpy(p->szName+tmp.u.cpanel.offsDispName, displayName);
273     strcpy(p->szName+tmp.u.cpanel.offsComment, comment);
274
275     *(WORD*)((char*)pidl+(size+2)) = 0;
276
277     pcheck(pidl);
278
279     return pidl;
280 }
281
282 /**************************************************************************
283  *  _ILGetCPanelPointer()
284  * gets a pointer to the control panel struct stored in the pidl
285  */
286 static PIDLCPanelStruct* _ILGetCPanelPointer(LPCITEMIDLIST pidl)
287 {
288     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
289
290     if (pdata && pdata->type==PT_CPLAPPLET)
291         return (PIDLCPanelStruct*)&(pdata->u.cpanel);
292
293     return NULL;
294 }
295
296  /**************************************************************************
297  *              ISF_ControlPanel_fnEnumObjects
298  */
299 static BOOL SHELL_RegisterCPanelApp(IEnumIDList* list, LPCSTR path)
300 {
301     LPITEMIDLIST pidl;
302     CPlApplet* applet;
303     CPanel panel;
304     CPLINFO info;
305     unsigned i;
306     int iconIdx;
307
308     char displayName[MAX_PATH];
309     char comment[MAX_PATH];
310
311     WCHAR wpath[MAX_PATH];
312
313     MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH);
314
315     panel.first = NULL;
316     applet = Control_LoadApplet(0, wpath, &panel);
317
318     if (applet)
319     {
320         for(i=0; i<applet->count; ++i)
321         {
322             WideCharToMultiByte(CP_ACP, 0, applet->info[i].szName, -1, displayName, MAX_PATH, 0, 0);
323             WideCharToMultiByte(CP_ACP, 0, applet->info[i].szInfo, -1, comment, MAX_PATH, 0, 0);
324
325             applet->proc(0, CPL_INQUIRE, i, (LPARAM)&info);
326
327             if (info.idIcon > 0)
328                 iconIdx = -info.idIcon; /* negative icon index instead of icon number */
329             else
330                 iconIdx = 0;
331
332             pidl = _ILCreateCPanelApplet(path, displayName, comment, iconIdx);
333
334             if (pidl)
335                 AddToEnumList(list, pidl);
336         }
337         Control_UnloadApplet(applet);
338     }
339     return TRUE;
340 }
341
342 static int SHELL_RegisterRegistryCPanelApps(IEnumIDList* list, HKEY hkey_root, LPCSTR szRepPath)
343 {
344     char name[MAX_PATH];
345     char value[MAX_PATH];
346     HKEY hkey;
347
348     int cnt = 0;
349
350     if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
351     {
352         int idx = 0;
353
354         for(;; ++idx)
355         {
356             DWORD nameLen = MAX_PATH;
357             DWORD valueLen = MAX_PATH;
358
359             if (RegEnumValueA(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
360                 break;
361
362             if (SHELL_RegisterCPanelApp(list, value))
363                 ++cnt;
364         }
365         RegCloseKey(hkey);
366     }
367
368     return cnt;
369 }
370
371 static int SHELL_RegisterCPanelFolders(IEnumIDList* list, HKEY hkey_root, LPCSTR szRepPath)
372 {
373     char name[MAX_PATH];
374     HKEY hkey;
375
376     int cnt = 0;
377
378     if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
379     {
380         int idx = 0;
381         for(;; ++idx)
382         {
383             if (RegEnumKeyA(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
384                 break;
385
386             if (*name == '{')
387             {
388                 LPITEMIDLIST pidl = _ILCreateGuidFromStrA(name);
389
390                 if (pidl && AddToEnumList(list, pidl))
391                     ++cnt;
392             }
393         }
394
395         RegCloseKey(hkey);
396     }
397
398   return cnt;
399 }
400
401 /**************************************************************************
402  *  CreateCPanelEnumList()
403  */
404 static BOOL CreateCPanelEnumList(
405     IEnumIDList * iface,
406     DWORD dwFlags)
407 {
408     CHAR szPath[MAX_PATH];
409     WIN32_FIND_DATAA wfd;
410     HANDLE hFile;
411
412     TRACE("(%p)->(flags=0x%08x)\n", iface, dwFlags);
413
414     /* enumerate control panel folders */
415     if (dwFlags & SHCONTF_FOLDERS)
416         SHELL_RegisterCPanelFolders(iface, HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
417
418     /* enumerate the control panel applets */
419     if (dwFlags & SHCONTF_NONFOLDERS)
420     {
421         LPSTR p;
422
423         GetSystemDirectoryA(szPath, MAX_PATH);
424         p = PathAddBackslashA(szPath);
425         strcpy(p, "*.cpl");
426
427         TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",iface,debugstr_a(szPath));
428         hFile = FindFirstFileA(szPath, &wfd);
429
430         if (hFile != INVALID_HANDLE_VALUE)
431         {
432             do
433             {
434                 if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
435                     continue;
436
437                 if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
438                     strcpy(p, wfd.cFileName);
439                     SHELL_RegisterCPanelApp((IEnumIDList*)iface, szPath);
440                 }
441             } while(FindNextFileA(hFile, &wfd));
442             FindClose(hFile);
443         }
444
445         SHELL_RegisterRegistryCPanelApps((IEnumIDList*)iface, HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
446         SHELL_RegisterRegistryCPanelApps((IEnumIDList*)iface, HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
447     }
448     return TRUE;
449 }
450
451 /**************************************************************************
452 *               ISF_ControlPanel_fnEnumObjects
453 */
454 static HRESULT WINAPI
455 ISF_ControlPanel_fnEnumObjects(IShellFolder2 * iface, HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
456 {
457     ICPanelImpl *This = (ICPanelImpl *)iface;
458
459     TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This, hwndOwner, dwFlags, ppEnumIDList);
460
461     *ppEnumIDList = IEnumIDList_Constructor();
462     if (*ppEnumIDList)
463         CreateCPanelEnumList(*ppEnumIDList, dwFlags);
464
465     TRACE("--(%p)->(new ID List: %p)\n", This, *ppEnumIDList);
466
467     return(*ppEnumIDList) ? S_OK : E_OUTOFMEMORY;
468 }
469
470 /**************************************************************************
471 *               ISF_ControlPanel_fnBindToObject
472 */
473 static HRESULT WINAPI
474 ISF_ControlPanel_fnBindToObject(IShellFolder2 * iface, LPCITEMIDLIST pidl,
475                                LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
476 {
477     ICPanelImpl *This = (ICPanelImpl *)iface;
478
479     TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbcReserved, shdebugstr_guid(riid), ppvOut);
480
481     return SHELL32_BindToChild(This->pidlRoot, NULL, pidl, riid, ppvOut);
482 }
483
484 /**************************************************************************
485 *       ISF_ControlPanel_fnBindToStorage
486 */
487 static HRESULT WINAPI
488 ISF_ControlPanel_fnBindToStorage(IShellFolder2 * iface,
489                                 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
490 {
491     ICPanelImpl *This = (ICPanelImpl *)iface;
492
493     FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved, shdebugstr_guid(riid), ppvOut);
494
495     *ppvOut = NULL;
496     return E_NOTIMPL;
497 }
498
499 /**************************************************************************
500 *       ISF_ControlPanel_fnCompareIDs
501 */
502
503 static HRESULT WINAPI
504 ISF_ControlPanel_fnCompareIDs(IShellFolder2 * iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
505 {
506     ICPanelImpl *This = (ICPanelImpl *)iface;
507
508     int nReturn;
509
510     TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
511     nReturn = SHELL32_CompareIDs(_IShellFolder_(This), lParam, pidl1, pidl2);
512     TRACE("-- %i\n", nReturn);
513     return nReturn;
514 }
515
516 /**************************************************************************
517 *       ISF_ControlPanel_fnCreateViewObject
518 */
519 static HRESULT WINAPI
520 ISF_ControlPanel_fnCreateViewObject(IShellFolder2 * iface, HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
521 {
522     ICPanelImpl *This = (ICPanelImpl *)iface;
523
524     LPSHELLVIEW pShellView;
525     HRESULT hr = E_INVALIDARG;
526
527     TRACE("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid(riid), ppvOut);
528
529     if (ppvOut) {
530         *ppvOut = NULL;
531
532         if (IsEqualIID(riid, &IID_IDropTarget)) {
533             WARN("IDropTarget not implemented\n");
534             hr = E_NOTIMPL;
535         } else if (IsEqualIID(riid, &IID_IContextMenu)) {
536             WARN("IContextMenu not implemented\n");
537             hr = E_NOTIMPL;
538         } else if (IsEqualIID(riid, &IID_IShellView)) {
539             pShellView = IShellView_Constructor((IShellFolder *) iface);
540             if (pShellView) {
541                 hr = IShellView_QueryInterface(pShellView, riid, ppvOut);
542                 IShellView_Release(pShellView);
543             }
544         }
545     }
546     TRACE("--(%p)->(interface=%p)\n", This, ppvOut);
547     return hr;
548 }
549
550 /**************************************************************************
551 *  ISF_ControlPanel_fnGetAttributesOf
552 */
553 static HRESULT WINAPI
554 ISF_ControlPanel_fnGetAttributesOf(IShellFolder2 * iface, UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
555 {
556     ICPanelImpl *This = (ICPanelImpl *)iface;
557
558     HRESULT hr = S_OK;
559
560     TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
561           This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
562
563     if (!rgfInOut)
564         return E_INVALIDARG;
565     if (cidl && !apidl)
566         return E_INVALIDARG;
567
568     if (*rgfInOut == 0)
569         *rgfInOut = ~0;
570
571     while(cidl > 0 && *apidl) {
572         pdump(*apidl);
573         SHELL32_GetItemAttributes(_IShellFolder_(This), *apidl, rgfInOut);
574         apidl++;
575         cidl--;
576     }
577     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
578     *rgfInOut &= ~SFGAO_VALIDATE;
579
580     TRACE("-- result=0x%08x\n", *rgfInOut);
581     return hr;
582 }
583
584 /**************************************************************************
585 *       ISF_ControlPanel_fnGetUIObjectOf
586 *
587 * PARAMETERS
588 *  HWND           hwndOwner, //[in ] Parent window for any output
589 *  UINT           cidl,      //[in ] array size
590 *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
591 *  REFIID         riid,      //[in ] Requested Interface
592 *  UINT*          prgfInOut, //[   ] reserved
593 *  LPVOID*        ppvObject) //[out] Resulting Interface
594 *
595 */
596 static HRESULT WINAPI
597 ISF_ControlPanel_fnGetUIObjectOf(IShellFolder2 * iface,
598                                 HWND hwndOwner,
599                                 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
600 {
601     ICPanelImpl *This = (ICPanelImpl *)iface;
602
603     LPITEMIDLIST pidl;
604     IUnknown *pObj = NULL;
605     HRESULT hr = E_INVALIDARG;
606
607     TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
608            This, hwndOwner, cidl, apidl, shdebugstr_guid(riid), prgfInOut, ppvOut);
609
610     if (ppvOut) {
611         *ppvOut = NULL;
612
613         if (IsEqualIID(riid, &IID_IContextMenu) &&(cidl >= 1)) {
614             pObj = (LPUNKNOWN) ISvItemCm_Constructor((IShellFolder *) iface, This->pidlRoot, apidl, cidl);
615             hr = S_OK;
616         } else if (IsEqualIID(riid, &IID_IDataObject) &&(cidl >= 1)) {
617             pObj = (LPUNKNOWN) IDataObject_Constructor(hwndOwner, This->pidlRoot, apidl, cidl);
618             hr = S_OK;
619         } else if (IsEqualIID(riid, &IID_IExtractIconA) &&(cidl == 1)) {
620             pidl = ILCombine(This->pidlRoot, apidl[0]);
621             pObj = (LPUNKNOWN) IExtractIconA_Constructor(pidl);
622             SHFree(pidl);
623             hr = S_OK;
624         } else if (IsEqualIID(riid, &IID_IExtractIconW) &&(cidl == 1)) {
625             pidl = ILCombine(This->pidlRoot, apidl[0]);
626             pObj = (LPUNKNOWN) IExtractIconW_Constructor(pidl);
627             SHFree(pidl);
628             hr = S_OK;
629         } else if ((IsEqualIID(riid,&IID_IShellLinkW) || IsEqualIID(riid,&IID_IShellLinkA))
630                                 && (cidl == 1)) {
631             pidl = ILCombine(This->pidlRoot, apidl[0]);
632             hr = IShellLink_ConstructFromFile(NULL, riid, pidl,(LPVOID*)&pObj);
633             SHFree(pidl);
634         } else {
635             hr = E_NOINTERFACE;
636         }
637
638         if (SUCCEEDED(hr) && !pObj)
639             hr = E_OUTOFMEMORY;
640
641         *ppvOut = pObj;
642     }
643     TRACE("(%p)->hr=0x%08x\n", This, hr);
644     return hr;
645 }
646
647 /**************************************************************************
648 *       ISF_ControlPanel_fnGetDisplayNameOf
649 */
650 static HRESULT WINAPI ISF_ControlPanel_fnGetDisplayNameOf(IShellFolder2 * iface, LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
651 {
652     ICPanelImpl *This = (ICPanelImpl *)iface;
653
654     CHAR szPath[MAX_PATH];
655     WCHAR wszPath[MAX_PATH+1]; /* +1 for potential backslash */
656     PIDLCPanelStruct* pcpanel;
657
658     *szPath = '\0';
659
660     TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
661     pdump(pidl);
662
663     if (!pidl || !strRet)
664         return E_INVALIDARG;
665
666     pcpanel = _ILGetCPanelPointer(pidl);
667
668     if (pcpanel) {
669         lstrcpyA(szPath, pcpanel->szName+pcpanel->offsDispName);
670
671         if (!(dwFlags & SHGDN_FORPARSING))
672             FIXME("retrieve display name from control panel app\n");
673     }
674     /* take names of special folders only if it's only this folder */
675     else if (_ILIsSpecialFolder(pidl)) {
676         BOOL bSimplePidl = _ILIsPidlSimple(pidl);
677
678         if (bSimplePidl) {
679             _ILSimpleGetTextW(pidl, wszPath, MAX_PATH); /* append my own path */
680         } else {
681             FIXME("special pidl\n");
682         }
683
684         if ((dwFlags & SHGDN_FORPARSING) && !bSimplePidl) { /* go deeper if needed */
685             int len = 0;
686
687             PathAddBackslashW(wszPath);
688             len = lstrlenW(wszPath);
689
690             if (!SUCCEEDED
691               (SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags | SHGDN_INFOLDER, wszPath + len, MAX_PATH + 1 - len)))
692                 return E_OUTOFMEMORY;
693             if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, szPath, MAX_PATH, NULL, NULL))
694                 wszPath[0] = '\0';
695         }
696     }
697
698     strRet->uType = STRRET_CSTR;
699     lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);
700
701     TRACE("--(%p)->(%s)\n", This, szPath);
702     return S_OK;
703 }
704
705 /**************************************************************************
706 *  ISF_ControlPanel_fnSetNameOf
707 *  Changes the name of a file object or subfolder, possibly changing its item
708 *  identifier in the process.
709 *
710 * PARAMETERS
711 *  HWND          hwndOwner,  //[in ] Owner window for output
712 *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
713 *  LPCOLESTR     lpszName,   //[in ] the items new display name
714 *  DWORD         dwFlags,    //[in ] SHGNO formatting flags
715 *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
716 */
717 static HRESULT WINAPI ISF_ControlPanel_fnSetNameOf(IShellFolder2 * iface, HWND hwndOwner, LPCITEMIDLIST pidl,   /*simple pidl */
718                                                   LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
719 {
720     ICPanelImpl *This = (ICPanelImpl *)iface;
721     FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut);
722     return E_FAIL;
723 }
724
725 static HRESULT WINAPI ISF_ControlPanel_fnGetDefaultSearchGUID(IShellFolder2 * iface, GUID * pguid)
726 {
727     ICPanelImpl *This = (ICPanelImpl *)iface;
728     FIXME("(%p)\n", This);
729     return E_NOTIMPL;
730 }
731 static HRESULT WINAPI ISF_ControlPanel_fnEnumSearches(IShellFolder2 * iface, IEnumExtraSearch ** ppenum)
732 {
733     ICPanelImpl *This = (ICPanelImpl *)iface;
734     FIXME("(%p)\n", This);
735     return E_NOTIMPL;
736 }
737 static HRESULT WINAPI ISF_ControlPanel_fnGetDefaultColumn(IShellFolder2 * iface, DWORD dwRes, ULONG * pSort, ULONG * pDisplay)
738 {
739     ICPanelImpl *This = (ICPanelImpl *)iface;
740
741     TRACE("(%p)\n", This);
742
743     if (pSort) *pSort = 0;
744     if (pDisplay) *pDisplay = 0;
745     return S_OK;
746 }
747 static HRESULT WINAPI ISF_ControlPanel_fnGetDefaultColumnState(IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
748 {
749     ICPanelImpl *This = (ICPanelImpl *)iface;
750
751     TRACE("(%p)\n", This);
752
753     if (!pcsFlags || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) return E_INVALIDARG;
754     *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags;
755     return S_OK;
756 }
757 static HRESULT WINAPI ISF_ControlPanel_fnGetDetailsEx(IShellFolder2 * iface, LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
758 {
759     ICPanelImpl *This = (ICPanelImpl *)iface;
760     FIXME("(%p)\n", This);
761     return E_NOTIMPL;
762 }
763
764 static HRESULT WINAPI ISF_ControlPanel_fnGetDetailsOf(IShellFolder2 * iface, LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
765 {
766     ICPanelImpl *This = (ICPanelImpl *)iface;
767     HRESULT hr;
768
769     TRACE("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
770
771     if (!psd || iColumn >= CONROLPANELSHELLVIEWCOLUMNS)
772         return E_INVALIDARG;
773
774     if (!pidl) {
775         psd->fmt = ControlPanelSFHeader[iColumn].fmt;
776         psd->cxChar = ControlPanelSFHeader[iColumn].cxChar;
777         psd->str.uType = STRRET_CSTR;
778         LoadStringA(shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid, psd->str.u.cStr, MAX_PATH);
779         return S_OK;
780     } else {
781         psd->str.u.cStr[0] = 0x00;
782         psd->str.uType = STRRET_CSTR;
783         switch(iColumn) {
784         case 0:         /* name */
785             hr = IShellFolder_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
786             break;
787         case 1:         /* comment */
788             _ILGetFileType(pidl, psd->str.u.cStr, MAX_PATH);
789             break;
790         }
791         hr = S_OK;
792     }
793
794     return hr;
795 }
796 static HRESULT WINAPI ISF_ControlPanel_fnMapColumnToSCID(IShellFolder2 * iface, UINT column, SHCOLUMNID * pscid)
797 {
798     ICPanelImpl *This = (ICPanelImpl *)iface;
799     FIXME("(%p)\n", This);
800     return E_NOTIMPL;
801 }
802
803 static const IShellFolder2Vtbl vt_ShellFolder2 =
804 {
805
806     ISF_ControlPanel_fnQueryInterface,
807     ISF_ControlPanel_fnAddRef,
808     ISF_ControlPanel_fnRelease,
809     ISF_ControlPanel_fnParseDisplayName,
810     ISF_ControlPanel_fnEnumObjects,
811     ISF_ControlPanel_fnBindToObject,
812     ISF_ControlPanel_fnBindToStorage,
813     ISF_ControlPanel_fnCompareIDs,
814     ISF_ControlPanel_fnCreateViewObject,
815     ISF_ControlPanel_fnGetAttributesOf,
816     ISF_ControlPanel_fnGetUIObjectOf,
817     ISF_ControlPanel_fnGetDisplayNameOf,
818     ISF_ControlPanel_fnSetNameOf,
819
820     /* ShellFolder2 */
821     ISF_ControlPanel_fnGetDefaultSearchGUID,
822     ISF_ControlPanel_fnEnumSearches,
823     ISF_ControlPanel_fnGetDefaultColumn,
824     ISF_ControlPanel_fnGetDefaultColumnState,
825     ISF_ControlPanel_fnGetDetailsEx,
826     ISF_ControlPanel_fnGetDetailsOf,
827     ISF_ControlPanel_fnMapColumnToSCID
828 };
829
830 /************************************************************************
831  *      ICPanel_PersistFolder2_QueryInterface
832  */
833 static HRESULT WINAPI ICPanel_PersistFolder2_QueryInterface(IPersistFolder2 * iface, REFIID iid, LPVOID * ppvObject)
834 {
835     ICPanelImpl *This = impl_from_IPersistFolder2(iface);
836
837     TRACE("(%p)\n", This);
838
839     return IUnknown_QueryInterface(_IUnknown_(This), iid, ppvObject);
840 }
841
842 /************************************************************************
843  *      ICPanel_PersistFolder2_AddRef
844  */
845 static ULONG WINAPI ICPanel_PersistFolder2_AddRef(IPersistFolder2 * iface)
846 {
847     ICPanelImpl *This = impl_from_IPersistFolder2(iface);
848
849     TRACE("(%p)->(count=%u)\n", This, This->ref);
850
851     return IUnknown_AddRef(_IUnknown_(This));
852 }
853
854 /************************************************************************
855  *      ISFPersistFolder_Release
856  */
857 static ULONG WINAPI ICPanel_PersistFolder2_Release(IPersistFolder2 * iface)
858 {
859     ICPanelImpl *This = impl_from_IPersistFolder2(iface);
860
861     TRACE("(%p)->(count=%u)\n", This, This->ref);
862
863     return IUnknown_Release(_IUnknown_(This));
864 }
865
866 /************************************************************************
867  *      ICPanel_PersistFolder2_GetClassID
868  */
869 static HRESULT WINAPI ICPanel_PersistFolder2_GetClassID(IPersistFolder2 * iface, CLSID * lpClassId)
870 {
871     ICPanelImpl *This = impl_from_IPersistFolder2(iface);
872
873     TRACE("(%p)\n", This);
874
875     if (!lpClassId)
876         return E_POINTER;
877     *lpClassId = CLSID_ControlPanel;
878
879     return S_OK;
880 }
881
882 /************************************************************************
883  *      ICPanel_PersistFolder2_Initialize
884  *
885  * NOTES: it makes no sense to change the pidl
886  */
887 static HRESULT WINAPI ICPanel_PersistFolder2_Initialize(IPersistFolder2 * iface, LPCITEMIDLIST pidl)
888 {
889     ICPanelImpl *This = impl_from_IPersistFolder2(iface);
890     TRACE("(%p)->(%p)\n", This, pidl);
891     return E_NOTIMPL;
892 }
893
894 /**************************************************************************
895  *      IPersistFolder2_fnGetCurFolder
896  */
897 static HRESULT WINAPI ICPanel_PersistFolder2_GetCurFolder(IPersistFolder2 * iface, LPITEMIDLIST * pidl)
898 {
899     ICPanelImpl *This = impl_from_IPersistFolder2(iface);
900
901     TRACE("(%p)->(%p)\n", This, pidl);
902
903     if (!pidl)
904         return E_POINTER;
905     *pidl = ILClone(This->pidlRoot);
906     return S_OK;
907 }
908
909 static const IPersistFolder2Vtbl vt_PersistFolder2 =
910 {
911
912     ICPanel_PersistFolder2_QueryInterface,
913     ICPanel_PersistFolder2_AddRef,
914     ICPanel_PersistFolder2_Release,
915     ICPanel_PersistFolder2_GetClassID,
916     ICPanel_PersistFolder2_Initialize,
917     ICPanel_PersistFolder2_GetCurFolder
918 };
919
920 HRESULT CPanel_GetIconLocationW(LPITEMIDLIST pidl,
921                LPWSTR szIconFile, UINT cchMax, int* piIndex)
922 {
923     PIDLCPanelStruct* pcpanel = _ILGetCPanelPointer(pidl);
924
925     if (!pcpanel)
926         return E_INVALIDARG;
927
928     MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, szIconFile, cchMax);
929     *piIndex = pcpanel->iconIdx!=-1? pcpanel->iconIdx: 0;
930
931     return S_OK;
932 }
933
934
935 /**************************************************************************
936 * IShellExecuteHookW Implementation
937 */
938
939 static HRESULT WINAPI IShellExecuteHookW_fnQueryInterface(
940                IShellExecuteHookW* iface, REFIID riid, void** ppvObject)
941 {
942     ICPanelImpl *This = impl_from_IShellExecuteHookW(iface);
943
944     TRACE("(%p)->(count=%u)\n", This, This->ref);
945
946     return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
947 }
948
949 static ULONG STDMETHODCALLTYPE IShellExecuteHookW_fnAddRef(IShellExecuteHookW* iface)
950 {
951     ICPanelImpl *This = impl_from_IShellExecuteHookW(iface);
952
953     TRACE("(%p)->(count=%u)\n", This, This->ref);
954
955     return IUnknown_AddRef(This->pUnkOuter);
956 }
957
958 static ULONG STDMETHODCALLTYPE IShellExecuteHookW_fnRelease(IShellExecuteHookW* iface)
959 {
960     ICPanelImpl *This = impl_from_IShellExecuteHookW(iface);
961
962     TRACE("(%p)\n", This);
963
964     return IUnknown_Release(This->pUnkOuter);
965 }
966
967 static HRESULT WINAPI IShellExecuteHookW_fnExecute(IShellExecuteHookW* iface, LPSHELLEXECUTEINFOW psei)
968 {
969     static const WCHAR wCplopen[] = {'c','p','l','o','p','e','n','\0'};
970     ICPanelImpl *This = (ICPanelImpl *)iface;
971
972     SHELLEXECUTEINFOW sei_tmp;
973     PIDLCPanelStruct* pcpanel;
974     WCHAR path[MAX_PATH];
975     WCHAR params[MAX_PATH];
976     BOOL ret;
977     int l;
978
979     TRACE("(%p)->execute(%p)\n", This, psei);
980
981     if (!psei)
982         return E_INVALIDARG;
983
984     pcpanel = _ILGetCPanelPointer(ILFindLastID(psei->lpIDList));
985
986     if (!pcpanel)
987         return E_INVALIDARG;
988
989     path[0] = '\"';
990     /* Return value from MultiByteToWideChar includes terminating NUL, which
991      * compensates for the starting double quote we just put in */
992     l = MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, path+1, MAX_PATH);
993
994     /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */
995     path[l++] = '"';
996     path[l] = '\0';
997
998     MultiByteToWideChar(CP_ACP, 0, pcpanel->szName+pcpanel->offsDispName, -1, params, MAX_PATH);
999
1000     memcpy(&sei_tmp, psei, sizeof(sei_tmp));
1001     sei_tmp.lpFile = path;
1002     sei_tmp.lpParameters = params;
1003     sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST;
1004     sei_tmp.lpVerb = wCplopen;
1005
1006     ret = ShellExecuteExW(&sei_tmp);
1007     if (ret)
1008         return S_OK;
1009     else
1010         return S_FALSE;
1011 }
1012
1013 static const IShellExecuteHookWVtbl vt_ShellExecuteHookW =
1014 {
1015
1016     IShellExecuteHookW_fnQueryInterface,
1017     IShellExecuteHookW_fnAddRef,
1018     IShellExecuteHookW_fnRelease,
1019
1020     IShellExecuteHookW_fnExecute
1021 };
1022
1023
1024 /**************************************************************************
1025 * IShellExecuteHookA Implementation
1026 */
1027
1028 static HRESULT WINAPI IShellExecuteHookA_fnQueryInterface(IShellExecuteHookA* iface, REFIID riid, void** ppvObject)
1029 {
1030     ICPanelImpl *This = impl_from_IShellExecuteHookA(iface);
1031
1032     TRACE("(%p)->(count=%u)\n", This, This->ref);
1033
1034     return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
1035 }
1036
1037 static ULONG STDMETHODCALLTYPE IShellExecuteHookA_fnAddRef(IShellExecuteHookA* iface)
1038 {
1039     ICPanelImpl *This = impl_from_IShellExecuteHookA(iface);
1040
1041     TRACE("(%p)->(count=%u)\n", This, This->ref);
1042
1043     return IUnknown_AddRef(This->pUnkOuter);
1044 }
1045
1046 static ULONG STDMETHODCALLTYPE IShellExecuteHookA_fnRelease(IShellExecuteHookA* iface)
1047 {
1048     ICPanelImpl *This = impl_from_IShellExecuteHookA(iface);
1049
1050     TRACE("(%p)\n", This);
1051
1052     return IUnknown_Release(This->pUnkOuter);
1053 }
1054
1055 static HRESULT WINAPI IShellExecuteHookA_fnExecute(IShellExecuteHookA* iface, LPSHELLEXECUTEINFOA psei)
1056 {
1057     ICPanelImpl *This = (ICPanelImpl *)iface;
1058
1059     SHELLEXECUTEINFOA sei_tmp;
1060     PIDLCPanelStruct* pcpanel;
1061     char path[MAX_PATH];
1062     BOOL ret;
1063
1064     TRACE("(%p)->execute(%p)\n", This, psei);
1065
1066     if (!psei)
1067         return E_INVALIDARG;
1068
1069     pcpanel = _ILGetCPanelPointer(ILFindLastID(psei->lpIDList));
1070
1071     if (!pcpanel)
1072         return E_INVALIDARG;
1073
1074     path[0] = '\"';
1075     lstrcpyA(path+1, pcpanel->szName);
1076
1077     /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */
1078     lstrcatA(path, "\" ");
1079     lstrcatA(path, pcpanel->szName+pcpanel->offsDispName);
1080
1081     memcpy(&sei_tmp, psei, sizeof(sei_tmp));
1082     sei_tmp.lpFile = path;
1083     sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST;
1084
1085     ret = ShellExecuteExA(&sei_tmp);
1086     if (ret)
1087         return S_OK;
1088     else
1089         return S_FALSE;
1090 }
1091
1092 static const IShellExecuteHookAVtbl vt_ShellExecuteHookA =
1093 {
1094     IShellExecuteHookA_fnQueryInterface,
1095     IShellExecuteHookA_fnAddRef,
1096     IShellExecuteHookA_fnRelease,
1097     IShellExecuteHookA_fnExecute
1098 };