Sync with trunk r43123
[reactos.git] / reactos / dll / win32 / shell32 / shfldr_cpanel.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
22 #include <precomp.h>
23
24
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26
27 /***********************************************************************
28 * control panel implementation in shell namespace
29 */
30
31 typedef struct {
32 const IShellFolder2Vtbl *lpVtbl;
33 LONG ref;
34 const IPersistFolder2Vtbl *lpVtblPersistFolder2;
35 const IShellExecuteHookWVtbl *lpVtblShellExecuteHookW;
36 const IShellExecuteHookAVtbl *lpVtblShellExecuteHookA;
37 const IContextMenu2Vtbl *lpVtblContextMenu;
38 IUnknown *pUnkOuter; /* used for aggregation */
39
40 /* both paths are parsible from the desktop */
41 LPITEMIDLIST pidlRoot; /* absolute pidl */
42 int dwAttributes; /* attributes returned by GetAttributesOf FIXME: use it */
43 LPCITEMIDLIST *apidl;
44 UINT cidl;
45 } ICPanelImpl, *LPICPanelImpl;
46
47 static const IShellFolder2Vtbl vt_ShellFolder2;
48 static const IPersistFolder2Vtbl vt_PersistFolder2;
49 static const IShellExecuteHookWVtbl vt_ShellExecuteHookW;
50 static const IShellExecuteHookAVtbl vt_ShellExecuteHookA;
51 static const IContextMenu2Vtbl vt_ContextMenu;
52
53 static LPICPanelImpl __inline impl_from_IPersistFolder2( IPersistFolder2 *iface )
54 {
55 return (LPICPanelImpl)((char*)iface - FIELD_OFFSET(ICPanelImpl, lpVtblPersistFolder2));
56 }
57
58 static LPICPanelImpl __inline impl_from_IContextMenu( IContextMenu2 *iface )
59 {
60 return (LPICPanelImpl)((char*)iface - FIELD_OFFSET(ICPanelImpl, lpVtblContextMenu));
61 }
62
63
64 static LPICPanelImpl __inline impl_from_IShellExecuteHookW( IShellExecuteHookW *iface )
65 {
66 return (LPICPanelImpl)((char*)iface - FIELD_OFFSET(ICPanelImpl, lpVtblShellExecuteHookW));
67 }
68
69 static LPICPanelImpl __inline impl_from_IShellExecuteHookA( IShellExecuteHookA *iface )
70 {
71 return (LPICPanelImpl)((char*)iface - FIELD_OFFSET(ICPanelImpl, lpVtblShellExecuteHookA));
72 }
73
74
75 /*
76 converts This to an interface pointer
77 */
78 #define _IUnknown_(This) (IUnknown*)&(This->lpVtbl)
79 #define _IShellFolder_(This) (IShellFolder*)&(This->lpVtbl)
80 #define _IShellFolder2_(This) (IShellFolder2*)&(This->lpVtbl)
81
82 #define _IPersist_(This) (IPersist*)&(This->lpVtblPersistFolder2)
83 #define _IPersistFolder_(This) (IPersistFolder*)&(This->lpVtblPersistFolder2)
84 #define _IPersistFolder2_(This) (IPersistFolder2*)&(This->lpVtblPersistFolder2)
85 #define _IShellExecuteHookW_(This) (IShellExecuteHookW*)&(This->lpVtblShellExecuteHookW)
86 #define _IShellExecuteHookA_(This) (IShellExecuteHookA*)&(This->lpVtblShellExecuteHookA)
87
88
89 /***********************************************************************
90 * IShellFolder [ControlPanel] implementation
91 */
92
93 static const shvheader ControlPanelSFHeader[] = {
94 {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},/*FIXME*/
95 {IDS_SHV_COLUMN9, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 200},/*FIXME*/
96 };
97
98 #define CONROLPANELSHELLVIEWCOLUMNS 2
99
100 /**************************************************************************
101 * IControlPanel_Constructor
102 */
103 HRESULT WINAPI IControlPanel_Constructor(IUnknown* pUnkOuter, REFIID riid, LPVOID * ppv)
104 {
105 ICPanelImpl *sf;
106
107 TRACE("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid(riid));
108
109 if (!ppv)
110 return E_POINTER;
111 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
112 return CLASS_E_NOAGGREGATION;
113
114 sf = (ICPanelImpl *) LocalAlloc(LMEM_ZEROINIT, sizeof(ICPanelImpl));
115 if (!sf)
116 return E_OUTOFMEMORY;
117
118 sf->ref = 0;
119 sf->apidl = NULL;
120 sf->cidl = 0;
121 sf->lpVtbl = &vt_ShellFolder2;
122 sf->lpVtblPersistFolder2 = &vt_PersistFolder2;
123 sf->lpVtblShellExecuteHookW = &vt_ShellExecuteHookW;
124 sf->lpVtblShellExecuteHookA = &vt_ShellExecuteHookA;
125 sf->lpVtblContextMenu = &vt_ContextMenu;
126 sf->pidlRoot = _ILCreateControlPanel(); /* my qualified pidl */
127 sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf);
128
129 if (!SUCCEEDED(IUnknown_QueryInterface(_IUnknown_(sf), riid, ppv))) {
130 IUnknown_Release(_IUnknown_(sf));
131 return E_NOINTERFACE;
132 }
133
134 TRACE("--(%p)\n", sf);
135 return S_OK;
136 }
137
138 /**************************************************************************
139 * ISF_ControlPanel_fnQueryInterface
140 *
141 * NOTES supports not IPersist/IPersistFolder
142 */
143 static HRESULT WINAPI ISF_ControlPanel_fnQueryInterface(IShellFolder2 * iface, REFIID riid, LPVOID * ppvObject)
144 {
145 ICPanelImpl *This = (ICPanelImpl *)iface;
146
147 TRACE("(%p)->(%s,%p)\n", This, shdebugstr_guid(riid), ppvObject);
148
149 *ppvObject = NULL;
150
151 if (IsEqualIID(riid, &IID_IUnknown) ||
152 IsEqualIID(riid, &IID_IShellFolder) || IsEqualIID(riid, &IID_IShellFolder2))
153 *ppvObject = This;
154 else if (IsEqualIID(riid, &IID_IPersist) ||
155 IsEqualIID(riid, &IID_IPersistFolder) || IsEqualIID(riid, &IID_IPersistFolder2))
156 *ppvObject = _IPersistFolder2_(This);
157 else if (IsEqualIID(riid, &IID_IShellExecuteHookW))
158 *ppvObject = _IShellExecuteHookW_(This);
159 else if (IsEqualIID(riid, &IID_IShellExecuteHookA))
160 *ppvObject = _IShellExecuteHookA_(This);
161
162 if (*ppvObject) {
163 IUnknown_AddRef((IUnknown *)(*ppvObject));
164 TRACE("-- Interface:(%p)->(%p)\n", ppvObject, *ppvObject);
165 return S_OK;
166 }
167 TRACE("-- Interface: E_NOINTERFACE\n");
168 return E_NOINTERFACE;
169 }
170
171 static ULONG WINAPI ISF_ControlPanel_fnAddRef(IShellFolder2 * iface)
172 {
173 ICPanelImpl *This = (ICPanelImpl *)iface;
174 ULONG refCount = InterlockedIncrement(&This->ref);
175
176 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
177
178 return refCount;
179 }
180
181 static ULONG WINAPI ISF_ControlPanel_fnRelease(IShellFolder2 * iface)
182 {
183 ICPanelImpl *This = (ICPanelImpl *)iface;
184 ULONG refCount = InterlockedDecrement(&This->ref);
185
186 TRACE("(%p)->(count=%u)\n", This, refCount + 1);
187
188 if (!refCount) {
189 TRACE("-- destroying IShellFolder(%p)\n", This);
190 SHFree(This->pidlRoot);
191 LocalFree((HLOCAL) This);
192 }
193 return refCount;
194 }
195
196 /**************************************************************************
197 * ISF_ControlPanel_fnParseDisplayName
198 */
199 static HRESULT WINAPI
200 ISF_ControlPanel_fnParseDisplayName(IShellFolder2 * iface,
201 HWND hwndOwner,
202 LPBC pbc,
203 LPOLESTR lpszDisplayName,
204 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
205 {
206 ICPanelImpl *This = (ICPanelImpl *)iface;
207 WCHAR szElement[MAX_PATH];
208 LPCWSTR szNext = NULL;
209 LPITEMIDLIST pidlTemp = NULL;
210 HRESULT hr = S_OK;
211 CLSID clsid;
212
213 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
214 This, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
215 pchEaten, ppidl, pdwAttributes);
216
217 if (!lpszDisplayName || !ppidl)
218 return E_INVALIDARG;
219
220 *ppidl = 0;
221
222 if (pchEaten)
223 *pchEaten = 0; /* strange but like the original */
224
225 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
226 {
227 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
228 TRACE ("-- element: %s\n", debugstr_w (szElement));
229 CLSIDFromString (szElement + 2, &clsid);
230 pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
231 }
232 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
233 {
234 *ppidl = pidlTemp;
235 return S_OK;
236 }
237
238 if (SUCCEEDED(hr) && pidlTemp)
239 {
240 if (szNext && *szNext)
241 {
242 hr = SHELL32_ParseNextElement(iface, hwndOwner, pbc,
243 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
244 }
245 else
246 {
247 if (pdwAttributes && *pdwAttributes)
248 hr = SHELL32_GetItemAttributes(_IShellFolder_ (This),
249 pidlTemp, pdwAttributes);
250 }
251 }
252
253 *ppidl = pidlTemp;
254
255 TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
256
257 return hr;
258 }
259
260 static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR name, LPCSTR displayName,
261 LPCSTR comment, int iconIdx)
262 {
263 PIDLCPanelStruct *p;
264 LPITEMIDLIST pidl;
265 PIDLDATA tmp;
266 int size0 = (char*)&tmp.u.cpanel.szName-(char*)&tmp.u.cpanel;
267 int size = size0;
268 int l;
269
270 tmp.type = PT_CPLAPPLET;
271 tmp.u.cpanel.dummy = 0;
272 tmp.u.cpanel.iconIdx = iconIdx;
273
274 l = strlen(name);
275 size += l+1;
276
277 tmp.u.cpanel.offsDispName = l+1;
278 l = strlen(displayName);
279 size += l+1;
280
281 tmp.u.cpanel.offsComment = tmp.u.cpanel.offsDispName+1+l;
282 l = strlen(comment);
283 size += l+1;
284
285 pidl = SHAlloc(size+4);
286 if (!pidl)
287 return NULL;
288
289 pidl->mkid.cb = size+2;
290 memcpy(pidl->mkid.abID, &tmp, 2+size0);
291
292 p = &((PIDLDATA*)pidl->mkid.abID)->u.cpanel;
293 strcpy(p->szName, name);
294 strcpy(p->szName+tmp.u.cpanel.offsDispName, displayName);
295 strcpy(p->szName+tmp.u.cpanel.offsComment, comment);
296
297 *(WORD*)((char*)pidl+(size+2)) = 0;
298
299 pcheck(pidl);
300
301 return pidl;
302 }
303
304 /**************************************************************************
305 * _ILGetCPanelPointer()
306 * gets a pointer to the control panel struct stored in the pidl
307 */
308 static PIDLCPanelStruct* _ILGetCPanelPointer(LPCITEMIDLIST pidl)
309 {
310 LPPIDLDATA pdata = _ILGetDataPointer(pidl);
311
312 if (pdata && pdata->type==PT_CPLAPPLET)
313 return (PIDLCPanelStruct*)&(pdata->u.cpanel);
314
315 return NULL;
316 }
317
318 /**************************************************************************
319 * ISF_ControlPanel_fnEnumObjects
320 */
321 static BOOL SHELL_RegisterCPanelApp(IEnumIDList* list, LPCSTR path)
322 {
323 LPITEMIDLIST pidl;
324 CPlApplet* applet;
325 CPanel panel;
326 CPLINFO info;
327 unsigned i;
328 int iconIdx;
329
330 char displayName[MAX_PATH];
331 char comment[MAX_PATH];
332
333 WCHAR wpath[MAX_PATH];
334
335 MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH);
336
337 panel.first = NULL;
338 applet = Control_LoadApplet(0, wpath, &panel);
339
340 if (applet)
341 {
342 for(i=0; i<applet->count; ++i)
343 {
344 WideCharToMultiByte(CP_ACP, 0, applet->info[i].szName, -1, displayName, MAX_PATH, 0, 0);
345 WideCharToMultiByte(CP_ACP, 0, applet->info[i].szInfo, -1, comment, MAX_PATH, 0, 0);
346
347 applet->proc(0, CPL_INQUIRE, i, (LPARAM)&info);
348
349 if (info.idIcon > 0)
350 iconIdx = -info.idIcon; /* negative icon index instead of icon number */
351 else
352 iconIdx = 0;
353
354 pidl = _ILCreateCPanelApplet(path, displayName, comment, iconIdx);
355
356 if (pidl)
357 AddToEnumList(list, pidl);
358 }
359 Control_UnloadApplet(applet);
360 }
361 return TRUE;
362 }
363
364 static int SHELL_RegisterRegistryCPanelApps(IEnumIDList* list, HKEY hkey_root, LPCSTR szRepPath)
365 {
366 char name[MAX_PATH];
367 char value[MAX_PATH];
368 HKEY hkey;
369
370 int cnt = 0;
371
372 if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
373 {
374 int idx = 0;
375
376 for(;; ++idx)
377 {
378 DWORD nameLen = MAX_PATH;
379 DWORD valueLen = MAX_PATH;
380
381 if (RegEnumValueA(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
382 break;
383
384 if (SHELL_RegisterCPanelApp(list, value))
385 ++cnt;
386 }
387 RegCloseKey(hkey);
388 }
389
390 return cnt;
391 }
392
393 static int SHELL_RegisterCPanelFolders(IEnumIDList* list, HKEY hkey_root, LPCSTR szRepPath)
394 {
395 char name[MAX_PATH];
396 HKEY hkey;
397
398 int cnt = 0;
399
400 if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
401 {
402 int idx = 0;
403 for(;; ++idx)
404 {
405 if (RegEnumKeyA(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
406 break;
407
408 if (*name == '{')
409 {
410 LPITEMIDLIST pidl = _ILCreateGuidFromStrA(name);
411
412 if (pidl && AddToEnumList(list, pidl))
413 ++cnt;
414 }
415 }
416
417 RegCloseKey(hkey);
418 }
419
420 return cnt;
421 }
422
423 /**************************************************************************
424 * CreateCPanelEnumList()
425 */
426 static BOOL CreateCPanelEnumList(
427 IEnumIDList * iface,
428 DWORD dwFlags)
429 {
430 CHAR szPath[MAX_PATH];
431 WIN32_FIND_DATAA wfd;
432 HANDLE hFile;
433
434 TRACE("(%p)->(flags=0x%08x)\n", iface, dwFlags);
435
436 /* enumerate control panel folders */
437 if (dwFlags & SHCONTF_FOLDERS)
438 SHELL_RegisterCPanelFolders(iface, HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
439
440 /* enumerate the control panel applets */
441 if (dwFlags & SHCONTF_NONFOLDERS)
442 {
443 LPSTR p;
444
445 GetSystemDirectoryA(szPath, MAX_PATH);
446 p = PathAddBackslashA(szPath);
447 strcpy(p, "*.cpl");
448
449 TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",iface,debugstr_a(szPath));
450 hFile = FindFirstFileA(szPath, &wfd);
451
452 if (hFile != INVALID_HANDLE_VALUE)
453 {
454 do
455 {
456 if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
457 continue;
458
459 if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
460 strcpy(p, wfd.cFileName);
461 if (strcmp(wfd.cFileName, "ncpa.cpl"))
462 SHELL_RegisterCPanelApp((IEnumIDList*)iface, szPath);
463 }
464 } while(FindNextFileA(hFile, &wfd));
465 FindClose(hFile);
466 }
467
468 SHELL_RegisterRegistryCPanelApps((IEnumIDList*)iface, HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
469 SHELL_RegisterRegistryCPanelApps((IEnumIDList*)iface, HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
470 }
471 return TRUE;
472 }
473
474 /**************************************************************************
475 * ISF_ControlPanel_fnEnumObjects
476 */
477 static HRESULT WINAPI
478 ISF_ControlPanel_fnEnumObjects(IShellFolder2 * iface, HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
479 {
480 ICPanelImpl *This = (ICPanelImpl *)iface;
481
482 TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This, hwndOwner, dwFlags, ppEnumIDList);
483
484 *ppEnumIDList = IEnumIDList_Constructor();
485 if (*ppEnumIDList)
486 CreateCPanelEnumList(*ppEnumIDList, dwFlags);
487
488 TRACE("--(%p)->(new ID List: %p)\n", This, *ppEnumIDList);
489
490 return(*ppEnumIDList) ? S_OK : E_OUTOFMEMORY;
491 }
492
493 /**************************************************************************
494 * ISF_ControlPanel_fnBindToObject
495 */
496 static HRESULT WINAPI
497 ISF_ControlPanel_fnBindToObject(IShellFolder2 * iface, LPCITEMIDLIST pidl,
498 LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
499 {
500 ICPanelImpl *This = (ICPanelImpl *)iface;
501
502 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbcReserved, shdebugstr_guid(riid), ppvOut);
503
504 return SHELL32_BindToChild(This->pidlRoot, NULL, pidl, riid, ppvOut);
505 }
506
507 /**************************************************************************
508 * ISF_ControlPanel_fnBindToStorage
509 */
510 static HRESULT WINAPI
511 ISF_ControlPanel_fnBindToStorage(IShellFolder2 * iface,
512 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
513 {
514 ICPanelImpl *This = (ICPanelImpl *)iface;
515
516 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved, shdebugstr_guid(riid), ppvOut);
517
518 *ppvOut = NULL;
519 return E_NOTIMPL;
520 }
521
522 /**************************************************************************
523 * ISF_ControlPanel_fnCompareIDs
524 */
525
526 static HRESULT WINAPI
527 ISF_ControlPanel_fnCompareIDs(IShellFolder2 * iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
528 {
529 ICPanelImpl *This = (ICPanelImpl *)iface;
530
531 int nReturn;
532
533 TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
534 nReturn = SHELL32_CompareIDs(_IShellFolder_(This), lParam, pidl1, pidl2);
535 TRACE("-- %i\n", nReturn);
536 return nReturn;
537 }
538
539 /**************************************************************************
540 * ISF_ControlPanel_fnCreateViewObject
541 */
542 static HRESULT WINAPI
543 ISF_ControlPanel_fnCreateViewObject(IShellFolder2 * iface, HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
544 {
545 ICPanelImpl *This = (ICPanelImpl *)iface;
546
547 LPSHELLVIEW pShellView;
548 HRESULT hr = E_INVALIDARG;
549
550 TRACE("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid(riid), ppvOut);
551
552 if (ppvOut) {
553 *ppvOut = NULL;
554
555 if (IsEqualIID(riid, &IID_IDropTarget)) {
556 WARN("IDropTarget not implemented\n");
557 hr = E_NOTIMPL;
558 } else if (IsEqualIID(riid, &IID_IContextMenu)) {
559 WARN("IContextMenu not implemented\n");
560 hr = E_NOTIMPL;
561 } else if (IsEqualIID(riid, &IID_IShellView)) {
562 pShellView = IShellView_Constructor((IShellFolder *) iface);
563 if (pShellView) {
564 hr = IShellView_QueryInterface(pShellView, riid, ppvOut);
565 IShellView_Release(pShellView);
566 }
567 }
568 }
569 TRACE("--(%p)->(interface=%p)\n", This, ppvOut);
570 return hr;
571 }
572
573 /**************************************************************************
574 * ISF_ControlPanel_fnGetAttributesOf
575 */
576 static HRESULT WINAPI
577 ISF_ControlPanel_fnGetAttributesOf(IShellFolder2 * iface, UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
578 {
579 ICPanelImpl *This = (ICPanelImpl *)iface;
580
581 HRESULT hr = S_OK;
582
583 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
584 This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
585
586 if (!rgfInOut)
587 return E_INVALIDARG;
588 if (cidl && !apidl)
589 return E_INVALIDARG;
590
591 if (*rgfInOut == 0)
592 *rgfInOut = ~0;
593
594 while(cidl > 0 && *apidl) {
595 pdump(*apidl);
596 SHELL32_GetItemAttributes(_IShellFolder_(This), *apidl, rgfInOut);
597 apidl++;
598 cidl--;
599 }
600 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
601 *rgfInOut &= ~SFGAO_VALIDATE;
602
603 TRACE("-- result=0x%08x\n", *rgfInOut);
604 return hr;
605 }
606
607 /**************************************************************************
608 * ISF_ControlPanel_fnGetUIObjectOf
609 *
610 * PARAMETERS
611 * HWND hwndOwner, //[in ] Parent window for any output
612 * UINT cidl, //[in ] array size
613 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
614 * REFIID riid, //[in ] Requested Interface
615 * UINT* prgfInOut, //[ ] reserved
616 * LPVOID* ppvObject) //[out] Resulting Interface
617 *
618 */
619 static HRESULT WINAPI
620 ISF_ControlPanel_fnGetUIObjectOf(IShellFolder2 * iface,
621 HWND hwndOwner,
622 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
623 {
624 ICPanelImpl *This = (ICPanelImpl *)iface;
625
626 LPITEMIDLIST pidl;
627 IUnknown *pObj = NULL;
628 HRESULT hr = E_INVALIDARG;
629
630 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
631 This, hwndOwner, cidl, apidl, shdebugstr_guid(riid), prgfInOut, ppvOut);
632
633 if (ppvOut) {
634 *ppvOut = NULL;
635
636 if (IsEqualIID(riid, &IID_IContextMenu) &&(cidl >= 1)) {
637 // TODO
638 // create a seperate item struct
639 //
640 pObj = (IUnknown*)(&This->lpVtblContextMenu);
641 This->apidl = apidl;
642 This->cidl = cidl;
643 IUnknown_AddRef(pObj);
644 hr = S_OK;
645 } else if (IsEqualIID(riid, &IID_IDataObject) &&(cidl >= 1)) {
646 pObj = (LPUNKNOWN) IDataObject_Constructor(hwndOwner, This->pidlRoot, apidl, cidl);
647 hr = S_OK;
648 } else if (IsEqualIID(riid, &IID_IExtractIconA) &&(cidl == 1)) {
649 pidl = ILCombine(This->pidlRoot, apidl[0]);
650 pObj = (LPUNKNOWN) IExtractIconA_Constructor(pidl);
651 SHFree(pidl);
652 hr = S_OK;
653 } else if (IsEqualIID(riid, &IID_IExtractIconW) &&(cidl == 1)) {
654 pidl = ILCombine(This->pidlRoot, apidl[0]);
655 pObj = (LPUNKNOWN) IExtractIconW_Constructor(pidl);
656 SHFree(pidl);
657 hr = S_OK;
658 } else if ((IsEqualIID(riid,&IID_IShellLinkW) || IsEqualIID(riid,&IID_IShellLinkA))
659 && (cidl == 1)) {
660 pidl = ILCombine(This->pidlRoot, apidl[0]);
661 hr = IShellLink_ConstructFromFile(NULL, riid, pidl,(LPVOID*)&pObj);
662 SHFree(pidl);
663 } else {
664 hr = E_NOINTERFACE;
665 }
666
667 if (SUCCEEDED(hr) && !pObj)
668 hr = E_OUTOFMEMORY;
669
670 *ppvOut = pObj;
671 }
672 TRACE("(%p)->hr=0x%08x\n", This, hr);
673 return hr;
674 }
675
676 /**************************************************************************
677 * ISF_ControlPanel_fnGetDisplayNameOf
678 */
679 static HRESULT WINAPI ISF_ControlPanel_fnGetDisplayNameOf(IShellFolder2 * iface, LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
680 {
681 ICPanelImpl *This = (ICPanelImpl *)iface;
682
683 CHAR szPath[MAX_PATH];
684 WCHAR wszPath[MAX_PATH+1]; /* +1 for potential backslash */
685 PIDLCPanelStruct* pcpanel;
686
687 *szPath = '\0';
688
689 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
690 pdump(pidl);
691
692 if (!pidl || !strRet)
693 return E_INVALIDARG;
694
695 pcpanel = _ILGetCPanelPointer(pidl);
696
697 if (pcpanel) {
698 lstrcpyA(szPath, pcpanel->szName+pcpanel->offsDispName);
699
700 if (!(dwFlags & SHGDN_FORPARSING))
701 FIXME("retrieve display name from control panel app\n");
702 }
703 /* take names of special folders only if it's only this folder */
704 else if (_ILIsSpecialFolder(pidl)) {
705 BOOL bSimplePidl = _ILIsPidlSimple(pidl);
706
707 if (bSimplePidl) {
708 _ILSimpleGetTextW(pidl, wszPath, MAX_PATH); /* append my own path */
709 } else {
710 FIXME("special pidl\n");
711 }
712
713 if ((dwFlags & SHGDN_FORPARSING) && !bSimplePidl) { /* go deeper if needed */
714 int len = 0;
715
716 PathAddBackslashW(wszPath);
717 len = wcslen(wszPath);
718
719 if (!SUCCEEDED
720 (SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, wszPath + len, MAX_PATH + 1 - len)))
721 return E_OUTOFMEMORY;
722 if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, szPath, MAX_PATH, NULL, NULL))
723 wszPath[0] = '\0';
724 } else {
725 if (bSimplePidl) {
726 if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, szPath, MAX_PATH, NULL, NULL))
727 wszPath[0] = '\0';
728 }
729 }
730 }
731
732 strRet->uType = STRRET_CSTR;
733 lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);
734
735 TRACE("--(%p)->(%s)\n", This, szPath);
736 return S_OK;
737 }
738
739 /**************************************************************************
740 * ISF_ControlPanel_fnSetNameOf
741 * Changes the name of a file object or subfolder, possibly changing its item
742 * identifier in the process.
743 *
744 * PARAMETERS
745 * HWND hwndOwner, //[in ] Owner window for output
746 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
747 * LPCOLESTR lpszName, //[in ] the items new display name
748 * DWORD dwFlags, //[in ] SHGNO formatting flags
749 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
750 */
751 static HRESULT WINAPI ISF_ControlPanel_fnSetNameOf(IShellFolder2 * iface, HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */
752 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
753 {
754 ICPanelImpl *This = (ICPanelImpl *)iface;
755 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut);
756 return E_FAIL;
757 }
758
759 static HRESULT WINAPI ISF_ControlPanel_fnGetDefaultSearchGUID(IShellFolder2 * iface, GUID * pguid)
760 {
761 ICPanelImpl *This = (ICPanelImpl *)iface;
762 FIXME("(%p)\n", This);
763 return E_NOTIMPL;
764 }
765 static HRESULT WINAPI ISF_ControlPanel_fnEnumSearches(IShellFolder2 * iface, IEnumExtraSearch ** ppenum)
766 {
767 ICPanelImpl *This = (ICPanelImpl *)iface;
768 FIXME("(%p)\n", This);
769 return E_NOTIMPL;
770 }
771 static HRESULT WINAPI ISF_ControlPanel_fnGetDefaultColumn(IShellFolder2 * iface, DWORD dwRes, ULONG * pSort, ULONG * pDisplay)
772 {
773 ICPanelImpl *This = (ICPanelImpl *)iface;
774
775 TRACE("(%p)\n", This);
776
777 if (pSort) *pSort = 0;
778 if (pDisplay) *pDisplay = 0;
779 return S_OK;
780 }
781 static HRESULT WINAPI ISF_ControlPanel_fnGetDefaultColumnState(IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
782 {
783 ICPanelImpl *This = (ICPanelImpl *)iface;
784
785 TRACE("(%p)\n", This);
786
787 if (!pcsFlags || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) return E_INVALIDARG;
788 *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags;
789 return S_OK;
790 }
791 static HRESULT WINAPI ISF_ControlPanel_fnGetDetailsEx(IShellFolder2 * iface, LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
792 {
793 ICPanelImpl *This = (ICPanelImpl *)iface;
794 FIXME("(%p)\n", This);
795 return E_NOTIMPL;
796 }
797
798 static HRESULT WINAPI ISF_ControlPanel_fnGetDetailsOf(IShellFolder2 * iface, LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
799 {
800 ICPanelImpl *This = (ICPanelImpl *)iface;
801 HRESULT hr;
802
803 TRACE("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
804
805 if (!psd || iColumn >= CONROLPANELSHELLVIEWCOLUMNS)
806 return E_INVALIDARG;
807
808 if (!pidl) {
809 psd->fmt = ControlPanelSFHeader[iColumn].fmt;
810 psd->cxChar = ControlPanelSFHeader[iColumn].cxChar;
811 psd->str.uType = STRRET_CSTR;
812 LoadStringA(shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid, psd->str.u.cStr, MAX_PATH);
813 return S_OK;
814 } else {
815 psd->str.u.cStr[0] = 0x00;
816 psd->str.uType = STRRET_CSTR;
817 switch(iColumn) {
818 case 0: /* name */
819 hr = IShellFolder_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
820 break;
821 case 1: /* comment */
822 _ILGetFileType(pidl, psd->str.u.cStr, MAX_PATH);
823 break;
824 }
825 hr = S_OK;
826 }
827
828 return hr;
829 }
830 static HRESULT WINAPI ISF_ControlPanel_fnMapColumnToSCID(IShellFolder2 * iface, UINT column, SHCOLUMNID * pscid)
831 {
832 ICPanelImpl *This = (ICPanelImpl *)iface;
833 FIXME("(%p)\n", This);
834 return E_NOTIMPL;
835 }
836
837 static const IShellFolder2Vtbl vt_ShellFolder2 =
838 {
839
840 ISF_ControlPanel_fnQueryInterface,
841 ISF_ControlPanel_fnAddRef,
842 ISF_ControlPanel_fnRelease,
843 ISF_ControlPanel_fnParseDisplayName,
844 ISF_ControlPanel_fnEnumObjects,
845 ISF_ControlPanel_fnBindToObject,
846 ISF_ControlPanel_fnBindToStorage,
847 ISF_ControlPanel_fnCompareIDs,
848 ISF_ControlPanel_fnCreateViewObject,
849 ISF_ControlPanel_fnGetAttributesOf,
850 ISF_ControlPanel_fnGetUIObjectOf,
851 ISF_ControlPanel_fnGetDisplayNameOf,
852 ISF_ControlPanel_fnSetNameOf,
853
854 /* ShellFolder2 */
855 ISF_ControlPanel_fnGetDefaultSearchGUID,
856 ISF_ControlPanel_fnEnumSearches,
857 ISF_ControlPanel_fnGetDefaultColumn,
858 ISF_ControlPanel_fnGetDefaultColumnState,
859 ISF_ControlPanel_fnGetDetailsEx,
860 ISF_ControlPanel_fnGetDetailsOf,
861 ISF_ControlPanel_fnMapColumnToSCID
862 };
863
864 /************************************************************************
865 * ICPanel_PersistFolder2_QueryInterface
866 */
867 static HRESULT WINAPI ICPanel_PersistFolder2_QueryInterface(IPersistFolder2 * iface, REFIID iid, LPVOID * ppvObject)
868 {
869 ICPanelImpl *This = impl_from_IPersistFolder2(iface);
870
871 TRACE("(%p)\n", This);
872
873 return IUnknown_QueryInterface(_IUnknown_(This), iid, ppvObject);
874 }
875
876 /************************************************************************
877 * ICPanel_PersistFolder2_AddRef
878 */
879 static ULONG WINAPI ICPanel_PersistFolder2_AddRef(IPersistFolder2 * iface)
880 {
881 ICPanelImpl *This = impl_from_IPersistFolder2(iface);
882
883 TRACE("(%p)->(count=%u)\n", This, This->ref);
884
885 return IUnknown_AddRef(_IUnknown_(This));
886 }
887
888 /************************************************************************
889 * ISFPersistFolder_Release
890 */
891 static ULONG WINAPI ICPanel_PersistFolder2_Release(IPersistFolder2 * iface)
892 {
893 ICPanelImpl *This = impl_from_IPersistFolder2(iface);
894
895 TRACE("(%p)->(count=%u)\n", This, This->ref);
896
897 return IUnknown_Release(_IUnknown_(This));
898 }
899
900 /************************************************************************
901 * ICPanel_PersistFolder2_GetClassID
902 */
903 static HRESULT WINAPI ICPanel_PersistFolder2_GetClassID(IPersistFolder2 * iface, CLSID * lpClassId)
904 {
905 ICPanelImpl *This = impl_from_IPersistFolder2(iface);
906
907 TRACE("(%p)\n", This);
908
909 if (!lpClassId)
910 return E_POINTER;
911 *lpClassId = CLSID_ControlPanel;
912
913 return S_OK;
914 }
915
916 /************************************************************************
917 * ICPanel_PersistFolder2_Initialize
918 *
919 * NOTES: it makes no sense to change the pidl
920 */
921 static HRESULT WINAPI ICPanel_PersistFolder2_Initialize(IPersistFolder2 * iface, LPCITEMIDLIST pidl)
922 {
923 ICPanelImpl *This = impl_from_IPersistFolder2(iface);
924 if (This->pidlRoot)
925 SHFree((LPVOID)This->pidlRoot);
926
927 This->pidlRoot = ILClone(pidl);
928 return S_OK;
929 }
930
931 /**************************************************************************
932 * IPersistFolder2_fnGetCurFolder
933 */
934 static HRESULT WINAPI ICPanel_PersistFolder2_GetCurFolder(IPersistFolder2 * iface, LPITEMIDLIST * pidl)
935 {
936 ICPanelImpl *This = impl_from_IPersistFolder2(iface);
937
938 TRACE("(%p)->(%p)\n", This, pidl);
939
940 if (!pidl)
941 return E_POINTER;
942 *pidl = ILClone(This->pidlRoot);
943 return S_OK;
944 }
945
946 static const IPersistFolder2Vtbl vt_PersistFolder2 =
947 {
948
949 ICPanel_PersistFolder2_QueryInterface,
950 ICPanel_PersistFolder2_AddRef,
951 ICPanel_PersistFolder2_Release,
952 ICPanel_PersistFolder2_GetClassID,
953 ICPanel_PersistFolder2_Initialize,
954 ICPanel_PersistFolder2_GetCurFolder
955 };
956
957 HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST pidl,
958 LPWSTR szIconFile, UINT cchMax, int* piIndex)
959 {
960 PIDLCPanelStruct* pcpanel = _ILGetCPanelPointer(pidl);
961
962 if (!pcpanel)
963 return E_INVALIDARG;
964
965 MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, szIconFile, cchMax);
966 *piIndex = pcpanel->iconIdx!=-1? pcpanel->iconIdx: 0;
967
968 return S_OK;
969 }
970
971
972 /**************************************************************************
973 * IShellExecuteHookW Implementation
974 */
975
976 static HRESULT WINAPI IShellExecuteHookW_fnQueryInterface(
977 IShellExecuteHookW* iface, REFIID riid, void** ppvObject)
978 {
979 ICPanelImpl *This = impl_from_IShellExecuteHookW(iface);
980
981 TRACE("(%p)->(count=%u)\n", This, This->ref);
982
983 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
984 }
985
986 static ULONG STDMETHODCALLTYPE IShellExecuteHookW_fnAddRef(IShellExecuteHookW* iface)
987 {
988 ICPanelImpl *This = impl_from_IShellExecuteHookW(iface);
989
990 TRACE("(%p)->(count=%u)\n", This, This->ref);
991
992 return IUnknown_AddRef(This->pUnkOuter);
993 }
994
995 static ULONG STDMETHODCALLTYPE IShellExecuteHookW_fnRelease(IShellExecuteHookW* iface)
996 {
997 ICPanelImpl *This = impl_from_IShellExecuteHookW(iface);
998
999 TRACE("(%p)\n", This);
1000
1001 return IUnknown_Release(This->pUnkOuter);
1002 }
1003
1004 HRESULT
1005 ExecuteAppletFromCLSID(LPOLESTR pOleStr)
1006 {
1007 WCHAR szCmd[MAX_PATH];
1008 WCHAR szExpCmd[MAX_PATH];
1009 PROCESS_INFORMATION pi;
1010 STARTUPINFOW si;
1011 WCHAR szBuffer[90] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
1012 DWORD dwType, dwSize;
1013
1014 wcscpy(&szBuffer[6], pOleStr);
1015 wcscat(szBuffer, L"\\shell\\open\\command");
1016
1017 dwSize = sizeof(szCmd);
1018 if (RegGetValueW(HKEY_CLASSES_ROOT, szBuffer, NULL, RRF_RT_REG_SZ, &dwType, (PVOID)szCmd, &dwSize) != ERROR_SUCCESS)
1019 {
1020 ERR("RegGetValueW failed with %u\n", GetLastError());
1021 return E_FAIL;
1022 }
1023
1024 #if 0
1025 if (dwType != RRF_RT_REG_SZ && dwType != RRF_RT_REG_EXPAND_SZ)
1026 return E_FAIL;
1027 #endif
1028
1029 if (!ExpandEnvironmentStringsW(szCmd, szExpCmd, sizeof(szExpCmd)/sizeof(WCHAR)))
1030 return E_FAIL;
1031
1032 ZeroMemory(&si, sizeof(si));
1033 si.cb = sizeof(si);
1034 if (!CreateProcessW(NULL, szExpCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
1035 return E_FAIL;
1036
1037 CloseHandle(pi.hProcess);
1038 CloseHandle(pi.hThread);
1039 return S_OK;
1040 }
1041
1042
1043 static HRESULT WINAPI IShellExecuteHookW_fnExecute(IShellExecuteHookW* iface, LPSHELLEXECUTEINFOW psei)
1044 {
1045 static const WCHAR wCplopen[] = {'c','p','l','o','p','e','n','\0'};
1046 ICPanelImpl *This = (ICPanelImpl *)iface;
1047
1048 SHELLEXECUTEINFOW sei_tmp;
1049 PIDLCPanelStruct* pcpanel;
1050 WCHAR path[MAX_PATH];
1051 WCHAR params[MAX_PATH];
1052 BOOL ret;
1053 HRESULT hr;
1054 int l;
1055
1056 TRACE("(%p)->execute(%p)\n", This, psei);
1057
1058 if (!psei)
1059 return E_INVALIDARG;
1060
1061 pcpanel = _ILGetCPanelPointer(ILFindLastID(psei->lpIDList));
1062
1063 if (!pcpanel)
1064 {
1065 LPOLESTR pOleStr;
1066
1067 IID * iid = _ILGetGUIDPointer(ILFindLastID(psei->lpIDList));
1068 if (!iid)
1069 return E_INVALIDARG;
1070 if (StringFromCLSID(iid, &pOleStr) == S_OK)
1071 {
1072
1073 hr = ExecuteAppletFromCLSID(pOleStr);
1074 CoTaskMemFree(pOleStr);
1075 return hr;
1076 }
1077
1078 return E_INVALIDARG;
1079 }
1080 path[0] = '\"';
1081 /* Return value from MultiByteToWideChar includes terminating NUL, which
1082 * compensates for the starting double quote we just put in */
1083 l = MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, path+1, MAX_PATH);
1084
1085 /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */
1086 path[l++] = '"';
1087 path[l] = '\0';
1088
1089 MultiByteToWideChar(CP_ACP, 0, pcpanel->szName+pcpanel->offsDispName, -1, params, MAX_PATH);
1090
1091 memcpy(&sei_tmp, psei, sizeof(sei_tmp));
1092 sei_tmp.lpFile = path;
1093 sei_tmp.lpParameters = params;
1094 sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST;
1095 sei_tmp.lpVerb = wCplopen;
1096
1097 ret = ShellExecuteExW(&sei_tmp);
1098 if (ret)
1099 return S_OK;
1100 else
1101 return S_FALSE;
1102 }
1103
1104 static const IShellExecuteHookWVtbl vt_ShellExecuteHookW =
1105 {
1106
1107 IShellExecuteHookW_fnQueryInterface,
1108 IShellExecuteHookW_fnAddRef,
1109 IShellExecuteHookW_fnRelease,
1110
1111 IShellExecuteHookW_fnExecute
1112 };
1113
1114
1115 /**************************************************************************
1116 * IShellExecuteHookA Implementation
1117 */
1118
1119 static HRESULT WINAPI IShellExecuteHookA_fnQueryInterface(IShellExecuteHookA* iface, REFIID riid, void** ppvObject)
1120 {
1121 ICPanelImpl *This = impl_from_IShellExecuteHookA(iface);
1122
1123 TRACE("(%p)->(count=%u)\n", This, This->ref);
1124
1125 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
1126 }
1127
1128 static ULONG STDMETHODCALLTYPE IShellExecuteHookA_fnAddRef(IShellExecuteHookA* iface)
1129 {
1130 ICPanelImpl *This = impl_from_IShellExecuteHookA(iface);
1131
1132 TRACE("(%p)->(count=%u)\n", This, This->ref);
1133
1134 return IUnknown_AddRef(This->pUnkOuter);
1135 }
1136
1137 static ULONG STDMETHODCALLTYPE IShellExecuteHookA_fnRelease(IShellExecuteHookA* iface)
1138 {
1139 ICPanelImpl *This = impl_from_IShellExecuteHookA(iface);
1140
1141 TRACE("(%p)\n", This);
1142
1143 return IUnknown_Release(This->pUnkOuter);
1144 }
1145
1146 static HRESULT WINAPI IShellExecuteHookA_fnExecute(IShellExecuteHookA* iface, LPSHELLEXECUTEINFOA psei)
1147 {
1148 ICPanelImpl *This = (ICPanelImpl *)iface;
1149
1150 SHELLEXECUTEINFOA sei_tmp;
1151 PIDLCPanelStruct* pcpanel;
1152 char path[MAX_PATH];
1153 BOOL ret;
1154
1155 TRACE("(%p)->execute(%p)\n", This, psei);
1156
1157 if (!psei)
1158 return E_INVALIDARG;
1159
1160 pcpanel = _ILGetCPanelPointer(ILFindLastID(psei->lpIDList));
1161
1162 if (!pcpanel)
1163 return E_INVALIDARG;
1164
1165 path[0] = '\"';
1166 lstrcpyA(path+1, pcpanel->szName);
1167
1168 /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */
1169 lstrcatA(path, "\" ");
1170 lstrcatA(path, pcpanel->szName+pcpanel->offsDispName);
1171
1172 memcpy(&sei_tmp, psei, sizeof(sei_tmp));
1173 sei_tmp.lpFile = path;
1174 sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST;
1175
1176 ret = ShellExecuteExA(&sei_tmp);
1177 if (ret)
1178 return S_OK;
1179 else
1180 return S_FALSE;
1181 }
1182
1183 static const IShellExecuteHookAVtbl vt_ShellExecuteHookA =
1184 {
1185 IShellExecuteHookA_fnQueryInterface,
1186 IShellExecuteHookA_fnAddRef,
1187 IShellExecuteHookA_fnRelease,
1188 IShellExecuteHookA_fnExecute
1189 };
1190
1191 /**************************************************************************
1192 * IContextMenu2 Implementation
1193 */
1194
1195 /************************************************************************
1196 * ICPanel_IContextMenu_QueryInterface
1197 */
1198 static HRESULT WINAPI ICPanel_IContextMenu2_QueryInterface(IContextMenu2 * iface, REFIID iid, LPVOID * ppvObject)
1199 {
1200 ICPanelImpl *This = impl_from_IContextMenu(iface);
1201
1202 TRACE("(%p)\n", This);
1203
1204 return IUnknown_QueryInterface(_IUnknown_(This), iid, ppvObject);
1205 }
1206
1207 /************************************************************************
1208 * ICPanel_IContextMenu_AddRef
1209 */
1210 static ULONG WINAPI ICPanel_IContextMenu2_AddRef(IContextMenu2 * iface)
1211 {
1212 ICPanelImpl *This = impl_from_IContextMenu(iface);
1213
1214 TRACE("(%p)->(count=%u)\n", This, This->ref);
1215
1216 return IUnknown_AddRef(_IUnknown_(This));
1217 }
1218
1219 /************************************************************************
1220 * ICPanel_IContextMenu_Release
1221 */
1222 static ULONG WINAPI ICPanel_IContextMenu2_Release(IContextMenu2 * iface)
1223 {
1224 ICPanelImpl *This = impl_from_IContextMenu(iface);
1225
1226 TRACE("(%p)->(count=%u)\n", This, This->ref);
1227
1228 return IUnknown_Release(_IUnknown_(This));
1229 }
1230
1231 /**************************************************************************
1232 * ICPanel_IContextMenu_QueryContextMenu()
1233 */
1234 static HRESULT WINAPI ICPanel_IContextMenu2_QueryContextMenu(
1235 IContextMenu2 *iface,
1236 HMENU hMenu,
1237 UINT indexMenu,
1238 UINT idCmdFirst,
1239 UINT idCmdLast,
1240 UINT uFlags)
1241 {
1242 WCHAR szBuffer[30] = {0};
1243 ULONG Count = 1;
1244
1245 ICPanelImpl *This = impl_from_IContextMenu(iface);
1246
1247 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
1248 This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
1249
1250 if (LoadStringW(shell32_hInstance, IDS_OPEN, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
1251 {
1252 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
1253 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, szBuffer, MFS_DEFAULT); //FIXME identifier
1254 Count++;
1255 }
1256
1257 if (LoadStringW(shell32_hInstance, IDS_CREATELINK, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
1258 {
1259 if (Count)
1260 {
1261 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_SEPARATOR, NULL, MFS_ENABLED);
1262 }
1263 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
1264
1265 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, szBuffer, MFS_ENABLED); //FIXME identifier
1266 Count++;
1267 }
1268 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
1269 }
1270
1271
1272 /**************************************************************************
1273 * ICPanel_IContextMenu_InvokeCommand()
1274 */
1275 static HRESULT WINAPI ICPanel_IContextMenu2_InvokeCommand(
1276 IContextMenu2 *iface,
1277 LPCMINVOKECOMMANDINFO lpcmi)
1278 {
1279 SHELLEXECUTEINFOW sei;
1280 WCHAR szPath[MAX_PATH];
1281 char szTarget[MAX_PATH];
1282 STRRET strret;
1283 WCHAR* pszPath;
1284 INT Length, cLength;
1285 PIDLCPanelStruct *pcpanel;
1286 IPersistFile * ppf;
1287 IShellLinkA * isl;
1288 ICPanelImpl *This = impl_from_IContextMenu(iface);
1289
1290 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
1291
1292 if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME
1293 {
1294 ZeroMemory(&sei, sizeof(sei));
1295 sei.cbSize = sizeof(sei);
1296 sei.fMask = SEE_MASK_INVOKEIDLIST;
1297 sei.lpIDList = ILCombine(This->pidlRoot, This->apidl[0]);
1298 sei.hwnd = lpcmi->hwnd;
1299 sei.nShow = SW_SHOWNORMAL;
1300 sei.lpVerb = L"open";
1301 ShellExecuteExW(&sei);
1302 if (sei.hInstApp <= (HINSTANCE)32)
1303 return E_FAIL;
1304 }
1305 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME
1306 {
1307 if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE))
1308 return E_FAIL;
1309
1310 pszPath = PathAddBackslashW(szPath);
1311 if (!pszPath)
1312 return E_FAIL;
1313
1314 if (IShellFolder_GetDisplayNameOf((IShellFolder*)This, This->apidl[0], SHGDN_FORPARSING, &strret) != S_OK)
1315 return E_FAIL;
1316
1317 Length = MAX_PATH - (pszPath - szPath);
1318 cLength = strlen(strret.u.cStr);
1319 if (Length < cLength + 5)
1320 {
1321 FIXME("\n");
1322 return E_FAIL;
1323 }
1324
1325 if (MultiByteToWideChar(CP_ACP, 0, strret.u.cStr, cLength +1, pszPath, Length))
1326 {
1327 pszPath += cLength;
1328 Length -= cLength;
1329 }
1330
1331 if (Length > 10)
1332 {
1333 wcscpy(pszPath, L" - ");
1334 cLength = LoadStringW(shell32_hInstance, IDS_LNK_FILE, &pszPath[3], Length -4) + 3;
1335 if (cLength + 5 > Length)
1336 cLength = Length - 5;
1337 Length -= cLength;
1338 pszPath += cLength;
1339 }
1340 wcscpy(pszPath, L".lnk");
1341
1342 pcpanel = _ILGetCPanelPointer(ILFindLastID(This->apidl[0]));
1343 if (pcpanel)
1344 {
1345 strncpy(szTarget, pcpanel->szName, MAX_PATH);
1346 }
1347 else
1348 {
1349 FIXME("\n");
1350 return E_FAIL;
1351 }
1352 if (SUCCEEDED(IShellLink_Constructor(NULL, &IID_IShellLinkA, (LPVOID*)&isl)))
1353 {
1354 IShellLinkA_SetPath(isl, szTarget);
1355 if (SUCCEEDED(IShellLinkA_QueryInterface(isl, &IID_IPersistFile, (LPVOID*)&ppf)))
1356 {
1357 IPersistFile_Save(ppf, szPath, TRUE);
1358 IPersistFile_Release(ppf);
1359 }
1360 IShellLinkA_Release(isl);
1361 }
1362 return NOERROR;
1363 }
1364 return S_OK;
1365 }
1366
1367 /**************************************************************************
1368 * ICPanel_IContextMenu_GetCommandString()
1369 *
1370 */
1371 static HRESULT WINAPI ICPanel_IContextMenu2_GetCommandString(
1372 IContextMenu2 *iface,
1373 UINT_PTR idCommand,
1374 UINT uFlags,
1375 UINT* lpReserved,
1376 LPSTR lpszName,
1377 UINT uMaxNameLen)
1378 {
1379 ICPanelImpl *This = impl_from_IContextMenu(iface);
1380
1381 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
1382
1383
1384 FIXME("unknown command string\n");
1385 return E_FAIL;
1386 }
1387
1388
1389
1390 /**************************************************************************
1391 * ICPanel_IContextMenu_HandleMenuMsg()
1392 */
1393 static HRESULT WINAPI ICPanel_IContextMenu2_HandleMenuMsg(
1394 IContextMenu2 *iface,
1395 UINT uMsg,
1396 WPARAM wParam,
1397 LPARAM lParam)
1398 {
1399 ICPanelImpl *This = impl_from_IContextMenu(iface);
1400
1401 TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam);
1402
1403 return E_NOTIMPL;
1404 }
1405
1406 static const IContextMenu2Vtbl vt_ContextMenu =
1407 {
1408 ICPanel_IContextMenu2_QueryInterface,
1409 ICPanel_IContextMenu2_AddRef,
1410 ICPanel_IContextMenu2_Release,
1411 ICPanel_IContextMenu2_QueryContextMenu,
1412 ICPanel_IContextMenu2_InvokeCommand,
1413 ICPanel_IContextMenu2_GetCommandString,
1414 ICPanel_IContextMenu2_HandleMenuMsg
1415 };
1416