Delphi压缩解压文件,无需第三方控件

一、首先引入两个写好的单元:

  1、D7zUtils.pas

unit D7zUtils;
  
interface
uses
  SysUtils, Classes, Sevenzip;
  
type
  TD7zFileType = (dftZip, dftBZ2, dftRar, dftArj, dftZ, dftLzh, dft7z, dftCab, dftNsis, dftLzma,
    dftPe, dftElf, dftMacho, dftUdf, dftXar, dftMub, dftHfs, dftDmg, dftCompound,
    dftWim, dftIso, dftBkf, dftChm, dftSplit, dftRpm, dftDeb, dftCpio, dftTar,
    dftGZip);
  TD7zFileTypes = set of TD7zFileType;
  
  TD7zipStrings = TStrings;
  TD7zipStringList = class(TStringList)
  public
    constructor Create();virtual;
  end;
  
  TOnPassword = procedure (Sender: TObject; var sPassword: WideString; var bContinue:Boolean) of object;
  TOnProgress = procedure (Sender: TObject; bIsTotal: boolean; iValue: Int64; var bContinue:Boolean) of object;
  
  TD7zipFile = class
  private
    FInArchive: I7zInArchive;
    FItems: TD7zipStrings;
    FTmpStream: TStream;
  private
    FCurrentItemPath: WideString;
    FOnPassword: TOnPassword;
    FOnProgress: TOnProgress;
  private
    FPasswordCallback: T7zPasswordCallback;
    FProgressCallback: T7zProgressCallback;
    function DoOnPassword(var sPassword: WideString): HRESULT;
    function DoOnProgress(bIsTotal: boolean; iValue: Int64): HRESULT;
  public
    constructor Create();virtual;
    destructor Destroy;override;
    function LoadFromFile(AFileName: WideString):Boolean;
    function LoadFromStream(AStream: TStream; AFileTypes: TD7zFileTypes=[]):Boolean;overload;
    function LoadFromStream(AStream: TStream; AFileType: TD7zFileType):Boolean;overload;
  public
    function GetItems(sPath: WideString; iFilter: Integer=0): TD7zipStrings;//iFilter: 0-All 1-File 2 Dir ;  sPath-暂不支持通配符
  public
    function ExtractItemToStream(sFileName: WideString; AStream: TStream):Boolean; //解压/获取单个文件
    function ExtractItemToFile(sFileName: WideString; sToFile: WideString):Boolean;//解压/获取单个文件
  public
    property CurrentItemPath: WideString read FCurrentItemPath;
  public
    //fileSystem functions
    function FileExists(sFileName: WideString):Boolean;
    function DirectoryExists(sDirName: WideString):Boolean;
    function GetCurrentDir(): WideString;
  public
    property OnPassword: TOnPassword read FOnPassword write FOnPassword;
    property OnProgress: TOnProgress read FOnProgress write FOnProgress;
  end;
  
implementation
  
function FUNC_PasswordCallback(sender: Pointer; var password: UnicodeString): HRESULT; stdcall;
begin
  // call a dialog box ...
  //password := 'password';
  //Result := S_OK;
  Result := S_FALSE;
  if sender=nil then Exit;
  Result := TD7zipFile(sender).DoOnPassword(password);
end;
  
function FUNC_ProgressCallback(sender: Pointer; total: boolean;
  value: Int64): HRESULT; stdcall;
begin
  Result := S_FALSE;
  if sender=nil then Exit;
  Result := TD7zipFile(sender).DoOnProgress(total, value);
end;
  
{ TD7zipFile }
  
constructor TD7zipFile.Create;
begin
  FItems:=TD7zipStringList.Create;
  FPasswordCallback := FUNC_PasswordCallback;
  FProgressCallback := FUNC_ProgressCallback;
end;
  
destructor TD7zipFile.Destroy;
begin
  FItems.Free;
  FreeAndNil(FTmpStream);
  inherited;
end;
  
function TD7zipFile.DirectoryExists(sDirName: WideString): Boolean;
var
  iIndex:Integer;
begin
  Result := False;
  if FInArchive=nil then Exit;
  if sDirName<>'' then
  if sDirName[Length(sDirName)]<>'\' then
  sDirName := sDirName +'\';
  iIndex := Self.FItems.IndexOf(sDirName);
  if iIndex=-1 then Exit;
  Result := FInArchive.ItemIsFolder[iIndex];
end;
  
function TD7zipFile.DoOnPassword(var sPassword: WideString): HRESULT;
var
  bContinue: Boolean;
begin
  bContinue := True;
  if Assigned(FOnPassword) then FOnPassword(Self, sPassword, bContinue);
  if bContinue then Result := S_OK else Result := S_FALSE;
end;
  
function TD7zipFile.DoOnProgress(bIsTotal: boolean;
  iValue: Int64): HRESULT;
var
  bContinue: Boolean;
begin
  bContinue := True;
  if Assigned(FOnProgress) then FOnProgress(Self, bIsTotal, iValue, bContinue);
  if bContinue then Result := S_OK else Result := S_FALSE;
end;
  
function TD7zipFile.ExtractItemToFile(sFileName: WideString;
  sToFile: WideString): Boolean;
var
  AStream: TStream;
begin
  AStream:=TFileStream.Create(sToFile, fmCreate);
  try
    Result := ExtractItemToStream(sFileName, AStream);
  finally
    AStream.Free;
  end;
end;
  
function TD7zipFile.ExtractItemToStream(sFileName: WideString;
  AStream: TStream): Boolean;
var
  iIndex: Integer;
begin
  Result := False;
  if FInArchive=nil then Exit;
  iIndex := FItems.IndexOf(sFileName);
  if iIndex=-1 then Exit;
  try
    FInArchive.ExtractItem(iIndex, AStream, False);
    Result := True;
  except
  end;
end;
  
function TD7zipFile.FileExists(sFileName: WideString): Boolean;
var
  iIndex:Integer;
begin
  Result := False;
  if FInArchive=nil then Exit;
  if sFileName<>'' then
  if sFileName[Length(sFileName)]<>'\' then
  sFileName := sFileName +'\';
  iIndex := Self.FItems.IndexOf(sFileName);
  if iIndex=-1 then Exit;
  Result := not FInArchive.ItemIsFolder[iIndex];
end;
  
function TD7zipFile.GetCurrentDir: WideString;
begin
  Result := FCurrentItemPath;
end;
  
