Написание плагина Total Commader .WCX (упаковщика)

Я пытаюсь создать простой плагин WCX для Total Commander.

Я скачал wcxhead.pas отсюда (это в файле справки): http://ghisler.fileburst.com/plugins/wcx_ref2.21se_chm.zip

Это официальный файл, ссылка на который приведена здесь: https://www.ghisler.com/plugins.htm

И создал свою собственную DLL:

library TST;

uses
  Windows,
  SysUtils,
  Classes,
  wcxhead;

{$E wcx}

var Num: Integer;

function OpenArchive (var ArchiveData: tOpenArchiveData): THANDLE; stdcall;
begin
  Result := 99999;

  Num := 0;
end;

function ReadHeader(hArcData: THANDLE; var HeaderData: tHeaderData): Integer; stdcall;
begin
  with HeaderData do begin

    FileName := 'my_file.ext';
    PackSize := 1000;
    UnpSize  := 2000;
    FileTime := 1876543;
    FileAttr := $3F;

  end;

  if Num < 1 then Result := 0
  else Result := E_END_ARCHIVE;

  Inc(Num);
end;

function ProcessFile(hArcData: THANDLE; Operation: Integer; DestPath: PChar; DestName: PChar): Integer; stdcall;
begin
  Result := 0;
end;

function CloseArchive(hArcData: THANDLE): Integer; stdcall;
begin
  Result := 0;
end;

procedure SetChangeVolProc(hArcData: THANDLE; pChangeVolProc1: tChangeVolProc);stdcall;
begin
//
end;

procedure SetProcessDataProc(hArcData: THANDLE; pProcessDataProc: tProcessDataProc); stdcall;
begin
//
end;

exports
  OpenArchive, ReadHeader, ProcessFile, CloseArchive, SetChangeVolProc, SetProcessDataProc;

end.

Вот wcxhead.pas

unit wcxhead;

interface





