This text is extracted from the original help file written in part by Jiri Barton.
The latest version of this reference and some packer plugins (part of them with source in C or Delphi) should be available on www.ghisler.com, addons section.
Copyright © 2000-2011 by Christian Ghisler, Ghisler Software GmbH. All Rights Reserved.
This help file is about writing packer plugins for the file manager Total Commander, available on www.ghisler.com. It describes the functions you need to implement to add a specific packer to Total Commander. You should also look at the available sample packers (with source), which give you some insight on plugin programming. There are samples for Microsoft Visual C++ and Delphi.
A WCX is nothing more than a 32-bit Windows DLL renamed to *.WCX, which supports a list of specific functions. Total Commander loads this library dynamically at runtime with LoadLibrary(), and loads all available functions with GetProcAddress(). This means that not all functions described here must be implemented (see below). All functions use the STDCALL calling convention with no C++ name mangling (see below), exactly like in most standard system libraries in Windows.
The minimum functions needed for a read-only plugin are:
All the following functions are optional. If you want to support them, you need to implement GetPackerCaps too, to tell Total Commander which functions are supported. If GetPackerCaps isn't available, Total Commander assumes that the plugin only supports unpacking. Even with a read-only plugin, you may want to implement GetPackerCaps and return PK_CAPS_SEARCHTEXT to allow Total Commander to search for text in archives of this type.
The first group allows to create or modify existing archives:
The following optional functions are for packing in memory:
This is used by Total Commander to create TAR.Plugin files in one step. For example, the .BZ2 plugin supports these functions. Most plugins can pack multiple files into one archive, and therefore will not need to implement these functions.
The following function tells the plugin to check whether it can handle the specified unknown file or not:
How Total Commander calls the extraction functions:
Here is a simple pseudocode declaration how Total Commander calls the extraction functions:
OpenArchive() with OpenMode==PK_OM_LIST repeat ReadHeader() ProcessFile(...,PK_SKIP,...) until error returned CloseArchive()
OpenArchive() with OpenMode==PK_OM_EXTRACT repeat ReadHeader() if WantToExtractThisFile() ProcessFile(...,PK_EXTRACT,...) else ProcessFile(...,PK_SKIP,...) until error returned CloseArchive()
Important note for C and C++ Programmers with Visual C++:
If using __stdcall the linker produces file names like "_ReadHeader@8"
To get a compatible plugin a "Def" file e.g. wcx.def has to be added to your project.
--Begin of wxc.def file to change export names for linker
EXPORTS CloseArchive=_CloseArchive@4 DeleteFiles=_DeleteFiles@8 GetPackerCaps=_GetPackerCaps@0 OpenArchive=_OpenArchive@4 PackFiles=_PackFiles@20 ProcessFile=_ProcessFile@16 ReadHeader=_ReadHeader@8 SetChangeVolProc=_SetChangeVolProc@8 SetProcessDataProc=_SetProcessDataProc@8 ConfigurePacker=_ConfigurePacker@8
--End of wcx.def file
The following function has been added to plugin version 2.21 second edition (all functions are otherwise unchanged):
The following function has been added to plugin version 2.21. It's optional:
The following function has been added to plugin version 2.20. It's optional:
The following function has been added to plugin version 2.12. It's optional:
The following function has been added to plugin version 2.1. It's optional:
The following functions have been added in packer plugin version 2.0. All of them are optional. Plugins written with the first specification will continue to work without changes.
OpenArchive should perform all necessary operations when an archive is to be opened.
HANDLE __stdcall OpenArchive (tOpenArchiveData *ArchiveData);
OpenArchive should return a unique handle representing the archive. The handle should remain valid until CloseArchive is called. If an error occurs, you should return zero, and specify the error by setting OpenResult member of ArchiveData.
You can use the ArchiveData to query information about the archive being open, and store the information in ArchiveData to some location that can be accessed via the handle.
Totalcmd calls ReadHeader to find out what files are in the archive.
int __stdcall ReadHeader (HANDLE hArcData, tHeaderData *HeaderData);
ReadHeader is called as long as it returns zero (as long as the previous call to this function returned zero). Each time it is called, HeaderData is supposed to provide Totalcmd with information about the next file contained in the archive. When all files in the archive have been returned, ReadHeader should return E_END_ARCHIVE which will prevent ReaderHeader from being called again. If an error occurs, ReadHeader should return one of the error values or 0 for no error.
hArcData contains the handle returned by OpenArchive. The programmer is encouraged to store other information in the location that can be accessed via this handle. For example, you may want to store the position in the archive when returning files information in ReadHeader.
In short, you are supposed to set at least PackSize, UnpSize, FileTime, and FileName members of tHeaderData. Totalcmd will use this information to display content of the archive when the archive is viewed as a directory.
ProcessFile should unpack the specified file or test the integrity of the archive.
int __stdcall ProcessFile (HANDLE hArcData, int Operation, char *DestPath, char *DestName);
ProcessFile should return zero on success, or one of the error values otherwise.
hArcData contains the handle previously returned by you in OpenArchive. Using this, you should be able to find out information (such as the archive filename) that you need for extracting files from the archive.
Unlike PackFiles, ProcessFile is passed only one filename. Either DestName contains the full path and file name and DestPath is NULL, or DestName contains only the file name and DestPath the file path. This is done for compatibility with unrar.dll.
When Total Commander first opens an archive, it scans all file names with OpenMode==PK_OM_LIST, so ReadHeader() is called in a loop with calling ProcessFile(...,PK_SKIP,...). When the user has selected some files and started to decompress them, Total Commander again calls ReadHeader() in a loop. For each file which is to be extracted, Total Commander calls ProcessFile() with Operation==PK_EXTRACT immediately after the ReadHeader() call for this file. If the file needs to be skipped, it calls it with Operation==PK_SKIP.
Each time DestName is set to contain the filename to be extracted, tested, or skipped. To find out what operation out of these last three you should apply to the current file within the archive, Operation is set to one of the following:
Constant | Value | Description |
---|---|---|
PK_SKIP | 0 | Skip this file |
PK_TEST | 1 | Test file integrity |
PK_EXTRACT | 2 | Extract to disk |
CloseArchive should perform all necessary operations when an archive is about to be closed.
int __stdcall CloseArchive (HANDLE hArcData);
CloseArchive should return zero on success, or one of the error values otherwise. It should free all the resources associated with the open archive.
The parameter hArcData refers to the value returned by a programmer within a previous call to OpenArchive.
This function allows you to notify user about changing a volume when packing files.
void __stdcall SetChangeVolProc (HANDLE hArcData, tChangeVolProc pChangeVolProc1);
pChangeVolProc1 contains a pointer to a function that you may want to call when notifying user to change volume (e.g. insterting another diskette). You need to store the value at some place if you want to use it; you can use hArcData that you have returned by OpenArchive to identify that place.
This function allows you to notify user about the progress when you un/pack files.
void __stdcall SetProcessDataProc (HANDLE hArcData, tProcessDataProc pProcessDataProc);
pProcessDataProc contains a pointer to a function that you may want to call when notifying user about the progress being made when you pack or extract files from an archive. You need to store the value at some place if you want to use it; you can use hArcData that you have returned by OpenArchive to identify that place.
PackFiles specifies what should happen when a user creates, or adds files to the archive.
int __stdcall PackFiles (char *PackedFile, char *SubPath, char *SrcPath, char *AddList, int Flags);
PackFiles should return zero on success, or one of the error values otherwise.
PackedFile refers to the archive that is to be created or modified. The string contains the full path.
SubPath is either NULL, when the files should be packed with the paths given with the file names, or not NULL when they should be placed below the given subdirectory within the archive. Example:
SrcPath contains path to the files in AddList. SrcPath and AddList together specify files that are to be packed into PackedFile. Each string in AddList is zero-delimited (ends in zero), and the AddList string ends with an extra zero byte, i.e. there are two zero bytes at the end of AddList.
Flags can contain a combination of the following values reflecting the user choice from within Totalcmd:
Constant | Value | Description |
---|---|---|
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 file with that password |
DeleteFiles should delete the specified files from the archive
int __stdcall DeleteFiles (char *PackedFile, char *DeleteList);
DeleteFiles should return zero on success, or one of the error values otherwise.
PackedFile contains full path and name of the archive.
DeleteList contains the list of files that should be deleted from the archive. The format of this string is the same as AddList within PackFiles.
GetPackerCaps tells Totalcmd what features your packer plugin supports.
int __stdcall GetPackerCaps();
Implement GetPackerCaps to return a combination of the following values:
Constant | Value | Description |
---|---|---|
PK_CAPS_NEW | 1 | Can create new archives |
PK_CAPS_MODIFY | 2 | Can modify existing archives |
PK_CAPS_MULTIPLE | 4 | Archive can contain multiple files |
PK_CAPS_DELETE | 8 | Can delete files |
PK_CAPS_OPTIONS | 16 | Has options dialog |
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 | Don't show packer icon, don't open with Enter but with Ctrl+PgDn |
PK_CAPS_ENCRYPT | 512 | Plugin supports encryption. |
Omitting PK_CAPS_NEW and PK_CAPS_MODIFY means PackFiles will never be called and so you don't have to implement PackFiles.
Omitting PK_CAPS_MULTIPLE means PackFiles will be supplied with just one file.
Leaving out PK_CAPS_DELETE means DeleteFiles will never be called.
Leaving out PK_CAPS_OPTIONS means ConfigurePacker will not be called.
PK_CAPS_MEMPACK enables the functions StartMemPack, PackToMem and DoneMemPack.
If PK_CAPS_BY_CONTENT is returned, Totalcmd calls the function CanYouHandleThisFile when the user presses Ctrl+PageDown on an unknown archive type.
Finally, if PK_CAPS_SEARCHTEXT is returned, Total Commander will search for text inside files packed with this plugin. This may not be a good idea for certain plugins like the diskdir plugin, where file contents may not be available.
If PK_CAPS_HIDE is set, the plugin will not show the file type as a packer. This is useful for plugins which are mainly used for creating files, e.g. to create batch files, avi files etc. The file needs to be opened with Ctrl+PgDn in this case, because Enter will launch the associated application.
If you change the return values of this function, e.g. add packing support, you need to reinstall the packer plugin in Total Commander, otherwise it will not detect the new capabilities.
ConfigurePacker gets called when the user clicks the Configure button from within "Pack files..." dialog box in Totalcmd.
void __stdcall ConfigurePacker (HWND Parent, HINSTANCE DllInstance);
Usually, you provide a user with a dialog box specifying a method and/or its parameters that should be applied in the packing process. Or, you just want to display a message box about what your plugin is, just like Christian Ghisler's DiskDir does.
In order to help you with a feedback, you can use a window handle of Totalcmd process, Parent. That is, you make your dialog box a child of Parent.
When creating a window, you may also need handle of the DLL (your DLL) that creates your dialog box, DllInstance.
You may decide not to implement this function. Then, make sure you omit PK_CAPS_OPTIONS from return values of GetPackerCaps.
StartMemPack starts packing into memory. This function is only needed if you want to create archives in combination with TAR, e.g. TAR.BZ2. It allows Totalcmd to create a TAR.Plugin file in a single step.
int __stdcall StartMemPack (int Options, char *FileName);
StartMemPack should return a user-defined handle (e.g. pointer to a structure) on success, zero otherwise.
FileName refers to the name of the file being packed - some packers store the name in the local header.
Options can contain a combination of the following values:
Constant | Value | Description |
---|---|---|
MEM_OPTIONS_WANTHEADERS | 1 | The output stream should include the complete headers (beginning+end) |
PackToMem packs the next chunk of data passed to it and/or returns the compressed data to the calling program. It is implemented together with StartMemPack and DoneMemPack
int __stdcall PackToMem (int hMemPack, char* BufIn, int InLen, int* Taken, char* BufOut, int OutLen, int* Written, int SeekBy);
PackToMem should return MEMPACK_OK (=0) on success, MEMPACK_DONE (=1) when done, or one of the error values otherwise.
hMemPack is the handle returned by StartMemPack()
BufIn is a pointer to the data which needs to be packed
InLen contains the number of bytes pointed to by BufIn
Taken has to receive the number of bytes taken from the buffer. If not the whole buffer is taken, the calling program will pass the remaining bytes to the plugin in a later call.
BufOut is a pointer to a buffer which can receive packed data
OutLen contains the size of the buffer pointed to by BufOut
Written has to receive the number of bytes placed in the buffer pointed to by BufOut
SeekBy may be set to the offset from the current output position by which the file pointer has to be moved BEFORE accepting the data in BufOut. This allows the plugin to modify a file header also AFTER packing, e.g. to write a CRC to the header.
PackToMem is the most complex function of the packer plugin. It is called by Total Commander in a loop as long as there is data to be packed, and as there is data to retrieve. The plugin should do the following:
DoneMemPack ends packing into memory. This function is used together with StartMemPack and PackToMem.
int __stdcall DoneMemPack (int hMemPack);
Return value: DoneMemPack should return zero if successful, or one of the error codes otherwise.
hMemPack is the handle returned by StartMemPack.
It may be called in two different cases:
CanYouHandleThisFile allows the plugin to handle files with different extensions than the one defined in Total Commander. It is called when the plugin defines PK_CAPS_BY_CONTENT, and the user tries to open an archive with Ctrl+PageDown.
BOOL __stdcall CanYouHandleThisFile (char *FileName);
CanYouHandleThisFile should return true (nonzero) if the plugin recognizes the file as an archive which it can handle. The detection must be by contents, NOT by extension. If this function is not implemented, Totalcmd assumes that only files with a given extension can be handled by the plugin.
Filename contains the fully qualified name (path+name) of the file to be checked.
PackSetDefaultParams is called immediately after loading the DLL, before any other function. This function is new in version 2.1. It requires Total Commander >=5.51, but is ignored by older versions.
void __stdcall PackSetDefaultParams(PackDefaultParamStruct* dps);
dps | This structure of type PackDefaultParamStruct currently contains the version number of the plugin interface, and the suggested location for the settings file (ini file). It is recommended to store any plugin-specific information either directly in that file, or in that directory under a different name. Make sure to use a unique header when storing data in this file, because it is shared by other file system plugins! If your plugin needs more than 1kbyte of data, you should use your own ini file because ini files are limited to 64k. |
Return value: the function has no return value.
This function is only called in Total Commander 5.51 and later. The plugin version will be >= 2.1.
PkSetCryptCallback is called when loading the plugin. The passed values should be stored in the plugin for later use. This function is only needed if you want to use the secure password store in Total Commander.
void __stdcall PkSetCryptCallback(tPkCryptProc pPkCryptProc, int CryptoNr, int Flags);
pPkCryptProc | Pointer to the crypto callback function. See PkCryptProc for a description of this function |
CryptoNr | A parameter which needs to be passed to the callback function |
Flags | Flags regarding the crypto connection. Currently only PK_CRYPTOPT_MASTERPASS_SET is defined. It is set when the user has defined a master password. |
Return value: this function does not return any value.
You can use this callback function to store passwords in Total Commander's secure password store. The user will be asked for the master password automatically.
Totalcmd calls ReadHeaderEx to find out what files are in the archive. This function is always called instead of ReadHeader if it is present. It only needs to be implemented if the supported archive type may contain files >2 GB. You should implement both ReadHeader and ReadHeaderEx in this case, for compatibility with older versions of Total Commander.
int __stdcall ReadHeaderEx (HANDLE hArcData, tHeaderDataEx *HeaderDataEx);
ReadHeaderEx is called as long as it returns zero (as long as the previous call to this function returned zero). Each time it is called, HeaderDataEx is supposed to provide Totalcmd with information about the next file contained in the archive. When all files in the archive have been returned, ReadHeaderEx should return E_END_ARCHIVE which will prevent ReaderHeaderEx from being called again. If an error occurs, ReadHeaderEx should return one of the error values or 0 for no error.
hArcData contains the handle returned by OpenArchive. The programmer is encouraged to store other information in the location that can be accessed via this handle. For example, you may want to store the position in the archive when returning files information in ReadHeaderEx.
In short, you are supposed to set at least PackSize, PackSizeHigh, UnpSize, UnpSizeHigh, FileTime, and FileName members of tHeaderDataEx. Totalcmd will use this information to display content of the archive when the archive is viewed as a directory.
GetBackgroundFlags is called to determine whether a plugin supports background packing or unpacking.
int __stdcall GetBackgroundFlags(void);
GetBackgroundFlags should return one of the following values:
Constant | Value | Description |
---|---|---|
BACKGROUND_UNPACK | 1 | Calls to OpenArchive, ReadHeader(Ex), ProcessFile and CloseArchive are thread-safe (unpack in background) |
BACKGROUND_PACK | 2 | Calls to PackFiles are thread-safe (pack in background) |
BACKGROUND_MEMPACK | 4 | Calls to StartMemPack, PackToMem and DoneMemPack are thread-safe |
To make your packer plugin thread-safe, you should remove any global variables which aren't the same for all pack or unpack operations. For example, the path to the ini file name can remain global, but something like the compression ratio, or file handles need to be stored separately.
Packing: The PackFiles function is just a single call, so you can store all variables on the stack (local variables of that function).
Unpacking: You can allocate a struct containing all the variables you need across function calls, like the compression method and ratio, and state variables, and return a pointer to this struct as a result to OpenArchive. This pointer will then passed to all other functions like ReadHeader as parameter hArcData.
Pack in memory: You can do the same in StartMemPack as described under Unpacking.
tHeaderData is a structure used in ReadHeader.
typedef struct { char ArcName[260]; char FileName[260]; int Flags; int PackSize; int UnpSize; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tHeaderData;
ArcName, FileName, PackSize, UnpSize contain the name of the archive, the name of the file within the archive, size of the file when packed, and the size of the file when extracted, respectively.
HostOS is there for compatibility with unrar.dll only, and should be set to zero.
FileCRC is the 32-bit CRC (cyclic redundancy check) checksum of the file. If not available, set to zero.
The Cmt* values can be used to transfer file comment information. They are currently not used in Total Commander, so they may be set to zero.
FileAttr can be set to any combination of the following values:
Value | Description |
---|---|
0x1 | Read-only file |
0x2 | Hidden file |
0x4 | System file |
0x8 | Volume ID file |
0x10 | Directory |
0x20 | Archive file |
0x3F | Any file |
FileTime contains the date and the time of the file's last update. Use the following algorithm to set the value:
FileTime = (year - 1980) << 25 | month << 21 | day << 16 | hour << 11 | minute << 5 | second/2;
Make sure that:tHeaderDataEx is a structure used in ReadHeaderEx.
typedef struct { char ArcName[1024]; char FileName[1024]; int Flags; unsigned int PackSize; unsigned int PackSizeHigh; unsigned int UnpSize; unsigned int UnpSizeHigh; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; char Reserved[1024]; } tHeaderDataEx;
ArcName, FileName, PackSize, UnpSize contain the name of the archive, the name of the file within the archive, size of the file when packed, and the size of the file when extracted, respectively. PackSizeHigh, UnpSizeHigh contain the upper 32 bit of a 64-bit size number. Set to 0 if the file is smaller than 4 GB.
HostOS is there for compatibility with unrar.dll only, and should be set to zero.
FileCRC is the 32-bit CRC (cyclic redundancy check) checksum of the file. If not available, set to zero.
The Cmt* values can be used to transfer file comment information. They are currently not used in Total Commander, so they may be set to zero.
FileAttr can be set to any combination of the following values:
Value | Description |
---|---|
0x1 | Read-only file |
0x2 | Hidden file |
0x4 | System file |
0x8 | Volume ID file |
0x10 | Directory |
0x20 | Archive file |
0x3F | Any file |
FileTime contains the date and the time of the file's last update. Use the following algorithm to set the value:
FileTime = (year - 1980) << 25 | month << 21 | day << 16 | hour << 11 | minute << 5 | second/2;
Make sure that:Reserved may be used in the future for additional data - you MUST set it to 0 for now to avoid problems with future versions of TC.
The Unicode version of this structure uses WCHAR[1024] for ArcName and FileName. "Reserved" is unchanged.
tOpenArchiveData is used in OpenArchive.
typedef struct { char* ArcName; int OpenMode; int OpenResult; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tOpenArchiveData;
ArcName contains the name of the archive to open.
OpenMode is set to one of the following values:
Constant | Value | Description |
---|---|---|
PK_OM_LIST | 0 | Open file for reading of file names only |
PK_OM_EXTRACT | 1 | Open file for processing (extract or test) |
OpenResult used to return one of the error values if an error occurs.
The Cmt* variables are for the file comment. They are currently not used by Total Commander, so may be set to NULL.
If the file is opened with OpenMode==PK_OM_LIST, ProcessFile will never be called by Total Commander.
The Unicode version of this function uses WCHAR* instead of char* for the text fields.
PackDefaultParamStruct is passed to PackSetDefaultParams to inform the plugin about the current plugin interface version and ini file location.
typedef struct { int size; DWORD PluginInterfaceVersionLow; DWORD PluginInterfaceVersionHi; char DefaultIniName[MAX_PATH]; } PackDefaultParamStruct;
size | The size of the structure, in bytes. Later revisions of the plugin interface may add more structure members, and will adjust this size field accordingly. |
PluginInterfaceVersionLow | Low value of plugin interface version. This is the value after the comma, multiplied by 100! Example. For plugin interface version 2.1, the low DWORD is 10 and the high DWORD is 2. |
PluginInterfaceVersionHi | High value of plugin interface version. |
DefaultIniName | Suggested location+name of the ini file where the plugin could store its data. This is a fully qualified path+file name, and will be in the same directory as the wincmd.ini. It's recommended to store the plugin data in this file or at least in this directory, because the plugin directory or the Windows directory may not be writable! |
tProcessDataProc is a typedef of the function that notifies the user about the progress when un/packing files.
typedef int (__stdcall *tProcessDataProc)(char *FileName, int Size);
SetProcessDataProc has provided you with a pointer to a function with this declaration. When you want to notify the user about the progress when un/packing files, call this function with appropriate parameters. The function itself is part of Totalcmd - you only specify what Totalcmd should display. In addition, Totalcmd displays the Cancel button that allows the user to abort the un/packing process. If the user has clicked on Cancel, the function returns zero.
FileName can be used to pass a pointer to the currently processed filename (0 terminated string), or NULL if it is not available.
Set Size to the number of bytes processed since the previous call to the function. For plugins which unpack in CloseArchive: Set size to negative percent value (-1..-100) to directly set first percent bar, -1000..-1100 for second percent bar (-1000=0%).
The keyword or constant __stdcall must be set according to the compiler that you will use to make the library. For example, this is STDCALL for cygwin and __stdcall for MSC.
tChangeValueProc is a typedef of the function that asks the user to change volume.
typedef int (__stdcall *tChangeVolProc)(char *ArcName, int Mode);
SetChangeVolProc has provided you with a pointer to a function with this declaration. When you want the user to be asked about changing volume, call this function with appropriate parameters. The function itself is part of Totalcmd - you only specify the question. Totalcmd then asks the user, and you get the answer as the result of the call to this function. If the user has aborted the operation, the function returns zero.
ArcName specifies the filename of the archive that you are processing, and will receive the name of the next volume.
Set Mode to one of the following values, according to what you want Totalcmd to ask the user:
Constant | Value | Description |
---|---|---|
PK_VOL_ASK | 0 | Ask user for location of next volume |
PK_VOL_NOTIFY | 1 | Notify app that next volume will be unpacked |
The keyword or constant __stdcall must be set according to the compiler that you will use to make the library. For example, this is STDCALL for cygwin and __stdcall for MSC.
tPkCryptProc is a callback function, which the plugin can call to store passwords in the secure password store, read them back, or copy them to a new connection.
typedef int (__stdcall *tPkCryptProc)(int CryptoNumber, int mode, char* ArchiveName, char* Password, int maxlen);
CryptoNumber | Here the plugin needs to pass the crypto number received through the PkSetCryptCallback function. |
mode | The mode of operation:
|
ArchiveName | Name of the archive for this operation. The plugin can give any name here which can be stored in Windows ini files. The plugin should encode names which cannot be stored in ini files, or give a reference code or so instead of the file name. |
Password | Operation-specific, usually the password to be stored/retrieved, or the target name when copying/moving a connection |
maxlen | Maximum length, in characters, the password buffer can store when calling one of the load functions |
Total Commander returns one of these values:
FS_FILE_OK | Success |
E_ECREATE | Encrypt/Decrypt failed |
E_EWRITE | Could not write password to password store |
E_EREAD | Password not found in password store |
E_NO_FILES | No master password entered yet |
When showing the details of an existing archive, you should call PK_CRYPT_LOAD_PASSWORD_NO_UI first. In case of error E_NO_FILES, show a button "Edit password". Only call PK_CRYPT_LOAD_PASSWORD when the user clicks that button, or tries to decrypt the archive. This way the user doesn't have to enter the master password if he just wanted to make some other changes to the archive settings.
Use the following values when you want to inform Totalcmd that an error ocurred.
Constant | Value | Description |
---|---|---|
0 | Success | |
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 |
With Total Commander 7.5 (packer plugin interface 2.20), Unicode support has been added to all plugin types. In principle, you need to implement the same functions as for ANSI, with two differences: The function name is changed from FunctionName to FunctionNameW, and Ansi strings are changed to wide char names.
Total Commander will call the Unicode functions on all NT-based systems (Windows NT, 2000, XP) if they are present. If not, or on Windows 9x/ME, Total Commander will call the Ansi functions.
The following functions of the packer plugin interface support Unicode:
The following functions do not exist in a Unicode form and must be implemented as Ansi:
What's the easiest way to support Unicode in an existing plugin?
int __stdcall FunctionName(char* SomeString1, char* SomeString2) { WCHAR SomeString1W[wdirtypemax], SomeString2W[wdirtypemax]; return FunctionNameW( awfilenamecopy(SomeString1W, SomeString1), awfilenamecopy(SomeString2W, SomeString2)); }The Macro awfilenamecopy will convert the Ansi string SomeString1 to Unicode and store it in SomeString1W. This variable must not be a pointer, because awfilenamecopy uses "countof" to get the target length.
With Total Commander 8, Total Commander is now also available in 64-bit. Since plugins are simple dlls, and 64-bit programs can only load 64-bit dlls, a plugin needs to be re-compiled with a 64-bit compiler to work with 64-bit Total Commander.
IMPORTANT: A 64-bit plugin must have the same name as the 32-bit plugin and be in the same directory, but '64' must be appended to the extension. Example: filesystem.wcx → filesystem.wcx64. 64-bit-only plugins must also end with '64'.
Since all 64-bit Windows versions support Unicode, it's sufficient to write a 64-bit Unicode-only plugin. However, if your existing 32-bit plugin only supports ANSI functions, you can port it without modifications to 64 bit. Total Commander 64-bit also supports the ANSI functions if it cannot find the Unicode functions. 64-bit Unicode plugins do not have an extension starting with 'u', they have the normal 'wcx64' extension.
Some porting notes:
All integer parameters in plugin functions remain 32-bit (e.g. in C: int, long, DWORD; Delphi: integer, dword), only pointers and handles are 64-bit wide now. Recompiling a program or dll with a 64-bit compiler usually takes care of this automatically without needing many changes. Problems can arise when converting pointers to integer or vice versa. Make sure to use 64-bit integer variables (e.g. size_t in C, ptrint or ptruint in Lazarus) for such operations.
If you have Visual Studio Professional 2005 or later, a 64-bit compiler is already included. If you use the free Express version or Visual Studio 2003, you need to install the Windows Software Development Kit (SDK) in addition to Visual Studio Express.
Here is how to add 64-bit support to an existing plugin:
Download links:
There is a 64-bit Lazarus/Free Pascal available, which can be used to create 64-bit dlls. Total Commander itself was compiled with Lazarus as a 64-bit application. There are menu items in the "Tools" menu to convert Delphi projects and forms to Lazarus.
Lazarus/Free Pascal works a bit differently from Delphi, so some functions may need to be changed. Here are the problems encountered when porting Total Commander:
Download links:
You should download and install the 64-bit daily snapshot from lazarus.freepascal.org. Click on "Daily snapshots", then on e.g. Lazarus + fpc 2.4.4 win64. The final releases are very outdated, so the snapshots usually work much better.
/* Contents of file wcxhead.h */ /* It contains definitions of error codes, flags and callbacks */ /* Error codes returned to calling application */ #define E_END_ARCHIVE 10 /* No more files in archive */ #define E_NO_MEMORY 11 /* Not enough memory */ #define E_BAD_DATA 12 /* CRC error in the data of the currently unpacked file */ #define E_BAD_ARCHIVE 13 /* The archive as a whole is bad, e.g. damaged headers */ #define E_UNKNOWN_FORMAT 14 /* Archive format unknown */ #define E_EOPEN 15 /* Cannot open existing file */ #define E_ECREATE 16 /* Cannot create file */ #define E_ECLOSE 17 /* Error closing file */ #define E_EREAD 18 /* Error reading from file */ #define E_EWRITE 19 /* Error writing to file */ #define E_SMALL_BUF 20 /* Buffer too small */ #define E_EABORTED 21 /* Function aborted by user */ #define E_NO_FILES 22 /* No files found */ #define E_TOO_MANY_FILES 23 /* Too many files to pack */ #define E_NOT_SUPPORTED 24 /* Function not supported */ /* flags for unpacking */ #define PK_OM_LIST 0 #define PK_OM_EXTRACT 1 /* flags for ProcessFile */ #define PK_SKIP 0 /* Skip this file */ #define PK_TEST 1 /* Test file integrity */ #define PK_EXTRACT 2 /* Extract to disk */ /* Flags passed through ChangeVolProc */ #define PK_VOL_ASK 0 /* Ask user for location of next volume */ #define PK_VOL_NOTIFY 1 /* Notify app that next volume will be unpacked */ /* Flags for packing */ /* For PackFiles */ #define PK_PACK_MOVE_FILES 1 /* Delete original after packing */ #define PK_PACK_SAVE_PATHS 2 /* Save path names of files */ #define PK_PACK_ENCRYPT 4 /* Ask user for password, then encrypt */ /* Returned by GetPackCaps */ #define PK_CAPS_NEW 1 /* Can create new archives */ #define PK_CAPS_MODIFY 2 /* Can modify exisiting archives */ #define PK_CAPS_MULTIPLE 4 /* Archive can contain multiple files */ #define PK_CAPS_DELETE 8 /* Can delete files */ #define PK_CAPS_OPTIONS 16 /* Has options dialog */ #define PK_CAPS_MEMPACK 32 /* Supports packing in memory */ #define PK_CAPS_BY_CONTENT 64 /* Detect archive type by content */ #define PK_CAPS_SEARCHTEXT 128 /* Allow searching for text in archives */ /* created with this plugin} */ #define PK_CAPS_HIDE 256 /* Show as normal files (hide packer */ /* icon), open with Ctrl+PgDn, not Enter*/ #define PK_CAPS_ENCRYPT 512 /* Plugin supports PK_PACK_ENCRYPT option*/ #define BACKGROUND_UNPACK 1 /* Which operations are thread-safe? */ #define BACKGROUND_PACK 2 #define BACKGROUND_MEMPACK 4 /* Flags for packing in memory */ #define MEM_OPTIONS_WANTHEADERS 1 /* Return archive headers with packed data */ /* Errors returned by PackToMem */ #define MEMPACK_OK 0 /* Function call finished OK, but there is more data */ #define MEMPACK_DONE 1 /* Function call finished OK, there is no more data */ #define PK_CRYPT_SAVE_PASSWORD 1 #define PK_CRYPT_LOAD_PASSWORD 2 // Load password only if master password has already been entered! #define PK_CRYPT_LOAD_PASSWORD_NO_UI 3 // Copy encrypted password to new archive name #define PK_CRYPT_COPY_PASSWORD 4 // Move password when renaming an archive #define PK_CRYPT_MOVE_PASSWORD 5 // Delete password #define PK_CRYPT_DELETE_PASSWORD 6 // The user already has a master password defined #define PK_CRYPTOPT_MASTERPASS_SET 1 typedef struct { char ArcName[260]; char FileName[260]; int Flags; int PackSize; int UnpSize; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tHeaderData; typedef struct { char ArcName[1024]; char FileName[1024]; int Flags; unsigned int PackSize; unsigned int PackSizeHigh; unsigned int UnpSize; unsigned int UnpSizeHigh; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; char Reserved[1024]; } tHeaderDataEx; typedef struct { WCHAR ArcName[1024]; WCHAR FileName[1024]; int Flags; unsigned int PackSize; unsigned int PackSizeHigh; unsigned int UnpSize; unsigned int UnpSizeHigh; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; char Reserved[1024]; } tHeaderDataExW; typedef struct { char* ArcName; int OpenMode; int OpenResult; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tOpenArchiveData; typedef struct { WCHAR* ArcName; int OpenMode; int OpenResult; WCHAR* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tOpenArchiveDataW; typedef struct { int size; DWORD PluginInterfaceVersionLow; DWORD PluginInterfaceVersionHi; char DefaultIniName[MAX_PATH]; } PackDefaultParamStruct; /* Definition of callback functions called by the DLL Ask to swap disk for multi-volume archive */ typedef int (__stdcall *tChangeVolProc)(char *ArcName,int Mode); typedef int (__stdcall *tChangeVolProcW)(WCHAR *ArcName,int Mode); /* Notify that data is processed - used for progress dialog */ typedef int (__stdcall *tProcessDataProc)(char *FileName,int Size); typedef int (__stdcall *tProcessDataProcW)(WCHAR *FileName,int Size); typedef int (__stdcall *tPkCryptProc)(int CryptoNr,int Mode, char* ArchiveName,char* Password,int maxlen); typedef int (__stdcall *tPkCryptProcW)(int CryptoNr,int Mode, WCHAR* ArchiveName,WCHAR* Password,int maxlen);
{ Contents of file wcxhead.pas } { It contains definitions of error codes, flags and callbacks } 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} #define 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:DWORD; 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:DWORD; 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.