4 * Copyright 2003 Martin Fuchs
5 * Copyright 2009 Andrew Hill
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 1. The selected items list should not be stored in CControlPanelFolder, it should
25 be a result returned by an internal method.
30 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
32 /***********************************************************************
33 * control panel implementation in shell namespace
36 class CControlPanelEnum
:
37 public IEnumIDListImpl
43 HRESULT WINAPI
Initialize(DWORD dwFlags
);
44 BOOL
RegisterCPanelApp(LPCSTR path
);
45 int RegisterRegistryCPanelApps(HKEY hkey_root
, LPCSTR szRepPath
);
46 int RegisterCPanelFolders(HKEY hkey_root
, LPCSTR szRepPath
);
47 BOOL
CreateCPanelEnumList(DWORD dwFlags
);
49 BEGIN_COM_MAP(CControlPanelEnum
)
50 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
54 /***********************************************************************
55 * IShellFolder [ControlPanel] implementation
58 static const shvheader ControlPanelSFHeader
[] = {
59 {IDS_SHV_COLUMN8
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},/*FIXME*/
60 {IDS_SHV_COLUMN9
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 200},/*FIXME*/
63 #define CONROLPANELSHELLVIEWCOLUMNS 2
65 CControlPanelEnum::CControlPanelEnum()
69 CControlPanelEnum::~CControlPanelEnum()
73 HRESULT WINAPI
CControlPanelEnum::Initialize(DWORD dwFlags
)
75 if (CreateCPanelEnumList(dwFlags
) == FALSE
)
80 static LPITEMIDLIST
_ILCreateCPanelApplet(LPCSTR pszName
, LPCSTR pszDisplayName
, LPCSTR pszComment
, int iIconIdx
)
82 PIDLCPanelStruct
*pCP
;
85 int cchName
, cchDisplayName
, cchComment
, cbData
;
87 /* Calculate lengths of given strings */
88 cchName
= strlen(pszName
);
89 cchDisplayName
= strlen(pszDisplayName
);
90 cchComment
= strlen(pszComment
);
93 cbData
= sizeof(pidl
->mkid
.cb
) + sizeof(pData
->type
) + sizeof(pData
->u
.cpanel
) - sizeof(pData
->u
.cpanel
.szName
)
94 + cchName
+ cchDisplayName
+ cchComment
+ 3;
95 pidl
= (LPITEMIDLIST
)SHAlloc(cbData
+ sizeof(WORD
));
99 /* Copy data to allocated memory */
100 pidl
->mkid
.cb
= cbData
;
101 pData
= (PIDLDATA
*)pidl
->mkid
.abID
;
102 pData
->type
= PT_CPLAPPLET
;
104 pCP
= &pData
->u
.cpanel
;
106 pCP
->iconIdx
= iIconIdx
;
107 strcpy(pCP
->szName
, pszName
);
108 pCP
->offsDispName
= cchName
+ 1;
109 strcpy(pCP
->szName
+ pCP
->offsDispName
, pszDisplayName
);
110 pCP
->offsComment
= pCP
->offsDispName
+ cchDisplayName
+ 1;
111 strcpy(pCP
->szName
+ pCP
->offsComment
, pszComment
);
113 /* Add PIDL NULL terminator */
114 *(WORD
*)(pCP
->szName
+ pCP
->offsComment
+ cchComment
+ 1) = 0;
121 /**************************************************************************
122 * _ILGetCPanelPointer()
123 * gets a pointer to the control panel struct stored in the pidl
125 static PIDLCPanelStruct
*_ILGetCPanelPointer(LPCITEMIDLIST pidl
)
127 LPPIDLDATA pdata
= _ILGetDataPointer(pidl
);
129 if (pdata
&& pdata
->type
== PT_CPLAPPLET
)
130 return (PIDLCPanelStruct
*) & (pdata
->u
.cpanel
);
135 BOOL
CControlPanelEnum::RegisterCPanelApp(LPCSTR path
)
144 char displayName
[MAX_PATH
];
145 char comment
[MAX_PATH
];
147 WCHAR wpath
[MAX_PATH
];
149 MultiByteToWideChar(CP_ACP
, 0, path
, -1, wpath
, MAX_PATH
);
152 applet
= Control_LoadApplet(0, wpath
, &panel
);
156 for (i
= 0; i
< applet
->count
; ++i
)
158 WideCharToMultiByte(CP_ACP
, 0, applet
->info
[i
].szName
, -1, displayName
, MAX_PATH
, 0, 0);
159 WideCharToMultiByte(CP_ACP
, 0, applet
->info
[i
].szInfo
, -1, comment
, MAX_PATH
, 0, 0);
161 applet
->proc(0, CPL_INQUIRE
, i
, (LPARAM
)&info
);
164 iconIdx
= -info
.idIcon
; /* negative icon index instead of icon number */
168 pidl
= _ILCreateCPanelApplet(path
, displayName
, comment
, iconIdx
);
173 Control_UnloadApplet(applet
);
178 int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root
, LPCSTR szRepPath
)
181 char value
[MAX_PATH
];
186 if (RegOpenKeyA(hkey_root
, szRepPath
, &hkey
) == ERROR_SUCCESS
)
192 DWORD nameLen
= MAX_PATH
;
193 DWORD valueLen
= MAX_PATH
;
195 if (RegEnumValueA(hkey
, idx
, name
, &nameLen
, NULL
, NULL
, (LPBYTE
)&value
, &valueLen
) != ERROR_SUCCESS
)
198 if (RegisterCPanelApp(value
))
207 int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root
, LPCSTR szRepPath
)
214 if (RegOpenKeyA(hkey_root
, szRepPath
, &hkey
) == ERROR_SUCCESS
)
219 if (RegEnumKeyA(hkey
, idx
, name
, MAX_PATH
) != ERROR_SUCCESS
)
224 LPITEMIDLIST pidl
= _ILCreateGuidFromStrA(name
);
226 if (pidl
&& AddToEnumList(pidl
))
237 /**************************************************************************
238 * CControlPanelEnum::CreateCPanelEnumList()
240 BOOL
CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags
)
242 CHAR szPath
[MAX_PATH
];
243 WIN32_FIND_DATAA wfd
;
246 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags
);
248 /* enumerate control panel folders */
249 if (dwFlags
& SHCONTF_FOLDERS
)
250 RegisterCPanelFolders(HKEY_LOCAL_MACHINE
, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
252 /* enumerate the control panel applets */
253 if (dwFlags
& SHCONTF_NONFOLDERS
)
257 GetSystemDirectoryA(szPath
, MAX_PATH
);
258 p
= PathAddBackslashA(szPath
);
261 TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n", this, debugstr_a(szPath
));
262 hFile
= FindFirstFileA(szPath
, &wfd
);
264 if (hFile
!= INVALID_HANDLE_VALUE
)
268 if (!(dwFlags
& SHCONTF_INCLUDEHIDDEN
) && (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
))
271 if (!(wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)) {
272 strcpy(p
, wfd
.cFileName
);
273 if (strcmp(wfd
.cFileName
, "ncpa.cpl"))
274 RegisterCPanelApp(szPath
);
276 } while(FindNextFileA(hFile
, &wfd
));
280 RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE
, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
281 RegisterRegistryCPanelApps(HKEY_CURRENT_USER
, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
286 CControlPanelFolder::CControlPanelFolder()
288 pidlRoot
= NULL
; /* absolute pidl */
289 dwAttributes
= 0; /* attributes returned by GetAttributesOf FIXME: use it */
294 CControlPanelFolder::~CControlPanelFolder()
296 TRACE("-- destroying IShellFolder(%p)\n", this);
300 HRESULT WINAPI
CControlPanelFolder::FinalConstruct()
302 pidlRoot
= _ILCreateControlPanel(); /* my qualified pidl */
303 if (pidlRoot
== NULL
)
304 return E_OUTOFMEMORY
;
308 /**************************************************************************
309 * CControlPanelFolder::ParseDisplayName
311 HRESULT WINAPI
CControlPanelFolder::ParseDisplayName(
314 LPOLESTR lpszDisplayName
,
317 DWORD
*pdwAttributes
)
319 WCHAR szElement
[MAX_PATH
];
320 LPCWSTR szNext
= NULL
;
321 LPITEMIDLIST pidlTemp
= NULL
;
325 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
326 this, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w(lpszDisplayName
),
327 pchEaten
, ppidl
, pdwAttributes
);
329 if (!lpszDisplayName
|| !ppidl
)
335 *pchEaten
= 0; /* strange but like the original */
337 if (lpszDisplayName
[0] == ':' && lpszDisplayName
[1] == ':')
339 szNext
= GetNextElementW (lpszDisplayName
, szElement
, MAX_PATH
);
340 TRACE ("-- element: %s\n", debugstr_w (szElement
));
341 CLSIDFromString (szElement
+ 2, &clsid
);
342 pidlTemp
= _ILCreateGuid (PT_GUID
, clsid
);
344 else if( (pidlTemp
= SHELL32_CreatePidlFromBindCtx(pbc
, lpszDisplayName
)) )
350 if (SUCCEEDED(hr
) && pidlTemp
)
352 if (szNext
&& *szNext
)
354 hr
= SHELL32_ParseNextElement(this, hwndOwner
, pbc
,
355 &pidlTemp
, (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
359 if (pdwAttributes
&& *pdwAttributes
)
360 hr
= SHELL32_GetItemAttributes(this,
361 pidlTemp
, pdwAttributes
);
367 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr
);
372 /**************************************************************************
373 * CControlPanelFolder::EnumObjects
375 HRESULT WINAPI
CControlPanelFolder::EnumObjects(
378 LPENUMIDLIST
*ppEnumIDList
)
380 CComObject
<CControlPanelEnum
> *theEnumerator
;
381 CComPtr
<IEnumIDList
> result
;
384 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner
, dwFlags
, ppEnumIDList
);
386 if (ppEnumIDList
== NULL
)
388 *ppEnumIDList
= NULL
;
389 ATLTRY (theEnumerator
= new CComObject
<CControlPanelEnum
>);
390 if (theEnumerator
== NULL
)
391 return E_OUTOFMEMORY
;
392 hResult
= theEnumerator
->QueryInterface (IID_IEnumIDList
, (void **)&result
);
393 if (FAILED (hResult
))
395 delete theEnumerator
;
398 hResult
= theEnumerator
->Initialize (dwFlags
);
399 if (FAILED (hResult
))
401 *ppEnumIDList
= result
.Detach ();
403 TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList
);
408 /**************************************************************************
409 * CControlPanelFolder::BindToObject
411 HRESULT WINAPI
CControlPanelFolder::BindToObject(
417 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl
, pbcReserved
, shdebugstr_guid(&riid
), ppvOut
);
419 return SHELL32_BindToChild(pidlRoot
, NULL
, pidl
, riid
, ppvOut
);
422 /**************************************************************************
423 * CControlPanelFolder::BindToStorage
425 HRESULT WINAPI
CControlPanelFolder::BindToStorage(
431 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl
, pbcReserved
, shdebugstr_guid(&riid
), ppvOut
);
437 /**************************************************************************
438 * CControlPanelFolder::CompareIDs
441 HRESULT WINAPI
CControlPanelFolder::CompareIDs(LPARAM lParam
, LPCITEMIDLIST pidl1
, LPCITEMIDLIST pidl2
)
445 TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam
, pidl1
, pidl2
);
446 nReturn
= SHELL32_CompareIDs(this, lParam
, pidl1
, pidl2
);
447 TRACE("-- %i\n", nReturn
);
451 /**************************************************************************
452 * CControlPanelFolder::CreateViewObject
454 HRESULT WINAPI
CControlPanelFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
* ppvOut
)
456 CComPtr
<IShellView
> pShellView
;
457 HRESULT hr
= E_INVALIDARG
;
459 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner
, shdebugstr_guid(&riid
), ppvOut
);
464 if (IsEqualIID(riid
, IID_IDropTarget
)) {
465 WARN("IDropTarget not implemented\n");
467 } else if (IsEqualIID(riid
, IID_IContextMenu
)) {
468 WARN("IContextMenu not implemented\n");
470 } else if (IsEqualIID(riid
, IID_IShellView
)) {
471 hr
= IShellView_Constructor((IShellFolder
*)this, &pShellView
);
473 hr
= pShellView
->QueryInterface(riid
, ppvOut
);
477 TRACE("--(%p)->(interface=%p)\n", this, ppvOut
);
481 /**************************************************************************
482 * CControlPanelFolder::GetAttributesOf
484 HRESULT WINAPI
CControlPanelFolder::GetAttributesOf(UINT cidl
, LPCITEMIDLIST
* apidl
, DWORD
* rgfInOut
)
488 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
489 this, cidl
, apidl
, rgfInOut
, rgfInOut
? *rgfInOut
: 0);
499 while(cidl
> 0 && *apidl
)
502 SHELL32_GetItemAttributes(this, *apidl
, rgfInOut
);
506 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
507 *rgfInOut
&= ~SFGAO_VALIDATE
;
509 TRACE("-- result=0x%08x\n", *rgfInOut
);
513 /**************************************************************************
514 * CControlPanelFolder::GetUIObjectOf
517 * HWND hwndOwner, //[in ] Parent window for any output
518 * UINT cidl, //[in ] array size
519 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
520 * REFIID riid, //[in ] Requested Interface
521 * UINT* prgfInOut, //[ ] reserved
522 * LPVOID* ppvObject) //[out] Resulting Interface
525 HRESULT WINAPI
CControlPanelFolder::GetUIObjectOf(HWND hwndOwner
,
526 UINT cidl
, LPCITEMIDLIST
* apidl
, REFIID riid
, UINT
* prgfInOut
, LPVOID
* ppvOut
)
529 IUnknown
*pObj
= NULL
;
530 HRESULT hr
= E_INVALIDARG
;
532 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
533 this, hwndOwner
, cidl
, apidl
, shdebugstr_guid(&riid
), prgfInOut
, ppvOut
);
538 if (IsEqualIID(riid
, IID_IContextMenu
) && (cidl
>= 1)) {
540 // create a seperate item struct
542 pObj
= (IContextMenu
*)this;
547 } else if (IsEqualIID(riid
, IID_IDataObject
) && (cidl
>= 1)) {
548 hr
= IDataObject_Constructor(hwndOwner
, pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
549 } else if (IsEqualIID(riid
, IID_IExtractIconA
) && (cidl
== 1)) {
550 pidl
= ILCombine(pidlRoot
, apidl
[0]);
551 pObj
= (LPUNKNOWN
) IExtractIconA_Constructor(pidl
);
554 } else if (IsEqualIID(riid
, IID_IExtractIconW
) && (cidl
== 1)) {
555 pidl
= ILCombine(pidlRoot
, apidl
[0]);
556 pObj
= (LPUNKNOWN
) IExtractIconW_Constructor(pidl
);
559 } else if ((IsEqualIID(riid
, IID_IShellLinkW
) || IsEqualIID(riid
, IID_IShellLinkA
))
561 pidl
= ILCombine(pidlRoot
, apidl
[0]);
562 hr
= IShellLink_ConstructFromFile(NULL
, riid
, pidl
, (LPVOID
*)&pObj
);
568 if (SUCCEEDED(hr
) && !pObj
)
573 TRACE("(%p)->hr=0x%08x\n", this, hr
);
577 /**************************************************************************
578 * CControlPanelFolder::GetDisplayNameOf
580 HRESULT WINAPI
CControlPanelFolder::GetDisplayNameOf(LPCITEMIDLIST pidl
, DWORD dwFlags
, LPSTRRET strRet
)
582 CHAR szName
[MAX_PATH
];
583 WCHAR wszName
[MAX_PATH
+1]; /* +1 for potential backslash */
584 PIDLCPanelStruct
*pCPanel
;
589 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl
, dwFlags
, strRet
);
595 pCPanel
= _ILGetCPanelPointer(pidl
);
599 /* copy display name from pidl - it was retrived from applet before;
600 SHGDN_FORPARSING does not need special handling */
601 lstrcpyA(szName
, pCPanel
->szName
+ pCPanel
->offsDispName
);
603 /* take names of special folders only if it's only this folder */
604 else if (_ILIsSpecialFolder(pidl
))
606 BOOL bSimplePidl
= _ILIsPidlSimple(pidl
);
607 SFGAOF Attr
= SFGAO_FILESYSTEM
;
609 SHELL32_GetItemAttributes(this, pidl
, &Attr
);
610 if (Attr
& SFGAO_FILESYSTEM
)
612 hr
= SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, wszName
, sizeof(wszName
));
616 else if (bSimplePidl
)
618 _ILSimpleGetTextW(pidl
, wszName
, MAX_PATH
); /* append my own path */
622 FIXME("special pidl\n");
623 if (dwFlags
& SHGDN_FORPARSING
)
625 /* go deeper if needed */
628 PathAddBackslashW(wszName
);
629 cchName
= wcslen(wszName
);
631 hr
= SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, wszName
+ cchName
, MAX_PATH
+ 1 - cchName
);
637 if (!WideCharToMultiByte(CP_ACP
, 0, wszName
, -1, szName
, MAX_PATH
, NULL
, NULL
))
641 strRet
->uType
= STRRET_CSTR
;
642 lstrcpynA(strRet
->cStr
, szName
, MAX_PATH
);
644 TRACE("--(%p)->(%s)\n", this, szName
);
648 /**************************************************************************
649 * CControlPanelFolder::SetNameOf
650 * Changes the name of a file object or subfolder, possibly changing its item
651 * identifier in the process.
654 * HWND hwndOwner, //[in ] Owner window for output
655 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
656 * LPCOLESTR lpszName, //[in ] the items new display name
657 * DWORD dwFlags, //[in ] SHGNO formatting flags
658 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
660 HRESULT WINAPI
CControlPanelFolder::SetNameOf(HWND hwndOwner
, LPCITEMIDLIST pidl
, /*simple pidl */
661 LPCOLESTR lpName
, DWORD dwFlags
, LPITEMIDLIST
* pPidlOut
)
663 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner
, pidl
, debugstr_w(lpName
), dwFlags
, pPidlOut
);
667 HRESULT WINAPI
CControlPanelFolder::GetDefaultSearchGUID(GUID
*pguid
)
669 FIXME("(%p)\n", this);
673 HRESULT WINAPI
CControlPanelFolder::EnumSearches(IEnumExtraSearch
**ppenum
)
675 FIXME("(%p)\n", this);
679 HRESULT WINAPI
CControlPanelFolder::GetDefaultColumn(DWORD dwRes
, ULONG
*pSort
, ULONG
*pDisplay
)
681 TRACE("(%p)\n", this);
683 if (pSort
) *pSort
= 0;
684 if (pDisplay
) *pDisplay
= 0;
688 HRESULT WINAPI
CControlPanelFolder::GetDefaultColumnState(UINT iColumn
, DWORD
*pcsFlags
)
690 TRACE("(%p)\n", this);
692 if (!pcsFlags
|| iColumn
>= CONROLPANELSHELLVIEWCOLUMNS
) return E_INVALIDARG
;
693 *pcsFlags
= ControlPanelSFHeader
[iColumn
].pcsFlags
;
697 HRESULT WINAPI
CControlPanelFolder::GetDetailsEx(LPCITEMIDLIST pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
699 FIXME("(%p)\n", this);
703 HRESULT WINAPI
CControlPanelFolder::GetDetailsOf(LPCITEMIDLIST pidl
, UINT iColumn
, SHELLDETAILS
*psd
)
707 TRACE("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
709 if (!psd
|| iColumn
>= CONROLPANELSHELLVIEWCOLUMNS
)
713 psd
->fmt
= ControlPanelSFHeader
[iColumn
].fmt
;
714 psd
->cxChar
= ControlPanelSFHeader
[iColumn
].cxChar
;
715 psd
->str
.uType
= STRRET_CSTR
;
716 LoadStringA(shell32_hInstance
, ControlPanelSFHeader
[iColumn
].colnameid
, psd
->str
.cStr
, MAX_PATH
);
719 psd
->str
.cStr
[0] = 0x00;
720 psd
->str
.uType
= STRRET_CSTR
;
723 hr
= GetDisplayNameOf(pidl
, SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
725 case 1: /* comment */
726 _ILGetFileType(pidl
, psd
->str
.cStr
, MAX_PATH
);
735 HRESULT WINAPI
CControlPanelFolder::MapColumnToSCID(UINT column
, SHCOLUMNID
*pscid
)
737 FIXME("(%p)\n", this);
741 /************************************************************************
742 * CControlPanelFolder::GetClassID
744 HRESULT WINAPI
CControlPanelFolder::GetClassID(CLSID
*lpClassId
)
746 TRACE("(%p)\n", this);
750 *lpClassId
= CLSID_ControlPanel
;
755 /************************************************************************
756 * CControlPanelFolder::Initialize
758 * NOTES: it makes no sense to change the pidl
760 HRESULT WINAPI
CControlPanelFolder::Initialize(LPCITEMIDLIST pidl
)
763 SHFree((LPVOID
)pidlRoot
);
765 pidlRoot
= ILClone(pidl
);
769 /**************************************************************************
770 * CControlPanelFolder::GetCurFolder
772 HRESULT WINAPI
CControlPanelFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
774 TRACE("(%p)->(%p)\n", this, pidl
);
778 *pidl
= ILClone(pidlRoot
);
782 HRESULT
CPanel_GetIconLocationW(LPCITEMIDLIST pidl
, LPWSTR szIconFile
, UINT cchMax
, int* piIndex
)
784 PIDLCPanelStruct
* pcpanel
= _ILGetCPanelPointer(pidl
);
789 MultiByteToWideChar(CP_ACP
, 0, pcpanel
->szName
, -1, szIconFile
, cchMax
);
790 *piIndex
= (int)pcpanel
->iconIdx
!= -1 ? pcpanel
->iconIdx
: 0;
796 /**************************************************************************
797 * IShellExecuteHookW Implementation
801 ExecuteAppletFromCLSID(LPOLESTR pOleStr
)
803 WCHAR szCmd
[MAX_PATH
];
804 WCHAR szExpCmd
[MAX_PATH
];
805 PROCESS_INFORMATION pi
;
807 WCHAR szBuffer
[90] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
808 DWORD dwType
, dwSize
;
810 wcscpy(&szBuffer
[6], pOleStr
);
811 wcscat(szBuffer
, L
"\\shell\\open\\command");
813 dwSize
= sizeof(szCmd
);
814 if (RegGetValueW(HKEY_CLASSES_ROOT
, szBuffer
, NULL
, RRF_RT_REG_SZ
, &dwType
, (PVOID
)szCmd
, &dwSize
) != ERROR_SUCCESS
)
816 ERR("RegGetValueW(%ls) failed with %u\n", szBuffer
, GetLastError());
820 if (!ExpandEnvironmentStringsW(szCmd
, szExpCmd
, sizeof(szExpCmd
) / sizeof(WCHAR
)))
823 ZeroMemory(&si
, sizeof(si
));
825 if (!CreateProcessW(NULL
, szExpCmd
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
))
828 CloseHandle(pi
.hProcess
);
829 CloseHandle(pi
.hThread
);
834 HRESULT WINAPI
CControlPanelFolder::Execute(LPSHELLEXECUTEINFOW psei
)
836 static const WCHAR wCplopen
[] = {'c', 'p', 'l', 'o', 'p', 'e', 'n', '\0'};
837 SHELLEXECUTEINFOW sei_tmp
;
838 PIDLCPanelStruct
* pcpanel
;
839 WCHAR path
[MAX_PATH
];
840 WCHAR params
[MAX_PATH
];
845 TRACE("(%p)->execute(%p)\n", this, psei
);
850 pcpanel
= _ILGetCPanelPointer(ILFindLastID((LPCITEMIDLIST
)psei
->lpIDList
));
856 IID
* iid
= _ILGetGUIDPointer(ILFindLastID((LPCITEMIDLIST
)psei
->lpIDList
));
859 if (StringFromCLSID(*iid
, &pOleStr
) == S_OK
)
861 hr
= ExecuteAppletFromCLSID(pOleStr
);
862 CoTaskMemFree(pOleStr
);
869 /* Return value from MultiByteToWideChar includes terminating NUL, which
870 * compensates for the starting double quote we just put in */
871 l
= MultiByteToWideChar(CP_ACP
, 0, pcpanel
->szName
, -1, path
+ 1, MAX_PATH
);
873 /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */
877 MultiByteToWideChar(CP_ACP
, 0, pcpanel
->szName
+ pcpanel
->offsDispName
, -1, params
, MAX_PATH
);
879 memcpy(&sei_tmp
, psei
, sizeof(sei_tmp
));
880 sei_tmp
.lpFile
= path
;
881 sei_tmp
.lpParameters
= params
;
882 sei_tmp
.fMask
&= ~SEE_MASK_INVOKEIDLIST
;
883 sei_tmp
.lpVerb
= wCplopen
;
885 ret
= ShellExecuteExW(&sei_tmp
);
892 /**************************************************************************
893 * IShellExecuteHookA Implementation
896 HRESULT WINAPI
CControlPanelFolder::Execute(LPSHELLEXECUTEINFOA psei
)
898 SHELLEXECUTEINFOA sei_tmp
;
899 PIDLCPanelStruct
* pcpanel
;
903 TRACE("(%p)->execute(%p)\n", this, psei
);
908 pcpanel
= _ILGetCPanelPointer(ILFindLastID((LPCITEMIDLIST
)psei
->lpIDList
));
914 lstrcpyA(path
+ 1, pcpanel
->szName
);
916 /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */
917 lstrcatA(path
, "\" ");
918 lstrcatA(path
, pcpanel
->szName
+ pcpanel
->offsDispName
);
920 memcpy(&sei_tmp
, psei
, sizeof(sei_tmp
));
921 sei_tmp
.lpFile
= path
;
922 sei_tmp
.fMask
&= ~SEE_MASK_INVOKEIDLIST
;
924 ret
= ShellExecuteExA(&sei_tmp
);
931 /**************************************************************************
932 * IContextMenu2 Implementation
935 /**************************************************************************
936 * ICPanel_IContextMenu_QueryContextMenu()
938 HRESULT WINAPI
CControlPanelFolder::QueryContextMenu(
945 WCHAR szBuffer
[30] = {0};
948 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
949 this, hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
951 if (LoadStringW(shell32_hInstance
, IDS_OPEN
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
953 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
954 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, IDS_OPEN
, MFT_STRING
, szBuffer
, MFS_DEFAULT
); //FIXME identifier
958 if (LoadStringW(shell32_hInstance
, IDS_CREATELINK
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
962 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
964 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
966 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, IDS_CREATELINK
, MFT_STRING
, szBuffer
, MFS_ENABLED
); //FIXME identifier
969 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Count
);
972 /**************************************************************************
973 * ICPanel_IContextMenu_InvokeCommand()
975 HRESULT WINAPI
CControlPanelFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
977 SHELLEXECUTEINFOW sei
;
978 WCHAR szPath
[MAX_PATH
];
979 char szTarget
[MAX_PATH
];
983 PIDLCPanelStruct
*pcpanel
;
984 CComPtr
<IPersistFile
> ppf
;
985 CComPtr
<IShellLinkA
> isl
;
988 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi
, lpcmi
->lpVerb
, lpcmi
->hwnd
);
990 if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(IDS_OPEN
)) //FIXME
992 ZeroMemory(&sei
, sizeof(sei
));
993 sei
.cbSize
= sizeof(sei
);
994 sei
.fMask
= SEE_MASK_INVOKEIDLIST
;
995 sei
.lpIDList
= ILCombine(pidlRoot
, apidl
[0]);
996 sei
.hwnd
= lpcmi
->hwnd
;
997 sei
.nShow
= SW_SHOWNORMAL
;
998 sei
.lpVerb
= L
"open";
1000 if (ShellExecuteExW(&sei
) == FALSE
)
1003 else if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(IDS_CREATELINK
)) //FIXME
1005 if (!SHGetSpecialFolderPathW(NULL
, szPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
))
1008 pszPath
= PathAddBackslashW(szPath
);
1012 if (GetDisplayNameOf(apidl
[0], SHGDN_FORPARSING
, &strret
) != S_OK
)
1015 Length
= MAX_PATH
- (pszPath
- szPath
);
1016 cLength
= strlen(strret
.cStr
);
1017 if (Length
< cLength
+ 5)
1023 if (MultiByteToWideChar(CP_ACP
, 0, strret
.cStr
, cLength
+ 1, pszPath
, Length
))
1031 wcscpy(pszPath
, L
" - ");
1032 cLength
= LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, &pszPath
[3], Length
- 4) + 3;
1033 if (cLength
+ 5 > Length
)
1034 cLength
= Length
- 5;
1038 wcscpy(pszPath
, L
".lnk");
1040 pcpanel
= _ILGetCPanelPointer(ILFindLastID(apidl
[0]));
1043 strncpy(szTarget
, pcpanel
->szName
, MAX_PATH
);
1047 FIXME("Couldn't retrieve pointer to cpl structure\n");
1050 hResult
= CShellLink::_CreatorClass::CreateInstance(NULL
, IID_IShellLinkA
, (void **)&isl
);
1051 if (SUCCEEDED(hResult
))
1053 isl
->SetPath(szTarget
);
1054 if (SUCCEEDED(isl
->QueryInterface(IID_IPersistFile
, (LPVOID
*)&ppf
)))
1055 ppf
->Save(szPath
, TRUE
);
1062 /**************************************************************************
1063 * ICPanel_IContextMenu_GetCommandString()
1066 HRESULT WINAPI
CControlPanelFolder::GetCommandString(
1073 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
1075 FIXME("unknown command string\n");
1079 /**************************************************************************
1080 * ICPanel_IContextMenu_HandleMenuMsg()
1082 HRESULT WINAPI
CControlPanelFolder::HandleMenuMsg(
1087 TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg
, wParam
, lParam
);