📄 bsskinshellctrls.pas
字号:
ICmd := LongInt(Command) - 1;
HR := CM.GetCommandString(ICmd, GCS_VERBA, nil, ZVerb, SizeOf(ZVerb));
Verb := StrPas(ZVerb);
Handled := False;
if Supports(Owner, IShellCommandVerb, SCV) then
begin
HR := 0;
SCV.ExecuteCommand(Verb, Handled);
end;
if not Handled then
begin
FillChar(ICI, SizeOf(ICI), #0);
with ICI do
begin
cbSize := SizeOf(ICI);
hWND := Owner.Handle;
lpVerb := MakeIntResource(ICmd);
nShow := SW_SHOWNORMAL;
end;
HR := CM.InvokeCommand(ICI);
end;
if Assigned(SCV) then
SCV.CommandCompleted(Verb, HR = S_OK);
end;
finally
DestroyMenu(Menu);
end;
end;
procedure DoContextMenuVerb(AFolder: TbsShellFolder; Verb: PChar);
var
ICI: TCMInvokeCommandInfo;
CM: IContextMenu;
PIDL: PItemIDList;
begin
if AFolder = nil then Exit;
FillChar(ICI, SizeOf(ICI), #0);
with ICI do
begin
cbSize := SizeOf(ICI);
fMask := CMIC_MASK_ASYNCOK;
hWND := 0;
lpVerb := Verb;
nShow := SW_SHOWNORMAL;
end;
PIDL := AFolder.RelativeID;
AFolder.ParentShellFolder.GetUIObjectOf(0, 1, PIDL, IID_IContextMenu, nil, CM);
CM.InvokeCommand(ICI);
end;
function GetIShellFolder(IFolder: IShellFolder; PIDL: PItemIDList;
Handle: THandle = 0): IShellFolder;
var
HR : HResult;
begin
if Assigned(IFolder) then
begin
HR := IFolder.BindToObject(PIDL, nil, IID_IShellFolder, Pointer(Result));
if HR <> S_OK then
IFolder.GetUIObjectOf(Handle, 1, PIDL, IID_IShellFolder, nil, Pointer(Result));
if HR <> S_OK then
IFolder.CreateViewObject(Handle, IID_IShellFolder, Pointer(Result));
end;
if not Assigned(Result) then
DesktopShellFolder.BindToObject(PIDL, nil, IID_IShellFolder, Pointer(Result));
end;
function GetIShellDetails(IFolder: IShellFolder; PIDL: PItemIDList;
Handle: THandle = 0): IShellDetails;
var
HR : HResult;
begin
if Assigned(IFolder) then
begin
HR := IFolder.BindToObject(PIDL, nil, IID_IShellDetails, Pointer(Result));
if HR <> S_OK then
IFolder.GetUIObjectOf(Handle, 1, PIDL, IID_IShellDetails, nil, Pointer(Result));
if HR <> S_OK then
IFolder.CreateViewObject(Handle, IID_IShellDetails, Pointer(Result));
end;
if not Assigned(Result) then
DesktopShellFolder.BindToObject(PIDL, nil, IID_IShellDetails, Pointer(Result));
end;
function GetIShellFolder2(IFolder: IShellFolder; PIDL: PItemIDList;
Handle: THandle = 0): IShellFolder2;
var
HR : HResult;
begin
if (Win32MajorVersion >= 5) then
begin
HR := DesktopShellFolder.BindToObject(PIDL, nil, IID_IShellFolder2, Pointer(Result));
if HR <> S_OK then
IFolder.GetUIObjectOf(Handle, 1, PIDL, IID_IShellFolder2, nil, Pointer(Result));
if (HR <> S_OK) and (IFolder <> nil) then
IFolder.BindToObject(PIDL, nil, IID_IShellFolder2, Pointer(Result));
end
else
Result := nil;
end;
function CreateRootFromPIDL(Value: PItemIDList): TbsShellFolder;
var
SF: IShellFolder;
begin
SF := GetIShellFolder(DesktopShellFolder, Value);
if SF = NIL then SF := DesktopShellFolder;
Result := TbsShellFolder.Create(DesktopFolder, Value, SF);
end;
function CreateRootFolder(RootFolder: TbsShellFolder; OldRoot : TRoot;
var NewRoot: TRoot): TbsShellFolder;
var
P: PWideChar;
NewPIDL: PItemIDList;
NumChars,
Flags,
HR: LongWord;
ErrorMsg : string;
begin
HR := S_FALSE;
if GetEnumValue(TypeInfo(TRootFolder), NewRoot) >= 0 then
begin
HR := SHGetSpecialFolderLocation(
0,
nFolder[GetCSIDLType(NewRoot)],
NewPIDL);
end
else if Length(NewRoot) > 0 then
begin
if NewRoot[Length(NewRoot)] = ':' then NewRoot := NewRoot + '\';
NumChars := Length(NewRoot);
Flags := 0;
P := StringToOleStr(NewRoot);
HR := DesktopShellFolder.ParseDisplayName(0, nil, P, NumChars, NewPIDL, Flags);
end;
if HR <> S_OK then
begin
ErrorMsg := Format( SErrorSettingPath, [ NewRoot ] );
NewRoot := OldRoot;
raise Exception.Create( ErrorMsg );
end;
Result := CreateRootFromPIDL(NewPIDL);
if Assigned(RootFolder) then RootFolder.Free;
end;
{ TbsShellFolder }
constructor TbsShellFolder.Create(AParent: TbsShellFolder; ID: PItemIDList; SF: IShellFolder);
var
DesktopID: PItemIDList;
begin
inherited Create;
FLevel := 0;
FDetails := TStringList.Create;
FIShellFolder := SF;
FIShellFolder2 := nil;
FIShellDetails := nil;
FParent := AParent;
FPIDL := CopyPIDL(ID);
if FParent <> nil then
FFullPIDL := ConcatPIDLs(AParent.FFullPIDL, ID)
else
begin
DesktopID := DesktopPIDL;
try
FFullPIDL := ConcatPIDLs(DesktopID, ID);
finally
DisposePIDL(DesktopID);
end;
end;
if FParent = nil then
FParent := DesktopFolder;
while AParent <> nil do
begin
AParent := AParent.Parent;
if AParent <> nil then Inc(FLevel);
end;
end;
destructor TbsShellFolder.Destroy;
begin
if Assigned(FDetails) then
FDetails.Free;
FDetails := nil;
if Assigned(FPIDL) then
DisposePIDL(FPIDL);
if Assigned(FFullPIDL) then
DisposePIDL(FFullPIDL);
inherited Destroy;
end;
function TbsShellFolder.GetDetailInterface: IInterface;
begin
if (not Assigned(FDetailInterface)) and Assigned(FIShellFolder) then
begin
FIShellDetails := GetIShellDetails(FIShellFolder, FFullPIDL, FViewHandle);
if (not Assigned(FIShellDetails)) and (Win32MajorVersion >= 5) then
begin
FIShellFolder2 := GetIShellFolder2(FIShellFolder, FFullPIDL, FViewHandle);
if not Assigned(FIShellFolder2) then
FIShellFolder2 := IShellFolder2(FIShellFolder);
end;
if Assigned(FIShellFolder2) then
Result := IInterface(FIShellFolder2)
else
Result := IInterface(FIShellDetails);
FDetailInterface := Result;
end
else
Result := FDetailInterface;
end;
function TbsShellFolder.GetShellDetails: IShellDetails;
begin
if not Assigned(FDetailInterface) then
GetDetailInterface;
Result := FIShellDetails;
end;
function TbsShellFolder.GetShellFolder2: IShellFolder2;
begin
if not Assigned(FDetailInterface) then
GetDetailInterface;
Result := FIShellFolder2;
end;
procedure TbsShellFolder.LoadColumnDetails(RootFolder: TbsShellFolder;
Handle: THandle; ColumnCount: integer);
procedure GetDetailsOf(AFolder: TbsShellFolder; var Details: TWin32FindData);
var
szPath: array[ 0 .. MAX_PATH] of char;
Path: string;
Handle: THandle;
begin
FillChar(Details, SizeOf(Details), 0);
FillChar(szPath,MAX_PATH,0);
Path := AFolder.PathName;
Handle := Windows.FindFirstFile(PChar(Path), Details);
try
if Handle = INVALID_HANDLE_VALUE then
NoFolderDetails(AFolder, Windows.GetLastError);
finally
Windows.FindClose(Handle);
end;
end;
function CalcFileSize(FindData: TWin32FindData): int64;
begin
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
Result := FindData.nFileSizeHigh * MAXDWORD + FindData.nFileSizeLow
else
Result := -1;
end;
function CalcModifiedDate(FindData: TWin32FindData): TDateTime;
var
LocalFileTime: TFileTime;
Age : integer;
begin
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
begin
FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
if FileTimeToDosDateTime(LocalFileTime, LongRec(Age).Hi,
LongRec(Age).Lo) then
begin
Result := FileDateToDateTime(Age);
Exit;
end;
end;
Result := -1;
end;
function DefaultDetailColumn(FindData: TWin32FindData; Col: integer): string;
begin
case Col of
1 : Result := IntToStr(CalcFileSize(FindData)); // Size
2 : Result := ExtractFileExt(FindData.cFileName); // Type
3 : Result := DateTimeToStr(CalcModifiedDate(FindData)); // Modified
4 : Result := IntToStr(FindData.dwFileAttributes);
end;
end;
procedure AddDetail(HR: HResult; PIDL: PItemIDList; SD: TShellDetails);
begin
if HR = S_OK then
FDetails.Add(StrRetToString(PIDL, SD.str))
else
FDetails.Add('');
end;
var
SF2: IShellFolder2;
ISD: IShellDetails;
J: Integer;
SD: TShellDetails;
HR: HResult;
FindData: TWin32FindData;
begin
if not Assigned(FDetails) or (FDetails.Count >= ColumnCount) then Exit;
FDetails.Clear;
FViewHandle := Handle;
SF2 := RootFolder.ShellFolder2;
if Assigned(SF2) then
begin
for J := 1 to ColumnCount do
begin
HR := SF2.GetDetailsOf(FPIDL, J, SD);
AddDetail(HR, FPIDL, SD);
end;
end
else
begin
ISD := RootFolder.ShellDetails;
if Assigned(ISD) then
begin
for J := 1 to ColumnCount do
begin
HR := ISD.GetDetailsOf(FPIDL, J, SD);
AddDetail(HR, FPIDL, SD);
end;
end
else if (fpFileSystem in RootFolder.Properties) then
begin
GetDetailsOf(Self, FindData);
for J := 1 to ColumnCount do
FDetails.Add(DefaultDetailColumn(FindData, J));
end;
end;
end;
function TbsShellFolder.GetDetails(Index: integer): string;
begin
if FDetails.Count > 0 then
Result := FDetails[Index-1]
else
Raise Exception.CreateFmt(SCallLoadDetails, [ Self.DisplayName ] );
end;
procedure TbsShellFolder.SetDetails(Index: integer; const Value: string);
begin
if Index < FDetails.Count then
FDetails[Index - 1] := Value
else
FDetails.Insert(Index - 1, Value);
end;
function TbsShellFolder.ParentShellFolder: IShellFolder;
begin
if FParent <> nil then
Result := FParent.ShellFolder
else
OLECheck(SHGetDesktopFolder(Result));
end;
function TbsShellFolder.Properties: TbsShellFolderProperties;
begin
Result := GetProperties(ParentShellFolder, FPIDL);
end;
function TbsShellFolder.Capabilities: TbsShellFolderCapabilities;
begin
Result := GetCaps(ParentShellFolder, FPIDL);
end;
function TbsShellFolder.SubFolders: Boolean;
begin
Result := GetHasSubFolders(ParentShellFolder, FPIDL);
end;
function TbsShellFolder.IsFolder: Boolean;
begin
Result := GetIsFolder(ParentShellFolder, FPIDL);
if Result
then
Result := UpperCase(ExtractFileExt(PathName)) <> '.ZIP';
end;
function TbsShellFolder.PathName: string;
begin
Result := GetDisplayName(DesktopShellFolder, FFullPIDL, SHGDN_FORPARSING);
end;
function TbsShellFolder.DisplayName
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -