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