You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Delphi中获取Windows控制面板项的文件名与目录路径

获取Delphi中控制面板项的可执行文件路径与工作目录

你的代码已经成功获取了控制面板项的显示名称,要进一步拿到SHELLEXECUTEINFO所需的lpFilelpDirectory,我们可以借助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

火山引擎 最新活动