const       {Error codes returned to calling application}
  E_END_ARCHIVE=     10;       {No more files in archive}
  E_NO_MEMORY=       11;       {Not enough memory}
  E_BAD_DATA=        12;       {CRC error in the data of the currently unpacked file}
  E_BAD_ARCHIVE=     13;       {The archive as a whole is bad, e.g. damaged headers}
  E_UNKNOWN_FORMAT=  14;       {Archive format unknown}
  E_EOPEN=           15;       {Cannot open existing file}
  E_ECREATE=         16;       {Cannot create file}
  E_ECLOSE=          17;       {Error closing file}
  E_EREAD=           18;       {Error reading from file}
  E_EWRITE=          19;       {Error writing to file}
  E_SMALL_BUF=       20;       {Buffer too small}
  E_EABORTED=        21;       {Function aborted by user}
  E_NO_FILES=        22;       {No files found}
  E_TOO_MANY_FILES=  23;       {Too many files to pack}
  E_NOT_SUPPORTED=   24;       {Function not supported}

  {Unpacking flags}
  PK_OM_LIST=           0;
  PK_OM_EXTRACT=        1;

  {Flags for ProcessFile}
  PK_SKIP=              0;     {Skip file (no unpacking)}
  PK_TEST=              1;     {Test file integrity}
  PK_EXTRACT=           2;     {Extract file to disk}

  {Flags passed through ChangeVolProc}
  PK_VOL_ASK=           0;     {Ask user for location of next volume}
  PK_VOL_NOTIFY=        1;     {Notify app that next volume will be unpacked}

  {Packing flags}

  {For PackFiles}
  PK_PACK_MOVE_FILES=   1;    {Delete original after packing}
  PK_PACK_SAVE_PATHS=   2;    {Save path names of files}
  PK_PACK_ENCRYPT=      4;    {Ask user for password, then encrypt}


  {Returned by GetPackCaps}
  PK_CAPS_NEW=          1;    {Can create new archives}
  PK_CAPS_MODIFY=       2;    {Can modify exisiting archives}
  PK_CAPS_MULTIPLE=     4;    {Archive can contain multiple files}
  PK_CAPS_DELETE=       8;    {Can delete files}
  PK_CAPS_OPTIONS=     16;    {Supports the options dialogbox}
  PK_CAPS_MEMPACK=     32;    {Supports packing in memory}
  PK_CAPS_BY_CONTENT=  64;    {Detect archive type by content}
  PK_CAPS_SEARCHTEXT= 128;    {Allow searching for text in archives
                              { created with this plugin}
  PK_CAPS_HIDE=       256;    { Show as normal files (hide packer icon) }
                              { open with Ctrl+PgDn, not Enter }
  PK_CAPS_ENCRYPT=    512;    { Plugin supports PK_PACK_ENCRYPT option }

  BACKGROUND_UNPACK=1;        { Which operations are thread-safe? }
  BACKGROUND_PACK=2;
  BACKGROUND_MEMPACK=4;       { For tar.pluginext in background }

  {Flags for packing in memory}
  MEM_OPTIONS_WANTHEADERS=1;  {Return archive headers with packed data}

  {Errors returned by PackToMem}
  MEMPACK_OK=           0;    {Function call finished OK, but there is more data}
  MEMPACK_DONE=         1;    {Function call finished OK, there is no more data}

  {Flags for PkCryptProc callback}
  PK_CRYPT_SAVE_PASSWORD=1;
  PK_CRYPT_LOAD_PASSWORD=2;
  PK_CRYPT_LOAD_PASSWORD_NO_UI=3;   { Load password only if master password has already been entered!}
  PK_CRYPT_COPY_PASSWORD=4;         { Copy encrypted password to new archive name}
  PK_CRYPT_MOVE_PASSWORD=5;         { Move password when renaming an archive}
  PK_CRYPT_DELETE_PASSWORD=6;       { Delete password}


  PK_CRYPTOPT_MASTERPASS_SET = 1;   // The user already has a master password defined


type
  {Definition of callback functions called by the DLL}
  {Ask to swap disk for multi-volume archive}
  PChangeVolProc=^TChangeVolProc;
  TChangeVolProc=function(ArcName:pchar;Mode:longint):longint; stdcall;
  PChangeVolProcW=^TChangeVolProcW;
  TChangeVolProcW=function(ArcName:pwidechar;Mode:longint):longint; stdcall;
  {Notify that data is processed - used for progress dialog}
  PProcessDataProc=^TProcessDataProc;
  TProcessDataProc=function(FileName:pchar;Size:longint):longint; stdcall;
  PProcessDataProcW=^TProcessDataProcW;
  TProcessDataProcW=function(FileName:pwidechar;Size:longint):longint; stdcall;
  PPkPluginCryptProc=^TPkPluginCryptProc;
  TPkPluginCryptProc=function(CryptoNr:integer;mode:integer;ArchiveName,
    Password:pchar;maxlen:integer):integer; stdcall;
  PPkPluginCryptProcW=^TPkPluginCryptProcW;
  TPkPluginCryptProcW=function(CryptoNr:integer;mode:integer;ArchiveName,
    Password:pwidechar;maxlen:integer):integer; stdcall;

type
  THeaderData=packed record
    ArcName:array [0..259] of char;
    FileName:array [0..259] of char;
    Flags,
    PackSize,
    UnpSize,
    HostOS,
    FileCRC,
    FileTime,
    UnpVer,
    Method,
    FileAttr:longint;
    CmtBuf:pchar;
    CmtBufSize,
    CmtSize,
    CmtState:longint;
  end;

  THeaderDataEx=packed record
    ArcName:array [0..1023] of char;
    FileName:array [0..1023] of char;
    Flags:longint;
    PackSize,
    PackSizeHigh,
    UnpSize,
    UnpSizeHigh: Cardinal;
    HostOS,
    FileCRC,
    FileTime,
    UnpVer,
    Method,
    FileAttr:longint;
    CmtBuf:pchar;
    CmtBufSize,
    CmtSize,
    CmtState:longint;
    Reserved:array[0..1023] of char;
  end;

  THeaderDataExW=packed record
    ArcName:array [0..1023] of widechar;
    FileName:array [0..1023] of widechar;
    Flags:longint;
    PackSize,
    PackSizeHigh,
    UnpSize,
    UnpSizeHigh: Cardinal;
    HostOS,
    FileCRC,
    FileTime,
    UnpVer,
    Method,
    FileAttr:longint;
    CmtBuf:pchar;
    CmtBufSize,
    CmtSize,
    CmtState:longint;
    Reserved:array[0..1023] of char;
  end;

  tOpenArchiveData=packed record
    ArcName:pchar;
    OpenMode,
    OpenResult:longint;
    CmtBuf:pchar;
    CmtBufSize,
    CmtSize,
    CmtState:longint;
  end;

  tOpenArchiveDataW=packed record
    ArcName:pwidechar;
    OpenMode,
    OpenResult:longint;
    CmtBuf:pwidechar;
    CmtBufSize,
    CmtSize,
    CmtState:longint;
  end;

  tPackDefaultParamStruct=record
    size,
    PluginInterfaceVersionLow,
    PluginInterfaceVersionHi:longint;
    DefaultIniName:array[0..259] of char;
  end;
  pPackDefaultParamStruct=^tPackDefaultParamStruct;




implementation

end.

Установил плагин в Total Commander. Теперь Total Commander открывает мои файлы .TST, но не показывает никаких файлов внутри. Он должен показать «my_file.ext».

Я даже нашел простой плагин WCX, но не вижу никакой разницы с моим кодом в важных вещах: https://github.com/ypid-bot/doublecmd/blob/master/plugins/wcx/unbz2/src/bz2func.pas


person Tom    schedule 15.01.2020    source источник


Ответы (2)


Хорошо, вот проблема ($ 3F означает «Любой файл»):

FileAttr := $3F;

должно быть (0 означает "Файл"):

FileAttr := 0;
person Tom    schedule 15.01.2020

Заголовок явно был создан во времена Delphi до Unicode. Предполагается, что char = AnsiChar, что неверно, начиная с Delphi 2009.

IIRC с форумов, 32-разрядная версия TotalCommander по-прежнему скомпилирована с Delphi 2 или Delphi 3 с большим количеством пользовательских RTL, чтобы сохранить ее компактность и эффективность.

Если вы используете Unicode-версию Delphi, попробуйте изменить char на AnsiChar и использовать экспорт *W() с поддержкой Unicode.

Также не используйте глобальные переменные для сохранения состояния доступа к упаковщику: вы должны использовать значение THandle для открытия/закрытия данного файла архива. Два архива могут быть открыты одновременно.

Изменить: поскольку вы используете Delphi 7, это не проблема Unicode. Но я бы попробовал

strpcopy(filename,'my_file.ext');
person Arnaud Bouchez    schedule 15.01.2020
comment
Спасибо. Я использую totalcmd32 (32-битная версия) и Delphi 7. Так что он должен быть совместим - person Tom; 15.01.2020
comment
TotalCommander 8.0 (и выше) 64-разрядная версия, скомпилированная с помощью FreePascal. - person zed; 15.01.2020