主题:使用IShellFolder接口不能正确列举控制面板项目
其他磁盘分区目录和文件是可以正常列举的,但对控制面板这个虚拟目录却不能正常列举,经过多种方式检查均找不出问题原因,现在将问题源码发出来,希望有人能够找出问题的原因和给出解决方案。
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, ActiveX, ShellAPI, ShlObj, ComObj,
Vcl.StdCtrls;
procedure EnumControlPanelItems();
var
controlPIDL, parentPIDL, pidlChild2: PItemIDList;
shellFolder1, shellFolder2: IShellFolder;
enumIDL1, enumIDL2: IEnumIDList;
pidlSub1, pidlSub2: PItemIDList;
dwFetched: DWORD;
dName: String; // 对象显示名称
begin
CoInitialize(nil);
try
// 获取控制面板PIDL
SHGetSpecialFolderLocation(0, CSIDL_CONTROLS, controlPIDL);
outputdebugstring(pwidechar('controlPIDL:' + inttostr(ILGetSize(controlPIDL))));
// 绑定“控制面板”文件夹shellFolder1
SHBindToParent(controlPIDL, IShellFolder, Pointer(shellFolder1), parentPIDL);
// 获取控制面板枚举对象enumIDL1
shellFolder1.EnumObjects(Application.Handle, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_SHAREABLE, enumIDL1);
// 这里可以正确列举控制面板第一级功能模块
while enumIDL1.Next(1, pidlSub1, dwFetched) = S_OK do
begin
// 获取显示名
dName := GetDisplayName(shellFolder1, pidlSub1);
outputdebugstring(pwidechar(dName));
// 错误原因可能是下面2个方法上,1:BindToObject,2:EnumObjects,可能是参数传递有问题
// 绑定到第二级下级文件夹的 IShellFolder 接口
shellFolder1.BindToObject(pidlSub1, nil, IID_IShellFolder, Pointer(shellFolder2));
// OLECheck((SHBindToObject(shellFolder1, pidlSub1, nil, IID_IShellFolder, Pointer(shellFolder2))));
// 获取第二级下级枚举对象enumIDL2
shellFolder2.EnumObjects(Application.Handle, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_SHAREABLE, enumIDL2);
// 是这里不能正确列举第二级下级子项目,大多返回S_FALSE,很多子项都不能列举出来
while enumIDL2.Next(1, pidlSub2, dwFetched) = S_OK do
begin
dName := GetDisplayName(shellFolder2, pidlSub2);
outputdebugstring(pwidechar(' ' + dName + inttostr(ILGetSize(pidlSub2))));
CoTaskMemFree(pidlSub2);
end;
CoTaskMemFree(pidlSub1);
end;
// 释放PIDL
CoTaskMemFree(parentPIDL);
CoTaskMemFree(controlPIDL);
finally
CoUninitialize;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
EnumControlPanelItems;
end;
下面给出执行源码输出结果
Debug Output: 系统和安全 Process Project1.exe (23360)
Debug Output: 网络和 Internet Process Project1.exe (23360)
Debug Output: 硬件和声音 Process Project1.exe (23360)
Debug Output: 程序 Process Project1.exe (23360)
Debug Output: 用户帐户 Process Project1.exe (23360)
Debug Output: 邮件176 Process Project1.exe (23360)
Debug Output: 外观和个性化 Process Project1.exe (23360)
Debug Output: 时钟和区域 Process Project1.exe (23360)
Debug Output: 轻松使用 Process Project1.exe (23360)
Debug Output: 所有控制面板项 Process Project1.exe (23360)
Debug Output: Flash Player174 Process Project1.exe (23360)
Debug Output: 邮件176 Process Project1.exe (23360)
Debug Output: 360强力卸载156 Process Project1.exe (23360)
Debug Output: 128 Process Project1.exe (23360)
Debug Output:
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, ActiveX, ShellAPI, ShlObj, ComObj,
Vcl.StdCtrls;
procedure EnumControlPanelItems();
var
controlPIDL, parentPIDL, pidlChild2: PItemIDList;
shellFolder1, shellFolder2: IShellFolder;
enumIDL1, enumIDL2: IEnumIDList;
pidlSub1, pidlSub2: PItemIDList;
dwFetched: DWORD;
dName: String; // 对象显示名称
begin
CoInitialize(nil);
try
// 获取控制面板PIDL
SHGetSpecialFolderLocation(0, CSIDL_CONTROLS, controlPIDL);
outputdebugstring(pwidechar('controlPIDL:' + inttostr(ILGetSize(controlPIDL))));
// 绑定“控制面板”文件夹shellFolder1
SHBindToParent(controlPIDL, IShellFolder, Pointer(shellFolder1), parentPIDL);
// 获取控制面板枚举对象enumIDL1
shellFolder1.EnumObjects(Application.Handle, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_SHAREABLE, enumIDL1);
// 这里可以正确列举控制面板第一级功能模块
while enumIDL1.Next(1, pidlSub1, dwFetched) = S_OK do
begin
// 获取显示名
dName := GetDisplayName(shellFolder1, pidlSub1);
outputdebugstring(pwidechar(dName));
// 错误原因可能是下面2个方法上,1:BindToObject,2:EnumObjects,可能是参数传递有问题
// 绑定到第二级下级文件夹的 IShellFolder 接口
shellFolder1.BindToObject(pidlSub1, nil, IID_IShellFolder, Pointer(shellFolder2));
// OLECheck((SHBindToObject(shellFolder1, pidlSub1, nil, IID_IShellFolder, Pointer(shellFolder2))));
// 获取第二级下级枚举对象enumIDL2
shellFolder2.EnumObjects(Application.Handle, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_SHAREABLE, enumIDL2);
// 是这里不能正确列举第二级下级子项目,大多返回S_FALSE,很多子项都不能列举出来
while enumIDL2.Next(1, pidlSub2, dwFetched) = S_OK do
begin
dName := GetDisplayName(shellFolder2, pidlSub2);
outputdebugstring(pwidechar(' ' + dName + inttostr(ILGetSize(pidlSub2))));
CoTaskMemFree(pidlSub2);
end;
CoTaskMemFree(pidlSub1);
end;
// 释放PIDL
CoTaskMemFree(parentPIDL);
CoTaskMemFree(controlPIDL);
finally
CoUninitialize;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
EnumControlPanelItems;
end;
下面给出执行源码输出结果
Debug Output: 系统和安全 Process Project1.exe (23360)
Debug Output: 网络和 Internet Process Project1.exe (23360)
Debug Output: 硬件和声音 Process Project1.exe (23360)
Debug Output: 程序 Process Project1.exe (23360)
Debug Output: 用户帐户 Process Project1.exe (23360)
Debug Output: 邮件176 Process Project1.exe (23360)
Debug Output: 外观和个性化 Process Project1.exe (23360)
Debug Output: 时钟和区域 Process Project1.exe (23360)
Debug Output: 轻松使用 Process Project1.exe (23360)
Debug Output: 所有控制面板项 Process Project1.exe (23360)
Debug Output: Flash Player174 Process Project1.exe (23360)
Debug Output: 邮件176 Process Project1.exe (23360)
Debug Output: 360强力卸载156 Process Project1.exe (23360)
Debug Output: 128 Process Project1.exe (23360)
Debug Output: