{----------------------------------------------------------------------------- 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/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: JvCABFile.PAS, released on 2001-02-28. The Initial Developer of the Original Code is Sébastien Buysse [sbuysse att buypin dott com] Portions created by Sébastien Buysse are Copyright (C) 2001 Sébastien Buysse. All Rights Reserved. Contributor(s): Michael Beck [mbeck att bigfoot dott com]. You may retrieve the latest version of this file at the Project JEDI's JVCL home page, located at http://jvcl.delphi-jedi.org Known Issues: -----------------------------------------------------------------------------} // $Id$ unit JvCabFile; {$I jvcl.inc} {$I windowsonly.inc} interface uses {$IFDEF UNITVERSIONING} JclUnitVersioning, {$ENDIF UNITVERSIONING} Windows, SysUtils, Classes, JvTypes, JvComponentBase; type TCABInfo = record CabinetPath: string; CabinetFile: string; DiskName: string; Id: Shortint; CabinetNumber: Shortint; end; TOnCABInfo = procedure(Sender: TObject; CABInfo: TCABInfo) of object; TOnExtracted = procedure(Sender: TObject; Successed: Boolean; var Cont: Boolean; Source, Dest: string) of object; TOnExtractFile = procedure(Sender: TObject; FileName: string; DestPath: string) of object; TOnNeedNewCabinet = procedure(Sender: TObject; var Cont: Boolean; CABInfo: TCABInfo; var NewPath: string) of object; {$IFDEF RTL230_UP} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$ENDIF RTL230_UP} TJvCABFile = class(TJvComponent) private FFileName: TFileName; FFiles: TStringList; FOnCABInfo: TOnCABInfo; FOnFiles: TNotifyEvent; FOnExtracted: TOnExtracted; FDestPath: string; {CArends} FDestFileName: string; {end-CArends} FOnExtractFile: TOnExtractFile; FOnNeed: TOnNeedNewCabinet; FTmpString: string; function GetFiles: TStrings; procedure SetFileName(const Value: TFileName); procedure SetFiles(const Value: TStrings); procedure RefreshFiles; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function ExtractAll(DestPath: string): Boolean; {CArends - Overloaded ExtractFile function ExtractFile(FileName: string; DestPath: string): Boolean; } function ExtractFile(FileName: string; DestPath: string): Boolean; overload; function ExtractFile(FileName, DestPath, DestFileName: string): Boolean; overload; {end-CArends} published property FileName: TFileName read FFileName write SetFileName; property Files: TStrings read GetFiles write SetFiles; property OnCABInfo: TOnCABInfo read FOnCABInfo write FOnCABInfo; property OnFilesListed: TNotifyEvent read FOnFiles write FOnFiles; property OnFileExtracted: TOnExtracted read FOnExtracted write FOnExtracted; property OnStartFileExtraction: TOnExtractFile read FOnExtractFile write FOnExtractFile; property OnNeedNewCabinet: TOnNeedNewCabinet read FOnNeed write FOnNeed; end; {$IFDEF UNITVERSIONING} const UnitVersioning: TUnitVersionInfo = ( RCSfile: '$URL$'; Revision: '$Revision$'; Date: '$Date$'; LogPath: 'JVCL\run' ); {$ENDIF UNITVERSIONING} implementation uses StrUtils, WinConvTypes, JvSetupAPI, JvConsts, JvResources; constructor TJvCABFile.Create(AOwner: TComponent); begin inherited Create(AOwner); FFiles := TStringList.Create; FFileName := ''; LoadSetupApi; if not IsSetupApiLoaded then raise EJVCLException.CreateRes(@RsEErrorSetupDll); end; destructor TJvCABFile.Destroy; begin FFiles.Free; UnloadSetupApi; inherited Destroy; end; procedure TJvCABFile.SetFileName(const Value: TFileName); begin FFileName := Value; RefreshFiles; end; function TJvCABFile.GetFiles: TStrings; begin Result := FFiles; end; procedure TJvCABFile.SetFiles(const Value: TStrings); begin //do nothing !!!! end; function CBack(Context: Pointer; Notification: UINT; Param1, Param2: UINT_PTR): UINT; stdcall; var CAB: PFileInCabinetInfo; Sender: TJvCABFile; CABInfo: TCABInfo; ParamInfo: PCabinetInfo; begin Result := ERROR_BAD_COMMAND; if Context <> nil then Sender := TJvCABFile(Context^) else Exit; // this callback is only for listing files in a Cabinet ... pouet pouet ! if Notification = SPFILENOTIFY_FILEINCABINET then // found a file in the Cabinet begin Result := FILEOP_SKIP; CAB := PFileInCabinetInfo(Param1); Sender.Files.Add(StrPas(CAB^.NameInCabinet)); end else if Notification = SPFILENOTIFY_CABINETINFO then // give Cabinet info begin if Assigned(Sender.FOnCABInfo) and (Param1 <> 0) then begin ParamInfo := PCabinetInfo(Param1); CABInfo.CabinetPath := StrPas(ParamInfo^.CabinetPath); CABInfo.CabinetFile := StrPas(ParamInfo^.CabinetFile); CABInfo.DiskName := StrPas(ParamInfo^.DiskName); CABInfo.Id := ParamInfo^.SetId; CABInfo.CabinetNumber := ParamInfo^.CabinetNumber; Sender.FOnCABInfo(Sender, CABInfo); end; Result := 0; end; end; function CExtract(Context: Pointer; Notification: UINT; Param1, Param2: UINT_PTR): UINT; stdcall; type PUINT_PTR = ^UINT_PTR; var CAB: PFileInCabinetInfo; Sender: TJvCABFile; CABInfo: TCABInfo; Cont: Boolean; Pathes: TFilePaths; Path: string; I: Integer; begin Result := ERROR_BAD_COMMAND; if Context <> nil then Sender := TJvCABFile(Context^) else Exit; // this callback is only for listing files in a Cabinet ... if Notification = SPFILENOTIFY_CABINETINFO then Result := 0 else if Notification = SPFILENOTIFY_FILEINCABINET then // found a file in the Cabinet begin try Result := FILEOP_DOIT; CAB := PFileInCabinetInfo(Param1); if Sender.FDestPath[Length(Sender.FDestPath)] = '\' then begin // extract all Path := Sender.FDestPath + StrPas(CAB^.NameInCabinet); for I := 1 to Length(Path) do CAB^.FullTargetName[I-1] := Path[I]; CAB^.FullTargetName[Length(Path)] := #0; if Assigned(Sender.FOnExtractFile) then Sender.FOnExtractFile(Sender, CAB^.FullTargetName, Sender.FDestPath); end else begin // Extract specific file if AnsiEndsText(StrPas(CAB^.NameInCabinet), Sender.FDestPath) then begin {CArends} if Length(Sender.FDestFileName) > 0 then Path := Sender.FDestFileName else {end-CArends} Path := Sender.FDestPath; for I := 1 to Length(Path) do CAB^.FullTargetName[I-1] := Path[I]; CAB^.FullTargetName[Length(Path)] := #0; if Assigned(Sender.FOnExtractFile) then Sender.FOnExtractFile(Sender, CAB^.FullTargetName, Sender.FDestPath); end else Result := FILEOP_SKIP; end; except Result := FILEOP_SKIP; end; end else if Notification = SPFILENOTIFY_FILEEXTRACTED then begin Cont := True; if Param1 <> 0 then Pathes := PFilePaths(Param1)^; if Assigned(Sender.FOnExtracted) then Sender.FOnExtracted(Sender, (Pathes.Win32Error = NO_ERROR), Cont, StrPas(Pathes.Source), StrPas(Pathes.Target)); if Cont then Result := NO_ERROR else Result := ERROR_BAD_COMMAND; end else if Notification = SPFILENOTIFY_NEEDNEWCABINET then begin if Param1 <> 0 then begin CABInfo.CabinetPath := StrPas(PCabinetInfo(Param1)^.CabinetPath); CABInfo.CabinetFile := StrPas(PCabinetInfo(Param1)^.CabinetFile); CABInfo.DiskName := StrPas(PCabinetInfo(Param1)^.DiskName); CABInfo.Id := PCabinetInfo(Param1)^.SetId; CABInfo.CabinetNumber := PCabinetInfo(Param1)^.CabinetNumber; Cont := True; Path := ''; if Assigned(Sender.FOnNeed) then begin Sender.FOnNeed(Sender, Cont, CABInfo, Path); Sender.FTmpString := Path; PUINT_PTR(Param2)^ := UINT_PTR(PChar(Sender.FTmpString)); end else Result := ERROR_BAD_COMMAND; end else Result := ERROR_BAD_COMMAND; end; end; procedure TJvCABFile.RefreshFiles; begin Files.Clear; if SetupIterateCabinet(PChar(FFileName), 0, CBack, @Self) then if Assigned(FOnFiles) then FOnFiles(Self); end; function TJvCABFile.ExtractAll(DestPath: string): Boolean; begin if DestPath[Length(DestPath)] <> PathDelim then DestPath := DestPath + PathDelim; FDestPath := DestPath; Result := SetupIterateCabinet(PChar(FFileName), 0, CExtract, @Self); end; function TJvCABFile.ExtractFile(FileName, DestPath: string): Boolean; begin if DestPath[Length(DestPath)] <> PathDelim then DestPath := DestPath + PathDelim; FDestPath := DestPath + FileName; Result := SetupIterateCabinet(PChar(FFileName), 0, CExtract, @Self); end; {CArends} function TJvCABFile.ExtractFile(FileName, DestPath, DestFileName: string): Boolean; begin if DestPath[Length(DestPath)] <> PathDelim then DestPath := DestPath + PathDelim; FDestFileName := DestPath + DestFileName; Result := ExtractFile(FileName, DestPath); FDestFileName := ''; end; {end-CArends} {$IFDEF UNITVERSIONING} initialization RegisterUnitVersion(HInstance, UnitVersioning); finalization UnregisterUnitVersion(HInstance); {$ENDIF UNITVERSIONING} end.