Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

TRARunrar

NEW 2025 32-bit and 64-bit Delphi wrapper for unrar.dll

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate this project.

README

winrarbanner03

TRAR

This complete re-envisioning, re-architecting and re-writing of Phillipe Wechsler's 2008/2009 Delphi component now supports both the 32-bit and 64-bit versions of unrar.dll from rarlab.com

listArchive, testArchive and extractArchive tested and working against the latest versions of unrar.dll (v7.11.1.1525 - 2025/03/19), including multi-volume RAR archives.

See below for usage examples.

TRAR as a Delphi IDE component has now been added. TRAR works just as well when used as standalone, included (i.e. "uses") units in a Delphi project, which is how I use it in my own projects. TRAR as a Delphi IDE component has been included purely in keeping with Phillipe's original.

A basic test project is included which will be enhanced based on feedback. TRAR has been, and continues to be, extensively used and tested in my own projects, which are not currently open source. I hope to rectify that in due course.

Updates, comments and suggestions always welcome on the Issues page.

My Extractor application (https://github.com/BazzaCuda/Extractorr contains a wrapper for 7z.dll. TRAR will be incorporated into that application at some point (primarily to support multi-volume RAR archives) and will therefore serve as an additional test project for TRAR (2025/03/24: this has now been done)

Of course, big thanks are due to Phillipe for his original 32-bit component, some 16 years ago!

N.B. If you download the DLL from rarlab.com, the code expects you to rename unrar.dll to either unrar32.dll or unrar64.dll, as appropriate, so that you can easily switch between compiling and running your application for either architecture; both DLLs are included for download in this project's releases.


Update History

v2.3 (2025-03-26)

WinRAR and UnRAR both create (and report) some very peculiar non-standard file attributes in RAR archives, both for directories and for files, e.g. 20020, 80010, 1A0010 and 1A0020. This makes distinguising directories from files more difficult than it should be.

After some investigation, it appears to be more reliable to simply check for the TRARHeaderDataEx.flags = 32 (see processFileHeader in RAR.pas), which seems to be consistent even when the non-standard file attributes are present.

N.B. listArchive should only lists files. Any directory paths will be included in the filenames.

v2.2 (2025-03-25)

Allow for RAR archives created [by a RarLab application] on Linux and Unix variants, e.g. Android. These have different file attribute values for files and directories which prevented TRAR from listing the files in such archives.

v2.1 (2025-03-21)

Correction to TRAROpenArchiveDataEx in line with unrar's C struct which was preventing any archive comment from being read.

Some header flags are not available when the RAR archive's header is encrypted - the comments in TRAR.processOpenArchive now reflect this.

Added findFiles, general-purpose file-finding function which defaults to finding .rar archives. see usage below.

Created a separate registerTRAR.pas unit for compiling the package project and for installing/updating the component. Having the registration code in RAR.pas was preventing 32-bit applications from being compiled as they had no access to DesignEditors and DesignIntf.


Planned Development

  • Extract a single file to a TStream instead of directly to disk

Recommended way to stay up to date with development

  1. Install the free "GitHub Desktop" for Windows (https://desktop.github.com/download//
  2. Clone the TRAR repository to a folder on your computer: File -> Clone Repository -> URL -> https://github.com/BazzaCuda/TRARunrar/
  3. "Use" RAR.pas directly from this folder in your Delphi projects.
  4. Check for updates periodically - indicated automatically in GitHub Desktop.
  5. If you do decide to install the TRAR component in your Delphi IDE, don't "Save changes to project RARComponent_D12?" when you close the TRAR package project.

Example usage:

delphi
uses
  RAR;

type
  TUI = class(TForm)
  strict private
    FRAR: TRAR;
  property
    RAR: TRAR read FRAR write FRAR;
  end; 

  procedure TUI.FormCreate(Sender: TObject);
  begin
    RAR                     := TRAR.create(SELF);
    RAR.onError             := RARError;
    RAR.onListFile          := RARListFile;
    RAR.onPasswordRequired  := RARPasswordRequired;
  end;

Testing a RAR archive:

delphi
case RAR.testArchive(archivePath) of FALSE: showMessage('Test Failed!'); end;

Getting information about the RAR archive:

delphi

  TRARArchiveInfo = record // defined in RAR.pas
    fileName:             Ansistring;
    fileNameW:            WideString;

    volume:               boolean;
    archiveComment:       boolean;
    locked:               boolean;
    solid:                boolean;
    newNumbering:         boolean;
    signed:               boolean;
    recovery:             boolean;
    headerEncrypted:      boolean;
    firstVolume:          boolean;
    SFX:                  boolean;
    
    packedSizeMVVolume:   cardinal;
    archiverMajorVersion: cardinal;
    archiverMinorVersion: cardinal;
    hostOS:               string;
    totalFiles:           integer;
    dictionarySize:       int64;
    compressedSize:       int64;
    unCompressedSize:     int64;
    multiVolume:          boolean;
    fileComment:          boolean;
  end;

  ...

// use prepareArchive to populate the TRARArchiveInfo record if you haven't yet performed one
// of the other RAR operations such as testArchive, listArchive, extractArchive
  RAR.prepareArchive(archivePath);
  chbHeaderEncrypted.checked := RAR.archiveInfo.headerEncrypted;

Getting information about each file in a RAR archive:

delphi

  TRARFileItem = record // defined in RAR.pas
    fileName:             AnsiString;
    fileNameW:            WideString;
    splitFile:            boolean;
    compressedSize:       cardinal;
    unCompressedSize:     cardinal;
    hostOS:               string;
    CRC32:                string;
    attributes:           cardinal;
    comment:              AnsiString;
    time:                 TDateTime;
    compressionStrength:  cardinal;
    archiverVersion:      cardinal;
    encrypted:            boolean;
    hash:                 string;
  end;

  ...

  RAR.onListFile := RARListFile; // must be procedure of object

  ...

  procedure TIndexer.RARListFile(const aFileItem: TRARFileItem);
  // fileName includes any path information in the RAR archive, e.g. folder1/file1.txt
  // this full path for each file must also be passed to extractArchive() or addFile() when specifying which files to extract
  begin
    memo1.lines.add(aFileItem.fileName); 
  end;

  ...

  RAR.listArchive(archivePath); // calls onListFile for each file in the RAR archive

  // RAR.archiveinformation.?  is also available now.

Extracting the entire RAR archive to a folder:

delphi
  RAR.extractArchive(archiveFile, extractPath); // TRAR will "forceDirectories()" the extraction path as necessary

  // RAR.archiveinformation.?  is also available now.

Extracting an individual file from a RAR archive:

delphi
  RAR.extractArchive(archiveFile, extractPath, filePath); // filePath is the entire path to the file _inside_ the RAR archive, including any subfolders

  // RAR.archiveinformation.?  is also available now.

Extracting a list of files from a RAR archive:

delphi
  RAR.clearFiles;
  RAR.prepareArchive(archiveFile); // reduces the internal overheads involved in repeated extractions

  // RAR.archiveinformation.?  is also available now.
  
  for i := 0 to memo1.lines.count - 1 do
    RAR.addFile(memo1.lines[i]); // must be the full path to the file in the RAR archive, e.g. folder1/myfile.txt

  showMessage(format('Extracting %d files', [RAR.fileCount]));
    
  RAR.extractPreparedArchive(archiveFile, extractPath);
  RAR.clearFiles; // good practice as this list takes precedence over specifying an individual file with RAR.extractArchive(archiveFile, extractPath, filePath);

Providing a password:

You can either provide a password up-front before calling the RAR operation, or you can provide the password when TRAR requests it.

Up-Front:

delphi
  RAR.password := 'this is the pw';
  RAR.testArchive(archivePath);

  // RAR.archiveinformation.?  is also available now.

On Request:

delphi
  RAR.onPasswordRequired := RARPasswordRequired; // must be procedure of object

  ...

  procedure TIndexer.RARPasswordRequired(const aFileName: AnsiString; out oNewPassword: AnsiString; out oCancel: boolean);
  begin
    case aFileName = 'I_know_this_pw.txt' of  TRUE: oNewPassword := 'this is the password';
                                             FALSE: oCancel      := TRUE;
    end;
  end;

Receiving error codes during RAR operations:

delphi
  RAR.onError := RARError; // must be procedure of object
  ...
  // the error codes and operations are defined in RAR_DLL.pas
  procedure TForm1.RARError(Sender: TObject; const aErrorCode: Integer; const aOperation: TRAROperation);
  begin
    lblError.caption := format('code: %d, operation: %d', [aErrorCode, aOperation]);
  end;

Checking the result after a RAR operation:

delphi
   RAR.testArchive(archivePath);
   label1.caption := format('RAR Result: %d', [RAR.lastResult]);

Receiving feedback during RAR operations:

delphi
  TRARProgressInfo = record // defined in RAR.pas
    fileName:           WideString; // the full path to the file within the RAR archive
    archiveBytesTotal:  LongInt;
    archiveBytesDone:   LongInt;
    fileBytesTotal:     LongInt;
    fileBytesDone:      LongInt;
  end;

  RAR.onProgress := RARProgress; // must be procedure of object
  ...
  // this gets called periodically during UnRAR.dll's processing, typically after each 4MB chunk of data (4,194,304 bytes)
  // onProgress will be called once only for each file that is smaller than this.
  procedure TIndexer.RARProgress(Sender: TObject; const aProgressInfo: TRARProgressInfo);
  begin
    // Sender is the TRAR object instance
    // N.B. excessive updating of labels and progressBars can have a detrimental effect on operational speed
    //      especially when extracting a long list of files (see addFile() above) 
  end;

Multi-Volume RAR archives:

These days, all the files of a multi-volume RAR archive (archive.part1.rar, archive.part2.rar, etc) will typically be in the same folder together and named correctly.

If this is the case, TRAR and unrar.dll will handle multi-volume RAR archives automatically. This applies to RAR archives that are numbered starting with ...part1.rar, or ...part01.rar, or ...part001.rar, etc.

On the rare occasion that they're in different locations, or the secondary parts haven't all been named uniformally, you can get TRAR to ask you for the full path to the next volume:

delphi
  RAR.onNextVolRequired := RARNextVolRequired; // must be procedure of object;
  ...
  procedure TIndexer.RARNextVolRequired(Sender: TObject; const aRequiredFileName: Ansistring; out oNewFileName: Ansistring; out oCancel: boolean);
  begin
    // Sender is the TRAR object instance
    case aRequiredFileName = 'myarchive.part6.rar' of  TRUE: oNewFileName := 'C:\Windows\System32\Whats_It_Doing_Here.part006.rar';
                                                      FALSE: oCancel      := TRUE; // no idea where it is
    end;
  end;

Helper functions which don't require opening the RAR archive:

delphi
  var vIsMultiVol := RAR.isMultiVol(archivePath); // is the filename a .part1.rar, .part01.rar or .part001.rar ?
delphi
  var vIsMultiVolPart := RAR.isMultiVolPart(archivePath); // is the filename .part2.rar, .part02.rar, .part002.rar or a later part?
delphi
function TRAR.findFiles(const aFolderPath: string; bSubFolders: boolean = TRUE; const aFileExts: string = '.rar'): integer;
// populates an internal TStringList to which you have full access via RAR.foundFiles
// returns the number of files in the list
// doesn't clear the list - that is left to the caller.
...
  var vFileCount := RAR.findFiles('C:\MyFiles\'); // defaults to recursing into sub-folders and finding files with .rar extension
  memo1.lines.assign(RAR.foundFiles);

Although it defaults to finding '.rar' files, findFiles is a general-purpose file finder. It will, however, always ignore multi-part volumes from part2/part02/part002 onwards. It will also currently ignore system files and folders, and hidden files and folders.

delphi
  RAR.foundFiles.clear;
  RAR.findFiles('C:\MyFiles', TRUE, '.txt.doc.rar.zip.dat');
...
  RAR.findFiles('C:\MyOtherFiles\', FALSE, ''); // empty extension list finds all files
...
  RAR.foundFiles.sorted := TRUE; 
  for var i := 0 to RAR.foundFiles.count - 1 do
    showMessage('Found another one: ' + RAR.foundFiles[i];

Get the DLL's file name:

delphi
  var vDLLName := RAR.DLLName; // will be unrar32.dll or unrar64.dll

Get the DLL's version number:

delphi
  var vDLLVersion: integer := RAR.DLLVersion;
// Currently v9, a constant defined in unrar.dll
// N.B. This is not the build version, which is currently v7.11.1.1525
delphi

  

More on the way