function TD7zipFile.GetItems(sPath: WideString; iFilter: Integer=0): TD7zipStrings;
  function IsItemChild(sParent, sChild: WideString):Boolean;
  //var
  //  sTmp: WideString;
  begin
    if (sParent='') then //获取全部
      Result := True
    else if (sParent='\\') then //根目录
      Result := Pos('\', sChild)=0
    else
    begin
      Result := (Pos(sParent, sChild)=1) and
                (Pos('\', Copy(sChild, Length(sParent)+1, Length(sChild)))=0);
    end;
  end;
var
  I: Integer;
  sTmp: WideString;
  bDir: Boolean;
begin
  Result := TD7zipStringList.Create;
  if (sPath='.') then //当前目录
  begin
    sPath := FCurrentItemPath;
  end
  else if (sPath='..') then //上一层目录
  begin
    if (FCurrentItemPath='') then FCurrentItemPath := '\\';
    if FCurrentItemPath<>'\\' then
    begin
      sPath := FCurrentItemPath;
      if sPath[Length(sPath)]='\' then
      sPath := Copy(sPath, 1, Length(sPath)-1);
      sPath := ExtractFilePath(sPath);
    end
    else
      sPath := FCurrentItemPath;
    if (sPath='') then sPath := '\\';
  end;
  if sPath<>'' then
  begin
    if sPath[Length(sPath)]<>'\' then sPath := sPath +'\';
    FCurrentItemPath := sPath;
  end;
  if (sPath<>'') and (sPath<>'\\') then
  begin
    Result.Add('.');
    Result.Add('..');
  end;  
  for I:=0 to FItems.Count-1 do
  begin
    bDir := False;
    sTmp := FItems.Strings[I];
    if sTmp<>'' then
    if sTmp[Length(sTmp)]='\' then
    begin
      sTmp := Copy(sTmp, 1, Length(sTmp)-1);
      bDir := True;
    end;
    if not IsItemChild(sPath, sTmp) then Continue;
    if (iFilter=0)
       or ((iFilter=1) and (not bDir))
       or ((iFilter=2) and (bDir)) then
      Result.Add(sTmp);
  end;
end;
  
function TD7zipFile.LoadFromFile(AFileName: WideString): Boolean;
  function FileExtToFileTypes(sExt: WideString): TD7zFileTypes;
  begin
    Result := [];
    if (sExt='.ZIP') or (sExt='.JAR') or (sExt='.XPI') then
      Include(Result, dftZip)
    else if (sExt='.BZ2') or (sExt='.BZIP2') or (sExt='.TBZ2') or (sExt='.TBZ') then
      Include(Result, dftBZ2)
    else if (sExt='.RAR') or (sExt='.R00') then
      Include(Result, dftRar)
    else if (sExt='.ARJ') then
      Include(Result, dftArj)
    else if (sExt='.Z') or (sExt='.TAZ') then
      Include(Result, dftZ)
    else if (sExt='.LZH') or (sExt='.LHA') then
      Include(Result, dftLzh)
    else if (sExt='.7Z') then
      Include(Result, dft7z)
    else if (sExt='.CAB') then
      Include(Result, dftCab)
    else if (sExt='.NSIS') then
      Include(Result, dftNsis) //安装包工具
    else if (sExt='.LZMA') or (sExt='.LZMA86') then
      Include(Result, dftLzma)
    else if (sExt='.EXE') then
    begin
      Include(Result, dftPe);
      Include(Result, dftNsis);
    end
    else if (sExt='.PE') or (sExt='.DLL') or (sExt='.SYS') then
      Include(Result, dftPe)
    else if (sExt='.ELF') then
      Include(Result, dftElf)
    else if (sExt='.MACHO') then
      Include(Result, dftMacho)
    else if (sExt='.UDF') then
      Include(Result, dftUdf)
    else if (sExt='.XAR') then
      Include(Result, dftXar)
    else if (sExt='.MUB') then
      Include(Result, dftMub)
    else if (sExt='.HFS') or (sExt='.CD') then
      Include(Result, dftHfs)
    else if (sExt='.DMG') then
      Include(Result, dftDmg)
    else if (sExt='.MSI') or (sExt='.DOC') or (sExt='.XLS') or (sExt='.PPT') then
      Include(Result, dftCompound)
    else if (sExt='.WIM') or (sExt='.SWM') then
      Include(Result, dftWim)
    else if (sExt='.ISO') then
    begin
      Include(Result, dftIso);
      Include(Result, dftUdf);
    end
    else if (sExt='.BKF') then
      Include(Result, dftBkf)
    else if (sExt='.CHM') or (sExt='.CHI') or (sExt='.CHQ') or (sExt='.CHW')
            or (sExt='.HXS') or (sExt='.HXI') or (sExt='.HXR') or (sExt='.HXQ')
            or (sExt='.HXW') or (sExt='.LIT') then
      Include(Result, dftChm)
    else if  (sExt='.001') then
      Include(Result, dftSplit)
    else if  (sExt='.RPM') then
      Include(Result, dftRpm)
    else if  (sExt='.DEB') then
      Include(Result, dftDeb)
    else if  (sExt='.CPIO') then
      Include(Result, dftCpio)
    else if  (sExt='.TAR') then
      Include(Result, dftTar)
    else if  (sExt='.GZ') or (sExt='.GZIP') or (sExt='.TGZ') or (sExt='.TPZ') then
      Include(Result, dftGZip);
  end;
begin
  Result := False;
  FreeAndNil(FTmpStream);
  FTmpStream:=TFileStream.Create(AFileName, fmOpenRead);
  try
    Result := LoadFromStream(FTmpStream, FileExtToFileTypes(UpperCase(ExtractFileExt(AFileName))));
  finally
    if not Result then FreeAndNil(FTmpStream);
  end;
end;
  
function TD7zipFile.LoadFromStream(AStream: TStream; AFileTypes: TD7zFileTypes=[]): Boolean;
var
  bUnknowType:Boolean;
  AFileType: TD7zFileType;
begin
  FInArchive := nil;
  Result := False;
  try
    bUnknowType := AFileTypes=[];
    AFileType := Low(TD7zFileType);
    while AFileType<High(TD7zFileType) do
    begin
      if (not Result) and (bUnknowType or (AFileType in AFileTypes)) then
        Result := LoadFromStream(AStream, AFileType);
      if Result then Break;
      Inc(AFileType);
    end;
    (*
    if (not Result) and (bUnknowType or (dftZip in AFileTypes)) then
      Result := LoadFromStream(AStream, dftZip);
    if (not Result) and (bUnknowType or (dftBZ2 in AFileTypes)) then
      Result := LoadFromStream(AStream, dftBZ2);
    if (not Result) and (bUnknowType or (dftRar in AFileTypes)) then
      Result := LoadFromStream(AStream, dftRar);
    if (not Result) and (bUnknowType or (dftArj in AFileTypes)) then
      Result := LoadFromStream(AStream, dftArj);
    if (not Result) and (bUnknowType or (dftZ in AFileTypes)) then
      Result := LoadFromStream(AStream, dftZ);
    if (not Result) and (bUnknowType or (dftLzh in AFileTypes)) then
      Result := LoadFromStream(AStream, dftLzh);
    if (not Result) and (bUnknowType or (dft7z in AFileTypes)) then
      Result := LoadFromStream(AStream, dft7z);
    if (not Result) and (bUnknowType or (dftCab in AFileTypes)) then
      Result := LoadFromStream(AStream, dftCab);
    if (not Result) and (bUnknowType or (dftNsis in AFileTypes)) then
      Result := LoadFromStream(AStream, dftNsis);
    if (not Result) and (bUnknowType or (dftLzma in AFileTypes)) then
      Result := LoadFromStream(AStream, dftLzma);
    if (not Result) and (bUnknowType or (dftPe in AFileTypes)) then
      Result := LoadFromStream(AStream, dftPe);
    if (not Result) and (bUnknowType or (dftElf in AFileTypes)) then
      Result := LoadFromStream(AStream, dftElf);
    if (not Result) and (bUnknowType or (dftMacho in AFileTypes)) then
      Result := LoadFromStream(AStream, dftMacho);
    if (not Result) and (bUnknowType or (dftUdf in AFileTypes)) then
      Result := LoadFromStream(AStream, dftUdf);
    if (not Result) and (bUnknowType or (dftXar in AFileTypes)) then
      Result := LoadFromStream(AStream, dftXar);
    if (not Result) and (bUnknowType or (dftMub in AFileTypes)) then
      Result := LoadFromStream(AStream, dftMub);
    if (not Result) and (bUnknowType or (dftHfs in AFileTypes)) then
      Result := LoadFromStream(AStream, dftHfs);
    if (not Result) and (bUnknowType or (dftDmg in AFileTypes)) then
      Result := LoadFromStream(AStream, dftDmg);
    if (not Result) and (bUnknowType or (dftCompound in AFileTypes)) then
      Result := LoadFromStream(AStream, dftCompound);
    if (not Result) and (bUnknowType or (dftWim in AFileTypes)) then
      Result := LoadFromStream(AStream, dftWim);
    if (not Result) and (bUnknowType or (dftIso in AFileTypes)) then
      Result := LoadFromStream(AStream, dftIso);
    if (not Result) and (bUnknowType or (dftBkf in AFileTypes)) then
      Result := LoadFromStream(AStream, dftBkf);
    if (not Result) and (bUnknowType or (dftChm in AFileTypes)) then
      Result := LoadFromStream(AStream, dftChm);
    if (not Result) and (bUnknowType or (dftSplit in AFileTypes)) then
      Result := LoadFromStream(AStream, dftSplit);
    if (not Result) and (bUnknowType or (dftRpm in AFileTypes)) then
      Result := LoadFromStream(AStream, dftRpm);
    if (not Result) and (bUnknowType or (dftDeb in AFileTypes)) then
      Result := LoadFromStream(AStream, dftDeb);
    if (not Result) and (bUnknowType or (dftCpio in AFileTypes)) then
      Result := LoadFromStream(AStream, dftCpio);
    if (not Result) and (bUnknowType or (dftTar in AFileTypes)) then
      Result := LoadFromStream(AStream, dftTar);
    if (not Result) and (bUnknowType or (dftGZip in AFileTypes)) then
      Result := LoadFromStream(AStream, dftGZip);
    *)
  except
    FInArchive := nil;
  end;
end;
  
function TD7zipFile.LoadFromStream(AStream: TStream;
  AFileType: TD7zFileType): Boolean;
var
  iIndex, I: Integer;
  zStream: IInStream;//T7zStream;
  sTmp, sTmpDir: WideString;
  iPos: Int64;
  sTmpDirListAdd, sTmpDirList: TD7zipStrings;
begin
  Result := False;
  FInArchive := nil;
  FCurrentItemPath := '\\';
  FItems.Clear;
  iPos := AStream.Position;
  case AFileType of
    dftZip   : FInArchive:= CreateInArchive(CLSID_CFormatZip);
    dftBZ2   : FInArchive:= CreateInArchive(CLSID_CFormatBZ2);
    dftRar   : FInArchive:= CreateInArchive(CLSID_CFormatRar);
    dftArj   : FInArchive:= CreateInArchive(CLSID_CFormatArj);
    dftZ     : FInArchive:= CreateInArchive(CLSID_CFormatZ);
    dftLzh   : FInArchive:= CreateInArchive(CLSID_CFormatLzh);
    dft7z    : FInArchive:= CreateInArchive(CLSID_CFormat7z);
    dftCab   : FInArchive:= CreateInArchive(CLSID_CFormatCab);
    dftNsis  : FInArchive:= CreateInArchive(CLSID_CFormatNsis);
    dftLzma  : FInArchive:= CreateInArchive(CLSID_CFormatLzma);
    dftPe    : FInArchive:= CreateInArchive(CLSID_CFormatPe);
    dftElf   : FInArchive:= CreateInArchive(CLSID_CFormatElf);
    dftMacho : FInArchive:= CreateInArchive(CLSID_CFormatMacho);
    dftUdf   : FInArchive:= CreateInArchive(CLSID_CFormatUdf);
    dftXar   : FInArchive:= CreateInArchive(CLSID_CFormatXar);
    dftMub   : FInArchive:= CreateInArchive(CLSID_CFormatMub);
    dftHfs   : FInArchive:= CreateInArchive(CLSID_CFormatHfs);
    dftDmg   : FInArchive:= CreateInArchive(CLSID_CFormatDmg);
    dftCompound : FInArchive:= CreateInArchive(CLSID_CFormatCompound);
    dftWim   : FInArchive:= CreateInArchive(CLSID_CFormatWim);
    dftIso   : FInArchive:= CreateInArchive(CLSID_CFormatIso);
    dftBkf   : FInArchive:= CreateInArchive(CLSID_CFormatBkf);
    dftChm   : FInArchive:= CreateInArchive(CLSID_CFormatChm);
    dftSplit : FInArchive:= CreateInArchive(CLSID_CFormatSplit);
    dftRpm   : FInArchive:= CreateInArchive(CLSID_CFormatRpm);
    dftDeb   : FInArchive:= CreateInArchive(CLSID_CFormatDeb);
    dftCpio  : FInArchive:= CreateInArchive(CLSID_CFormatCpio);
    dftTar   : FInArchive:= CreateInArchive(CLSID_CFormatTar);
    dftGZip  : FInArchive:= CreateInArchive(CLSID_CFormatGZip);
    else
      Exit;
  end;
  
  zStream := T7zStream.Create(AStream);
  try
    FInArchive.OpenStream(zStream);
    FInArchive.SetPasswordCallback(Self, FPasswordCallback);
    FInArchive.SetProgressCallback(Self, FProgressCallback);
    sTmpDirListAdd := TD7zipStringList.Create;
    sTmpDirList := TD7zipStringList.Create;
    try
      for I:=0 to FInArchive.NumberOfItems-1 do
      begin
        sTmp := FInArchive.ItemPath[I];
        if FInArchive.ItemIsFolder[I] then
        begin
          if (sTmp<>'') and (sTmp[Length(sTmp)]<>'\') then
            sTmp := sTmp+'\';
          if sTmpDirList.IndexOf(sTmp)=-1 then
            sTmpDirList.Add(sTmp);
          //else //已添加到临时列表则需要删除
          begin
            iIndex := sTmpDirListAdd.IndexOf(sTmp);
            if iIndex>-1 then
            sTmpDirListAdd.Delete(iIndex);
          end;
        end
        else
        begin
          sTmpDir := ExtractFilePath(sTmp);
          if sTmpDirList.IndexOf(sTmpDir)=-1 then
          begin //未添加的文件夹需要添加到临时列表里
            if sTmpDirListAdd.IndexOf(sTmpDir)=-1 then
            sTmpDirListAdd.Add(sTmpDir);
          end;
        end;
        FItems.Add(sTmp);
      end;
      FItems.AddStrings(sTmpDirListAdd);
    finally
      sTmpDirList.Free;
      sTmpDirListAdd.Free;
      zStream := nil;
    end;
    Result := True;
  except
    zStream := nil;
    FInArchive := nil;
    AStream.Position := iPos;
  end;
end;
  
{ TD7zipStringList }
  
constructor TD7zipStringList.Create;
begin
  Self.CaseSensitive := False;//忽略大小写
end;

end.

  2、SevenZip.pas

(* ****************************************************************************** *)
(* 7-ZIP DELPHI API *)
(* *)
(* The contents of this file are subject to the Mozilla Public License Version *)
(* 1.1 (the "License"); you may not use this file except in compliance with the *)
(* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ *)
(* *)
(* Software distributed under the License is distributed on an "AS IS" basis, *)
(* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *)
(* the specific language governing rights and limitations under the License. *)
(* *)
(* Unit owner : Henri Gourvest <<a href="mailto:hgourvest@gmail.com">hgourvest@gmail.com</a>> *)
(* V1.2 *)
(* ****************************************************************************** *)
unit SevenZip;
{$ALIGN ON}
{$MINENUMSIZE 4}
{$WARN SYMBOL_PLATFORM OFF}
     
interface
     
uses SysUtils, Windows, ActiveX, Classes, Contnrs;
     
type
  PVarType = ^TVarType;
  PCardArray = ^TCardArray;
  TCardArray = array [0 .. MaxInt div SizeOf(Cardinal) - 1] of Cardinal;
{$IFNDEF UNICODE}
  UnicodeString = WideString;
{$ENDIF}
     
  // ******************************************************************************
  // PropID.h
  // ******************************************************************************
const
  kpidNoProperty = 0;
  kpidHandlerItemIndex = 2;
  kpidPath = 3; // VT_BSTR
  kpidName = 4; // VT_BSTR
  kpidExtension = 5; // VT_BSTR
  kpidIsFolder = 6; // VT_BOOL
  kpidSize = 7; // VT_UI8
  kpidPackedSize = 8; // VT_UI8
  kpidAttributes = 9; // VT_UI4
  kpidCreationTime = 10; // VT_FILETIME
  kpidLastAccessTime = 11; // VT_FILETIME
  kpidLastWriteTime = 12; // VT_FILETIME
  kpidSolid = 13; // VT_BOOL
  kpidCommented = 14; // VT_BOOL
  kpidEncrypted = 15; // VT_BOOL
  kpidSplitBefore = 16; // VT_BOOL
  kpidSplitAfter = 17; // VT_BOOL
  kpidDictionarySize = 18; // VT_UI4
  kpidCRC = 19; // VT_UI4
  kpidType = 20; // VT_BSTR
  kpidIsAnti = 21; // VT_BOOL
  kpidMethod = 22; // VT_BSTR
  kpidHostOS = 23; // VT_BSTR
  kpidFileSystem = 24; // VT_BSTR
  kpidUser = 25; // VT_BSTR
  kpidGroup = 26; // VT_BSTR
  kpidBlock = 27; // VT_UI4
  kpidComment = 28; // VT_BSTR
  kpidPosition = 29; // VT_UI4
  kpidPrefix = 30; // VT_BSTR
  kpidNumSubDirs = 31; // VT_UI4
  kpidNumSubFiles = 32; // VT_UI4
  kpidUnpackVer = 33; // VT_UI1
  kpidVolume = 34; // VT_UI4
  kpidIsVolume = 35; // VT_BOOL
  kpidOffset = 36; // VT_UI8
  kpidLinks = 37; // VT_UI4
  kpidNumBlocks = 38; // VT_UI4
  kpidNumVolumes = 39; // VT_UI4
  kpidTimeType = 40; // VT_UI4
  kpidBit64 = 41; // VT_BOOL
  kpidBigEndian = 42; // VT_BOOL
  kpidCpu = 43; // VT_BSTR
  kpidPhySize = 44; // VT_UI8
  kpidHeadersSize = 45; // VT_UI8
  kpidChecksum = 46; // VT_UI4
  kpidCharacts = 47; // VT_BSTR
  kpidVa = 48; // VT_UI8
  kpidTotalSize = $1100; // VT_UI8
  kpidFreeSpace = kpidTotalSize + 1; // VT_UI8
  kpidClusterSize = kpidFreeSpace + 1; // VT_UI8
  kpidVolumeName = kpidClusterSize + 1; // VT_BSTR
  kpidLocalName = $1200; // VT_BSTR
  kpidProvider = kpidLocalName + 1; // VT_BSTR
  kpidUserDefined = $10000;
     
  // ******************************************************************************
  // IProgress.h
  // ******************************************************************************
type
  IProgress = interface(IUnknown)
    ['{23170F69-40C1-278A-0000-000000050000}']
    function SetTotal(total: Int64): HRESULT; stdcall;
    function SetCompleted(completeValue: PInt64): HRESULT; stdcall;
  end;
     
  // ******************************************************************************
  // IPassword.h
  // ******************************************************************************
  ICryptoGetTextPassword = interface(IUnknown)
    ['{23170F69-40C1-278A-0000-000500100000}']
    function CryptoGetTextPassword(var password: TBStr): HRESULT; stdcall;
  end;
     
  ICryptoGetTextPassword2 = interface(IUnknown)
    ['{23170F69-40C1-278A-0000-000500110000}']
    function CryptoGetTextPassword2(passwordIsDefined: PInteger;
      var password: TBStr): HRESULT; stdcall;
  end;
     
  // ******************************************************************************
  // IStream.h
  // "23170F69-40C1-278A-0000-000300xx0000"
  // ******************************************************************************
  ISequentialInStream = interface(IUnknown)
    ['{23170F69-40C1-278A-0000-000300010000}']
    function Read(data: Pointer; size: Cardinal; processedSize: PCardinal)
      : HRESULT; stdcall;
    (*
      Out: if size != 0, return_value = S_OK and (*processedSize == 0),
      then there are no more bytes in stream.
      if (size > 0) && there are bytes in stream,
      this function must read at least 1 byte.
      This function is allowed to read less than number of remaining bytes in stream.
      You must call Read function in loop, if you need exact amount of data
    *)
  end;
     
  ISequentialOutStream = interface(IUnknown)
    ['{23170F69-40C1-278A-0000-000300020000}']
    function Write(data: Pointer; size: Cardinal; processedSize: PCardinal)
      : HRESULT; stdcall;
    (*
      if (size > 0) this function must write at least 1 byte.
      This function is allowed to write less than "size".
      You must call Write function in loop, if you need to write exact amount of data
    *)
  end;
     
  IInStream = interface(ISequentialInStream)
    ['{23170F69-40C1-278A-0000-000300030000}']
    function Seek(offset: Int64; seekOrigin: Cardinal; newPosition: PInt64)
      : HRESULT; stdcall;
  end;
     
  IOutStream = interface(ISequentialOutStream)
    ['{23170F69-40C1-278A-0000-000300040000}']
    function Seek(offset: Int64; seekOrigin: Cardinal; newPosition: PInt64)
      : HRESULT; stdcall;
    function SetSize(newSize: Int64): HRESULT; stdcall;
  end;
     
  IStreamGetSize = interface(IUnknown)
    ['{23170F69-40C1-278A-0000-000300060000}']
    function GetSize(size: PInt64): HRESULT; stdcall;
  end;
     
  IOutStreamFlush = interface(IUnknown)
    ['{23170F69-40C1-278A-0000-000300070000}']
    function Flush: HRESULT; stdcall;
  end;
     
  // ******************************************************************************
  // IArchive.h
  // ******************************************************************************
  // MIDL_INTERFACE("23170F69-40C1-278A-0000-000600xx0000")
  // #define ARCHIVE_INTERFACE_SUB(i, base, x) \
  // DEFINE_GUID(IID_ ## i, \
  // 0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x06, 0x00, x, 0x00, 0x00); \
  // struct i: public base
  // #define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
type
  // NFileTimeType
  NFileTimeType = (kWindows = 0, kUnix, kDOS);
  // NArchive::
  NArchive = (kName = 0, // string
    kClassID, // GUID
    kExtension, // string zip rar gz
    kAddExtension, // sub archive: tar
    kUpdate, // bool
    kKeepName, // bool
    kStartSignature, // string[4] ex: PK.. 7z.. Rar!
    kFinishSignature, kAssociate);
  // NArchive::NExtract::NAskMode
  NAskMode = (kExtract = 0, kTest, kSkip);
  // NArchive::NExtract::NOperationResult
  NExtOperationResult = (kOK = 0, kUnSupportedMethod, kDataError, kCRCError);
  // NArchive::NUpdate::NOperationResult
  NUpdOperationResult = (kOK_ = 0, kError);
     
  IArchiveOpenCallback = interface
    ['{23170F69-40C1-278A-0000-000600100000}']
    function SetTotal(files, bytes: PInt64): HRESULT; stdcall;
    function SetCompleted(files, bytes: PInt64): HRESULT; stdcall;
  end;
     
  IArchiveExtractCallback = interface(IProgress)
    ['{23170F69-40C1-278A-0000-000600200000}']
    function GetStream(index: Cardinal; var outStream: ISequentialOutStream;
      askExtractMode: NAskMode): HRESULT; stdcall;
    // GetStream OUT: S_OK - OK, S_FALSE - skeep this file
    function PrepareOperation(askExtractMode: NAskMode): HRESULT; stdcall;
    function SetOperationResult(resultEOperationResult: NExtOperationResult)
      : HRESULT; stdcall;
  end;
     
  IArchiveOpenVolumeCallback = interface
    ['{23170F69-40C1-278A-0000-000600300000}']
    function GetProperty(propID: propID; var value: OleVariant)
      : HRESULT; stdcall;
    function GetStream(const name: PWideChar; var inStream: IInStream)
      : HRESULT; stdcall;
  end;
     
  IInArchiveGetStream = interface
    ['{23170F69-40C1-278A-0000-000600400000}']
    function GetStream(index: Cardinal; var stream: ISequentialInStream)
      : HRESULT; stdcall;
  end;
     
  IArchiveOpenSetSubArchiveName = interface
    ['{23170F69-40C1-278A-0000-000600500000}']
    function SetSubArchiveName(name: PWideChar): HRESULT; stdcall;
  end;
     
  IInArchive = interface
    ['{23170F69-40C1-278A-0000-000600600000}']
    function Open(stream: IInStream; const maxCheckStartPosition: PInt64;
      openArchiveCallback: IArchiveOpenCallback): HRESULT; stdcall;
    function Close: HRESULT; stdcall;
    function GetNumberOfItems(var numItems: Cardinal): HRESULT; stdcall;
    function GetProperty(index: Cardinal; propID: propID; var value: OleVariant)
      : HRESULT; stdcall;
    function Extract(indices: PCardArray; numItems: Cardinal; testMode: Integer;
      extractCallback: IArchiveExtractCallback): HRESULT; stdcall;
    // indices must be sorted
    // numItems = 0xFFFFFFFF means all files
    // testMode != 0 means "test files operation"
    function GetArchiveProperty(propID: propID; var value: OleVariant)
      : HRESULT; stdcall;
    function GetNumberOfProperties(numProperties: PCardinal): HRESULT; stdcall;
    function GetPropertyInfo(index: Cardinal; name: PBSTR; propID: PPropID;
      varType: PVarType): HRESULT; stdcall;
    function GetNumberOfArchiveProperties(var numProperties: Cardinal)
      : HRESULT; stdcall;
    function GetArchivePropertyInfo(index: Cardinal; name: PBSTR;
      propID: PPropID; varType: PVarType): HRESULT; stdcall;
  end;
     
  IArchiveUpdateCallback = interface(IProgress)
    ['{23170F69-40C1-278A-0000-000600800000}']
    function GetUpdateItemInfo(index: Cardinal; newData: PInteger;
      // 1 - new data, 0 - old data
      newProperties: PInteger; // 1 - new properties, 0 - old properties
      indexInArchive: PCardinal
      // -1 if there is no in archive, or if doesn't matter
      ): HRESULT; stdcall;
    function GetProperty(index: Cardinal; propID: propID; var value: OleVariant)
      : HRESULT; stdcall;
    function GetStream(index: Cardinal; var inStream: ISequentialInStream)
      : HRESULT; stdcall;
    function SetOperationResult(operationResult: Integer): HRESULT; stdcall;
  end;
     
  IArchiveUpdateCallback2 = interface(IArchiveUpdateCallback)
    ['{23170F69-40C1-278A-0000-000600820000}']
    function GetVolumeSize(index: Cardinal; size: PInt64): HRESULT; stdcall;
    function GetVolumeStream(index: Cardinal;
      var volumeStream: ISequentialOutStream): HRESULT; stdcall;
  end;
     
  IOutArchive = interface
    ['{23170F69-40C1-278A-0000-000600A00000}']
    function UpdateItems(outStream: ISequentialOutStream; numItems: Cardinal;
      updateCallback: IArchiveUpdateCallback): HRESULT; stdcall;
    function GetFileTimeType(type_: PCardinal): HRESULT; stdcall;
  end;
     
  ISetProperties = interface
    ['{23170F69-40C1-278A-0000-000600030000}']
    function SetProperties(names: PPWideChar; values: PPROPVARIANT;
      numProperties: Integer): HRESULT; stdcall;
  end;
     
  // ******************************************************************************
  // ICoder.h
  // "23170F69-40C1-278A-0000-000400xx0000"
  // ******************************************************************************
  ICompressProgressInfo = interface
    ['{23170F69-40C1-278A-0000-000400040000}']
    function SetRatioInfo(inSize, outSize: PInt64): HRESULT; stdcall;
  end;
     
  ICompressCoder = interface
    ['{23170F69-40C1-278A-0000-000400050000}']
    function Code(inStream, outStream: ISequentialInStream;
      inSize, outSize: PInt64; progress: ICompressProgressInfo)
      : HRESULT; stdcall;
  end;
     
  ICompressCoder2 = interface
    ['{23170F69-40C1-278A-0000-000400180000}']
    function Code(var inStreams: ISequentialInStream; var inSizes: PInt64;
      numInStreams: Cardinal; var outStreams: ISequentialOutStream;
      var outSizes: PInt64; numOutStreams: Cardinal;
      progress: ICompressProgressInfo): HRESULT; stdcall;
  end;
     
const
  // NCoderPropID::
  kDictionarySize = $400;
  kUsedMemorySize = kDictionarySize + 1;
  kOrder = kUsedMemorySize + 1;
  kPosStateBits = $440;
  kLitContextBits = kPosStateBits + 1;
  kLitPosBits = kLitContextBits + 1;
  kNumFastBytes = $450;
  kMatchFinder = kNumFastBytes + 1;
  kMatchFinderCycles = kMatchFinder + 1;
  kNumPasses = $460;
  kAlgorithm = $470;
  kMultiThread = $480;
  kNumThreads = kMultiThread + 1;
  kEndMarker = $490;
     
type
  ICompressSetCoderProperties = interface
    ['{23170F69-40C1-278A-0000-000400200000}']
    function SetCoderProperties(propIDs: PPropID; properties: PROPVARIANT;
      numProperties: Cardinal): HRESULT; stdcall;
  end;
     
  (*
    CODER_INTERFACE(ICompressSetCoderProperties, 0x21)
    {
    STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE;
    };
  *)
  ICompressSetDecoderProperties2 = interface
    ['{23170F69-40C1-278A-0000-000400220000}']
    function SetDecoderProperties2(data: PByte; size: Cardinal)
      : HRESULT; stdcall;
  end;
     
  ICompressWriteCoderProperties = interface
    ['{23170F69-40C1-278A-0000-000400230000}']
    function WriteCoderProperties(outStreams: ISequentialOutStream)
      : HRESULT; stdcall;
  end;
     
  ICompressGetInStreamProcessedSize = interface
    ['{23170F69-40C1-278A-0000-000400240000}']
    function GetInStreamProcessedSize(value: PInt64): HRESULT; stdcall;
  end;
     
  ICompressSetCoderMt = interface
    ['{23170F69-40C1-278A-0000-000400250000}']
    function SetNumberOfThreads(numThreads: Cardinal): HRESULT; stdcall;
  end;
     
  ICompressGetSubStreamSize = interface
    ['{23170F69-40C1-278A-0000-000400300000}']
    function GetSubStreamSize(subStream: Int64; value: PInt64)
      : HRESULT; stdcall;
  end;
     
  ICompressSetInStream = interface
    ['{23170F69-40C1-278A-0000-000400310000}']
    function SetInStream(inStream: ISequentialInStream): HRESULT; stdcall;
    function ReleaseInStream: HRESULT; stdcall;
  end;
     
  ICompressSetOutStream = interface
    ['{23170F69-40C1-278A-0000-000400320000}']
    function SetOutStream(outStream: ISequentialOutStream): HRESULT; stdcall;
    function ReleaseOutStream: HRESULT; stdcall;
  end;
     
  ICompressSetInStreamSize = interface
    ['{23170F69-40C1-278A-0000-000400330000}']
    function SetInStreamSize(inSize: PInt64): HRESULT; stdcall;
  end;
     
  ICompressSetOutStreamSize = interface
    ['{23170F69-40C1-278A-0000-000400340000}']
    function SetOutStreamSize(outSize: PInt64): HRESULT; stdcall;
  end;
     
  ICompressFilter = interface
    ['{23170F69-40C1-278A-0000-000400400000}']
    function Init: HRESULT; stdcall;
    function Filter(data: PByte; size: Cardinal): Cardinal; stdcall;
    // Filter return outSize (Cardinal)
    // if (outSize <= size): Filter have converted outSize bytes
    // if (outSize > size): Filter have not converted anything.
    // and it needs at least outSize bytes to convert one block
    // (it's for crypto block algorithms).
  end;
     
  ICryptoProperties = interface
    ['{23170F69-40C1-278A-0000-000400800000}']
    function SetKey(data: PByte; size: Cardinal): HRESULT; stdcall;
    function SetInitVector(data: PByte; size: Cardinal): HRESULT; stdcall;
  end;
     
  ICryptoSetPassword = interface
    ['{23170F69-40C1-278A-0000-000400900000}']
    function CryptoSetPassword(data: PByte; size: Cardinal): HRESULT; stdcall;
  end;
     
  ICryptoSetCRC = interface
    ['{23170F69-40C1-278A-0000-000400A00000}']
    function CryptoSetCRC(crc: Cardinal): HRESULT; stdcall;
  end;
     
  /// ///
  // It's for DLL file
  // NMethodPropID::
  NMethodPropID = (kID = 0, kName_, kDecoder, kEncoder, kInStreams, kOutStreams,
    kDescription, kDecoderIsAssigned, kEncoderIsAssigned);
  // ******************************************************************************
  // CLASSES
  // ******************************************************************************
  T7zPasswordCallback = function(sender: Pointer; var password: UnicodeString)
    : HRESULT; stdcall;
  T7zGetStreamCallBack = function(sender: Pointer; index: Cardinal;
    var outStream: ISequentialOutStream): HRESULT; stdcall;
  T7zProgressCallback = function(sender: Pointer; total: boolean; value: Int64)
    : HRESULT; stdcall;
     
  I7zInArchive = interface
    ['{022CF785-3ECE-46EF-9755-291FA84CC6C9}']
    procedure OpenFile(const filename: string); stdcall;
    procedure OpenStream(stream: IInStream); stdcall;
    procedure Close; stdcall;
    function GetNumberOfItems: Cardinal; stdcall;
    function GetItemPath(const index: Integer): UnicodeString; stdcall;
    function GetItemName(const index: Integer): UnicodeString; stdcall;
    function GetItemSize(const index: Integer): Cardinal; stdcall;
    function GetItemIsFolder(const index: Integer): boolean; stdcall;
    function GetInArchive: IInArchive;
    procedure ExtractItem(const item: Cardinal; stream: TStream;
      test: longbool); stdcall;
    procedure ExtractItems(items: PCardArray; count: Cardinal; test: longbool;
      sender: Pointer; callback: T7zGetStreamCallBack); stdcall;
    procedure ExtractAll(test: longbool; sender: Pointer;
      callback: T7zGetStreamCallBack); stdcall;
    procedure ExtractTo(const path: string); stdcall;
    procedure SetPasswordCallback(sender: Pointer;
      callback: T7zPasswordCallback); stdcall;
    procedure SetPassword(const password: UnicodeString); stdcall;
    procedure SetProgressCallback(sender: Pointer;
      callback: T7zProgressCallback); stdcall;
    procedure SetClassId(const classid: TGUID);
    function GetClassId: TGUID;
    property classid: TGUID read GetClassId write SetClassId;
    property NumberOfItems: Cardinal read GetNumberOfItems;
    property ItemPath[const index: Integer]: UnicodeString read GetItemPath;
    property ItemName[const index: Integer]: UnicodeString read GetItemName;
    property ItemSize[const index: Integer]: Cardinal read GetItemSize;
    property ItemIsFolder[const index: Integer]: boolean read GetItemIsFolder;
    property InArchive: IInArchive read GetInArchive;
  end;
     
  I7zOutArchive = interface
    ['{BAA9D5DC-9FF4-4382-9BFD-EC9065BD0125}']
    procedure AddStream(stream: TStream; Ownership: TStreamOwnership;
      Attributes: Cardinal; CreationTime, LastWriteTime: TFileTime;
      const path: UnicodeString; IsFolder, IsAnti: boolean); stdcall;
    procedure AddFile(const filename: TFileName;
      const path: UnicodeString); stdcall;
    procedure AddFiles(const Dir, path, Willcards: string;
      recurse: boolean); stdcall;
    procedure SaveToFile(const filename: TFileName); stdcall;
    procedure SaveToStream(stream: TStream); stdcall;
    procedure SetProgressCallback(sender: Pointer;
      callback: T7zProgressCallback); stdcall;
    procedure CrearBatch; stdcall;
    procedure SetPassword(const password: UnicodeString); stdcall;
    procedure SetPropertie(name: UnicodeString; value: OleVariant); stdcall;
    procedure SetClassId(const classid: TGUID);
    function GetClassId: TGUID;
    property classid: TGUID read GetClassId write SetClassId;
  end;
     
  I7zCodec = interface
    ['{AB48F772-F6B1-411E-907F-1567DB0E93B3}']
  end;
     
  T7zStream = class(TInterfacedObject, IInStream, IStreamGetSize,
    ISequentialOutStream, ISequentialInStream, IOutStream, IOutStreamFlush)
  private
    FStream: TStream;
    FOwnership: TStreamOwnership;
  protected
    function Read(data: Pointer; size: Cardinal; processedSize: PCardinal)
      : HRESULT; stdcall;
    function Seek(offset: Int64; seekOrigin: Cardinal; newPosition: PInt64)
      : HRESULT; stdcall;
    function GetSize(size: PInt64): HRESULT; stdcall;
    function SetSize(newSize: Int64): HRESULT; stdcall;
    function Write(data: Pointer; size: Cardinal; processedSize: PCardinal)
      : HRESULT; stdcall;
    function Flush: HRESULT; stdcall;
  public
    constructor Create(stream: TStream;
      Ownership: TStreamOwnership = soReference);
    destructor Destroy; override;
  end;
     
  // I7zOutArchive property setters
type
  TZipCompressionMethod = (mzCopy, mzDeflate, mzDeflate64, mzBZip2);
  T7zCompressionMethod = (m7Copy, m7LZMA, m7BZip2, m7PPMd, m7Deflate,
    m7Deflate64);
  // ZIP 7z GZIP BZ2
procedure SetCompressionLevel(Arch: I7zOutArchive; level: Cardinal); // X X X X
procedure SetMultiThreading(Arch: I7zOutArchive; ThreadCount: Cardinal);
// X X X
procedure SetCompressionMethod(Arch: I7zOutArchive;
  method: TZipCompressionMethod); // X
procedure SetDictionnarySize(Arch: I7zOutArchive; size: Cardinal);
// < 32 // X X
procedure SetDeflateNumPasses(Arch: I7zOutArchive; pass: Cardinal); // X X X
procedure SetNumFastBytes(Arch: I7zOutArchive; fb: Cardinal); // X X
procedure SetNumMatchFinderCycles(Arch: I7zOutArchive; mc: Cardinal); // X X
procedure SevenZipSetCompressionMethod(Arch: I7zOutArchive;
  method: T7zCompressionMethod); // X
procedure SevenZipSetBindInfo(Arch: I7zOutArchive; const bind: UnicodeString);
// X
procedure SevenZipSetSolidSettings(Arch: I7zOutArchive; solid: boolean); // X
procedure SevenZipRemoveSfxBlock(Arch: I7zOutArchive; remove: boolean); // X
procedure SevenZipAutoFilter(Arch: I7zOutArchive; auto: boolean); // X
procedure SevenZipCompressHeaders(Arch: I7zOutArchive; compress: boolean); // X
procedure SevenZipCompressHeadersFull(Arch: I7zOutArchive; compress: boolean);
// X
procedure SevenZipEncryptHeaders(Arch: I7zOutArchive; Encrypt: boolean); // X
procedure SevenZipVolumeMode(Arch: I7zOutArchive; Mode: boolean); // X
// filetime util functions
function DateTimeToFileTime(dt: TDateTime): TFileTime;
function FileTimeToDateTime(ft: TFileTime): TDateTime;
function CurrentFileTime: TFileTime;
// constructors
function CreateInArchive(const classid: TGUID): I7zInArchive; overload;
function CreateInArchive(const filename: WideString): I7zInArchive;overload;
function CreateOutArchive(const classid: TGUID): I7zOutArchive;
     
     
     
const
  CLSID_CFormatZip: TGUID = '{23170F69-40C1-278A-1000-000110010000}';
  // zip jar xpi
  CLSID_CFormatBZ2: TGUID = '{23170F69-40C1-278A-1000-000110020000}';
  // bz2 bzip2 tbz2 tbz
  CLSID_CFormatRar: TGUID = '{23170F69-40C1-278A-1000-000110030000}'; // rar r00
  CLSID_CFormatArj: TGUID = '{23170F69-40C1-278A-1000-000110040000}'; // arj
  CLSID_CFormatZ: TGUID = '{23170F69-40C1-278A-1000-000110050000}'; // z taz
  CLSID_CFormatLzh: TGUID = '{23170F69-40C1-278A-1000-000110060000}'; // lzh lha
  CLSID_CFormat7z: TGUID = '{23170F69-40C1-278A-1000-000110070000}'; // 7z
  CLSID_CFormatCab: TGUID = '{23170F69-40C1-278A-1000-000110080000}'; // cab
  CLSID_CFormatNsis: TGUID = '{23170F69-40C1-278A-1000-000110090000}';
  CLSID_CFormatLzma: TGUID = '{23170F69-40C1-278A-1000-0001100A0000}';
  // lzma lzma86
  CLSID_CFormatPe: TGUID = '{23170F69-40C1-278A-1000-000110DD0000}';
  CLSID_CFormatElf: TGUID = '{23170F69-40C1-278A-1000-000110DE0000}';
  CLSID_CFormatMacho: TGUID = '{23170F69-40C1-278A-1000-000110DF0000}';
  CLSID_CFormatUdf: TGUID = '{23170F69-40C1-278A-1000-000110E00000}'; // iso
  CLSID_CFormatXar: TGUID = '{23170F69-40C1-278A-1000-000110E10000}'; // xar
  CLSID_CFormatMub: TGUID = '{23170F69-40C1-278A-1000-000110E20000}';
  CLSID_CFormatHfs: TGUID = '{23170F69-40C1-278A-1000-000110E30000}';
  CLSID_CFormatDmg: TGUID = '{23170F69-40C1-278A-1000-000110E40000}'; // dmg
  CLSID_CFormatCompound: TGUID = '{23170F69-40C1-278A-1000-000110E50000}';
  // msi doc xls ppt
  CLSID_CFormatWim: TGUID = '{23170F69-40C1-278A-1000-000110E60000}'; // wim swm
  CLSID_CFormatIso: TGUID = '{23170F69-40C1-278A-1000-000110E70000}'; // iso
  CLSID_CFormatBkf: TGUID = '{23170F69-40C1-278A-1000-000110E80000}';
  CLSID_CFormatChm: TGUID = '{23170F69-40C1-278A-1000-000110E90000}';
  // chm chi chq chw hxs hxi hxr hxq hxw lit
  CLSID_CFormatSplit: TGUID = '{23170F69-40C1-278A-1000-000110EA0000}'; // 001
  CLSID_CFormatRpm: TGUID = '{23170F69-40C1-278A-1000-000110EB0000}'; // rpm
  CLSID_CFormatDeb: TGUID = '{23170F69-40C1-278A-1000-000110EC0000}'; // deb
  CLSID_CFormatCpio: TGUID = '{23170F69-40C1-278A-1000-000110ED0000}'; // cpio
  CLSID_CFormatTar: TGUID = '{23170F69-40C1-278A-1000-000110EE0000}'; // tar
  CLSID_CFormatGZip: TGUID = '{23170F69-40C1-278A-1000-000110EF0000}';
  // gz gzip tgz tpz
     
implementation
     
const
  MAXCHECK: Int64 = (1 shl 20);
  ZipCompressionMethod: array [TZipCompressionMethod] of UnicodeString =
    ('COPY', 'DEFLATE', 'DEFLATE64', 'BZIP2');
  SevCompressionMethod: array [T7zCompressionMethod] of UnicodeString = ('COPY',
    'LZMA', 'BZIP2', 'PPMD', 'DEFLATE', 'DEFLATE64');
     
function DateTimeToFileTime(dt: TDateTime): TFileTime;
var
  st: TSystemTime;
begin
  DateTimeToSystemTime(dt, st);
  if not(SystemTimeToFileTime(st, Result) and LocalFileTimeToFileTime(Result,
    Result)) then
    RaiseLastOSError;
end;
     
function FileTimeToDateTime(ft: TFileTime): TDateTime;
var
  st: TSystemTime;
begin
  if not(FileTimeToLocalFileTime(ft, ft) and FileTimeToSystemTime(ft, st)) then
    RaiseLastOSError;
  Result := SystemTimeToDateTime(st);
end;
     
function CurrentFileTime: TFileTime;
begin
  GetSystemTimeAsFileTime(Result);
end;
     
procedure RINOK(const hr: HRESULT);
begin
  if hr <> S_OK then
    raise Exception.Create(SysErrorMessage(hr));
end;
     
procedure SetCardinalProperty(Arch: I7zOutArchive; const name: UnicodeString;
  card: Cardinal);
var
  value: OleVariant;
begin
  TPropVariant(value).vt := VT_UI4;
  TPropVariant(value).ulVal := card;
  Arch.SetPropertie(name, value);
end;
     
procedure SetBooleanProperty(Arch: I7zOutArchive; const name: UnicodeString;
  bool: boolean);
begin
  case bool of
    true:
      Arch.SetPropertie(name, 'ON');
    false:
      Arch.SetPropertie(name, 'OFF');
  end;
end;
     
procedure SetCompressionLevel(Arch: I7zOutArchive; level: Cardinal);
begin
  SetCardinalProperty(Arch, 'X', level);
end;
     
procedure SetMultiThreading(Arch: I7zOutArchive; ThreadCount: Cardinal);
begin
  SetCardinalProperty(Arch, 'MT', ThreadCount);
end;
     
procedure SetCompressionMethod(Arch: I7zOutArchive;
  method: TZipCompressionMethod);
begin
  Arch.SetPropertie('M', ZipCompressionMethod[method]);
end;
     
procedure SetDictionnarySize(Arch: I7zOutArchive; size: Cardinal);
begin
  SetCardinalProperty(Arch, 'D', size);
end;
     
procedure SetDeflateNumPasses(Arch: I7zOutArchive; pass: Cardinal);
begin
  SetCardinalProperty(Arch, 'PASS', pass);
end;
     
procedure SetNumFastBytes(Arch: I7zOutArchive; fb: Cardinal);
begin
  SetCardinalProperty(Arch, 'FB', fb);
end;
     
procedure SetNumMatchFinderCycles(Arch: I7zOutArchive; mc: Cardinal);
begin
  SetCardinalProperty(Arch, 'MC', mc);
end;
     
procedure SevenZipSetCompressionMethod(Arch: I7zOutArchive;
  method: T7zCompressionMethod);
begin
  Arch.SetPropertie('0', SevCompressionMethod[method]);
end;
     
procedure SevenZipSetBindInfo(Arch: I7zOutArchive; const bind: UnicodeString);
begin
  Arch.SetPropertie('B', bind);
end;
     
procedure SevenZipSetSolidSettings(Arch: I7zOutArchive; solid: boolean);
begin
  SetBooleanProperty(Arch, 'S', solid);
end;
     
procedure SevenZipRemoveSfxBlock(Arch: I7zOutArchive; remove: boolean);
begin
  SetBooleanProperty(Arch, 'RSFX', remove);
end;
     
procedure SevenZipAutoFilter(Arch: I7zOutArchive; auto: boolean);
begin
  SetBooleanProperty(Arch, 'F', auto);
end;
     
procedure SevenZipCompressHeaders(Arch: I7zOutArchive; compress: boolean);
begin
  SetBooleanProperty(Arch, 'HC', compress);
end;
     
procedure SevenZipCompressHeadersFull(Arch: I7zOutArchive; compress: boolean);
begin
  SetBooleanProperty(Arch, 'HCF', compress);
end;
     
procedure SevenZipEncryptHeaders(Arch: I7zOutArchive; Encrypt: boolean);
begin
  SetBooleanProperty(Arch, 'HE', Encrypt);
end;
     
procedure SevenZipVolumeMode(Arch: I7zOutArchive; Mode: boolean);
begin
  SetBooleanProperty(Arch, 'V', Mode);
end;
     
type
  T7zPlugin = class(TInterfacedObject)
  private
    FHandle: THandle;
    FCreateObject: function(const clsid, iid: TGUID; var outObject)
      : HRESULT; stdcall;
  public
    constructor Create(const lib: string); virtual;
    destructor Destroy; override;
    procedure CreateObject(const clsid, iid: TGUID; var obj);
  end;
     
  T7zCodec = class(T7zPlugin, I7zCodec, ICompressProgressInfo)
  private
    FGetMethodProperty: function(index: Cardinal; propID: NMethodPropID;
      var value: OleVariant): HRESULT; stdcall;
    FGetNumberOfMethods: function(numMethods: PCardinal): HRESULT; stdcall;
    function GetNumberOfMethods: Cardinal;
    function GetMethodProperty(index: Cardinal; propID: NMethodPropID)
      : OleVariant;
    function GetName(const index: Integer): string;
  protected
    function SetRatioInfo(inSize, outSize: PInt64): HRESULT; stdcall;
  public
    function GetDecoder(const index: Integer): ICompressCoder;
    function GetEncoder(const index: Integer): ICompressCoder;
    constructor Create(const lib: string); override;
    property MethodProperty[index: Cardinal; propID: NMethodPropID]: OleVariant
      read GetMethodProperty;
    property NumberOfMethods: Cardinal read GetNumberOfMethods;
    property Name[const index: Integer]: string read GetName;
  end;
     
  T7zArchive = class(T7zPlugin)
  private
    FGetHandlerProperty: function(propID: NArchive; var value: OleVariant)
      : HRESULT; stdcall;
    FClassId: TGUID;
    procedure SetClassId(const classid: TGUID);
    function GetClassId: TGUID;
  public
    function GetHandlerProperty(const propID: NArchive): OleVariant;
    function GetLibStringProperty(const index: NArchive): string;
    function GetLibGUIDProperty(const index: NArchive): TGUID;
    constructor Create(const lib: string); override;
    property HandlerProperty[const propID: NArchive]: OleVariant
      read GetHandlerProperty;
    property Name: string index kName read GetLibStringProperty;
    property classid: TGUID read GetClassId write SetClassId;
    property Extension: string index kExtension read GetLibStringProperty;
  end;
     
  T7zInArchive = class(T7zArchive, I7zInArchive, IProgress,
    IArchiveOpenCallback, IArchiveExtractCallback, ICryptoGetTextPassword,
    IArchiveOpenVolumeCallback, IArchiveOpenSetSubArchiveName)
  private
    FInArchive: IInArchive;
    FPasswordCallback: T7zPasswordCallback;
    FPasswordSender: Pointer;
    FProgressCallback: T7zProgressCallback;
    FProgressSender: Pointer;
    FStream: TStream;
    FPasswordIsDefined: boolean;
    FPassword: UnicodeString;
    FSubArchiveMode: boolean;
    FSubArchiveName: UnicodeString;
    FExtractCallBack: T7zGetStreamCallBack;
    FExtractSender: Pointer;
    FExtractPath: string;
    function GetInArchive: IInArchive;
    function GetItemProp(const item: Cardinal; prop: propID): OleVariant;
  protected
    // I7zInArchive
    procedure OpenFile(const filename: string); stdcall;
    procedure OpenStream(stream: IInStream); stdcall;
    procedure Close; stdcall;
    function GetNumberOfItems: Cardinal; stdcall;
    function GetItemPath(const index: Integer): UnicodeString; stdcall;
    function GetItemName(const index: Integer): UnicodeString; stdcall;
    function GetItemSize(const index: Integer): Cardinal; stdcall; stdcall;
    function GetItemIsFolder(const index: Integer): boolean; stdcall;
    procedure ExtractItem(const item: Cardinal; stream: TStream;
      test: longbool); stdcall;
    procedure ExtractItems(items: PCardArray; count: Cardinal; test: longbool;
      sender: Pointer; callback: T7zGetStreamCallBack); stdcall;
    procedure SetPasswordCallback(sender: Pointer;
      callback: T7zPasswordCallback); stdcall;
    procedure SetProgressCallback(sender: Pointer;
      callback: T7zProgressCallback); stdcall;
    procedure ExtractAll(test: longbool; sender: Pointer;
      callback: T7zGetStreamCallBack); stdcall;
    procedure ExtractTo(const path: string); stdcall;
    procedure SetPassword(const password: UnicodeString); stdcall;
    // IArchiveOpenCallback
    function SetTotal(files, bytes: PInt64): HRESULT; overload; stdcall;
    function SetCompleted(files, bytes: PInt64): HRESULT; overload; stdcall;
    // IProgress
    function SetTotal(total: Int64): HRESULT; overload; stdcall;
    function SetCompleted(completeValue: PInt64): HRESULT; overload; stdcall;
    // IArchiveExtractCallback
    function GetStream(index: Cardinal; var outStream: ISequentialOutStream;
      askExtractMode: NAskMode): HRESULT; overload; stdcall;
    function PrepareOperation(askExtractMode: NAskMode): HRESULT; stdcall;
    function SetOperationResult(resultEOperationResult: NExtOperationResult)
      : HRESULT; overload; stdcall;
    // ICryptoGetTextPassword
    function CryptoGetTextPassword(var password: TBStr): HRESULT; stdcall;
    // IArchiveOpenVolumeCallback
    function GetProperty(propID: propID; var value: OleVariant): HRESULT;
      overload; stdcall;
    function GetStream(const name: PWideChar; var inStream: IInStream): HRESULT;
      overload; stdcall;
    // IArchiveOpenSetSubArchiveName
    function SetSubArchiveName(name: PWideChar): HRESULT; stdcall;
  public
    constructor Create(const lib: string); override;
    destructor Destroy; override;
    property InArchive: IInArchive read GetInArchive;
  end;
     
  T7zOutArchive = class(T7zArchive, I7zOutArchive, IArchiveUpdateCallback,
    ICryptoGetTextPassword2)
  private
    FOutArchive: IOutArchive;
    FBatchList: TObjectList;
    FProgressCallback: T7zProgressCallback;
    FProgressSender: Pointer;
    FPassword: UnicodeString;
    function GetOutArchive: IOutArchive;
  protected
    // I7zOutArchive
    procedure AddStream(stream: TStream; Ownership: TStreamOwnership;
      Attributes: Cardinal; CreationTime, LastWriteTime: TFileTime;
      const path: UnicodeString; IsFolder, IsAnti: boolean); stdcall;
    procedure AddFile(const filename: TFileName;
      const path: UnicodeString); stdcall;
    procedure AddFiles(const Dir, path, Willcards: string;
      recurse: boolean); stdcall;
    procedure SaveToFile(const filename: TFileName); stdcall;
    procedure SaveToStream(stream: TStream); stdcall;
    procedure SetProgressCallback(sender: Pointer;
      callback: T7zProgressCallback); stdcall;
    procedure CrearBatch; stdcall;
    procedure SetPassword(const password: UnicodeString); stdcall;
    procedure SetPropertie(name: UnicodeString; value: OleVariant); stdcall;
    // IProgress
    function SetTotal(total: Int64): HRESULT; stdcall;
    function SetCompleted(completeValue: PInt64): HRESULT; stdcall;
    // IArchiveUpdateCallback
    function GetUpdateItemInfo(index: Cardinal; newData: PInteger;
      // 1 - new data, 0 - old data
      newProperties: PInteger; // 1 - new properties, 0 - old properties
      indexInArchive: PCardinal
      // -1 if there is no in archive, or if doesn't matter
      ): HRESULT; stdcall;
    function GetProperty(index: Cardinal; propID: propID; var value: OleVariant)
      : HRESULT; stdcall;
    function GetStream(index: Cardinal; var inStream: ISequentialInStream)
      : HRESULT; stdcall;
    function SetOperationResult(operationResult: Integer): HRESULT; stdcall;
    // ICryptoGetTextPassword2
    function CryptoGetTextPassword2(passwordIsDefined: PInteger;
      var password: TBStr): HRESULT; stdcall;
  public
    constructor Create(const lib: string); override;
    destructor Destroy; override;
    property OutArchive: IOutArchive read GetOutArchive;
  end;
     
function CreateInArchive(const classid: TGUID): I7zInArchive;
begin
  Result := T7zInArchive.Create('7z.dll');
  Result.classid := classid;
end;
     
function CreateInArchive(const filename: WideString): I7zInArchive;
var
  sExt: WideString;
begin
  Result := T7zInArchive.Create('7z.dll');
  sExt := UpperCase(ExtractFileExt(filename));
  if (sExt='.ZIP') or (sExt='.JAR') or (sExt='.XPI') then
    Result.classid := CLSID_CFormatZip
  else if (sExt='.BZ2') or (sExt='.BZIP2') or (sExt='.TBZ2') or (sExt='.TBZ') then
    Result.classid := CLSID_CFormatBZ2
  else if (sExt='.RAR') or (sExt='.R00') then
    Result.classid := CLSID_CFormatRar
  else if (sExt='.ARJ') then
    Result.classid := CLSID_CFormatArj
  else if (sExt='.Z') or (sExt='.TAZ') then
    Result.classid := CLSID_CFormatZ
  else if (sExt='.LZH') or (sExt='.LHA') then
    Result.classid := CLSID_CFormatLzh
  else if (sExt='.7Z') then
    Result.classid := CLSID_CFormat7z
  else if (sExt='.CAB') then
    Result.classid := CLSID_CFormatCab
  else if (sExt='.NSIS') then
    Result.classid := CLSID_CFormatNsis
  else if (sExt='.LZMA') or (sExt='.LZMA86') then
    Result.classid := CLSID_CFormatLzma
  else if (sExt='.PE') or (sExt='.EXE') or (sExt='.DLL') or (sExt='.SYS') then
    Result.classid := CLSID_CFormatPe
  else if (sExt='.ELF') then
    Result.classid := CLSID_CFormatElf
  else if (sExt='.MACHO') then
    Result.classid := CLSID_CFormatMacho
  else if {(sExt='.ISO') or }(sExt='.UDF') then
    Result.classid := CLSID_CFormatUdf
  else if (sExt='.XAR') then
    Result.classid := CLSID_CFormatXar
  else if (sExt='.MUB') then
    Result.classid := CLSID_CFormatMub
  else if (sExt='.HGS') or (sExt='.CD') then
    Result.classid := CLSID_CFormatHfs
  else if (sExt='.DMG') then
    Result.classid := CLSID_CFormatDmg
  else if (sExt='.MSI') or (sExt='.DOC') or (sExt='.XLS') or (sExt='.PPT') then
    Result.classid := CLSID_CFormatCompound
  else if (sExt='.WIM') or (sExt='.SWM') then
    Result.classid := CLSID_CFormatWim
  else if (sExt='.ISO') then
    Result.classid := CLSID_CFormatIso
  else if (sExt='.BKF') then
    Result.classid := CLSID_CFormatBkf
  else if (sExt='.CHM') or (sExt='.CHI') or (sExt='.CHQ') or (sExt='.CHW')
          or (sExt='.HXS') or (sExt='.HXI') or (sExt='.HXR') or (sExt='.HXQ')
          or (sExt='.HXW') or (sExt='.LIT') then
    Result.classid := CLSID_CFormatChm
  else if  (sExt='.001') then
    Result.classid := CLSID_CFormatSplit
  else if  (sExt='.RPM') then
    Result.classid := CLSID_CFormatRpm
  else if  (sExt='.DEB') then
    Result.classid := CLSID_CFormatDeb
  else if  (sExt='.CPIO') then
    Result.classid := CLSID_CFormatCpio
  else if  (sExt='.TAR') then
    Result.classid := CLSID_CFormatTar
  else if  (sExt='.GZ') or (sExt='.GZIP') or (sExt='.TGZ') or (sExt='.TPZ') then
    Result.classid := CLSID_CFormatGZip;
  Result.OpenFile(filename);
end;

function CreateOutArchive(const classid: TGUID): I7zOutArchive;
begin
  Result := T7zOutArchive.Create('7z.dll');
  Result.classid := classid;
end;
    
{ T7zPlugin }
constructor T7zPlugin.Create(const lib: string);
begin
  FHandle := LoadLibrary(PChar(lib));
  if FHandle = 0 then
    raise Exception.CreateFmt('Error loading library %s', [lib]);
  FCreateObject := GetProcAddress(FHandle, 'CreateObject');
  if not(Assigned(FCreateObject)) then
  begin
    FreeLibrary(FHandle);
    raise Exception.CreateFmt('%s is not a 7z library', [lib]);
  end;
end;
    
destructor T7zPlugin.Destroy;
begin
  FreeLibrary(FHandle);
  inherited;
end;
    
procedure T7zPlugin.CreateObject(const clsid, iid: TGUID; var obj);
var
  hr: HRESULT;
begin
  hr := FCreateObject(clsid, iid, obj);
  if failed(hr) then
    raise Exception.Create(SysErrorMessage(hr));
end;
    
{ T7zCodec }
constructor T7zCodec.Create(const lib: string);
begin
  inherited;
  FGetMethodProperty := GetProcAddress(FHandle, 'GetMethodProperty');
  FGetNumberOfMethods := GetProcAddress(FHandle, 'GetNumberOfMethods');
  if not(Assigned(FGetMethodProperty) and Assigned(FGetNumberOfMethods)) then
  begin
    FreeLibrary(FHandle);
    raise Exception.CreateFmt('%s is not a codec library', [lib]);
  end;
end;
    
function T7zCodec.GetDecoder(const index: Integer): ICompressCoder;
var
  v: OleVariant;
begin
  v := MethodProperty[index, kDecoder];
  CreateObject(TPropVariant(v).puuid^, ICompressCoder, Result);
end;
    
function T7zCodec.GetEncoder(const index: Integer): ICompressCoder;
var
  v: OleVariant;
begin
  v := MethodProperty[index, kEncoder];
  CreateObject(TPropVariant(v).puuid^, ICompressCoder, Result);
end;
    
function T7zCodec.GetMethodProperty(index: Cardinal; propID: NMethodPropID)
  : OleVariant;
var
  hr: HRESULT;
begin
  hr := FGetMethodProperty(index, propID, Result);
  if failed(hr) then
    raise Exception.Create(SysErrorMessage(hr));
end;
    
function T7zCodec.GetName(const index: Integer): string;
begin
  Result := MethodProperty[index, kName_];
end;
    
function T7zCodec.GetNumberOfMethods: Cardinal;
var
  hr: HRESULT;
begin
  hr := FGetNumberOfMethods(@Result);
  if failed(hr) then
    raise Exception.Create(SysErrorMessage(hr));
end;
    
function T7zCodec.SetRatioInfo(inSize, outSize: PInt64): HRESULT;
begin
  Result := S_OK;
end;
    
{ T7zInArchive }
procedure T7zInArchive.Close; stdcall;
begin
  FPasswordIsDefined := false;
  FSubArchiveMode := false;
  FInArchive.Close;
  FInArchive := nil;
end;
    
constructor T7zInArchive.Create(const lib: string);
begin
  inherited;
  FPasswordCallback := nil;
  FPasswordSender := nil;
  FPasswordIsDefined := false;
  FSubArchiveMode := false;
  FExtractCallBack := nil;
  FExtractSender := nil;
end;
    
destructor T7zInArchive.Destroy;
begin
  FInArchive := nil;
  inherited;
end;
    
function T7zInArchive.GetInArchive: IInArchive;
begin
  if FInArchive = nil then
    CreateObject(classid, IInArchive, FInArchive);
  Result := FInArchive;
end;
    
function T7zInArchive.GetItemPath(const index: Integer): UnicodeString; stdcall;
begin
  Result := UnicodeString(GetItemProp(index, kpidPath));
end;
    
function T7zInArchive.GetNumberOfItems: Cardinal; stdcall;
begin
  RINOK(FInArchive.GetNumberOfItems(Result));
end;
    
procedure T7zInArchive.OpenFile(const filename: string); stdcall;
var
  strm: IInStream;
begin
  strm := T7zStream.Create(TFileStream.Create(filename, fmOpenRead or
    fmShareDenyNone), soOwned);
  try
    RINOK(InArchive.Open(strm, @MAXCHECK, self as IArchiveOpenCallback));
  finally
    strm := nil;
  end;
end;
    
procedure T7zInArchive.OpenStream(stream: IInStream); stdcall;
begin
  RINOK(InArchive.Open(stream, @MAXCHECK, self as IArchiveOpenCallback));
end;
    
function T7zInArchive.GetItemIsFolder(const index: Integer): boolean; stdcall;
begin
  Result := boolean(GetItemProp(index, kpidIsFolder));
end;
    
function T7zInArchive.GetItemProp(const item: Cardinal; prop: propID)
  : OleVariant;
begin
  FInArchive.GetProperty(item, prop, Result);
end;
    
procedure T7zInArchive.ExtractItem(const item: Cardinal; stream: TStream;
  test: longbool); stdcall;
begin
  FStream := stream;
  try
    if test then
      RINOK(FInArchive.Extract(@item, 1, 1, self as IArchiveExtractCallback))
    else
      RINOK(FInArchive.Extract(@item, 1, 0, self as IArchiveExtractCallback));
  finally
    FStream := nil;
  end;
end;
    
function T7zInArchive.GetStream(index: Cardinal;
  var outStream: ISequentialOutStream; askExtractMode: NAskMode): HRESULT;
var
  path: string;
begin
  if askExtractMode = kExtract then
    if FStream <> nil then
      outStream := T7zStream.Create(FStream, soReference)
        as ISequentialOutStream
    else if Assigned(FExtractCallBack) then
    begin
      Result := FExtractCallBack(FExtractSender, index, outStream);
      Exit;
    end
    else if FExtractPath <> '' then
    begin
      if not GetItemIsFolder(index) then
      begin
        path := FExtractPath + GetItemPath(index);
        ForceDirectories(ExtractFilePath(path));
        outStream := T7zStream.Create(TFileStream.Create(path,
          fmCreate), soOwned);
      end;
    end;
  Result := S_OK;
end;
    
function T7zInArchive.PrepareOperation(askExtractMode: NAskMode): HRESULT;
begin
  Result := S_OK;
end;
    
function T7zInArchive.SetCompleted(completeValue: PInt64): HRESULT;
begin
  if Assigned(FProgressCallback) and (completeValue <> nil) then
    Result := FProgressCallback(FProgressSender, false, completeValue^)
  else
    Result := S_OK;
end;
    
function T7zInArchive.SetCompleted(files, bytes: PInt64): HRESULT;
begin
  Result := S_OK;
end;
    
function T7zInArchive.SetOperationResult(resultEOperationResult
  : NExtOperationResult): HRESULT;
begin
  Result := S_OK;
end;
    
function T7zInArchive.SetTotal(total: Int64): HRESULT;
begin
  if Assigned(FProgressCallback) then
    Result := FProgressCallback(FProgressSender, true, total)
  else
    Result := S_OK;
end;
    
function T7zInArchive.SetTotal(files, bytes: PInt64): HRESULT;
begin
  Result := S_OK;
end;
    
function T7zInArchive.CryptoGetTextPassword(var password: TBStr): HRESULT;
var
  wpass: UnicodeString;
begin
  if FPasswordIsDefined then
  begin
    password := SysAllocString(PWideChar(FPassword));
    Result := S_OK;
  end
  else if Assigned(FPasswordCallback) then
  begin
    Result := FPasswordCallback(FPasswordSender, wpass);
    if Result = S_OK then
    begin
      password := SysAllocString(PWideChar(wpass));
      FPasswordIsDefined := true;
      FPassword := wpass;
    end;
  end
  else
    Result := S_FALSE;
end;
    
function T7zInArchive.GetProperty(propID: propID;
  var value: OleVariant): HRESULT;
begin
  Result := S_OK;
end;
    
function T7zInArchive.GetStream(const name: PWideChar;
  var inStream: IInStream): HRESULT;
begin
  Result := S_OK;
end;
    
procedure T7zInArchive.SetPasswordCallback(sender: Pointer;
  callback: T7zPasswordCallback); stdcall;
begin
  FPasswordSender := sender;
  FPasswordCallback := callback;
end;
    
function T7zInArchive.SetSubArchiveName(name: PWideChar): HRESULT;
begin
  FSubArchiveMode := true;
  FSubArchiveName := name;
  Result := S_OK;
end;
    
function T7zInArchive.GetItemName(const index: Integer): UnicodeString; stdcall;
begin
  Result := UnicodeString(GetItemProp(index, kpidName));
end;
    
function T7zInArchive.GetItemSize(const index: Integer): Cardinal; stdcall;
begin
  Result := Cardinal(GetItemProp(index, kpidSize));
end;
    
procedure T7zInArchive.ExtractItems(items: PCardArray; count: Cardinal;
  test: longbool; sender: Pointer; callback: T7zGetStreamCallBack); stdcall;
begin
  FExtractCallBack := callback;
  FExtractSender := sender;
  try
    if test then
      RINOK(FInArchive.Extract(items, count, 1,
        self as IArchiveExtractCallback))
    else
      RINOK(FInArchive.Extract(items, count, 0,
        self as IArchiveExtractCallback));
  finally
    FExtractCallBack := nil;
    FExtractSender := nil;
  end;
end;
    
procedure T7zInArchive.SetProgressCallback(sender: Pointer;
  callback: T7zProgressCallback); stdcall;
begin
  FProgressSender := sender;
  FProgressCallback := callback;
end;
    
procedure T7zInArchive.ExtractAll(test: longbool; sender: Pointer;
  callback: T7zGetStreamCallBack);
begin
  FExtractCallBack := callback;
  FExtractSender := sender;
  try
    if test then
      RINOK(FInArchive.Extract(nil, $FFFFFFFF, 1,
        self as IArchiveExtractCallback))
    else
      RINOK(FInArchive.Extract(nil, $FFFFFFFF, 0,
        self as IArchiveExtractCallback));
  finally
    FExtractCallBack := nil;
    FExtractSender := nil;
  end;
end;
    
procedure T7zInArchive.ExtractTo(const path: string);
begin
  FExtractPath := IncludeTrailingPathDelimiter(path);
  try
    RINOK(FInArchive.Extract(nil, $FFFFFFFF, 0,
      self as IArchiveExtractCallback));
  finally
    FExtractPath := '';
  end;
end;
    
procedure T7zInArchive.SetPassword(const password: UnicodeString);
begin
  FPassword := password;
  FPasswordIsDefined := FPassword <> '';
end;
    
{ T7zArchive }
constructor T7zArchive.Create(const lib: string);
begin
  inherited;
  FGetHandlerProperty := GetProcAddress(FHandle, 'GetHandlerProperty');
  if not Assigned(FGetHandlerProperty) then
  begin
    FreeLibrary(FHandle);
    raise Exception.CreateFmt('%s is not a Format library', [lib]);
  end;
  FClassId := GUID_NULL;
end;
    
function T7zArchive.GetClassId: TGUID;
begin
  Result := FClassId;
end;
    
function T7zArchive.GetHandlerProperty(const propID: NArchive): OleVariant;
var
  hr: HRESULT;
begin
  hr := FGetHandlerProperty(propID, Result);
  if failed(hr) then
    raise Exception.Create(SysErrorMessage(hr));
end;
    
function T7zArchive.GetLibGUIDProperty(const index: NArchive): TGUID;
var
  v: OleVariant;
begin
  v := HandlerProperty[index];
  Result := TPropVariant(v).puuid^;
end;
    
function T7zArchive.GetLibStringProperty(const index: NArchive): string;
begin
  Result := HandlerProperty[Index];
end;
    
procedure T7zArchive.SetClassId(const classid: TGUID);
begin
  FClassId := classid;
end;
    
{ T7zStream }
constructor T7zStream.Create(stream: TStream; Ownership: TStreamOwnership);
begin
  inherited Create;
  FStream := stream;
  FOwnership := Ownership;
end;
    
destructor T7zStream.Destroy;
begin
  if FOwnership = soOwned then
  begin
    FStream.Free;
    FStream := nil;
  end;
  inherited;
end;
    
function T7zStream.Flush: HRESULT;
begin
  Result := S_OK;
end;
    
function T7zStream.GetSize(size: PInt64): HRESULT;
begin
  if size <> nil then
    size^ := FStream.size;
  Result := S_OK;
end;
    
function T7zStream.Read(data: Pointer; size: Cardinal;
  processedSize: PCardinal): HRESULT;
var
  len: Integer;
begin
  len := FStream.Read(data^, size);
  if processedSize <> nil then
    processedSize^ := len;
  Result := S_OK;
end;
    
function T7zStream.Seek(offset: Int64; seekOrigin: Cardinal;
  newPosition: PInt64): HRESULT;
begin
  FStream.Seek(offset, TSeekOrigin(seekOrigin));
  if newPosition <> nil then
    newPosition^ := FStream.Position;
  Result := S_OK;
end;
    
function T7zStream.SetSize(newSize: Int64): HRESULT;
begin
  FStream.size := newSize;
  Result := S_OK;
end;
    
function T7zStream.Write(data: Pointer; size: Cardinal;
  processedSize: PCardinal): HRESULT;
var
  len: Integer;
begin
  len := FStream.Write(data^, size);
  if processedSize <> nil then
    processedSize^ := len;
  Result := S_OK;
end;
    
type
  TSourceMode = (smStream, smFile);
    
  T7zBatchItem = class
    SourceMode: TSourceMode;
    stream: TStream;
    Attributes: Cardinal;
    CreationTime, LastWriteTime: TFileTime;
    path: UnicodeString;
    IsFolder, IsAnti: boolean;
    filename: TFileName;
    Ownership: TStreamOwnership;
    size: Cardinal;
    destructor Destroy; override;
  end;
    
destructor T7zBatchItem.Destroy;
begin
  if (Ownership = soOwned) and (stream <> nil) then
    stream.Free;
  inherited;
end;
    
{ T7zOutArchive }
procedure T7zOutArchive.AddFile(const filename: TFileName;
  const path: UnicodeString);
var
  item: T7zBatchItem;
  Handle: THandle;
begin
  if not FileExists(filename) then
    Exit;
  item := T7zBatchItem.Create;
  item.SourceMode := smFile;
  item.stream := nil;
  item.filename := filename;
  item.path := path;
  Handle := FileOpen(filename, fmOpenRead or fmShareDenyNone);
  GetFileTime(Handle, @item.CreationTime, nil, @item.LastWriteTime);
  item.size := GetFileSize(Handle, nil);
  CloseHandle(Handle);
  item.Attributes := GetFileAttributes(PChar(filename));
  item.IsFolder := false;
  item.IsAnti := false;
  item.Ownership := soOwned;
  FBatchList.Add(item);
end;
    
procedure T7zOutArchive.AddFiles(const Dir, path, Willcards: string;
  recurse: boolean);
var
  lencut: Integer;
  willlist: TStringList;
  zedir: string;
  procedure Traverse(p: string);
  var
    f: TSearchRec;
    i: Integer;
    item: T7zBatchItem;
  begin
    if recurse then
    begin
      if FindFirst(p + '*.*', faDirectory, f) = 0 then
        repeat
          if (f.name[1] <> '.') then
            Traverse(IncludeTrailingPathDelimiter(p + f.name));
        until FindNext(f) <> 0;
      SysUtils.FindClose(f);
    end;
    for i := 0 to willlist.count - 1 do
    begin
      if FindFirst(p + willlist[i], faReadOnly or faHidden or faSysFile or
        faArchive, f) = 0 then
        repeat
          item := T7zBatchItem.Create;
          item.SourceMode := smFile;
          item.stream := nil;
          item.filename := p + f.name;
          item.path := copy(item.filename, lencut, length(item.filename) -
            lencut + 1);
          if path <> '' then
            item.path := IncludeTrailingPathDelimiter(path) + item.path;
          item.CreationTime := f.FindData.ftCreationTime;
          item.LastWriteTime := f.FindData.ftLastWriteTime;
          item.Attributes := f.FindData.dwFileAttributes;
          item.size := f.size;
          item.IsFolder := false;
          item.IsAnti := false;
          item.Ownership := soOwned;
          FBatchList.Add(item);
        until FindNext(f) <> 0;
      SysUtils.FindClose(f);
    end;
  end;
    
begin
  willlist := TStringList.Create;
  try
    willlist.Delimiter := ';';
    willlist.DelimitedText := Willcards;
    zedir := IncludeTrailingPathDelimiter(Dir);
    lencut := length(zedir) + 1;
    Traverse(zedir);
  finally
    willlist.Free;
  end;
end;
    
procedure T7zOutArchive.AddStream(stream: TStream; Ownership: TStreamOwnership;
  Attributes: Cardinal; CreationTime, LastWriteTime: TFileTime;
  const path: UnicodeString; IsFolder, IsAnti: boolean); stdcall;
var
  item: T7zBatchItem;
begin
  item := T7zBatchItem.Create;
  item.SourceMode := smStream;
  item.Attributes := Attributes;
  item.CreationTime := CreationTime;
  item.LastWriteTime := LastWriteTime;
  item.path := path;
  item.IsFolder := IsFolder;
  item.IsAnti := IsAnti;
  item.stream := stream;
  item.size := stream.size;
  item.Ownership := Ownership;
  FBatchList.Add(item);
end;
    
procedure T7zOutArchive.CrearBatch;
begin
  FBatchList.Clear;
end;
    
constructor T7zOutArchive.Create(const lib: string);
begin
  inherited;
  FBatchList := TObjectList.Create;
  FProgressCallback := nil;
  FProgressSender := nil;
end;
    
function T7zOutArchive.CryptoGetTextPassword2(passwordIsDefined: PInteger;
  var password: TBStr): HRESULT;
begin
  if FPassword <> '' then
  begin
    passwordIsDefined^ := 1;
    password := SysAllocString(PWideChar(FPassword));
  end
  else
    passwordIsDefined^ := 0;
  Result := S_OK;
end;
    
destructor T7zOutArchive.Destroy;
begin
  FOutArchive := nil;
  FBatchList.Free;
  inherited;
end;
    
function T7zOutArchive.GetOutArchive: IOutArchive;
begin
  if FOutArchive = nil then
    CreateObject(classid, IOutArchive, FOutArchive);
  Result := FOutArchive;
end;
    
function T7zOutArchive.GetProperty(index: Cardinal; propID: propID;
  var value: OleVariant): HRESULT;
var
  item: T7zBatchItem;
begin
  item := T7zBatchItem(FBatchList[index]);
  case propID of
    kpidAttributes:
      begin
        TPropVariant(value).vt := VT_UI4;
        TPropVariant(value).ulVal := item.Attributes;
      end;
    kpidLastWriteTime:
      begin
        TPropVariant(value).vt := VT_FILETIME;
        TPropVariant(value).filetime := item.LastWriteTime;
      end;
    kpidPath:
      begin
        if item.path <> '' then
          value := item.path;
      end;
    kpidIsFolder:
      value := item.IsFolder;
    kpidSize:
      begin
        TPropVariant(value).vt := VT_UI8;
        TPropVariant(value).uhVal.QuadPart := item.size;
      end;
    kpidCreationTime:
      begin
        TPropVariant(value).vt := VT_FILETIME;
        TPropVariant(value).filetime := item.CreationTime;
      end;
    kpidIsAnti:
      value := item.IsAnti;
  else
    // beep(0,0);
  end;
  Result := S_OK;
end;
    
function T7zOutArchive.GetStream(index: Cardinal;
  var inStream: ISequentialInStream): HRESULT;
var
  item: T7zBatchItem;
begin
  item := T7zBatchItem(FBatchList[index]);
  case item.SourceMode of
    smFile:
      inStream := T7zStream.Create(TFileStream.Create(item.filename,
        fmOpenRead or fmShareDenyNone), soOwned);
    smStream:
      begin
        item.stream.Seek(0, soFromBeginning);
        inStream := T7zStream.Create(item.stream);
      end;
  end;
  Result := S_OK;
end;
    
function T7zOutArchive.GetUpdateItemInfo(index: Cardinal;
  newData, newProperties: PInteger; indexInArchive: PCardinal): HRESULT;
begin
  newData^ := 1;
  newProperties^ := 1;
  indexInArchive^ := Cardinal(-1);
  Result := S_OK;
end;
    
procedure T7zOutArchive.SaveToFile(const filename: TFileName);
var
  f: TFileStream;
begin
  f := TFileStream.Create(filename, fmCreate);
  try
    SaveToStream(f);
  finally
    f.Free;
  end;
end;
    
procedure T7zOutArchive.SaveToStream(stream: TStream);
var
  strm: ISequentialOutStream;
begin
  strm := T7zStream.Create(stream);
  try
    RINOK(OutArchive.UpdateItems(strm, FBatchList.count,
      self as IArchiveUpdateCallback));
  finally
    strm := nil;
  end;
end;
    
function T7zOutArchive.SetCompleted(completeValue: PInt64): HRESULT;
begin
  if Assigned(FProgressCallback) and (completeValue <> nil) then
    Result := FProgressCallback(FProgressSender, false, completeValue^)
  else
    Result := S_OK;
end;
    
function T7zOutArchive.SetOperationResult(operationResult: Integer): HRESULT;
begin
  Result := S_OK;
end;
    
procedure T7zOutArchive.SetPassword(const password: UnicodeString);
begin
  FPassword := password;
end;
    
procedure T7zOutArchive.SetProgressCallback(sender: Pointer;
  callback: T7zProgressCallback);
begin
  FProgressCallback := callback;
  FProgressSender := sender;
end;
    
procedure T7zOutArchive.SetPropertie(name: UnicodeString; value: OleVariant);
var
  intf: ISetProperties;
  p: PWideChar;
begin
  intf := OutArchive as ISetProperties;
  p := PWideChar(name);
  RINOK(intf.SetProperties(@p, @TPropVariant(value), 1));
end;
    
function T7zOutArchive.SetTotal(total: Int64): HRESULT;
begin
  if Assigned(FProgressCallback) then
    Result := FProgressCallback(FProgressSender, true, total)
  else
    Result := S_OK;
end;
    
end.

二、将 7z.dll 放到程序运行目录

https://download.csdn.net/download/qq_33397419/86401066

三、使用方法

uses
  D7zUtils, SevenZip;


//-------------------------------------------------------------

//【解压文件】
procedure TForm1.btn1Click(Sender: TObject);
begin
  with CreateInArchive(CLSID_CFormatZip) do
  begin
    //将1.zip中文件解压到C盘根目录
    OpenFile('c:\1.zip');
    ExtractTo('c:\');
  end;
end;

//-------------------------------------------------------------

//【压缩文件】
procedure TForm1.btn2Click(Sender: TObject);
begin
  with CreateOutArchive(CLSID_CFormatZip) do
  begin
    //将1.txt中文件压缩到1.zip
    AddFile('c:\1.txt','1.txt');
    SaveToFile('c:\1.zip')
  end;
end;

路过的点个赞再走,谢谢~😊😊😊😀😀😀

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值