如何在Delphi中获取Windows控制面板项的文件名与目录路径
获取Delphi中控制面板项的可执行文件路径与工作目录
你的代码已经成功获取了控制面板项的显示名称,要进一步拿到SHELLEXECUTEINFO所需的lpFile和lpDirectory,我们可以借助IShellLink接口来提取这些信息。下面是修改后的完整实现:
unit Unit1; interface uses CodeSiteLogging, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private procedure GetControlPanelItems; { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses Winapi.ShlObj, Winapi.ShellAPI, System.Win.ComObj, Winapi.ActiveX; {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin GetControlPanelItems; end; procedure TForm1.GetControlPanelItems; var psfDeskTop: IShellFolder; psfControl: IShellFolder; pidControl: PITEMIDLIST; pidChild: PITEMIDLIST; pidAbsolute: PItemIdList; pEnumList: IEnumIDList; celtFetched: ULONG; FileInfo: SHFILEINFOW; ShExeInfo: SHELLEXECUTEINFO; ShellLink: IShellLink; szPath: array[0..MAX_PATH] of WideChar; szDir: array[0..MAX_PATH] of WideChar; begin OleCheck(SHGetDesktopFolder(psfDeskTop)); OleCheck(SHGetSpecialFolderLocation(0, CSIDL_CONTROLS, pidControl)); OleCheck(psfDeskTop.BindToObject(pidControl, nil, IID_IShellFolder, psfControl)); OleCheck(psfControl.EnumObjects(0, SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN or SHCONTF_FOLDERS, pEnumList)); while pEnumList.Next(1, pidChild, celtFetched) = 0 do begin pidAbsolute := ILCombine(pidControl, pidChild); // 获取显示名称(保留原有逻辑) SHGetFileInfo(LPCTSTR(pidAbsolute), 0, FileInfo, SizeOf(FileInfo), SHGFI_PIDL or SHGFI_DISPLAYNAME or SHGFI_TYPENAME); CodeSite.Send('TForm1.GetControlPanelItems: szDisplayName', FileInfo.szDisplayName); // 获取IShellLink接口以提取路径信息 if psfControl.GetUIObjectOf(0, 1, @pidChild, IID_IShellLink, nil, Pointer(ShellLink)) = S_OK then begin // 获取可执行文件路径 ZeroMemory(@szPath, SizeOf(szPath)); OleCheck(ShellLink.GetPath(szPath, MAX_PATH, nil, SLGP_UNCPRIORITY)); // 获取工作目录 ZeroMemory(@szDir, SizeOf(szDir)); OleCheck(ShellLink.GetWorkingDirectory(szDir, MAX_PATH)); // 填充SHELLEXECUTEINFO结构 ZeroMemory(@ShExeInfo, SizeOf(ShExeInfo)); ShExeInfo.cbSize := SizeOf(ShExeInfo); ShExeInfo.lpVerb := 'Open'; ShExeInfo.lpFile := szPath; ShExeInfo.lpDirectory := szDir; ShExeInfo.nShow := SW_SHOWNORMAL; CodeSite.Send('TForm1.GetControlPanelItems: ShExeInfo.lpFile', String(szPath)); CodeSite.Send('TForm1.GetControlPanelItems: ShExeInfo.lpDirectory', String(szDir)); // 如需直接启动控制面板项,可取消注释下面一行 // ShellExecuteEx(@ShExeInfo); end; // 释放PIDL资源,避免内存泄漏 CoTaskMemFree(pidChild); CoTaskMemFree(pidAbsolute); end; CoTaskMemFree(pidControl); end; end.
关键说明:
IShellLink接口:通过IShellFolder::GetUIObjectOf获取控制面板项的IShellLink实例,它能解析出快捷方式对应的目标路径、工作目录等核心信息。- 路径获取逻辑:
GetPath方法使用SLGP_UNCPRIORITY标志优先返回UNC格式路径(如果存在),保证路径在网络环境下的可用性;GetWorkingDirectory则直接提取启动项的工作目录。 - 资源管理:所有通过COM接口获取的PIDL资源必须用
CoTaskMemFree手动释放,防止内存泄漏。 - 特殊项兼容:少数系统内置控制面板项(如“系统属性”)没有独立可执行文件,但
IShellLink仍能返回正确的启动参数,确保ShellExecuteEx可以正常调用。
内容的提问来源于stack exchange,提问作者user1580348




