mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
424 lines
14 KiB
ObjectPascal
424 lines
14 KiB
ObjectPascal
unit uShellFileSource;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Dialogs,
|
|
Windows, ShlObj,
|
|
uFileSourceProperty,
|
|
uVirtualFileSource, uFileProperty, uFileSource,
|
|
uFileSourceOperation, uFile, uFileSourceOperationTypes;
|
|
|
|
type
|
|
|
|
{ IShellFileSource }
|
|
|
|
IShellFileSource = interface(IVirtualFileSource)
|
|
['{1E598290-5E66-423C-BB55-333E293106E8}']
|
|
function CreateFolder(AParent: IShellFolder2; const Name: String): HRESULT;
|
|
function FindFolder(const Path: String; out AValue: IShellFolder2): HRESULT;
|
|
function FindObject(const AObject: String; out AValue: PItemIDList): HRESULT;
|
|
function FindObject(AParent: IShellFolder2; const AName: String; out AValue: PItemIDList): HRESULT;
|
|
end;
|
|
|
|
{ TShellFileSource }
|
|
|
|
TShellFileSource = class(TVirtualFileSource, IShellFileSource)
|
|
private
|
|
FRootPath: String;
|
|
FDrives: PItemIDList;
|
|
FRootFolder: IShellFolder2;
|
|
FDesktopFolder: IShellFolder;
|
|
protected
|
|
function SetCurrentWorkingDirectory(NewDir: String): Boolean; override;
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
|
|
class function IsSupportedPath(const Path: String): Boolean; override;
|
|
class function CreateFile(const APath: String): TFile; override;
|
|
class function GetMainIcon(out Path: String): Boolean; override;
|
|
|
|
class function RootName: String;
|
|
|
|
function CreateFolder(AParent: IShellFolder2; const Name: String): HRESULT;
|
|
function FindFolder(const Path: String; out AValue: IShellFolder2): HRESULT;
|
|
function FindObject(const AObject: String; out AValue: PItemIDList): HRESULT;
|
|
function FindObject(AParent: IShellFolder2; const AName: String; out AValue: PItemIDList): HRESULT;
|
|
|
|
function CreateDirectory(const Path: String): Boolean; override;
|
|
function FileSystemEntryExists(const Path: String): Boolean; override;
|
|
|
|
function GetOperationsTypes: TFileSourceOperationTypes; override;
|
|
function GetSupportedFileProperties: TFilePropertiesTypes; override;
|
|
function GetRootDir(sPath: String): String; override; overload;
|
|
function GetProperties: TFileSourceProperties; override;
|
|
|
|
function CreateListOperation(TargetPath: String): TFileSourceOperation; override;
|
|
function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override;
|
|
function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; override;
|
|
function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override;
|
|
function CreateMoveOperation(var SourceFiles: TFiles;
|
|
TargetPath: String): TFileSourceOperation; override;
|
|
function CreateCopyOperation(var SourceFiles: TFiles;
|
|
TargetPath: String): TFileSourceOperation; override;
|
|
function CreateCopyInOperation(SourceFileSource: IFileSource;
|
|
var SourceFiles: TFiles;
|
|
TargetPath: String): TFileSourceOperation; override;
|
|
function CreateCopyOutOperation(TargetFileSource: IFileSource;
|
|
var SourceFiles: TFiles;
|
|
TargetPath: String): TFileSourceOperation; override;
|
|
function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override;
|
|
function CreateSetFilePropertyOperation(var theTargetFiles: TFiles;
|
|
var theNewProperties: TFileProperties): TFileSourceOperation; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
ActiveX, ComObj,DCConvertEncoding, uShellFolder, uShellListOperation,
|
|
uShellCopyOperation, uShellFileOperation, uShellCreateDirectoryOperation,
|
|
uShellExecuteOperation, uShellSetFilePropertyOperation, uShellFileSourceUtil,
|
|
uShellDeleteOperation, uShellMoveOperation, UShellCalcStatisticsOperation,
|
|
DCStrUtils, uLng, uShlObjAdditional;
|
|
|
|
{ TShellFileSource }
|
|
|
|
function TShellFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
constructor TShellFileSource.Create;
|
|
begin
|
|
inherited Create;
|
|
OleCheck(SHGetDesktopFolder(FDesktopFolder));
|
|
OleCheck(SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, {%H-}FDrives));
|
|
OleCheck(FDesktopFolder.BindToObject(FDrives, nil, IID_IShellFolder2, Pointer(FRootFolder)));
|
|
FRootPath := GetDisplayName(FDesktopFolder, FDrives, SHGDN_INFOLDER);
|
|
FOperationsClasses[fsoMove] := TShellMoveOperation.GetOperationClass;
|
|
FOperationsClasses[fsoCopy] := TShellCopyOperation.GetOperationClass;
|
|
FOperationsClasses[fsoCopyIn] := TShellCopyInOperation.GetOperationClass;
|
|
FOperationsClasses[fsoCopyOut] := TShellCopyOutOperation.GetOperationClass;
|
|
end;
|
|
|
|
destructor TShellFileSource.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
CoTaskMemFree(FDrives);
|
|
end;
|
|
|
|
class function TShellFileSource.IsSupportedPath(const Path: String): Boolean;
|
|
begin
|
|
Result:= StrBegins(Path, PathDelim + PathDelim + PathDelim + RootName);
|
|
end;
|
|
|
|
class function TShellFileSource.CreateFile(const APath: String): TFile;
|
|
begin
|
|
Result := TFile.Create(APath);
|
|
with Result do
|
|
begin
|
|
AttributesProperty := TFileAttributesProperty.CreateOSAttributes;
|
|
SizeProperty := TFileSizeProperty.Create;
|
|
ModificationTimeProperty := TFileModificationDateTimeProperty.Create;
|
|
CreationTimeProperty := TFileCreationDateTimeProperty.Create;
|
|
LinkProperty := TFileShellProperty.Create;
|
|
CommentProperty := TFileCommentProperty.Create;
|
|
end;
|
|
end;
|
|
|
|
class function TShellFileSource.GetMainIcon(out Path: String): Boolean;
|
|
begin
|
|
Result:= True;
|
|
Path:= '%SystemRoot%\System32\shell32.dll,15';
|
|
end;
|
|
|
|
class function TShellFileSource.RootName: String;
|
|
var
|
|
DrivesPIDL: PItemIDList;
|
|
DesktopFolder: IShellFolder;
|
|
begin
|
|
OleCheckUTF8(SHGetDesktopFolder(DesktopFolder));
|
|
OleCheckUTF8(SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, {%H-}DrivesPIDL));
|
|
Result:= GetDisplayName(DesktopFolder, DrivesPIDL, SHGDN_INFOLDER);
|
|
end;
|
|
|
|
function TShellFileSource.FindObject(const AObject: String; out
|
|
AValue: PItemIDList): HRESULT;
|
|
var
|
|
APath: String;
|
|
AFolder: IShellFolder2;
|
|
AItemPIDL, AFolderPIDL: PItemIDList;
|
|
begin
|
|
APath:= ExtractFileDir(AObject);
|
|
Result:= FindFolder(APath, AFolder);
|
|
|
|
if Succeeded(Result) then
|
|
begin
|
|
Result:= FindObject(AFolder, ExtractFileName(AObject), AItemPIDL);
|
|
|
|
if Succeeded(Result) then
|
|
begin
|
|
Result:= SHGetIDListFromObject(AFolder, AFolderPIDL);
|
|
if Succeeded(Result) then
|
|
begin
|
|
AValue:= ILCombine(AFolderPIDL, AItemPIDL);
|
|
CoTaskMemFree(AFolderPIDL);
|
|
end;
|
|
CoTaskMemFree(AItemPIDL);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TShellFileSource.FindObject(AParent: IShellFolder2;
|
|
const AName: String; out AValue: PItemIDList): HRESULT;
|
|
var
|
|
AItemName: String;
|
|
PIDL: PItemIDList;
|
|
NumIDs: LongWord = 0;
|
|
EnumIDList: IEnumIDList;
|
|
begin
|
|
Result:= AParent.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_STORAGE or SHCONTF_INCLUDEHIDDEN, EnumIDList);
|
|
|
|
if Succeeded(Result) then
|
|
begin
|
|
while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do
|
|
begin
|
|
AItemName:= GetDisplayNameEx(AParent, PIDL, SHGDN_INFOLDER);
|
|
if AName = AItemName then
|
|
begin
|
|
AValue:= PIDL;
|
|
Exit(S_OK);
|
|
end;
|
|
CoTaskMemFree(PIDL);
|
|
end;
|
|
end;
|
|
Result:= STG_E_FILENOTFOUND;
|
|
end;
|
|
|
|
function TShellFileSource.FindFolder(const Path: String; out
|
|
AValue: IShellFolder2): HRESULT;
|
|
|
|
function List(var AFolder: IShellFolder2; const AObject: String): HRESULT;
|
|
var
|
|
AName: String;
|
|
PIDL: PItemIDList;
|
|
NumIDs: LongWord = 0;
|
|
AValue: IShellFolder2;
|
|
EnumIDList: IEnumIDList;
|
|
begin
|
|
Result:= AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_STORAGE or SHCONTF_INCLUDEHIDDEN, EnumIDList);
|
|
|
|
if Succeeded(Result) then
|
|
begin
|
|
while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do
|
|
try
|
|
AName:= GetDisplayNameEx(AFolder, PIDL, SHGDN_INFOLDER);
|
|
|
|
if AName = AObject then
|
|
begin
|
|
Result:= AFolder.BindToObject(PIDL, nil, IID_IShellFolder2, Pointer(AValue));
|
|
if Succeeded(Result) then AFolder:= AValue;
|
|
Exit;
|
|
end;
|
|
finally
|
|
CoTaskMemFree(PIDL);
|
|
end;
|
|
end;
|
|
Result:= STG_E_PATHNOTFOUND;
|
|
end;
|
|
|
|
var
|
|
Index: Integer;
|
|
APath: TStringArray;
|
|
begin
|
|
APath:= Path.Split([PathDelim], TStringSplitOptions.ExcludeEmpty);
|
|
|
|
if Length(APath) = 0 then
|
|
Result:= STG_E_PATHNOTFOUND
|
|
else begin
|
|
if (APath[0] <> FRootPath) then
|
|
Result:= STG_E_PATHNOTFOUND
|
|
else begin
|
|
AValue:= FRootFolder;
|
|
// Find subdirectory
|
|
for Index:= 1 to High(APath) do
|
|
begin
|
|
Result:= List(AValue, APath[Index]);
|
|
if Failed(Result) then Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TShellFileSource.CreateFolder(AParent: IShellFolder2;
|
|
const Name: String): HRESULT;
|
|
var
|
|
AName: WideString;
|
|
AParentItem: IShellItem;
|
|
AFileOp: IFileOperation;
|
|
AParentPIDL: PItemIDList;
|
|
begin
|
|
AName:= CeUtf8ToUtf16(Name);
|
|
Result:= SHGetIDListFromObject(AParent, AParentPIDL);
|
|
if Succeeded(Result) then
|
|
try
|
|
Result:= SHCreateItemFromIDList(AParentPIDL, IShellItem, AParentItem);
|
|
if Succeeded(Result) then
|
|
begin
|
|
AFileOp:= CreateComObject(CLSID_FileOperation) as IFileOperation;
|
|
Result:= AFileOp.NewItem(AParentItem, FILE_ATTRIBUTE_DIRECTORY, PWideChar(AName), nil, nil);
|
|
if Succeeded(Result) then
|
|
begin
|
|
Result:= AFileOp.PerformOperations();
|
|
end;
|
|
end;
|
|
finally
|
|
CoTaskMemFree(AParentPIDL);
|
|
end;
|
|
end;
|
|
|
|
function TShellFileSource.CreateDirectory(const Path: String): Boolean;
|
|
var
|
|
AName: String;
|
|
AParent: IShellFolder2;
|
|
begin
|
|
AName:= ExtractFileName(Path);
|
|
Result:= Succeeded(FindFolder(ExtractFileDir(Path), AParent));
|
|
if Result then
|
|
begin
|
|
Result:= Succeeded(CreateFolder(AParent, AName));
|
|
end;
|
|
end;
|
|
|
|
function TShellFileSource.FileSystemEntryExists(const Path: String): Boolean;
|
|
var
|
|
AObject: PItemIDList;
|
|
begin
|
|
Result:= Succeeded(FindObject(Path, AObject));
|
|
if Result then CoTaskMemFree(AObject);
|
|
end;
|
|
|
|
function TShellFileSource.GetOperationsTypes: TFileSourceOperationTypes;
|
|
begin
|
|
Result := [fsoList, fsoExecute, fsoDelete, fsoCreateDirectory,
|
|
fsoCopyIn, fsoCopyOut, fsoSetFileProperty,
|
|
fsoCalcStatistics];
|
|
end;
|
|
|
|
function TShellFileSource.GetSupportedFileProperties: TFilePropertiesTypes;
|
|
begin
|
|
Result := inherited GetSupportedFileProperties
|
|
+ [fpSize,
|
|
fpAttributes,
|
|
fpModificationTime,
|
|
fpCreationTime,
|
|
uFileProperty.fpLink,
|
|
fpComment
|
|
];
|
|
end;
|
|
|
|
function TShellFileSource.GetRootDir(sPath: String): String;
|
|
begin
|
|
Result:= PathDelim + PathDelim + PathDelim + FRootPath + PathDelim;
|
|
end;
|
|
|
|
function TShellFileSource.GetProperties: TFileSourceProperties;
|
|
begin
|
|
Result := [fspVirtual];
|
|
end;
|
|
|
|
function TShellFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result:= TShellListOperation.Create(TargetFileSource, TargetPath);
|
|
end;
|
|
|
|
function TShellFileSource.CreateDeleteOperation(var FilesToDelete: TFiles
|
|
): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result:= TShellDeleteOperation.Create(TargetFileSource, FilesToDelete);
|
|
end;
|
|
|
|
function TShellFileSource.CreateCreateDirectoryOperation(BasePath: String;
|
|
DirectoryPath: String): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result := TShellCreateDirectoryOperation.Create(TargetFileSource, BasePath, DirectoryPath);
|
|
end;
|
|
|
|
function TShellFileSource.CreateExecuteOperation(var ExecutableFile: TFile;
|
|
BasePath, Verb: String): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result:= TShellExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb);
|
|
end;
|
|
|
|
function TShellFileSource.CreateMoveOperation(var SourceFiles: TFiles;
|
|
TargetPath: String): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result := TShellMoveOperation.Create(TargetFileSource, SourceFiles, TargetPath);
|
|
end;
|
|
|
|
function TShellFileSource.CreateCopyOperation(var SourceFiles: TFiles;
|
|
TargetPath: String): TFileSourceOperation;
|
|
var
|
|
SourceFileSource: IFileSource;
|
|
begin
|
|
SourceFileSource := Self;
|
|
Result:= TShellCopyOperation.Create(SourceFileSource, SourceFileSource, SourceFiles, TargetPath);
|
|
end;
|
|
|
|
function TShellFileSource.CreateCopyInOperation(SourceFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result:= TShellCopyInOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath);
|
|
end;
|
|
|
|
function TShellFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation;
|
|
var
|
|
SourceFileSource: IFileSource;
|
|
begin
|
|
SourceFileSource := Self;
|
|
Result := TShellCopyOutOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath);
|
|
end;
|
|
|
|
function TShellFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles
|
|
): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result := TShellCalcStatisticsOperation.Create(TargetFileSource, theFiles);
|
|
end;
|
|
|
|
function TShellFileSource.CreateSetFilePropertyOperation(
|
|
var theTargetFiles: TFiles; var theNewProperties: TFileProperties
|
|
): TFileSourceOperation;
|
|
var
|
|
TargetFileSource: IFileSource;
|
|
begin
|
|
TargetFileSource := Self;
|
|
Result := TShellSetFilePropertyOperation.Create(TargetFileSource, theTargetFiles, theNewProperties);
|
|
end;
|
|
|
|
end.
|
|
|