Jump to content

DllCall DllCallbackRegister Crashes The Gui


DXRW4E
 Share

Recommended Posts

Hi all, the problem occurs with every dllcall that to do with the Extract Cab file, both Setupapi & AdvPack, here is an example using AdvPack

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Local $Form, $Button1, $nMsg, $Test
$Form1 = GUICreate("Test", 472, 210, 259, 207)
$Button1 = GUICtrlCreateButton("Test", 56, 56, 353, 81)
GUISetState(@SW_SHOW)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button1
            ;; example "..\WinXPCD\I386\DRIVER.CAB"
            $Test = FileOpenDialog("Cab Files", @DesktopDir, "Cab Files (*.cab;*.*_;*.*$)", 1)
            If Not @Error Then
                DirCreate(StringLeft($Test, StringInStr($Test, ".", 1, -1) - 1))
                Local $ExtractFilesW = DllCall("AdvPack.DLL", "LONG", "ExtractFilesW", "wstr", $Test, "wstr", StringLeft($Test, StringInStr($Test, ".", 1, -1) - 1), "DWORD", 0, "ptr", 0, "ptr", 0, "DWORD", 0)
                ;Local $ExtractFiles = DllCall("AdvPack.DLL", "LONG", "ExtractFiles", "str", $Test, "str", StringLeft($Test, StringInStr($Test, ".", 1, -1) - 1), "DWORD", 0, "ptr", 0, "ptr", 0, "DWORD", 0)
            EndIf
    EndSwitch
WEnd

the point is that the GUi crashes (when archive Cab and a little big, example ..\WinXPCD\I386\DRIVER.CAB), however the process of extract file, proceed right, on his own

sorry for my english

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Link to comment
Share on other sites

Hi JFX, the point is just that, that happens to me with the setupapi, but used as an example advpack saw there was more simple

;#requireadmin
#include <Array.au3>;
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global Const $h_SetupApiDll = DllOpen("SetupApi.dll")
Global Const $h_Kernel32DLL = DllOpen("Kernel32.dll")

;;
;; These are used with SetupIterateCabinet().
;;
Global Const $SPFILENOTIFY_CABINETINFO      = 16    ;; 0x00000010
Global Const $SPFILENOTIFY_FILEINCABINET      = 17    ;; 0x00000011
Global Const $SPFILENOTIFY_NEEDNEWCABINET    = 18    ;; 0x00000012
Global Const $SPFILENOTIFY_FILEEXTRACTED      = 19    ;; 0x00000013
Global Const $SPFILENOTIFY_FILEOPDELAYED      = 20    ;; 0x00000014

;;
;; File operation codes and callback outcomes.
;;
Global Const $FILEOP_ABORT                  = 0
Global Const $FILEOP_DOIT                    = 1
Global Const $FILEOP_SKIP                    = 2
Global Const $FILEOP_RETRY                  = $FILEOP_DOIT
Global Const $FILEOP_NEWPATH                  = 4

Global Const $_Context = "WCHAR Encoding[12];WCHAR tContext[108];int Act;WCHAR DestDir[508];WCHAR sDir[508];int cFiles;int sFiles;WCHAR cFilename[508];int cFileSize;WCHAR sFilter[508]"
Global $PSPFILECALLBACK, $cCallbackEx, $cCallback[11], $FileInCabinetInfo, $FilePathInfo, $CabinetInfo
Global Const $_PSP_FILE_CALLBACK = "" & _
    "ptr" & _      ; Context, context used by the callback routine
    ";UINT" & _  ; Notification, cabinet notification
    ";UINT_PTR" & _ ; Param1, additional notification information
    ";UINT_PTR"  ; Param2, additional notification information
;  $MsgHandler
;    Pointer to a FileCallback routine that will process the notifications SetupIterateCabinet returns as it iterates through the files
;    in the cabinet file. The callback routine may then return a value specifying whether to decompress, copy, or skip the file.
Global $PSP_FILE_CALLBACK = DllCallbackRegister("_FILE_CALLBACK", "UINT", $_PSP_FILE_CALLBACK)
Global $pPSP_FILE_CALLBACK = DllCallbackGetPtr($PSP_FILE_CALLBACK)
Global $CABINET_CALLBACK_EX = DllCallbackRegister("_CABINET_CALLBACK_EX", "UINT", $_PSP_FILE_CALLBACK)
Global $pCABINET_CALLBACK_EX = DllCallbackGetPtr($CABINET_CALLBACK_EX)
Global $CABINET_CALLBACK = DllCallbackRegister("_CABINET_CALLBACK", "UINT", $_PSP_FILE_CALLBACK)
Global $pCABINET_CALLBACK = DllCallbackGetPtr($CABINET_CALLBACK)

Global Const $_FILE_IN_CABINET_INFO_A = "" & _
    "ptr" & _                  ; File name as it exists within the cabinet file. ("CHAR NameInCabinet[260]" - "STR NameInCabinet")
    ";DWORD FileSize" & _      ; Uncompressed size of the file in the cabinet, in bytes.
    ";DWORD Win32Error" & _  ; If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
    ";WORD DosDate" & _      ; Date that the file was last saved.
    ";WORD DosTime" & _      ; MS-DOS time stamp of the file in the cabinet.
    ";WORD DosAttribs" & _    ; Attributes of the file in the cabinet.
    ";CHAR FullTargetName[260]" ; Target path and file name. (";STR FullTargetName")
Global Const $_FILE_IN_CABINET_INFO_W = "" & _
    "ptr" & _                   ;  File name as it exists within the cabinet file. ("WCHAR NameInCabinet[260]" -  "WSTR NameInCabinet")
    ";DWORD FileSize" & _       ; Uncompressed size of the file in the cabinet, in bytes.
    ";DWORD Win32Error" & _   ; If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
    ";WORD DosDate" & _       ; Date that the file was last saved.
    ";WORD DosTime" & _       ; MS-DOS time stamp of the file in the cabinet.
    ";WORD DosAttribs" & _     ; Attributes of the file in the cabinet.
    ";WCHAR FullTargetName[260]" ; ";WCHAR FullTargetName[260]" - ";WSTR FullTargetName", Target path and file name.
Global Const $_FILE_IN_CABINET_INFO_X = "" & _
    "ptr" & _                   ;  File name as it exists within the cabinet file. ("WCHAR NameInCabinet[260]" -  "WSTR NameInCabinet")
    ";DWORD FileSize" & _       ; Uncompressed size of the file in the cabinet, in bytes.
    ";DWORD Win32Error" & _   ; If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
    ";WORD DosDate" & _       ; Date that the file was last saved.
    ";WORD DosTime" & _       ; MS-DOS time stamp of the file in the cabinet.
    ";WORD DosAttribs" & _     ; Attributes of the file in the cabinet.
    ";WCHAR FullTargetName[520]" ; ";WCHAR FullTargetName[260]" - ";WSTR FullTargetName", Target path and file name.
Global $_FILE_IN_CABINET_INFO = $_FILE_IN_CABINET_INFO_W ;, $FILE_IN_CABINET_INFO = DllStructCreate($_FILE_IN_CABINET_INFO_W)

Global Const $_FILEPATHS_A = "" & _
    "ptr" & _              ; Path to the target file. ("CHAR Target[260]" - "STR Target")
    ";ptr" & _            ; Path to the source file. This member is not used when the FILEPATHS structure is used with a file delete operation. (";CHAR Source[260]" - ";STR Source")
    ";UINT Win32Error" & _  ; If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
    ";DWORD Flags"        ; Additional information that depends on the notification sent with the FILEPATHS structure.
Global Const $_FILEPATHS_W = "" & _
    "ptr" & _              ; Path to the target file. ("WCHAR Target[260]" - "STR Target")
    ";ptr" & _            ; Path to the source file. This member is not used when the FILEPATHS structure is used with a file delete operation. (";WCHAR Source[260]" - ";STR Source")
    ";UINT Win32Error" & _   ; If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
    ";DWORD Flags"         ; Additional information that depends on the notification sent with the FILEPATHS structure.
Global $_FILEPATHS = $_FILEPATHS_W ;,$FILEPATHS = DllStructCreate($_FILEPATHS_W)

Global Const $_CABINET_INFO_A = "" & _
    "ptr" & _              ; Path to the cabinet file. ("CHAR CabinetPath[260]" - "STR CabinetPath")
    ";ptr" & _            ; Name of the cabinet file. (";CHAR CabinetFile[260]" - ";STR CabinetFile")
    ";ptr" & _            ; Name of the source media that contains the cabinet file. (";CHAR DiskName[260]" - ";STR DiskName")
    ";USHORT SetId" & _  ; Identifier of the current set. This number is generated by the software that builds the cabinet.
    ";USHORT CabinetNumber" ; Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
                            ;   a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
Global Const $_CABINET_INFO_W = "" & _
    "ptr" & _              ; Path to the cabinet file. ("WCHAR CabinetPath[260]" - "WSTR CabinetPath")
    ";ptr" & _            ; Name of the cabinet file. (";WCHAR CabinetFile[260]" - ";WSTR CabinetFile")
    ";ptr" & _            ; Name of the source media that contains the cabinet file. (";WCHAR DiskName[260]" - ";WSTR DiskName")
    ";USHORT SetId" & _  ; Identifier of the current set. This number is generated by the software that builds the cabinet.
    ";USHORT CabinetNumber" ; Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
                            ;   a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
Global $_CABINET_INFO = $_CABINET_INFO_W ;,$CABINET_INFO = DllStructCreate($_CABINET_INFO_W)

Local $a1, $a2, $a, $b, $c, $d, $Context

;~ $Context = DllStructCreate($_Context)
;~ DllStructSetData($Context, "Encoding", "WCHAR[260]")
;~ DllStructSetData($Context, "tContext", $_FILE_IN_CABINET_INFO_W)
;~ DllStructSetData($Context, "Act", "1")
;~ ;;DllStructSetData($Context, "DestDir", "D:\aa aa\amd64_3ware.inf.resources_31bf3856ad364e35_6.2.")
;~ ;DllStructSetData($Context, "sFilter", "Startu.*n\.dll\.m.*i")

Local $Form, $Button1, $nMsg, $Test
$Form1 = GUICreate("Test", 472, 210, 259, 207)
$Button1 = GUICtrlCreateButton("Test", 56, 56, 353, 81)
GUISetState(@SW_SHOW)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button1
            ;; example "..\WinXPCD\I386\DRIVER.CAB"
            $Test = FileOpenDialog("Cab Files", @DesktopDir, "Cab Files (*.cab;*.*_;*.*$)", 1)
            If Not @Error Then
                _SetupIterateCabinet($Test, 1)
                ;;DirCreate(StringLeft($Test, StringInStr($Test, ".", 1, -1) - 1))
                ;;Local $ExtractFilesW = DllCall("AdvPack.DLL", "LONG", "ExtractFilesW", "wstr", $Test, "wstr", StringLeft($Test, StringInStr($Test, ".", 1, -1) - 1), "DWORD", 0, "ptr", 0, "ptr", 0, "DWORD", 0)
                ;;Local $ExtractFiles = DllCall("AdvPack.DLL", "LONG", "ExtractFiles", "str", $Test, "str", StringLeft($Test, StringInStr($Test, ".", 1, -1) - 1), "DWORD", 0, "ptr", 0, "ptr", 0, "DWORD", 0)
            EndIf
    EndSwitch
WEnd


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupIterateCabinet
; Description ...: The SetupIterateCabinet function iterates through all the files in a cabinet and sends a notification to a callback function for each file found.
; Syntax.........: _SetupIterateCabinet($CabinetFile, $Action,  $DestDir, $sFilter)
; Parameters ....: $CabinetFile - Cabinet (.CAB) file to iterate through.
;                 $Action     - Optional
;                   |0 = Count Files & Total Size, Default
;                   |1 = Extract Files
;                 $DestDir   - Optional, Destination directory (Default is $CabinetFile)
;                 $sFilter   - Optional the filter to use, default is ".*" $sFilter is REGEXP Mod, See Pattern Parameters in StringRegExp
; Return values .: Success  - Return The total number of bytes and Set @Extended = The count of files
;                 Failure - @Error
;                 |1 = Path not found or invalid
;                 |2 = If there is an error creating the directory.
;                 |3 = No File(s) Found
;                 |4 = The function fails
; Remarks .......: Global Array $cCallback
;                   If Set $Action = 0
;                     $cCallback[0] = The count of files
;                     $cCallback[1] = The total number of bytes
;                     $cCallback[2] = Destination directory
;                     $cCallback[3] = $sFilter
;                     $cCallback[4] = Last processed File SubDir
;                     $cCallback[5] = Last processed File Name
;                     $cCallback[6] = Last processed File Size
;                     $cCallback[7] = ;;;
;
;                   If Set $Action = 1
;                     $cCallback[0] = The count of files processed
;                     $cCallback[1] = The total number of bytes extracted
;                     $cCallback[2] = Destination directory
;                     $cCallback[3] = $sFilter
;                     $cCallback[4] = Last processed File SubDir
;                     $cCallback[5] = Last processed File Name
;                     $cCallback[6] = Last processed File Size
;                     $cCallback[7] = ;;;
; Remarks .......:
; Related .......:
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupIterateCabinet($CabinetFile, $Action = 0, $DestDir = "", $sFilter = ".*")
    $CabinetFile = StringRegExpReplace($CabinetFile, "[\\/]+", "\\")
    If Not FileExists($CabinetFile) Then Return SetError(1, 0, 0)
    If $Action Then
        If Not $DestDir Then
            $DestDir = StringRegExpReplace($CabinetFile, "(?i)\.cab$", "\\")
            $DestDir = StringLeft($DestDir, StringInStr($DestDir, "\", 1, -1))
        EndIf
        If StringRight($DestDir, 1) <> "\" Then $DestDir = StringRegExpReplace($DestDir & "\", "[\\/]+", "\\")
        If Not FileExists($DestDir) And DirCreate($DestDir) = 0 Then Return SetError(2, 0, 0)    ;_WinAPI_GetLastErrorEx()
    EndIf
    Global $cCallback[11] = [0,0,$DestDir]
    If Not ($sFilter = ".*") Then $cCallback[3] = $sFilter
    Local $SetupIterateCabinet = DllCall($h_SetupApiDll, "BOOL", "SetupIterateCabinetW", "wstr", $CabinetFile, "DWORD", 0, "ptr", $pCABINET_CALLBACK, "ptr", $Action)
    If @Error Or Not $SetupIterateCabinet[0] Then Return SetError(4, 0, "")    ;SetError(4, _WinAPI_GetLastErrorEx(), "")
    If Not $cCallback[0] Then Return SetError(3, 0, "")
    Return SetError(0, $cCallback[0], $cCallback[1])
EndFunc    ;==>_SetupIterateCabinet


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupIterateCabinetEx
; Description ...: The SetupIterateCabinet function iterates through all the files in a cabinet and sends a notification to a callback function for each file found.
; Syntax.........: _SetupIterateCabinetEx($CabinetFile, $iFlags,  $DestDir, $sFilter)
; Parameters ....: $CabinetFile - Cabinet (.CAB) file to iterate through.
;                 $iFlags     - Optional, Default is ANSI Mod (MAX_PATH = 260), add the flags together for multiple operations:
;                   |0 = Count Files & Total Size, Default
;                   |1 = List Files & Total Size & LastEditFies & Attributes & Count Files
;                   |2 = Extract Files
;                   |4 = Unicode Mod (MAX_PATH = 260)
;                   |8 = Unicode Mod, (try to use MAX_PATH = 520)
;                 |16 = $sFilter do Case-Sensitive matching (By Default $sFilter do Case-Insensitive matching)
;                 |32 = $sFilter is REGEXP Mod, See Pattern Parameters in StringRegExp (Can not be combined with flag 16)
;                 $DestDir   - Optional, Destination directory (Default is $CabinetFile)
;                 $sFilter   - Optional the filter to use, default is *. (Multiple filter groups such as "All "*.png|*.jpg|*.bmp") Search the Autoit3 helpfile for the word "WildCards" For details.
; Return values .: Success  - Return Value or 2D Array (See Remarks)
;                 Failure - @Error
;                 |1 = Path not found or invalid
;                 |2 = If there is an error creating the directory.
;                 |3 = No File(s) Found
;                 |4 = The function fails, set extended = GetLastError.
; Remarks .......: If Not Set $iFlags = 1 or $iFlags = 2
;                   Set @Extended = The count of files processed and Return The total number of bytes
;                   If is set the $iFlag = 1 Return is 2D array and is made up as follows:
;                     $array[0][0] = Number of Files
;                     $array[0][1] = All Files Size in byte
;                     $array[1][0] = 1st File Name
;                     $array[1][1] = 1st File Size in byte
;                     $array[1][2] = 1st File Data-Time (Modified)
;                     $array[1][3] = 1st File Attributes
;                     $array[1][4] = 1st File SubDirectory (example file Path DirName\FilesName.xxx, $array[1][0] = "FilesName.xxx" and $array[1][4] = "DirName\")
;                     $array[2][0] = 2st File Name
;                     $array[2][1] = 2st File Size in byte
;                     $array[2][2] = 2st File Data-Time (Modified)
;                     $array[2][3] = 2st File Attributes
;                     $array[2][4] = 2st File SubDirectory (example file Path DirName1\DirName2\FilesName.xxx, $array[2][0] = "FilesName.xxx" and $array[2][4] = "DirName1\DirName2\")
;                     $array[n][xx] = nth File\Folder
;                 If is set the $iFlag = 2
;                   Set @Extended = The count of files processed and Return The total number of bytes extracted.
; Remarks .......:
; Related .......:
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupIterateCabinetEx($CabinetFile, $iFlags = 1, $DestDir = "", $sFilter = "*")
    $CabinetFile = StringRegExpReplace($CabinetFile, "[\\/]+", "\\")
    If Not FileExists($CabinetFile) Then Return SetError(1, 0, 0)
    Local $SetupIterateCabinet, $cFilter = StringReplace($sFilter, "*", "")
    If BitAND($iFlags, 2) = 2 Then
        If Not $DestDir Then
            $DestDir = StringRegExpReplace($CabinetFile, "(?i)\.cab$", "\\")
            $DestDir = StringLeft($DestDir, StringInStr($DestDir, "\", 1, -1))
        EndIf
        If StringRight($DestDir, 1) <> "\" Then $DestDir = StringRegExpReplace($DestDir & "\", "[\\/]+", "\\")
        If Not FileExists($DestDir) And DirCreate($DestDir) = 0 Then Return SetError(2, _WinAPI_GetLastErrorEx(), 0)
    EndIf
    If $cFilter And BitAND($iFlags, 32) <> 32 Then $sFilter = StringRegExpReplace(BitAND($iFlags, 16) & "(?i)(", "16\(\?\i\)|\d+", "") & StringRegExpReplace(StringRegExpReplace(StringRegExpReplace(StringRegExpReplace($sFilter, "[^*?|]+", "\\Q$0\\E"), "\\E(?=\||$)", "$0\$"), "(?<=^|\|)\\Q", "^$0"), "\*+", ".*") & ")"
    Global $cCallbackEx[1564][5] = [[0,0,1562,1563]]
    If BitAND($iFlags, 1) = 1 Then $cCallbackEx[1563][0] = 1
    If BitAND($iFlags, 2) = 2 Then $cCallbackEx[1563][0] = 2
    $cCallbackEx[1563][3] = $DestDir
    If $cFilter Then $cCallbackEx[1563][4] = $sFilter
    If BitAND($iFlags, 4) = 4 Then
        $cCallbackEx[1563][1] = $_FILE_IN_CABINET_INFO_W
        $cCallbackEx[1563][2] = "WCHAR[260]"
        $SetupIterateCabinet = DllCall($h_SetupApiDll, "BOOL", "SetupIterateCabinetW", "wstr", $CabinetFile, "DWORD", 0, "ptr", $pCABINET_CALLBACK_EX, "ptr", 0)
    ElseIf BitAND($iFlags, 8) = 8 Then
        $cCallbackEx[1563][1] = $_FILE_IN_CABINET_INFO_X
        $cCallbackEx[1563][2] = "WCHAR[520]"
        $SetupIterateCabinet = DllCall($h_SetupApiDll, "BOOL", "SetupIterateCabinetW", "wstr", $CabinetFile, "DWORD", 0, "ptr", $pCABINET_CALLBACK_EX, "ptr", 0)
    Else
        $cCallbackEx[1563][1] = $_FILE_IN_CABINET_INFO_A
        $cCallbackEx[1563][2] = "CHAR[260]"
        $SetupIterateCabinet = DllCall($h_SetupApiDll, "BOOL", "SetupIterateCabinet", "str", $CabinetFile, "DWORD", 0, "ptr", $pCABINET_CALLBACK_EX, "ptr", 0)
    EndIf
    If @Error Or Not $SetupIterateCabinet[0] Then Return SetError(4, _WinAPI_GetLastErrorEx(), "")
    If $cCallbackEx[0][0] = 0 Then Return SetError(3, 0, "")
    If BitAND($iFlags, 1) <> 1 Then Return SetError(0, $cCallbackEx[0][0], $cCallbackEx[0][1])
    ReDim $cCallbackEx[$cCallbackEx[0][0] + 1][5]
    $SetupIterateCabinet = $cCallbackEx
    $cCallbackEx = 0
    Return $SetupIterateCabinet
EndFunc    ;==>_SetupIterateCabinetEx


; #FUNCTION# ==============================================================================================================================================
; Name...........: _WinAPI_SetupIterateCabinet
; Description ...: The SetupIterateCabinet function iterates through all the files in a cabinet and sends a notification to a callback function for each file found.
; Syntax.........: _WinAPI_SetupIterateCabinet($CabinetFile, $Context, $iFlags)
; Parameters ....: $CabinetFile - Cabinet (.CAB) file to iterate through.
;                 $Context   - The $Context struct returned by DllStructCreate($_Context) (value that is passed into the routine specified in MsgHandler. This enables the callback routine to track)
;                    Example:
;                     $Context = DllStructCreate($_Context)
;                     DllStructSetData($Context, "Encoding", "WCHAR[260]") ; Unicode Mod (MAX_PATH = 260) or "CHAR[260]" ANSI Mod (MAX_PATH = 260) or "WCHAR[520]" Unicode Mod (try to use MAX_PATH = 520)
;                     DllStructSetData($Context, "tContext", $_FILE_IN_CABINET_INFO_W)
;                        ;; Unicode Mod (MAX_PATH = 260) $_FILE_IN_CABINET_INFO_W - "ptr;DWORD FileSize;DWORD Win32Error;WORD DosDate;WORD DosTime;WORD DosAttribs;WCHAR FullTargetName[260]"
;                        ;; ANSI Mod (MAX_PATH = 260)    $_FILE_IN_CABINET_INFO_A - "ptr;DWORD FileSize;DWORD Win32Error;WORD DosDate;WORD DosTime;WORD DosAttribs;CHAR FullTargetName[260]"
;                        ;; Unicode Mod (MAX_PATH = 520) $_FILE_IN_CABINET_INFO_X - "ptr;DWORD FileSize;DWORD Win32Error;WORD DosDate;WORD DosTime;WORD DosAttribs;WCHAR FullTargetName[520]"
;                    DllStructSetData($Context, "Act", "0") ; Optional, "0" = Get Count Files & Total Size Or 1 = List Files & Total Size & LastEditFiles & Attributes & Count Files Or 2 = Extract
;                    DllStructSetData($Context, "DestDir", "X:\xxx\") ; Optional, Destination directory (Default is $CabinetFile)
;                        DllStructSetData($Context, "sFilter", ".*\.dll") ; sFilter is REGEXP Mod, See Pattern Parameters in StringRegExp
; Return values .:
; Return values .: Success  - Return Value (See Remarks)
;                 Failure - @Error
;                 |1 = Path not found or invalid
;                 |2 = $Context is not DllStruct type as return by DllStructCreate($_Context)
;                 |3 = If there is an error creating the (Extract) directory.
;                 |4 = No File(s) Found
;                 |5 = The function fails, set extended = GetLastError.
; Remarks .......: If Action - DllStructGetData($Context, "Act") = 0
;                   Set @Extended = The count of files processed & Return The total number of bytes
;                 If Action - DllStructGetData($Context, "Act") = 1
;                   Set @Extended = The count of files processed & Return List Files & Total Size & LastEditFiles & Attributes
;                        FileName1.xxx|147968|17/08/2001 22.36|32 & @LF & FileName2.xxx|187654|05/12/2012 02.36|32 & @LF & FileName1.xxx|ect ect ect
;                 If Action - DllStructGetData($Context, "Act") = 2
;                   Set @Extended = The count of files processed & Return The total number of bytes extracted.
; Related .......:
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _WinAPI_SetupIterateCabinet($CabinetFile, $Context)
    If Not FileExists($CabinetFile) Then Return SetError(1, 0, 0)
    If Not IsDllStruct($Context) Then Return SetError(2, 0, 0)
    Local $DestDir, $SetupIterateCabinet
    If DllStructGetData($Context, "Act") = 2 Then
        $DestDir = DllStructGetData($Context, "DestDir")
        If Not $DestDir Then
            $DestDir = StringRegExpReplace($CabinetFile, "(?i)\.cab$", "\\")
            $DestDir = StringLeft($DestDir, StringInStr($DestDir, "\", 1, -1))
        EndIf
        If StringRight($DestDir, 1) <> "\" Then $DestDir = StringRegExpReplace($DestDir & "\", "[\\/]+", "\\")
        If Not FileExists($DestDir) And DirCreate($DestDir) = 0 Then Return SetError(3, _WinAPI_GetLastErrorEx(), 0)
        DllStructSetData($Context, "DestDir", $DestDir)
    EndIf
    Global $PSPFILECALLBACK
    If DllStructGetData($Context, "Encoding") = "CHAR[260]" Then
        $SetupIterateCabinet = DllCall($h_SetupApiDll, "BOOL", "SetupIterateCabinet", "str", $CabinetFile, "DWORD", 0, "ptr", $pPSP_FILE_CALLBACK, "ptr", DllStructGetPtr($Context))
    Else
        $SetupIterateCabinet = DllCall($h_SetupApiDll, "BOOL", "SetupIterateCabinetW", "wstr", $CabinetFile, "DWORD", 0, "ptr", $pPSP_FILE_CALLBACK, "ptr", DllStructGetPtr($Context))
    EndIf
    If @Error Or Not $SetupIterateCabinet[0] Then Return SetError(5, _WinAPI_GetLastErrorEx(), "")
    If DllStructGetData($Context, "cFiles") = 0 Then Return SetError(4, 0, "")
    If DllStructGetData($Context, "Act") <> 1 Then Return SetError(0, DllStructGetData($Context, "cFiles"), DllStructGetData($Context, "sFiles"))
    Return SetError(0, DllStructGetData($Context, "cFiles"), $PSPFILECALLBACK)
EndFunc    ;==>_WinAPI_SetupIterateCabinet


Func _CABINET_CALLBACK($Context, $Notification, $Param1, $Param2)
    Switch $Notification
        Case $SPFILENOTIFY_FILEINCABINET ;; 17 - 0x00000011
            ; FILE_IN_CABINET_INFO structure ($FileInCabinetInfo)
            $FileInCabinetInfo = DllStructCreate($_FILE_IN_CABINET_INFO_W, $Param1)
            ;    If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
            ;$Win32Error = DllStructGetData($FileInCabinetInfo, "Win32Error")
            If DllStructGetData($FileInCabinetInfo, "Win32Error") Then Return $FILEOP_SKIP
            If Not $Context Then
                If $cCallback[3] And StringRegExp(StringRegExpReplace(DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($FileInCabinetInfo, 1)), 1), ".*\\", ""), $cCallback[3]) = 0 Then Return $FILEOP_SKIP
                $cCallback[0] += 1
                $cCallback[1] += DllStructGetData($FileInCabinetInfo, "FileSize")
                Return $FILEOP_SKIP
            EndIf
            ;    File name as it exists within the cabinet file.
            ;;;$NameInCabinet = DllStructGetData($FileInCabinetInfo, "NameInCabinet")
            $cCallback[7] = DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($FileInCabinetInfo, 1)), 1)
            $cCallback[8] = StringInStr($cCallback[7], "\", 1, -1)
            $cCallback[9] = StringTrimLeft($cCallback[7], $cCallback[8])
            If $cCallback[3] And StringRegExp($cCallback[9], $cCallback[3]) = 0 Then Return $FILEOP_SKIP
            If $cCallback[8] Then
                $cCallback[8] = StringLeft($cCallback[7], $cCallback[8])
                If $Context And Not ($cCallback[4] == $cCallback[8]) And DirCreate($cCallback[2] & $cCallback[8]) = 0 Then Return $FILEOP_SKIP
                $cCallback[4] = $cCallback[8]
            Else
                $cCallback[4] = ""
            EndIf
            ;;$cCallback[10] &= $cCallback[7] & ";"
            $cCallback[0] += 1
            $cCallback[5] = $cCallback[9]
            ;    Uncompressed size of the file in the cabinet, in bytes.
            $cCallback[6] = DllStructGetData($FileInCabinetInfo, "FileSize")
            ;    Target path and file name.
            ;;;$FullTargetName = DllStructSetData($FileInCabinetInfo, "FullTargetName", "xxxx")
            DllStructSetData($FileInCabinetInfo, "FullTargetName", $cCallback[2] & $cCallback[4] & $cCallback[5])
            Return $FILEOP_DOIT
            ;;    ;    Date that the file was last saved.
            ;;    $cCallback[7] = DllStructGetData($FileInCabinetInfo, "DosDate")
            ;;    ;    MS-DOS time stamp of the file in the cabinet.
            ;;    $cCallback[8] = DllStructGetData($FileInCabinetInfo, "DosTime")
            ;;    ;    _DOSDateTimeToStr($cCallback[7], $cCallback[8])
            ;;    $cCallback[7] = StringFormat("%02d/%02d/%04d %02d.%02d", BitAND($cCallback[7], 31), BitAND(BitShift($cCallback[7], 5), 15), BitAND(BitShift($cCallback[7], 9), 63) + 1980, BitAND(BitShift($cCallback[8], 11), 31), BitAND(BitShift($cCallback[8], 5), 63))
            ;;    ;    Attributes of the file in the cabinet.
            ;;    ;;;$cCallback[8] = DllStructGetData($FileInCabinetInfo, "DosAttribs")
            ;;    $cCallback[1] += $cCallback[6]
            ;;    Return $FILEOP_SKIP

            ; callback routine should return one of the following.
            ;     $FILEOP_ABORT = 0    ;Abort cabinet processing.
            ;    $FILEOP_SKIP = 1    ;Do not extract the file, skip it.
            ;    $FILEOP_DOIT = 2    ;Extract the file.

            ; If your callback routine returns $FILEOP_DOIT, the name to use for the extracted file should be specified in the FullTargetName member
            ;   of the FILE_IN_CABINET_INFO ($FileInCabinetInfo) structure passed to the routine in Param1 ($FileInCabinetInfo).

            ; Note: There is no default cabinet callback routine. The setup application should supply a callback routine to handle the
            ;   notifications sent by SetupIterateCabinet.
        Case $SPFILENOTIFY_FILEEXTRACTED ;; 19 - 0x00000013
            ; $Param2 Unused.
            $FilePathInfo = DllStructCreate($_FILEPATHS, $Param1)
            ; $FilePathInfo contains path information for the extracted file, The SourceFile member of the FILEPATHS structure contains the full
            ;   source path of the cabinet. The TargetFile member supplies the full target path of the file to be installed on the system

            ;    Path to the target file.
            ;;;$TargetFile = DllStructGetData($FilePathInfo, "Target")
            ;Local $TargetFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($FilePathInfo, 1)), 1)
            ;    Path to the source file. This member is not used when the FILEPATHS structure is used with a file delete operation.
            ;;;$SourceFile = DllStructGetData($FilePathInfo, "Source")
            ;Local $SourceFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($FilePathInfo, 2)), 1)
            ;    If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
            ;Local $FNFE_Win32Error = DllStructGetData($FilePathInfo, "Win32Error")
            ;    Additional information that depends on the notification sent with the FILEPATHS structure.
            ;Local $Flags = DllStructGetData($FilePathInfo, "Flags")
            ; Additional information that depends on the notification sent with the FILEPATHS structure.
            ;     For SPFILENOTIFY_COPYERROR notifications, Flags specifies dialog box behavior and can be one of the following values.
            ;           $SP_COPY_NOBROWSE   - Do not offer the user the option to browse.
            ;         $SP_COPY_NOSKIP    - Do not offer the user the option to skip the file.
            ;         $SP_COPY_WARNIFSKIP - Inform the user that skipping the file may affect the installation.
            ;
            ;     For SPFILENOTIFY_FILEOPDELAYED notifications, Flags specifies the type of file operation delayed and can be one of the following values.
            ;           $FILEOP_COPY   - A file copy operation was delayed.
            ;         $FILEOP_DELETE - A file delete operation was delayed.

            ; cabinet callback routine should return one of the following values.
            ;     NO_ERROR - No error was encountered, continue processing the cabinet.
            ;     ERROR_XXX - An error of the specified type occurred. SetupIterateCabinet will return zero. GetLastError will return the specified error code.

            ; Note: There is no default cabinet callback routine supplied with the Setup API. Your setup application should supply a callback routine to
            ;   handle the notifications sent by the SetupIterateCabinet function.
            If DllStructGetData($FilePathInfo, "Win32Error") Then Return DllStructGetData($FilePathInfo, "Win32Error")
            $cCallback[1] += $cCallback[6]
            Return 0 ;NO_ERROR
        Case $SPFILENOTIFY_CABINETINFO ;; 16 - 0x00000010
            Return 0 ;NO_ERROR
            $CabinetInfo = DllStructCreate($_CABINET_INFO, $Param1)
            ;If the callback returns NO_ERROR, $Param2 is a pointer to a null-terminated string.
            ;  If the string is not empty, it specifies a new path to the cabinet.
            Local $CabinetPath, $CabinetFile, $DiskName, $SetId, $CabinetNumber, $NewPath

            ;    Path to the cabinet file.
            ;;$CabinetPath = DllStructGetData($CabinetInfo, "CabinetPath")
            $CabinetPath = DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($CabinetInfo, 1)), 1)
            ;    Name of the cabinet file.
            ;;;$CabinetFile = DllStructGetData($CabinetInfo, "CabinetFile")
            $CabinetFile = DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($CabinetInfo, 2)), 1)
            ;    Name of the source media that contains the cabinet file.
            ;;;$DiskName = DllStructGetData($CabinetInfo, "DiskName")
            $DiskName = DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($CabinetInfo, 2)), 1)
            ;    Identifier of the current set. This number is generated by the software that builds the cabinet.
            $SetId = DllStructGetData($CabinetInfo, "SetId")
            ;    Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
            ;      a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
            $CabinetNumber = DllStructGetData($CabinetInfo, "CabinetNumber")

            ; $SPFILENOTIFY_NEEDNEWCABINET will not have to ever happen, so set to return error, or use FileOpenDialog()
            ;   example $NewPath = FileOpenDialog("Cab Files", @DesktopDir & "\", "Cab Files (*.cab;*.*_;*.*$)", 1)
            ;Return 3 ;ERROR_PATH_NOT_FOUND, The system cannot find the path specified.

            ; routine should return one of the following values.
            ;     NO_ERROR  - No error was encountered, continue processing the cabinet.
            ;    ERROR_XXX - An error of the specified type occurred. The SetupIterateCabinet function will return FALSE, and the specified
            ;       error code will be returned by a call to GetLastError.

            ; Note: There is no default cabinet callback routine; thus, you must supply a callback routine to handle the notifications sent by SetupIterateCabinet.

            ; Remarks: If the callback routine returns NO_ERROR, SetupIterateCabinet checks the buffer pointed to by Param2. If the buffer is not empty,
            ;           then it contains a new source path. If the buffer is empty, the source path is assumed to be unchanged.
            ;
            ;         callback function should ensure that the cabinet is accessible before it returns, calling the SetupPromptForDisk function,
            ;            if new media needs to be inserted.

            Return 0 ;NO_ERROR
        Case $SPFILENOTIFY_NEEDNEWCABINET ;; 18 - 0x00000012
            $CabinetInfo = DllStructCreate($_CABINET_INFO, $Param1)
            ;If the callback returns NO_ERROR, $Param2 is a pointer to a null-terminated string.
            ;  If the string is not empty, it specifies a new path to the cabinet.
            Local $CabinetPath, $CabinetFile, $DiskName, $SetId, $CabinetNumber, $NewPath

            ;    Path to the cabinet file.
            ;;;$CabinetPath = DllStructGetData($CabinetInfo, "CabinetPath")
            $CabinetPath = DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($CabinetInfo, 1)), 1)
            ;    Name of the cabinet file.
            ;;;$CabinetFile = DllStructGetData($CabinetInfo, "CabinetFile")
            ;$CabinetFile = DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($CabinetInfo, 2)), 1)
            ;    Name of the source media that contains the cabinet file.
            ;;;$DiskName = DllStructGetData($CabinetInfo, "DiskName")
            ;$DiskName = DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($CabinetInfo, 2)), 1)
            ;    Identifier of the current set. This number is generated by the software that builds the cabinet.
            ;$SetId = DllStructGetData($CabinetInfo, "SetId")
            ;    Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
            ;      a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
            $CabinetNumber = DllStructGetData($CabinetInfo, "CabinetNumber")

            ; $SPFILENOTIFY_NEEDNEWCABINET will not have to ever happen, so set to return error 3 ERROR_PATH_NOT_FOUND - The system cannot find the path specified,
            ;   or use FileOpenDialog(), example FileOpenDialog("Cab Files", @DesktopDir & "\", "Cab Files (*.cab;*.*_;*.*$)", 1)
            $NewPath = FileOpenDialog("Cab Files", $CabinetPath, "Cab Files (*.cab;*.*_;*.*$)", 1)
            If @Error Then Return 3 ;ERROR_PATH_NOT_FOUND, The system cannot find the path specified.
            DllStructSetData(DllStructCreate("WCHAR[260]", $Param2), 1, $NewPath)
            Return 0 ;NO_ERROR

            ; routine should return one of the following values.
            ;     NO_ERROR  - No error was encountered, continue processing the cabinet.
            ;    ERROR_XXX - An error of the specified type occurred. The SetupIterateCabinet function will return FALSE, and the specified
            ;       error code will be returned by a call to GetLastError.

            ; Note: There is no default cabinet callback routine; thus, you must supply a callback routine to handle the notifications sent by SetupIterateCabinet.

            ; Remarks: If the callback routine returns NO_ERROR, SetupIterateCabinet checks the buffer pointed to by Param2. If the buffer is not empty,
            ;           then it contains a new source path. If the buffer is empty, the source path is assumed to be unchanged.
            ;
            ;         callback function should ensure that the cabinet is accessible before it returns, calling the SetupPromptForDisk function,
            ;            if new media needs to be inserted.

        ;Case Else
            ;
        EndSwitch
    Return $FILEOP_ABORT
EndFunc


Func _CABINET_CALLBACK_EX($Context, $Notification, $Param1, $Param2)
    Switch $Notification
        Case $SPFILENOTIFY_FILEINCABINET ;; 17 - 0x00000011
            ; FILE_IN_CABINET_INFO structure ($FileInCabinetInfo)
            $cCallbackEx[0][4] = DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][1], $Param1)
            ;    If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
            ;$Win32Error = DllStructGetData($cCallbackEx[0][4], "Win32Error")
            If DllStructGetData($cCallbackEx[0][4], "Win32Error") Then Return $FILEOP_SKIP
            If $cCallbackEx[0][0] = $cCallbackEx[0][2] Then
                If $cCallbackEx[0][2] = 3198976 Then Return $FILEOP_ABORT
                $cCallbackEx[0][2] *= 2
                ReDim $cCallbackEx[$cCallbackEx[0][2] + 2][5]
                For $i = 0 To 4
                    $cCallbackEx[$cCallbackEx[0][2] + 1][$i] = $cCallbackEx[$cCallbackEx[0][3]][$i]
                Next
                $cCallbackEx[0][3] = $cCallbackEx[0][2] + 1
            EndIf
            $cCallbackEx[0][0] += 1
            If Not ($cCallbackEx[$cCallbackEx[0][3]][0] & $cCallbackEx[$cCallbackEx[0][3]][4]) Then
                $cCallbackEx[0][1] += DllStructGetData($cCallbackEx[0][4], "FileSize")
                Return $FILEOP_SKIP
            EndIf
            ;    File name as it exists within the cabinet file.
            ;;;$NameInCabinet = DllStructGetData($cCallbackEx[0][4], "NameInCabinet")
            $cCallbackEx[$cCallbackEx[0][0]][0] = DllStructGetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], DllStructGetData($cCallbackEx[0][4], 1)), 1)
            $cCallbackEx[$cCallbackEx[0][0]][1] = StringInStr($cCallbackEx[$cCallbackEx[0][0]][0], "\", 1, -1)
            $cCallbackEx[$cCallbackEx[0][0]][2] = StringTrimLeft($cCallbackEx[$cCallbackEx[0][0]][0], $cCallbackEx[$cCallbackEx[0][0]][1])
            If $cCallbackEx[$cCallbackEx[0][3]][4] And StringRegExp($cCallbackEx[$cCallbackEx[0][0]][2], $cCallbackEx[$cCallbackEx[0][3]][4]) = 0 Then
                $cCallbackEx[0][0] -= 1
                Return $FILEOP_SKIP
            EndIf
            If $cCallbackEx[$cCallbackEx[0][0]][1] Then
                $cCallbackEx[$cCallbackEx[0][0]][4] = StringLeft($cCallbackEx[$cCallbackEx[0][0]][0], $cCallbackEx[$cCallbackEx[0][0]][1])
                $cCallbackEx[$cCallbackEx[0][0]][0] = $cCallbackEx[$cCallbackEx[0][0]][2]
                If $cCallbackEx[$cCallbackEx[0][3]][0] = 2 And Not ($cCallbackEx[$cCallbackEx[0][0] - 1][4] == $cCallbackEx[$cCallbackEx[0][0]][4]) Then
                    If Not DirCreate($cCallbackEx[$cCallbackEx[0][3]][3] & $cCallbackEx[$cCallbackEx[0][0]][4]) Then
                        $cCallbackEx[0][0] -= 1
                        Return $FILEOP_SKIP
                    EndIf
                EndIf
            EndIf
            ;    Uncompressed size of the file in the cabinet, in bytes.
            $cCallbackEx[$cCallbackEx[0][0]][1] = DllStructGetData($cCallbackEx[0][4], "FileSize")
            If $cCallbackEx[$cCallbackEx[0][3]][0] = 2 Then
                ;    Target path and file name.
                ;;;$FullTargetName = DllStructSetData($cCallbackEx[0][4], "FullTargetName", "xxxx")
                DllStructSetData($cCallbackEx[0][4], "FullTargetName", $cCallbackEx[$cCallbackEx[0][3]][3] & $cCallbackEx[$cCallbackEx[0][0]][4] & $cCallbackEx[$cCallbackEx[0][0]][0])
                Return $FILEOP_DOIT
            Else
                ;    Date that the file was last saved.
                $cCallbackEx[$cCallbackEx[0][0]][2] = DllStructGetData($cCallbackEx[0][4], "DosDate")
                ;    MS-DOS time stamp of the file in the cabinet.
                $cCallbackEx[$cCallbackEx[0][0]][3] = DllStructGetData($cCallbackEx[0][4], "DosTime")
                ;    _DOSDateTimeToStr($cCallbackEx[$cCallbackEx[0][0]][2], $cCallbackEx[$cCallbackEx[0][0]][3])
                $cCallbackEx[$cCallbackEx[0][0]][2] = StringFormat("%02d/%02d/%04d %02d.%02d", BitAND($cCallbackEx[$cCallbackEx[0][0]][2], 31), BitAND(BitShift($cCallbackEx[$cCallbackEx[0][0]][2], 5), 15), BitAND(BitShift($cCallbackEx[$cCallbackEx[0][0]][2], 9), 63) + 1980, BitAND(BitShift($cCallbackEx[$cCallbackEx[0][0]][3], 11), 31), BitAND(BitShift($cCallbackEx[$cCallbackEx[0][0]][3], 5), 63))
                ;    Attributes of the file in the cabinet.
                $cCallbackEx[$cCallbackEx[0][0]][3] = DllStructGetData($cCallbackEx[0][4], "DosAttribs")
                $cCallbackEx[0][1] += $cCallbackEx[$cCallbackEx[0][0]][1]
                Return $FILEOP_SKIP
            EndIf
            ; callback routine should return one of the following.
            ;     $FILEOP_ABORT = 0    ;Abort cabinet processing.
            ;    $FILEOP_SKIP = 1    ;Do not extract the file, skip it.
            ;    $FILEOP_DOIT = 2    ;Extract the file.

            ; If your callback routine returns $FILEOP_DOIT, the name to use for the extracted file should be specified in the FullTargetName member
            ;   of the FILE_IN_CABINET_INFO ($cCallbackEx[0][4]) structure passed to the routine in Param1 ($cCallbackEx[0][4]).

            ; Note: There is no default cabinet callback routine. The setup application should supply a callback routine to handle the
            ;   notifications sent by SetupIterateCabinet.
        Case $SPFILENOTIFY_FILEEXTRACTED ;; 19 - 0x00000013
            ; $Param2 Unused.
            $cCallbackEx[0][4] = DllStructCreate($_FILEPATHS, $Param1)
            ; $cCallbackEx[0][4] ($FilePathInfo) contains path information for the extracted file, The SourceFile member of the FILEPATHS structure contains the full
            ;   source path of the cabinet. The TargetFile member supplies the full target path of the file to be installed on the system

            ;    Path to the target file.
            ;;;$TargetFile = DllStructGetData($cCallbackEx[0][4], "Target")
            ;Local $TargetFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($cCallbackEx[0][4], 1)), 1)
            ;    Path to the source file. This member is not used when the FILEPATHS structure is used with a file delete operation.
            ;;;$SourceFile = DllStructGetData($cCallbackEx[0][4], "Source")
            ;Local $SourceFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($cCallbackEx[0][4], 2)), 1)
            ;    If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
            ;Local $FNFE_Win32Error = DllStructGetData($cCallbackEx[0][4], "Win32Error")
            ;    Additional information that depends on the notification sent with the FILEPATHS structure.
            ;Local $Flags = DllStructGetData($cCallbackEx[0][4], "Flags")
            ; Additional information that depends on the notification sent with the FILEPATHS structure.
            ;     For SPFILENOTIFY_COPYERROR notifications, Flags specifies dialog box behavior and can be one of the following values.
            ;           $SP_COPY_NOBROWSE   - Do not offer the user the option to browse.
            ;         $SP_COPY_NOSKIP    - Do not offer the user the option to skip the file.
            ;         $SP_COPY_WARNIFSKIP - Inform the user that skipping the file may affect the installation.
            ;
            ;     For SPFILENOTIFY_FILEOPDELAYED notifications, Flags specifies the type of file operation delayed and can be one of the following values.
            ;           $FILEOP_COPY   - A file copy operation was delayed.
            ;         $FILEOP_DELETE - A file delete operation was delayed.

            ; cabinet callback routine should return one of the following values.
            ;     NO_ERROR - No error was encountered, continue processing the cabinet.
            ;     ERROR_XXX - An error of the specified type occurred. SetupIterateCabinet will return zero. GetLastError will return the specified error code.

            ; Note: There is no default cabinet callback routine supplied with the Setup API. Your setup application should supply a callback routine to
            ;   handle the notifications sent by the SetupIterateCabinet function.
            If DllStructGetData($cCallbackEx[0][4], "Win32Error") Then Return DllStructGetData($cCallbackEx[0][4], "Win32Error")
            $cCallbackEx[0][1] += $cCallbackEx[$cCallbackEx[0][0]][1]
            Return 0 ;NO_ERROR
        Case $SPFILENOTIFY_CABINETINFO ;; 16 - 0x00000010
            Return 0 ;NO_ERROR
            ; $CabinetInfo - $cCallbackEx[0][4]
            $cCallbackEx[0][4] = DllStructCreate($_CABINET_INFO, $Param1)
            ;If the callback returns NO_ERROR, $Param2 is a pointer to a null-terminated string.
            ;  If the string is not empty, it specifies a new path to the cabinet.
            Local $CabinetPath, $CabinetFile, $DiskName, $SetId, $CabinetNumber, $NewPath

            ;    Path to the cabinet file.
            ;;$CabinetPath = DllStructGetData($cCallbackEx[0][4], "CabinetPath")
            $CabinetPath = DllStructGetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], DllStructGetData($cCallbackEx[0][4], 1)), 1)
            ;    Name of the cabinet file.
            ;;;$CabinetFile = DllStructGetData($cCallbackEx[0][4], "CabinetFile")
            $CabinetFile = DllStructGetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], DllStructGetData($cCallbackEx[0][4], 2)), 1)
            ;    Name of the source media that contains the cabinet file.
            ;;;$DiskName = DllStructGetData($cCallbackEx[0][4], "DiskName")
            $DiskName = DllStructGetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], DllStructGetData($cCallbackEx[0][4], 2)), 1)
            ;    Identifier of the current set. This number is generated by the software that builds the cabinet.
            $SetId = DllStructGetData($cCallbackEx[0][4], "SetId")
            ;    Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
            ;      a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
            $CabinetNumber = DllStructGetData($cCallbackEx[0][4], "CabinetNumber")

            ; $SPFILENOTIFY_NEEDNEWCABINET will not have to ever happen, so set to return error, or use FileOpenDialog()
            ;   example $NewPath = FileOpenDialog("Cab Files", @DesktopDir & "\", "Cab Files (*.cab;*.*_;*.*$)", 1)
            ;Return 3 ;ERROR_PATH_NOT_FOUND, The system cannot find the path specified.

            ; routine should return one of the following values.
            ;     NO_ERROR  - No error was encountered, continue processing the cabinet.
            ;    ERROR_XXX - An error of the specified type occurred. The SetupIterateCabinet function will return FALSE, and the specified
            ;       error code will be returned by a call to GetLastError.

            ; Note: There is no default cabinet callback routine; thus, you must supply a callback routine to handle the notifications sent by SetupIterateCabinet.

            ; Remarks: If the callback routine returns NO_ERROR, SetupIterateCabinet checks the buffer pointed to by Param2. If the buffer is not empty,
            ;           then it contains a new source path. If the buffer is empty, the source path is assumed to be unchanged.
            ;
            ;         callback function should ensure that the cabinet is accessible before it returns, calling the SetupPromptForDisk function,
            ;            if new media needs to be inserted.

            Return 0 ;NO_ERROR
        Case $SPFILENOTIFY_NEEDNEWCABINET ;; 18 - 0x00000012
            ; $CabinetInfo - $cCallbackEx[0][4]
            $cCallbackEx[0][4] = DllStructCreate($_CABINET_INFO, $Param1)
            ;If the callback returns NO_ERROR, $Param2 is a pointer to a null-terminated string.
            ;  If the string is not empty, it specifies a new path to the cabinet.
            Local $CabinetPath, $CabinetFile, $DiskName, $SetId, $CabinetNumber, $NewPath

            ;    Path to the cabinet file.
            ;;;$CabinetPath = DllStructGetData($cCallbackEx[0][4], "CabinetPath")
            $CabinetPath = DllStructGetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], DllStructGetData($cCallbackEx[0][4], 1)), 1)
            ;    Name of the cabinet file.
            ;;;$CabinetFile = DllStructGetData($cCallbackEx[0][4], "CabinetFile")
            ;$CabinetFile = DllStructGetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], DllStructGetData($cCallbackEx[0][4], 2)), 1)
            ;    Name of the source media that contains the cabinet file.
            ;;;$DiskName = DllStructGetData($cCallbackEx[0][4], "DiskName")
            ;$DiskName = DllStructGetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], DllStructGetData($cCallbackEx[0][4], 2)), 1)
            ;    Identifier of the current set. This number is generated by the software that builds the cabinet.
            ;$SetId = DllStructGetData($cCallbackEx[0][4], "SetId")
            ;    Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
            ;      a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
            $CabinetNumber = DllStructGetData($cCallbackEx[0][4], "CabinetNumber")

            ; $SPFILENOTIFY_NEEDNEWCABINET will not have to ever happen, so set to return error 3 ERROR_PATH_NOT_FOUND - The system cannot find the path specified,
            ;   or use FileOpenDialog(), example FileOpenDialog("Cab Files", @DesktopDir & "\", "Cab Files (*.cab;*.*_;*.*$)", 1)
            $NewPath = FileOpenDialog("Cab Files", $CabinetPath, "Cab Files (*.cab;*.*_;*.*$)", 1)
            If @Error Then Return 3 ;ERROR_PATH_NOT_FOUND, The system cannot find the path specified.
            DllStructSetData(DllStructCreate($cCallbackEx[$cCallbackEx[0][3]][2], $Param2), 1, $NewPath)
            Return 0 ;NO_ERROR

            ; routine should return one of the following values.
            ;     NO_ERROR  - No error was encountered, continue processing the cabinet.
            ;    ERROR_XXX - An error of the specified type occurred. The SetupIterateCabinet function will return FALSE, and the specified
            ;       error code will be returned by a call to GetLastError.

            ; Note: There is no default cabinet callback routine; thus, you must supply a callback routine to handle the notifications sent by SetupIterateCabinet.

            ; Remarks: If the callback routine returns NO_ERROR, SetupIterateCabinet checks the buffer pointed to by Param2. If the buffer is not empty,
            ;           then it contains a new source path. If the buffer is empty, the source path is assumed to be unchanged.
            ;
            ;         callback function should ensure that the cabinet is accessible before it returns, calling the SetupPromptForDisk function,
            ;            if new media needs to be inserted.

        ;Case Else
            ;
        EndSwitch
    Return $FILEOP_ABORT
EndFunc


Func _FILE_CALLBACK($Context, $Notification, $Param1, $Param2)
    Switch $Notification
        Case $SPFILENOTIFY_FILEINCABINET ;; 17 - 0x00000011
            Local $sContext = DllStructCreate($_Context, $Context), $Act = DllStructGetData($sContext, "Act"), $sFilter = DllStructGetData($sContext, "sFilter")
            Local $FileInCabinetInfo = DllStructCreate(DllStructGetData($sContext, "tContext"), $Param1)
            ;    If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
            ;$FNFIC_Win32Error = DllStructGetData($FileInCabinetInfo, "Win32Error")
            If DllStructGetData($FileInCabinetInfo, "Win32Error") Then Return $FILEOP_SKIP
            If Not $Act And Not $sFilter Then
                DllStructSetData($sContext, "cFiles", DllStructGetData($sContext, "cFiles") + 1)
                DllStructSetData($sContext, "sFiles", DllStructGetData($sContext, "sFiles") + DllStructGetData($FileInCabinetInfo, "FileSize"))
                Return $FILEOP_SKIP
            EndIf
            Local $tContext = DllStructGetData($sContext, 1), $DestDir, $NameInCabinet, $sNameInCabinet, $FileSize, $DosDate, $DosTime;;, $DateTimeStr, $DosAttribs, $CabinetFile, $FNFIC_Win32Error, $FullTargetName
            $DestDir = DllStructGetData($sContext, "DestDir")
            ;    File name as it exists within the cabinet file.
            ;;;$NameInCabinet = DllStructGetData($FileInCabinetInfo, "NameInCabinet")
            $NameInCabinet = DllStructGetData(DllStructCreate($tContext, DllStructGetData($FileInCabinetInfo, 1)), 1)
            DllStructSetData($sContext, "cFilename", $NameInCabinet)
            $sNameInCabinet = StringInStr($NameInCabinet, "\", 1, -1)
            If $sFilter And StringRegExp(StringTrimLeft($NameInCabinet, $sNameInCabinet), $sFilter) = 0 Then Return $FILEOP_SKIP
            If $sNameInCabinet Then
                $sNameInCabinet = StringLeft($NameInCabinet, $sNameInCabinet)
                If $Act = 2 And Not (DllStructGetData($sContext, "sDir") == $sNameInCabinet) Then
                    If Not DirCreate($DestDir & $sNameInCabinet) Then Return $FILEOP_SKIP
                    DllStructSetData($sContext, "sDir", $sNameInCabinet)
                EndIf
            EndIf
            DllStructSetData($sContext, "cFiles", DllStructGetData($sContext, "cFiles") + 1)
            ;    Uncompressed size of the file in the cabinet, in bytes.
            $FileSize = DllStructGetData($FileInCabinetInfo, "FileSize")
            DllStructSetData($sContext, "cFileSize", $FileSize)
            If $Act = 2 Then
                ;    Target path and file name.
                ;;;$FullTargetName = DllStructSetData($FileInCabinetInfo, "FullTargetName", "xxxx")
                DllStructSetData($FileInCabinetInfo, "FullTargetName", DllStructGetData($sContext, "DestDir") & $NameInCabinet)
                Return $FILEOP_DOIT
            Else
                ;    Date that the file was last saved.
                $DosDate = DllStructGetData($FileInCabinetInfo, "DosDate")
                ;    MS-DOS time stamp of the file in the cabinet.
                $DosTime = DllStructGetData($FileInCabinetInfo, "DosTime")
                ;    _DOSDateTimeToStr($DosDate, $DosTime)
                ;$DateTimeStr = StringFormat("%02d/%02d/%04d %02d.%02d", BitAND($DosDate, 31), BitAND(BitShift($DosDate, 5), 15), BitAND(BitShift($DosDate, 9), 63) + 1980, BitAND(BitShift($DosTime, 11), 31), BitAND(BitShift($DosTime, 5), 63))
                ;    Attributes of the file in the cabinet.
                ;$DosAttribs = DllStructGetData($FileInCabinetInfo, "DosAttribs")
                DllStructSetData($sContext, "sFiles", DllStructGetData($sContext, "sFiles") + $FileSize)
                $PSPFILECALLBACK &= $NameInCabinet & "|" & $FileSize & "|" & StringFormat("%02d/%02d/%04d %02d.%02d", BitAND($DosDate, 31), BitAND(BitShift($DosDate, 5), 15), BitAND(BitShift($DosDate, 9), 63) + 1980, BitAND(BitShift($DosTime, 11), 31), BitAND(BitShift($DosTime, 5), 63)) & "|" & DllStructGetData($FileInCabinetInfo, "DosAttribs") & @LF
                Return $FILEOP_SKIP
            EndIf
            ; callback routine should return one of the following.
            ;     $FILEOP_ABORT = 0    ;Abort cabinet processing.
            ;    $FILEOP_SKIP = 1    ;Do not extract the file, skip it.
            ;    $FILEOP_DOIT = 2    ;Extract the file.

            ; If your callback routine returns $FILEOP_DOIT, the name to use for the extracted file should be specified in the FullTargetName member
            ;   of the FILE_IN_CABINET_INFO ($FileInCabinetInfo) structure passed to the routine in Param1 ($FileInCabinetInfo).

            ; Note: There is no default cabinet callback routine. The setup application should supply a callback routine to handle the
            ;   notifications sent by SetupIterateCabinet.
        Case $SPFILENOTIFY_FILEEXTRACTED ;; 19 - 0x00000013
            ; $Param2 Unused.
            Local $FilePathInfo = DllStructCreate($_FILEPATHS, $Param1), $sContext = DllStructCreate($_Context, $Context);, $tContext = DllStructGetData($sContext, 1)
            ; $FilePathInfo contains path information for the extracted file, The SourceFile member of the FILEPATHS structure contains the full
            ;   source path of the cabinet. The TargetFile member supplies the full target path of the file to be installed on the system

            ;    Path to the target file.
            ;;;$TargetFile = DllStructGetData($FilePathInfo, "Target")
            ;Local $TargetFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($FilePathInfo, 1)), 1)
            ;    Path to the source file. This member is not used when the FILEPATHS structure is used with a file delete operation.
            ;;;$SourceFile = DllStructGetData($FilePathInfo, "Source")
            ;Local $SourceFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($FilePathInfo, 2)), 1)
            ;    If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
            ;Local $FNFE_Win32Error = DllStructGetData($FilePathInfo, "Win32Error")
            ;    Additional information that depends on the notification sent with the FILEPATHS structure.
            ;Local $Flags = DllStructGetData($FilePathInfo, "Flags")
            ; Additional information that depends on the notification sent with the FILEPATHS structure.
            ;     For SPFILENOTIFY_COPYERROR notifications, Flags specifies dialog box behavior and can be one of the following values.
            ;           $SP_COPY_NOBROWSE   - Do not offer the user the option to browse.
            ;         $SP_COPY_NOSKIP    - Do not offer the user the option to skip the file.
            ;         $SP_COPY_WARNIFSKIP - Inform the user that skipping the file may affect the installation.
            ;
            ;     For SPFILENOTIFY_FILEOPDELAYED notifications, Flags specifies the type of file operation delayed and can be one of the following values.
            ;           $FILEOP_COPY   - A file copy operation was delayed.
            ;         $FILEOP_DELETE - A file delete operation was delayed.

            ; cabinet callback routine should return one of the following values.
            ;     NO_ERROR - No error was encountered, continue processing the cabinet.
            ;     ERROR_XXX - An error of the specified type occurred. SetupIterateCabinet will return zero. GetLastError will return the specified error code.

            ; Note: There is no default cabinet callback routine supplied with the Setup API. Your setup application should supply a callback routine to
            ;   handle the notifications sent by the SetupIterateCabinet function.
            If DllStructGetData($sContext, "Win32Error") Then Return DllStructGetData($sContext, "Win32Error")
            DllStructSetData($sContext, "sFiles", DllStructGetData($sContext, "sFiles") + DllStructGetData($sContext, "cFileSize"))
            Return 0 ;NO_ERROR
        Case $SPFILENOTIFY_CABINETINFO ;; 16 - 0x00000010
            Return 0 ;NO_ERROR
            Local $CabinetInfo = DllStructCreate($_CABINET_INFO, $Param1), $sContext = DllStructCreate($_Context, $Context), $tContext = DllStructGetData($sContext, 1)
            ;If the callback returns NO_ERROR, $Param2 is a pointer to a null-terminated string.
            ;  If the string is not empty, it specifies a new path to the cabinet.
            Local $CabinetPath, $CabinetFile, $DiskName, $SetId, $CabinetNumber, $NewPath

            ;    Path to the cabinet file.
            ;;$CabinetPath = DllStructGetData($CabinetInfo, "CabinetPath")
            $CabinetPath = DllStructGetData(DllStructCreate($tContext, DllStructGetData($CabinetInfo, 1)), 1)
            ;    Name of the cabinet file.
            ;;;$CabinetFile = DllStructGetData($CabinetInfo, "CabinetFile")
            $CabinetFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($CabinetInfo, 2)), 1)
            ;    Name of the source media that contains the cabinet file.
            ;;;$DiskName = DllStructGetData($CabinetInfo, "DiskName")
            $DiskName = DllStructGetData(DllStructCreate($tContext, DllStructGetData($CabinetInfo, 2)), 1)
            ;    Identifier of the current set. This number is generated by the software that builds the cabinet.
            $SetId = DllStructGetData($CabinetInfo, "SetId")
            ;    Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
            ;      a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
            $CabinetNumber = DllStructGetData($CabinetInfo, "CabinetNumber")

            ; $SPFILENOTIFY_NEEDNEWCABINET will not have to ever happen, so set to return error, or use FileOpenDialog()
            ;   example $NewPath = FileOpenDialog("Cab Files", @DesktopDir & "\", "Cab Files (*.cab;*.*_;*.*$)", 1)
            ;Return 3 ;ERROR_PATH_NOT_FOUND, The system cannot find the path specified.

            ; routine should return one of the following values.
            ;     NO_ERROR  - No error was encountered, continue processing the cabinet.
            ;    ERROR_XXX - An error of the specified type occurred. The SetupIterateCabinet function will return FALSE, and the specified
            ;       error code will be returned by a call to GetLastError.

            ; Note: There is no default cabinet callback routine; thus, you must supply a callback routine to handle the notifications sent by SetupIterateCabinet.

            ; Remarks: If the callback routine returns NO_ERROR, SetupIterateCabinet checks the buffer pointed to by Param2. If the buffer is not empty,
            ;           then it contains a new source path. If the buffer is empty, the source path is assumed to be unchanged.
            ;
            ;         callback function should ensure that the cabinet is accessible before it returns, calling the SetupPromptForDisk function,
            ;            if new media needs to be inserted.

            Return 0 ;NO_ERROR
        Case $SPFILENOTIFY_NEEDNEWCABINET ;; 18 - 0x00000012
            Local $CabinetInfo = DllStructCreate($_CABINET_INFO, $Param1), $sContext = DllStructCreate($_Context, $Context), $tContext = DllStructGetData($sContext, 1)
            ;If the callback returns NO_ERROR, $Param2 is a pointer to a null-terminated string.
            ;  If the string is not empty, it specifies a new path to the cabinet.
            Local $CabinetPath, $CabinetFile, $DiskName, $SetId, $CabinetNumber, $NewPath

            ;    Path to the cabinet file.
            ;;;$CabinetPath = DllStructGetData($CabinetInfo, "CabinetPath")
            $CabinetPath = DllStructGetData(DllStructCreate($tContext, DllStructGetData($CabinetInfo, 1)), 1)
            ;    Name of the cabinet file.
            ;;;$CabinetFile = DllStructGetData($CabinetInfo, "CabinetFile")
            ;$CabinetFile = DllStructGetData(DllStructCreate($tContext, DllStructGetData($CabinetInfo, 2)), 1)
            ;    Name of the source media that contains the cabinet file.
            ;;;$DiskName = DllStructGetData($CabinetInfo, "DiskName")
            ;$DiskName = DllStructGetData(DllStructCreate($tContext, DllStructGetData($CabinetInfo, 2)), 1)
            ;    Identifier of the current set. This number is generated by the software that builds the cabinet.
            ;$SetId = DllStructGetData($CabinetInfo, "SetId")
            ;    Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
            ;      a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
            $CabinetNumber = DllStructGetData($CabinetInfo, "CabinetNumber")

            ; $SPFILENOTIFY_NEEDNEWCABINET will not have to ever happen, so set to return error 3 ERROR_PATH_NOT_FOUND - The system cannot find the path specified,
            ;   or use FileOpenDialog(), example FileOpenDialog("Cab Files", @DesktopDir & "\", "Cab Files (*.cab;*.*_;*.*$)", 1)
            $NewPath = FileOpenDialog("Cab Files", $CabinetPath, "Cab Files (*.cab;*.*_;*.*$)", 1)
            If @Error Then Return 3 ;ERROR_PATH_NOT_FOUND, The system cannot find the path specified.
            DllStructSetData(DllStructCreate($tContext, $Param2), 1, $NewPath)
            Return 0 ;NO_ERROR

            ; routine should return one of the following values.
            ;     NO_ERROR  - No error was encountered, continue processing the cabinet.
            ;    ERROR_XXX - An error of the specified type occurred. The SetupIterateCabinet function will return FALSE, and the specified
            ;       error code will be returned by a call to GetLastError.

            ; Note: There is no default cabinet callback routine; thus, you must supply a callback routine to handle the notifications sent by SetupIterateCabinet.

            ; Remarks: If the callback routine returns NO_ERROR, SetupIterateCabinet checks the buffer pointed to by Param2. If the buffer is not empty,
            ;           then it contains a new source path. If the buffer is empty, the source path is assumed to be unchanged.
            ;
            ;         callback function should ensure that the cabinet is accessible before it returns, calling the SetupPromptForDisk function,
            ;            if new media needs to be inserted.

        ;Case Else
            ;
        EndSwitch
    Return $FILEOP_ABORT
EndFunc


; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_DOSDateTimeToStr
; Description ...: Decode a DOS date to a string
; Syntax.........: _WinAPI_DOSDateTimeToStr($iDosDate, $iDosTime)
; Parameters ....: $iDosDate - MS-DOS date, packed as follows:
;                 |Bits  0- 4 Day of the month (1–31)
;                 |Bits  5- 8 Month (1 = January, 2 = February, and so on)
;                 |Bits  9-15 Year offset from 1980 (add 1980 to get actual year)
;                 $iDosTime - MS-DOS date, packed as follows:
;                 |Bits  0- 4 Second divided by 2
;                 |Bits  5-10 Minute (0–59)
;                 |Bits 11-15 Hour (0–23 on a 24-hour clock)
;                 $LCID    - The locale identifier (LCID), Default is 1033 (EN-US)
; Return values .: Success  - Date/time string formatted as dd/MM/yyyy HH.mm
; Author ........: DXRW4E
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _WinAPI_DOSDateTimeToStr($iDosDate, $iDosTime, $LCID = "1033")
    Local $aResult, $bResult, $tTime = DllStructCreate("struct;dword Lo;dword Hi;endstruct"), $tSystTime = DllStructCreate("struct;word Year;word Month;word Dow;word Day;word Hour;word Minute;word Second;word MSeconds;endstruct")
    DllCall("kernel32.dll", "bool", "DosDateTimeToFileTime", "word", $iDosDate, "word", $iDosTime, "struct*", $tTime)
    DllCall("kernel32.dll", "bool", "FileTimeToSystemTime", "struct*", $tTime, "struct*", $tSystTime)
    $aResult = DllCall("kernel32.dll", "int", "GetDateFormatW", "ulong", $LCID, "dword", 0, "struct*", $tSystTime, "wstr", "dd/MM/yyyy", "wstr", "", "int", 2048)
    $bResult = DllCall("kernel32.dll", "int", "GetTimeFormatW", "ulong", $LCID, "dword", 0, "struct*", $tSystTime, "wstr", " HH.mm", "wstr", "", "int", 2048)
    ;;If @error Then Return SetError(@error, @extended, 0)
    Return $aResult[5] & $bResult[5]
EndFunc   ;==>_WinAPI_DOSDateTimeToStr


; #FUNCTION# ====================================================================================================================
; Name...........: _DOSDateTimeToStr
; Description ...: Decode a DOS date to a string
; Syntax.........: _DOSDateTimeToStr($iDosDate, $iDosTime)
; Parameters ....: $iDosDate    - MS-DOS date, packed as follows:
;                 |Bits  0- 4 Day of the month (1–31)
;                 |Bits  5- 8 Month (1 = January, 2 = February, and so on)
;                 |Bits  9-15 Year offset from 1980 (add 1980 to get actual year)
;                 $iDosTime    - MS-DOS date, packed as follows:
;                 |Bits  0- 4 Second divided by 2
;                 |Bits  5-10 Minute (0–59)
;                 |Bits 11-15 Hour (0–23 on a 24-hour clock)
; Return values .: Success    - Date/time string formatted as mm/dd/yyyy hh:mm:ss
; Author ........: Paul Campbell (PaulIA)
; Modified.......: DXRW4E
; Remarks .......:
; Related .......: _Date_Time_DOSDateTimeToStr, _Date_Time_DOSDateToStr, _Date_Time_DOSTimeToStr
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _DOSDateTimeToStr($iDosDate, $iDosTime)
;;    The MS-DOS date. The date is a packed value with the following format.
;;      Bits   Description
;;      0-4    Day of the month (1–31) = BitAND($iDosDate, 31)
;;      5-8    Month (1 - January, 2 - February, and so on) = BitAND(BitShift($iDosDate, 5), 15)
;;      9-15   Year offset from 1980 (add 1980 to get actual year) = BitAND(BitShift($iDosDate, 9), 63) + 1980
;;
;;    The MS-DOS time. The time is a packed value with the following format.
;;      Bits   Description
;;      0-4     Second divided by 2 = BitAND($iDosTime, 31) * 2
;;      5-10     Minute (0–59) = BitAND(BitShift($iDosTime, 5), 63)
;;      11-15  Hour (0–23 on a 24-hour clock) = BitAND(BitShift($iDosTime, 11), 31)
    Return StringFormat("%02d/%02d/%04d %02d.%02d", BitAND($iDosDate, 31), BitAND(BitShift($iDosDate, 5), 15), BitAND(BitShift($iDosDate, 9), 63) + 1980, BitAND(BitShift($iDosTime, 11), 31), BitAND(BitShift($iDosTime, 5), 63))
EndFunc   ;==>_WinAPI_DOSDateTimeToStr


Func _WinAPI_GetLastErrorEx()
    Local $GetLastError = DllCall($h_Kernel32DLL, "long", "GetLastError")
    Return $GetLastError[0]
EndFunc    ;==>_WinAPI_GetLastErrorEx

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Link to comment
Share on other sites

You mean the GUI freeze, do you?

the GUI is completely down, I can not write Label or otherwise, does not respond any more any gui control ect ect

I am no expert, but I think maybe a bug in autoit hmmmm, because at work the CPU and RAM and All are ok, there no symptom indicating them and an error occurred during some process, in fact the CPU and the RAM even if archive cab and large, I still work in low levels, and only GUI which does not responding hmmmmmm

sorry for my english

Ciao

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Link to comment
Share on other sites

  • 3 months later...

here is still the same story, just wanted to know this is a problem of autoit???? (who causes the GUI Error (Process failed to respond ect ect ect), DllCall or DllCallbackRegister), or something what we have to improve in the script, sinned and really useful work in unicode mode with cabinet

;#include <array.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <ProgressConstants.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>


Global $hGui, $hFilePathButton, $hFilePathInput, $hExtractDirInput, $hExtractDirButton, $hStartButton, $hLabel, $hProgress

#Region ;Global Variables and Constants

Global Const $h_Kernel32DLL = DllOpen("Kernel32.dll")
Global Const $h_CabiNetDLL = DllOpen("CabiNet.dll")

Global $hDefaultProcessHeap = DllCall($h_Kernel32DLL, "HANDLE", "GetProcessHeap")
If Not @Error And $hDefaultProcessHeap[0] Then $hDefaultProcessHeap = $hDefaultProcessHeap[0]
Global Const $GPTR              = 0x0040    ;Combines GMEM_FIXED and GMEM_ZEROINIT.
Global $acMacros

Global Const $CP_UTF8                 = 65001

Global $FNALLOC  = DllCallbackRegister("_FNALLOC", "ptr:cdecl", "ulong")
Global $FNFREE    = DllCallbackRegister("_FNFREE", "none:cdecl", "HANDLE")
Global $FNOPEN    = DllCallbackRegister("_FNOPEN", "HANDLE:cdecl", "ptr;int;int")    ;"ptr;int;int"
Global $FNREAD    = DllCallbackRegister("_FNREAD", "int:cdecl", "INT_PTR;ptr;uint")    ;"HANDLE;ptr;uint"
Global $FNWRITE  = DllCallbackRegister("_FNWRITE", "int:cdecl", "INT_PTR;ptr;uint")    ;"HANDLE;ptr;uint"
Global $FNCLOSE  = DllCallbackRegister("_FNCLOSE", "int:cdecl", "INT_PTR")    ;"HANDLE"
Global $FNSEEK    = DllCallbackRegister("_FNSEEK", "int:cdecl", "INT_PTR;long;int")    ;"HANDLE;long;int"
Global $FNFDINOTIFY = DllCallbackRegister("_FNFDINOTIFY", "none:cdecl", "int;ptr")

Global $PFNALLOC     = DllCallbackGetPtr($FNALLOC)
Global $PFNFREE   = DllCallbackGetPtr($FNFREE)
Global $PFNOPEN   = DllCallbackGetPtr($FNOPEN)
Global $PFNREAD   = DllCallbackGetPtr($FNREAD)
Global $PFNWRITE     = DllCallbackGetPtr($FNWRITE)
Global $PFNCLOSE     = DllCallbackGetPtr($FNCLOSE)
Global $PFNSEEK   = DllCallbackGetPtr($FNSEEK)
Global $PFNFDINOTIFY = DllCallbackGetPtr($FNFDINOTIFY)

Global Const $GENERIC_READ                   = 0x80000000 ;; $SDDL_GENERIC_READ = "GR"
Global Const $GENERIC_WRITE                 = 0x40000000 ;; $SDDL_GENERIC_WRITE = "GW"
Global Const $GENERIC_EXECUTE                 = 0x20000000 ;; $SDDL_GENERIC_EXECUTE = "GX"
Global Const $GENERIC_ALL                     = 0x10000000 ;; $SDDL_GENERIC_ALL = "GA"
Global Const $GENERIC_READ_WRITE               = BitOR($GENERIC_READ, $GENERIC_WRITE)

;;Global Const $CREATE_NEW = 1
Global Const $CREATE_ALWAYS = 2
Global Const $OPEN_EXISTING = 3
;;Global Const $OPEN_ALWAYS = 4
;;Global Const $TRUNCATE_EXISTING = 5

;;;; from msvcrt/fcntl.h */
;;/* Specifiy one of these flags to define the access mode. */
Global Const $_O_RDONLY    = 0
Global Const $_O_WRONLY    = 1
Global Const $_O_RDWR        = 2

;;/* Mask for access mode bits in the _open flags. */
Global Const $_O_ACCMODE      = 0x0003    ;BitOR($_O_RDONLY, $_O_WRONLY, $_O_RDWR)

Global Const $_O_APPEND       = 0x0008    ;;/* Writes will add to the end of the file. */

Global Const $_O_RANDOM       = 0x0010
Global Const $_O_SEQUENTIAL   = 0x0020
Global Const $_O_TEMPORARY      = 0x0040    ;;/* Make the file dissappear after closing.  * WARNING: Even if not created by _open! */
Global Const $_O_NOINHERIT      = 0x0080

Global Const $_O_CREAT        = 0x0100    ;;/* Create the file if it does not exist. */
Global Const $_O_TRUNC        = 0x0200    ;;/* Truncate the file if it does exist. */
Global Const $_O_EXCL          = 0x0400    ;;/* Open only if the file does not exist. */

Global Const $_O_SHORT_LIVED  = 0x1000

;;/* NOTE: Text is the default even if the given _O_TEXT bit is not on. */
Global Const $_O_TEXT          = 0x4000    ;;/* CR-LF in file becomes LF in memory. */
Global Const $_O_BINARY       = 0x8000    ;;/* Input and output is not translated. */
Global Const $_O_RAW          = $_O_BINARY

Global Const $FILE_SHARE_READ   = 0x01
;;Global Const $FILE_SHARE_WRITE  = 0x02
;;Global Const $FILE_SHARE_DELETE = 0x04

;;Global Const $FILE_ATTRIBUTE_READONLY         = 0x00000001
;;Global Const $FILE_ATTRIBUTE_HIDDEN             = 0x00000002
;;Global Const $FILE_ATTRIBUTE_SYSTEM             = 0x00000004
;;Global Const $FILE_ATTRIBUTE_DIRECTORY           = 0x00000010
Global Const $FILE_ATTRIBUTE_ARCHIVE             = 0x00000020
;;Global Const $FILE_ATTRIBUTE_DEVICE             = 0x00000040
Global Const $FILE_ATTRIBUTE_NORMAL           = 0x00000080
;;Global Const $FILE_ATTRIBUTE_TEMPORARY           = 0x00000100
;;Global Const $FILE_ATTRIBUTE_SPARSE_FILE       = 0x00000200
;;Global Const $FILE_ATTRIBUTE_REPARSE_POINT       = 0x00000400
;;Global Const $FILE_ATTRIBUTE_COMPRESSED         = 0x00000800
;;Global Const $FILE_ATTRIBUTE_OFFLINE           = 0x00001000
;;Global Const $FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000
;;Global Const $FILE_ATTRIBUTE_ENCRYPTED           = 0x00004000


Global Const $MAX_CAB_SIZE      = 0x7FFFFFFF
Global Const $CB_MAX_CHUNK      = 32768
Global Const $CB_MAX_DISK        = 0x7ffffff
Global Const $CB_MAX_FILENAME    = 256
Global Const $CB_MAX_CABINET_NAME = 256
Global Const $CB_MAX_CAB_PATH    = 256
Global Const $CB_MAX_DISK_NAME    = 256

Global Const $tcompMASK_TYPE          = 0x000F  ;; Mask for compression type
Global Const $tcompTYPE_NONE          = 0x0000  ;; No compression
Global Const $tcompTYPE_MSZIP        = 0x0001  ;; MSZIP
Global Const $tcompTYPE_QUANTUM    = 0x0002  ;; Quantum
Global Const $tcompTYPE_LZX        = 0x0003  ;; LZX
Global Const $tcompBAD              = 0x000F  ;; Unspecified compression type

Global Const $tcompMASK_LZX_WINDOW    = 0x1F00  ;; Mask for LZX Compression Memory
Global Const $tcompLZX_WINDOW_LO      = 0x0F00  ;; Lowest LZX Memory (15)
Global Const $tcompLZX_WINDOW_HI      = 0x1500  ;; Highest LZX Memory (21)
Global Const $tcompSHIFT_LZX_WINDOW   = 8      ;; Amount to shift over to get int

Global Const $tcompMASK_QUANTUM_LEVEL  = 0x00F0  ;; Mask for Quantum Compression Level
Global Const $tcompQUANTUM_LEVEL_LO    = 0x0010  ;; Lowest Quantum Level (1)
Global Const $tcompQUANTUM_LEVEL_HI    = 0x0070  ;; Highest Quantum Level (7)
Global Const $tcompSHIFT_QUANTUM_LEVEL = 4     ;; Amount to shift over to get int

Global Const $tcompMASK_QUANTUM_MEM   = 0x1F00  ;; Mask for Quantum Compression Memory
Global Const $tcompQUANTUM_MEM_LO    = 0x0A00  ;; Lowest Quantum Memory (10)
Global Const $tcompQUANTUM_MEM_HI    = 0x1500  ;; Highest Quantum Memory (21)
Global Const $tcompSHIFT_QUANTUM_MEM  = 8      ;; Amount to shift over to get int

Global Const $tcompMASK_RESERVED      = 0xE000  ;; Reserved bits (high 3 bits)

;;
;; These are used with SetupIterateCabinet().
;;
Global Const $SPFILENOTIFY_CABINETINFO      = 16    ;; 0x00000010
Global Const $SPFILENOTIFY_FILEINCABINET      = 17    ;; 0x00000011
Global Const $SPFILENOTIFY_NEEDNEWCABINET    = 18    ;; 0x00000012
Global Const $SPFILENOTIFY_FILEEXTRACTED      = 19    ;; 0x00000013
Global Const $SPFILENOTIFY_FILEOPDELAYED      = 20    ;; 0x00000014

;;/***    FCIERROR - Error codes returned in erf.erfOper field
;; *
;; */
Const Enum _ ;FCIERROR
    $FCIERR_NONE, _           ;; No error
    $FCIERR_OPEN_SRC, _       ;; Failure opening file to be stored in cabinet, erf.erfTyp has C run-time *errno* value
    $FCIERR_READ_SRC, _       ;; Failure reading file to be stored in cabinet, erf.erfTyp has C run-time *errno* value
    $FCIERR_ALLOC_FAIL, _       ;; Out of memory in FCI
    $FCIERR_TEMP_FILE, _         ;; Could not create a temporary file,  erf.erfTyp has C run-time *errno* value
    $FCIERR_BAD_COMPR_TYPE, _    ;; Unknown compression type
    $FCIERR_CAB_FILE, _       ;; Could not create cabinet file, erf.erfTyp has C run-time *errno* value
    $FCIERR_USER_ABORT, _       ;; Client requested abort
    $FCIERR_MCI_FAIL, _       ;; Failure compressing data
    $FCIERR_CAB_FORMAT_LIMIT     ;; Data-size or file-count exceeded CAB format limits.
;;;; The following values are returned for FCI:
;;Global Const $FCIERR_NONE          = 0x00 ;; No Error.
;;Global Const $FCIERR_OPEN_SRC      = 0x01 ;; Failure opening the file to be stored in the cabinet.
;;Global Const $FCIERR_READ_SRC      = 0x02 ;; Failure reading the file to be stored in the cabinet.
;;Global Const $FCIERR_ALLOC_FAIL      = 0x03 ;; Out of memory in FCI.
;;Global Const $FCIERR_TEMP_FILE        = 0x04 ;; Could not create a temporary file.
;;Global Const $FCIERR_BAD_COMPR_TYPE   = 0x05 ;; Unknown compression type.
;;Global Const $FCIERR_CAB_FILE      = 0x06 ;; Could not create the cabinet file.
;;Global Const $FCIERR_USER_ABORT      = 0x07 ;; FCI aborted.
;;Global Const $FCIERR_MCI_FAIL      = 0x08 ;; Failure compressing data.
;;Global Const $FCIERR_CAB_FORMAT_LIMIT = 0x09 ;; Data-size or file-count exceeded CAB format limits.

;;/*
;; * FAT file attribute flag used by FCI/FDI to indicate that
;; * the filename in the CAB is a UTF string
;; */
Global Const $_A_NAME_IS_UTF  = 0x80

;;/*
;; * FAT file attribute flag used by FCI/FDI to indicate that
;; * the file should be executed after extraction
;; */
Global Const $_A_EXEC        = 0x40

Global Const $statusFile      = 0   ;; Add File to Folder callback
Global Const $statusFolder    = 1   ;; Add Folder to Cabinet callback
Global Const $statusCabinet   = 2   ;; Write out a completed cabinet callback

;;/***    FDIERROR - Error codes returned in erf.erfOper field
;; *
;; *  In general, FDI will only fail if one of the passed in memory or
;; *  file I/O functions fails.  Other errors are pretty unlikely, and are
;; *  caused by corrupted cabinet files, passing in a file which is not a
;; *  cabinet file, or cabinet files out of order.
;; *
;; *  Description:    Summary of error.
;; *  Cause:          List of possible causes of this error.
;; *  Response:    How client might respond to this error, or avoid it in
;; *                  the first place.
;; */
;;typedef enum {
;;    FDIERROR_NONE,
;;      // Description: No error
;;      // Cause:      Function was successfull.
;;      // Response:    Keep going!
;;
;;    FDIERROR_CABINET_NOT_FOUND,
;;      // Description: Cabinet not found
;;      // Cause:      Bad file name or path passed to FDICopy(), or returned
;;      //            to fdintNEXT_CABINET.
;;      // Response:    To prevent this error, validate the existence of the
;;      //            the cabinet *before* passing the path to FDI.
;;
;;    FDIERROR_NOT_A_CABINET,
;;      // Description: Cabinet file does not have the correct format
;;      // Cause:      File passed to to FDICopy(), or returned to
;;      //            fdintNEXT_CABINET, is too small to be a cabinet file,
;;      //            or does not have the cabinet signature in its first
;;      //            four bytes.
;;      // Response:    To prevent this error, call FDIIsCabinet() to check a
;;      //            cabinet before calling FDICopy() or returning the
;;      //            cabinet path to fdintNEXT_CABINET.
;;
;;    FDIERROR_UNKNOWN_CABINET_VERSION,
;;      // Description: Cabinet file has an unknown version number.
;;      // Cause:      File passed to to FDICopy(), or returned to
;;      //            fdintNEXT_CABINET, has what looks like a cabinet file
;;      //            header, but the version of the cabinet file format
;;      //            is not one understood by this version of FDI.  The
;;      //            erf.erfType field is filled in with the version number
;;      //            found in the cabinet file.
;;      // Response:    To prevent this error, call FDIIsCabinet() to check a
;;      //            cabinet before calling FDICopy() or returning the
;;      //            cabinet path to fdintNEXT_CABINET.
;;
;;    FDIERROR_CORRUPT_CABINET,
;;      // Description: Cabinet file is corrupt
;;      // Cause:      FDI returns this error any time it finds a problem
;;      //            with the logical format of a cabinet file, and any
;;      //            time one of the passed-in file I/O calls fails when
;;      //            operating on a cabinet (PFNOPEN, PFNSEEK, PFNREAD,
;;      //            or PFNCLOSE).  The client can distinguish these two
;;      //            cases based upon whether the last file I/O call
;;      //            failed or not.
;;      // Response:    Assuming this is not a real corruption problem in
;;      //            a cabinet file, the file I/O functions could attempt
;;      //            to do retries on failure (for example, if there is a
;;      //            temporary network connection problem).  If this does
;;      //            not work, and the file I/O call has to fail, then the
;;      //            FDI client will have to clean up and call the
;;      //            FDICopy() function again.
;;
;;    FDIERROR_ALLOC_FAIL,
;;      // Description: Could not allocate enough memory
;;      // Cause:      FDI tried to allocate memory with the PFNALLOC
;;      //            function, but it failed.
;;      // Response:    If possible, PFNALLOC should take whatever steps
;;      //            are possible to allocate the memory requested.  If
;;      //            memory is not immediately available, it might post a
;;      //            dialog asking the user to free memory, for example.
;;      //            Note that the bulk of FDI's memory allocations are
;;      //            made at FDICreate() time and when the first cabinet
;;      //            file is opened during FDICopy().
;;
;;    FDIERROR_BAD_COMPR_TYPE,
;;      // Description: Unknown compression type in a cabinet folder
;;      // Cause:      [Should never happen.]  A folder in a cabinet has an
;;      //            unknown compression type.  This is probably caused by
;;      //            a mismatch between the version of FCI.LIB used to
;;      //            create the cabinet and the FDI.LIB used to read the
;;      //            cabinet.
;;      // Response:    Abort.
;;
;;    FDIERROR_MDI_FAIL,
;;      // Description: Failure decompressing data from a cabinet file
;;      // Cause:      The decompressor found an error in the data coming
;;      //            from the file cabinet.  The cabinet file was corrupted.
;;      //            [11-Apr-1994 bens When checksuming is turned on, this
;;      //            error should never occur.]
;;      // Response:    Probably should abort; only other choice is to cleanup
;;      //            and call FDICopy() again, and hope there was some
;;      //            intermittent data error that will not reoccur.
;;
;;    FDIERROR_TARGET_FILE,
;;      // Description: Failure writing to target file
;;      // Cause:      FDI returns this error any time it gets an error back
;;      //            from one of the passed-in file I/O calls fails when
;;      //            writing to a file being extracted from a cabinet.
;;      // Response:    To avoid or minimize this error, the file I/O functions
;;      //            could attempt to avoid failing.  A common cause might
;;      //            be disk full -- in this case, the PFNWRITE function
;;      //            could have a check for free space, and put up a dialog
;;      //            asking the user to free some disk space.
;;
;;    FDIERROR_RESERVE_MISMATCH,
;;      // Description: Cabinets in a set do not have the same RESERVE sizes
;;      // Cause:      [Should never happen]. FDI requires that the sizes of
;;      //            the per-cabinet, per-folder, and per-data block
;;      //            RESERVE sections be consistent across all the cabinets
;;      //            in a set.
;;      // Response:    Abort.
;;
;;    FDIERROR_WRONG_CABINET,
;;      // Description: Cabinet returned on fdintNEXT_CABINET is incorrect
;;      // Cause:      NOTE: THIS ERROR IS NEVER RETURNED BY FDICopy()!
;;      //            Rather, FDICopy() keeps calling the fdintNEXT_CABINET
;;      //            callback until either the correct cabinet is specified,
;;      //            or you return ABORT.
;;      //            When FDICopy() is extracting a file that crosses a
;;      //            cabinet boundary, it calls fdintNEXT_CABINET to ask
;;      //            for the path to the next cabinet.  Not being very
;;      //            trusting, FDI then checks to make sure that the
;;      //            correct continuation cabinet was supplied!  It does
;;      //            this by checking the "setID" and "iCabinet" fields
;;      //            in the cabinet.  When MAKECAB.EXE creates a set of
;;      //            cabinets, it constructs the "setID" using the sum
;;      //            of the bytes of all the destination file names in
;;      //            the cabinet set.  FDI makes sure that the 16-bit
;;      //            setID of the continuation cabinet matches the
;;      //            cabinet file just processed.  FDI then checks that
;;      //            the cabinet number (iCabinet) is one more than the
;;      //            cabinet number for the cabinet just processed.
;;      // Response:    You need code in your fdintNEXT_CABINET (see below)
;;      //            handler to do retries if you get recalled with this
;;      //            error.  See the sample code (EXTRACT.C) to see how
;;      //            this should be handled.
;;
;;    FDIERROR_USER_ABORT,
;;      // Description: FDI aborted.
;;      // Cause:      An FDI callback returnd -1 (usually).
;;      // Response:    Up to client.
;;
;;} FDIERROR;
Const Enum _ ;FDIERROR
    $FDIERROR_NONE, _                   ;; No error
    $FDIERROR_CABINET_NOT_FOUND, _     ;; Cabinet not found
    $FDIERROR_NOT_A_CABINET, _         ;; Cabinet file does not have the correct format
    $FDIERROR_UNKNOWN_CABINET_VERSION, _ ;; Cabinet file has an unknown version number.
    $FDIERROR_CORRUPT_CABINET, _         ;; Cabinet file is corrupt
    $FDIERROR_ALLOC_FAIL, _           ;; Could not allocate enough memory
    $FDIERROR_BAD_COMPR_TYPE, _       ;; Unknown compression type in a cabinet folder
    $FDIERROR_MDI_FAIL, _               ;; Failure decompressing data from a cabinet file
    $FDIERROR_TARGET_FILE, _             ;; Failure writing to target file
    $FDIERROR_RESERVE_MISMATCH, _       ;; Cabinets in a set do not have the same RESERVE sizes
    $FDIERROR_WRONG_CABINET, _         ;; Cabinet returned on fdintNEXT_CABINET is incorrect
    $FDIERROR_USER_ABORT                 ;; FDI aborted.
;;;; The following values are returned for FDI:
;;Global Const $FDIERROR_NONE                   = 0x00 ;; No error.
;;Global Const $FDIERROR_CABINET_NOT_FOUND     = 0x01 ;; The cabinet file was not found.
;;Global Const $FDIERROR_NOT_A_CABINET         = 0x02 ;; The cabinet file does not have the correct format.
;;Global Const $FDIERROR_UNKNOWN_CABINET_VERSION = 0x03 ;; The cabinet file has an unknown version number.
;;Global Const $FDIERROR_CORRUPT_CABINET         = 0x04 ;; The cabinet file is corrupt.
;;Global Const $FDIERROR_ALLOC_FAIL           = 0x05 ;; Insufficient memory.
;;Global Const $FDIERROR_BAD_COMPR_TYPE       = 0x06 ;; Unknown compression type used in the cabinet folder.
;;Global Const $FDIERROR_MDI_FAIL               = 0x07 ;; Failure decompressing data from the cabinet file.
;;Global Const $FDIERROR_TARGET_FILE             = 0x08 ;; Failure writing to the target file.
;;Global Const $FDIERROR_RESERVE_MISMATCH       = 0x09 ;; The cabinets within a set do not have the same RESERVE sizes.
;;Global Const $FDIERROR_WRONG_CABINET         = 0x0A ;; The cabinet returned by fdintNEXT_CABINET is incorrect.
;;Global Const $FDIERROR_USER_ABORT           = 0x0B ;; FDI aborted.

;;/***    FDIDECRYPTTYPE - PFNFDIDECRYPT command types
;; *
;; */
Const Enum _ ;FDIDECRYPTTYPE; /* fdidt */
    $fdidtNEW_CABINET, _                ;; New cabinet
    $fdidtNEW_FOLDER, _              ;; New folder
    $fdidtDECRYPT                      ;; Decrypt a data block
;;Global Const $fdidtNEW_CABINET    = 0x00 ;; New cabinet
;;Global Const $fdidtNEW_FOLDER  = 0x01 ;; New folder
;;Global Const $fdidtDECRYPT        = 0x02 ;; Decrypt a data block

;;/***    FDINOTIFICATIONTYPE - FDICopy notification types
;; *
;; */
Const Enum _ ;FDINOTIFICATIONTYPE; /* fdint */
    $fdintCABINET_INFO, _           ;; General information about cabinet
    $fdintPARTIAL_FILE, _           ;; First file in cabinet is continuation
    $fdintCOPY_FILE, _             ;; File to be copied
    $fdintCLOSE_FILE_INFO, _         ;; close the file, set relevant info
    $fdintNEXT_CABINET, _           ;; File continued to next cabinet
    $fdintENUMERATE               ;; Enumeration status
;;Global Const $fdintCABINET_INFO    = 0x00 ;; General information about the cabinet.
;;Global Const $fdintPARTIAL_FILE    = 0x01 ;; First file in the cabinet is a continuation of a file from previous cabinet.
;;Global Const $fdintCOPY_FILE     = 0x02 ;; Information identifying the file to be copied.
;;Global Const $fdintCLOSE_FILE_INFO = 0x03 ;; Close the file, set relevant information.
;;Global Const $fdintNEXT_CABINET    = 0x04 ;; File continued to next cabinet.
;;Global Const $fdintENUMERATE     = 0x05 ;; Enumeration status.

;;/*** cpuType values for FDICreate()
;; *
;; *  (Ignored by 32-bit FDI.)
;; */
Global Const $cpuUNKNOWN        = -1    ;;/* FDI does detection */
Global Const $cpu80286        = 0    ;;/* '286 opcodes only */
Global Const $cpu80386        = 1    ;;/* '386 opcodes used */

; *******************************************************************************************************************************
; Time Structures
; *******************************************************************************************************************************
; ===============================================================================================================================
; #STRUCTURE# ===================================================================================================================
; Name...........: $tagFILETIME
; Description ...: Contains the number of 100-nanosecond intervals since January 1, 1601
; Fields ........: Lo - The low order part of the file time
;                 Hi - The high order part of the file time
; Author ........: Paul Campbell (PaulIA)
; Remarks .......:
; ===============================================================================================================================
Global Const $tagFILETIME = "struct;dword Lo;dword Hi;endstruct"
Global $FileTime = DllStructCreate($tagFILETIME)
Global $lpFileTime = DllStructGetPtr($FileTime)
Global $LocalFileTime = DllStructCreate($tagFILETIME)
Global $lpLocalFileTime = DllStructGetPtr($LocalFileTime)

#EndRegion ;Global Variables and Constants


#Region ;Cabinet API Structures
;;  This section details the following Cabinet API Structures:
;;      Structure             - Description
;;      CABINETDLLVERSIONINFO - Contains the version information for Cabinet.dll.
;;      CCAB                  - Contains cabinet information.
;;      ERF                - Returns error information from FCI/FDI. The caller should not modify this structure.
;;      FDICABINETINFO      - Contains details about a particular cabinet file.
;;      FDINOTIFICATION    - Provide information to FNFDINOTIFY.
;;      SESSION            - Contains information about the current session.
;;
;;  The following structures are used with cabinets.
;;      CABINET_INFO          - Cabinet file information.
;;      FILE_IN_CABINET_INFO  - Information about a file in a cabinet.
;;


;;    The CABINET_INFO structure stores information about a cabinet file. The SetupIterateCabinet function specifies this structure as a parameter
;;       when it sends a SPFILENOTIFY_NEEDNEWCABINET notification to the cabinet callback routine.
;;
;;        typedef struct _CABINET_INFO {
;;          PCTSTR CabinetPath;
;;          PCTSTR CabinetFile;
;;          PCTSTR DiskName;
;;          USHORT SetId;
;;          USHORT CabinetNumber;
;;        } CABINET_INFO, *PCABINET_INFO;
;;
;;        typedef struct _CABINET_INFO_W {
;;            PCWSTR CabinetPath;
;;            PCWSTR CabinetFile;
;;            PCWSTR DiskName;
;;            USHORT SetId;
;;            USHORT CabinetNumber;
;;        } CABINET_INFO_W, *PCABINET_INFO_W;
;;
;;    Members
;;        CabinetPath
;;            Path to the cabinet file.
;;        CabinetFile
;;            Name of the cabinet file.
;;        DiskName
;;            Name of the source media that contains the cabinet file.
;;        SetId
;;            Identifier of the current set. This number is generated by the software that builds the cabinet.
;;        CabinetNumber
;;            Number of the cabinet. This number is generated by the software that builds the cabinet and is generally a zero- or 1-based index
;;              indicating the ordinal of the position of the cabinet within a set.
;;
Global Const $tds_CABINET_INFO_A = "" & _ ; The CABINET_INFO structure stores information about a cabinet file.
    "ptr    CabinetPath;" & _            ; Path to the cabinet file. ("CHAR CabinetPath[256]")
    "ptr    CabinetFile;" & _            ; Name of the cabinet file. ("CHAR CabinetFile[256];")
    "ptr    DiskName;" & _              ; Name of the source media that contains the cabinet file. ("CHAR DiskName[256];")
    "USHORT SetId;" & _                ; Identifier of the current set. This number is generated by the software that builds the cabinet.
    "USHORT CabinetNumber"              ; Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
                                          ;   a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.

Global Const $tds_CABINET_INFO_W = "" & _ ; The CABINET_INFO structure stores information about a cabinet file.
    "ptr    CabinetPath;" & _            ; Path to the cabinet file. ("WCHAR CabinetPath[256]")
    "ptr    CabinetFile;" & _            ; Name of the cabinet file. ("WCHAR CabinetFile[256];")
    "ptr    DiskName;" & _              ; Name of the source media that contains the cabinet file. ("WCHAR DiskName[256];")
    "USHORT SetId;" & _                ; Identifier of the current set. This number is generated by the software that builds the cabinet.
    "USHORT CabinetNumber"              ; Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
                                          ;   a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.

Global Const $tds__CABINET = "" & _    ; The CABINET_INFO structure stores information about a cabinet file.
    "char   achCabPath[256];" & _    ; Cabinet file path
    "char   achCabFilename[256];" & _ ; Cabinet file name.ext
    "char   achDiskName[256];" & _    ; User readable disk label
    "USHORT setID;" & _            ; Identifier of the current set. This number is generated by the software that builds the cabinet.
    "USHORT iCabinet"                ; Number of the cabinet. This number is generated by the software that builds the cabinet and is generally
                                      ;   a zero- or 1-based index indicating the ordinal of the position of the cabinet within a set.
Global Const $tds_CABINET = "STRUCT;" & $tds_CABINET_INFO_A & ";ENDSTRUCT"


;;    The FILE_IN_CABINET_INFO structure provides information about a file found in the cabinet. The SetupIterateCabinet function sends this structure
;;      as one of the parameters when it sends a SPFILENOTIFY_FILEINCABINET notification to the cabinet callback routine.
;;
;;        typedef struct _FILE_IN_CABINET_INFO {
;;          PCTSTR NameInCabinet;
;;          DWORD  FileSize;
;;          DWORD  Win32Error;
;;          WORD   DosDate;
;;          WORD   DosTime;
;;          WORD   DosAttribs;
;;          TCHAR  FullTargetName[MAX_PATH];
;;        } FILE_IN_CABINET_INFO, *PFILE_IN_CABINET_INFO;
;;
;;        typedef struct _FILE_IN_CABINET_INFO_W {
;;            PCWSTR NameInCabinet;
;;            DWORD  FileSize;
;;            DWORD  Win32Error;
;;            WORD   DosDate;
;;            WORD   DosTime;
;;            WORD   DosAttribs;
;;            WCHAR  FullTargetName[MAX_PATH];
;;        } FILE_IN_CABINET_INFO_W, *PFILE_IN_CABINET_INFO_W;
;;
;;    Member
;;        NameInCabinet
;;            File name as it exists within the cabinet file.
;;        FileSize
;;            Uncompressed size of the file in the cabinet, in bytes.
;;        Win32Error
;;            If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
;;        DosDate
;;            Date that the file was last saved.
;;        DosTime
;;            MS-DOS time stamp of the file in the cabinet.
;;        DosAttribs
;;            Attributes of the file in the cabinet.
;;        FullTargetName
;;            Target path and file name.
Global Const $tds_FILE_IN_CABINET_INFO_A = "" & _ ; The FILE_IN_CABINET_INFO structure provides information about a file found in the cabinet.
    "ptr   NameInCabinet;" & _                  ; File name as it exists within the cabinet file. ("CHAR NameInCabinet[260]")
    "DWORD FileSize;" & _                        ; Uncompressed size of the file in the cabinet, in bytes.
    "DWORD Win32Error;" & _                    ; If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
    "WORD  DosDate;" & _                          ; Date that the file was last saved.
    "WORD  DosTime;" & _                          ; MS-DOS time stamp of the file in the cabinet.
    "WORD  DosAttribs;" & _                    ; Attributes of the file in the cabinet.
    "CHAR FullTargetName[260];"                ; Target path and file name.

Global Const $tds_FILE_IN_CABINET_INFO_W = "" & _ ; The FILE_IN_CABINET_INFO structure provides information about a file found in the cabinet.
    "ptr   NameInCabinet;" & _                  ; File name as it exists within the cabinet file. ("WCHAR NameInCabinet[260]")
    "DWORD FileSize;" & _                        ; Uncompressed size of the file in the cabinet, in bytes.
    "DWORD Win32Error;" & _                    ; If an error occurs, this member is the system error code. If no error has occurred, it is NO_ERROR.
    "WORD  DosDate;" & _                          ; Date that the file was last saved.
    "WORD  DosTime;" & _                          ; MS-DOS time stamp of the file in the cabinet.
    "WORD  DosAttribs;" & _                    ; Attributes of the file in the cabinet.
    "WCHAR FullTargetName[260];"                  ; Target path and file name.
Global $tds_FILE_IN_CABINET_INFO = $tds_FILE_IN_CABINET_INFO_W ;, $FILE_IN_CABINET_INFO = DllStructCreate($tds_FILE_IN_CABINET_INFO_W)



;;    The CABINETDLLVERSIONINFO contains the version information for Cabinet.dll.
;;        typedef struct {
;;          DWORD cbStruct;
;;          DWORD dwReserved1;
;;          DWORD dwReserved2;
;;          DWORD dwFileVersionMS;
;;          DWORD dwFileVersionLS;
;;        } CABINETDLLVERSIONINFO, *PCABINETDLLVERSIONINFO;
;;
;;    Members
;;        cbStruct
;;            The size of this structure, in bytes.
;;        dwReserved1
;;            Reserved.
;;        dwReserved2
;;            Reserved.
;;        dwFileVersionMS
;;            Contains the most significant bits of the version information. Bits 0-15 contain the minor version, and bits 16-31 contain the major version.
;;        dwFileVersionLS
;;            Contains the least significant bits of the version information. Bits 0-15 contain the revision number, and bits 16-31 contain the build number.
;;
Global Const $tds_CABINETDLLVERSIONINFO = "" & _ ; The CABINETDLLVERSIONINFO contains the version information for Cabinet.dll.
    "DWORD cbStruct;" & _                       ; The size of this structure, in bytes.
    "DWORD dwReserved1;" & _                     ; Reserved.
    "DWORD dwReserved2;" & _                     ; Reserved.
    "DWORD dwFileVersionMS;" & _                 ; Contains the most significant bits of the version information. Bits 0-15 contain the minor version, and bits 16-31 contain the major version.
    "DWORD dwFileVersionLS"                   ; Contains the least significant bits of the version information. Bits 0-15 contain the revision number, and bits 16-31 contain the build number.


;;    The CCAB structure contains cabinet information.
;;        typedef struct _CCAB {
;;          ULONG  cb;
;;          ULONG  cbFolderThresh;
;;          UINT   cbReservesCFHeader;
;;          UINT   cbReserveCFFolder;
;;          UINT   cbReserveCFData;
;;          int    iCab;
;;          int    iDisk;
;;          USHORT setID;
;;          char   szDisk[CB_MAX_DISK_NAME];
;;          char   szCab[CB_MAX_CABINET_NAME];
;;          char   szCabPath[CB_MAX_CAB_PATH];
;;        } CCAB, *PCCAB;
;;
;;    Members
;;        cb
;;            The maximum size, in bytes, of a cabinet created by FCI.
;;        cbFolderThresh
;;            The maximum size, in bytes, that a folder will contain before a new folder is created.
;;        cbReservesCFHeader
;;            The size, in bytes, of the CFHeader reserve area. Possible value range is 0-60,000.
;;        cbReserveCFFolder
;;            The size, in bytes, of the CFFolder reserve area. Possible value range is 0-255.
;;        cbReserveCFData
;;            The size, in bytes, of the CFData reserve area. Possible value range is 0-255.
;;        iCab
;;            The number of created cabinets.
;;        iDisk
;;            The maximum size, in bytes, of a cabinet created by FCI.
;;        setID
;;            A value that represents the association between a collection of linked cabinet files.
;;        szDisk
;;            The name of the disk on which the cabinet is placed.
;;        szCab
;;            The name of the cabinet.
;;        szCabPath
;;            The full path that indicates where to create the cabinet.
;;
;; /***    CCAB - Current Cabinet
;; *
;; *  This structure is used for passing in the cabinet parameters to FCI,
;; *  and is passed back on certain FCI callbacks to provide cabinet
;; *  information to the client.
;; */
Global Const $tds_CCAB = "" & _   ; The CCAB structure contains cabinet information.
    "ULONG  cb;" & _                 ; size available for cabinet on this media
    "ULONG  cbFolderThresh;" & _     ; Thresshold for forcing a new Folder
    "UINT   cbReservesCFHeader;" & _ ; Space to reserve in CFHEADER
    "UINT   cbReserveCFFolder;" & _  ; Space to reserve in CFFOLDER
    "UINT   cbReserveCFData;" & _    ; Space to reserve in CFDATA
    "int    iCab;" & _             ; sequential numbers for cabinets
    "int    iDisk;" & _           ; Disk number
    "USHORT setID;" & _           ; Cabinet set ID
    "char   szDisk[256];" & _       ; current disk name
    "char   szCab[256];" & _         ; current cabinet name
    "char   szCabPath[256]"       ; path for creating cabinet


;;    The ERF structure contains error information from FCI/FDI. The caller should not modify this structure.
;;        typedef struct {
;;          int  erfOper;
;;          int  erfType;
;;          BOOL fError;
;;        } ERF FAR *PERF;
;;
;;    Members
;;        erfOper
;;            An FCI/FDI error code.
;;            The following values are returned for FCI:
;;                Value                      - Meaning
;;                FCIERR_NONE            0x00 - No Error.
;;                FCIERR_OPEN_SRC        0x01 - Failure opening the file to be stored in the cabinet.
;;                FCIERR_READ_SRC        0x02 - Failure reading the file to be stored in the cabinet.
;;                FCIERR_ALLOC_FAIL    0x03 - Out of memory in FCI.
;;                FCIERR_TEMP_FILE      0x04 - Could not create a temporary file.
;;                FCIERR_BAD_COMPR_TYPE   0x05 - Unknown compression type.
;;                FCIERR_CAB_FILE        0x06 - Could not create the cabinet file.
;;                FCIERR_USER_ABORT    0x07 - FCI aborted.
;;                FCIERR_MCI_FAIL        0x08 - Failure compressing data.
;;                FCIERR_CAB_FORMAT_LIMIT 0x09 - Data-size or file-count exceeded CAB format limits.
;;            The following values are returned for FDI:
;;                Value                               - Meaning
;;                FDIERROR_NONE                 0x00 - No error.
;;                FDIERROR_CABINET_NOT_FOUND       0x01 - The cabinet file was not found.
;;                FDIERROR_NOT_A_CABINET           0x02 - The cabinet file does not have the correct format.
;;                FDIERROR_UNKNOWN_CABINET_VERSION 0x03 - The cabinet file has an unknown version number.
;;                FDIERROR_CORRUPT_CABINET       0x04 - The cabinet file is corrupt.
;;                FDIERROR_ALLOC_FAIL             0x05 - Insufficient memory.
;;                FDIERROR_BAD_COMPR_TYPE         0x06 - Unknown compression type used in the cabinet folder.
;;                FDIERROR_MDI_FAIL             0x07 - Failure decompressing data from the cabinet file.
;;                FDIERROR_TARGET_FILE           0x08 - Failure writing to the target file.
;;                FDIERROR_RESERVE_MISMATCH     0x09 - The cabinets within a set do not have the same RESERVE sizes.
;;                FDIERROR_WRONG_CABINET           0x0A - The cabinet returned by fdintNEXT_CABINET is incorrect.
;;                FDIERROR_USER_ABORT             0x0B - FDI aborted.
;;        erfType
;;            An optional error value filled in by FCI/FDI. For FCI, this is usually the C runtime errno value.
;;        fError
;;            A flag that indicates an error. If TRUE, an error is present.
;;
;; /***    ERF - Error structure
;; *
;; *  This structure returns error information from FCI/FDI.  The caller should
;; *  not modify this structure.
;; */
Global Const $tds_ERF = "" & _ ; The ERF structure contains error information from FCI/FDI. The caller should not modify this structure.
    "int  erfOper;" & _     ; FCI/FDI error code -- see FDIERROR_XXX, and FCIERR_XXX equates for details.
    "int  erfType;" & _     ; Optional error value filled in by FCI/FDI, For FCI, this is usually the C run-time *errno* value.
    "BOOL fError"             ; TRUE => error present
Global $ERF  = DllStructCreate($tds_ERF)
Global $PERF = DllStructGetPtr($ERF)

;;    The FDICABINETINFO structure contains details about a particular cabinet file.
;;        typedef struct {
;;          long   cbCabinet;
;;          USHORT cFolders;
;;          USHORT cFiles;
;;          USHORT setID;
;;          USHORT iCabinet;
;;          BOOL   fReserve;
;;          BOOL   hasprev;
;;          BOOL   hasnext;
;;        } FDICABINETINFO FAR *PFDICABINETINFO;
;;
;;    Members
;;        cbCabinet
;;            The total length of the cabinet file.
;;        cFolders
;;            The count of the folders in the cabinet.
;;        cFiles
;;            The count of the files in the cabinet.
;;        setID
;;            The identifier of the cabinet set.
;;        iCabinet
;;            The cabinet number in set. This index is zero based.
;;        fReserve
;;            If this value is set to TRUE, a reserved area is present in the cabinet.
;;        hasprev
;;            If this value is set to TRUE, the cabinet is linked to a previous cabinet. This is accomplished by having a file continued from the previous
;;              cabinet into the current one.
;;        hasnext
;;            If this value is set to TRUE, the current cabinet is linked to the next cabinet by having a file continued from the current cabinet into the next one.
;;
Global Const $tds_FDICABINETINFO = "" & _ ; The FDICABINETINFO structure contains details about a particular cabinet file.
    "long   cbCabinet;" & _            ; Total length of cabinet file
    "USHORT cFolders;" & _              ; Count of folders in cabinet
    "USHORT cFiles;" & _                  ; Count of files in cabinet
    "USHORT setID;" & _                ; Cabinet set ID
    "USHORT iCabinet;" & _              ; Cabinet number in set (0 based)
    "BOOL   fReserve;" & _              ; TRUE => RESERVE present in cabinet
    "BOOL   hasprev;" & _                ; TRUE => Cabinet is chained prev
    "BOOL   hasnext"                      ; TRUE => Cabinet is chained next
Global $FDICABINETINFO  = DllStructCreate($tds_FDICABINETINFO)
Global $PFDICABINETINFO = DllStructGetPtr($FDICABINETINFO)


;;    The FDINOTIFICATION structure to provide information to FNFDINOTIFY.
;;        typedef struct _FDINOTIFICATION {
;;          LONG     cb;
;;          char FAR *psz1;
;;          char FAR *psz2;
;;          char FAR *psz3;
;;          void FAR *pv;
;;          INT_PTR  hf;
;;          USHORT   date;
;;          USHORT   time;
;;          USHORT   attribs;
;;          USHORT   setID;
;;          USHORT   iCabinet;
;;          USHORT   iFolder;
;;          FDIERROR fdie;
;;        } FDINOTIFICATION, *PFDINOTIFICATION;
;;
;;    Members
;;        cb
;;            The size, in bytes, of a cabinet element.
;;        psz1
;;            A null-terminated string.
;;        psz2
;;            A null-terminated string.
;;        psz3
;;            A null-terminated string.
;;        pv
;;            Pointer to an application-defined value.
;;        hf
;;            Application-defined value used to identify the opened file.
;;        date
;;            The MS-DOS date.
;;            Bits    - Description
;;            0-4        - Day of the month (1-31)
;;            5-8        - Month (1 = January, 2 = February, etc.)
;;            9-15    - Year offset from 1980 (add 1980
;;        time
;;            The MS-DOS time.
;;            Bits    - Description
;;            0-4    - Second divided by 2
;;            5-10    - Minute (0-59)
;;            11-15   - Hour (0-23 on a 24-hour clock)
;;        attribs
;;            The file attributes. For possible values and their descriptions, see File Attributes.
;;        setID
;;            The identifier for a cabinet set.
;;        iCabinet
;;            The number of the cabinets within a set.
;;        iFolder
;;            The number of folders within a cabinet.
;;        fdie
;;            An FDI error code. Possible values include:
;;            Value                              - Meaning
;;            FDIERROR_NONE                 0x00 - No error.
;;            FDIERROR_CABINET_NOT_FOUND       0x01 - The cabinet file was not found.
;;            FDIERROR_NOT_A_CABINET           0x02 - The cabinet file does not have the correct format.
;;            FDIERROR_UNKNOWN_CABINET_VERSION 0x03 - The cabinet file has an unknown version number.
;;            FDIERROR_CORRUPT_CABINET       0x04 - The cabinet file is corrupt.
;;            FDIERROR_ALLOC_FAIL             0x05 - Insufficient memory.
;;            FDIERROR_BAD_COMPR_TYPE         0x06 - Unknown compression type used in the cabinet folder.
;;            FDIERROR_MDI_FAIL             0x07 - Failure decompressing data from the cabinet file.
;;            FDIERROR_TARGET_FILE           0x08 - Failure writing to the target file.
;;            FDIERROR_RESERVE_MISMATCH     0x09 - The cabinets within a set do not have the same RESERVE sizes.
;;            FDIERROR_WRONG_CABINET           0x0A - The cabinet returned by fdintNEXT_CABINET is incorrect.
;;            FDIERROR_USER_ABORT             0x0B - FDI aborted.
;;
;; /***    FDINOTIFICATION - Notification structure for PFNFDINOTIFY
;; *
;; *  See the FDINOTIFICATIONTYPE (in FNFDINOTIFY() Function) definition for information on usage and
;; *  meaning of these fields.
;; */
Global Const $tds_FDINOTIFICATION = "" & _ ; The FDINOTIFICATION structure to provide information to FNFDINOTIFY.
    "LONG    cb;" & _                     ; The size, in bytes, of a cabinet element.
    "ptr     psz1;" & _                 ; Points to a 256 character buffer
    "ptr     psz2;" & _                 ; Points to a 256 character buffer
    "ptr     psz3;" & _                 ; Points to a 256 character buffer
    "ptr     pv;" & _                     ; Value for client
    "INT_PTR hf;" & _                     ; Application-defined value used to identify the opened file.
    "USHORT  date;" & _                 ; The MS-DOS date.
    "USHORT  time;" & _                 ; The MS-DOS time.
    "USHORT  attribs;" & _               ; The file attributes
    "USHORT  setID;" & _                   ; Cabinet set ID
    "USHORT  iCabinet;" & _             ; Cabinet number (0-based)
    "USHORT  iFolder;" & _               ; Folder number (0-based)
    "int     fdie"                       ; FDI error code


;;    The SESSION structure contains information about the current session.
;;        typedef struct {
;;          ACTION    act;
;;          HFILELIST hflist;
;;          BOOL      fAllCabinets;
;;          BOOL      fOverwrite;
;;          BOOL      fNoLineFeed;
;;          BOOL      fSelfExtract;
;;          long      cbSelfExtractSize;
;;          long      cbSelfExtractSize;
;;          int    ahfSelf[cMAX_CAB_FILE_OPEN];
;;          int    cErrors;
;;          HFDI      hfdi;
;;          ERF    erf;
;;          long      cFiles;
;;          long      cbTotalBytes;
;;          PERROR    perr;
;;          SPILLERR  se;
;;          long      cbSpill;
;;          char      achSelf[cbFILE_NAME_MAX];
;;          char      achMsg[cbMAX_LINE*2];
;;          char      achLine;
;;          char      achLocation;
;;          char      achFile;
;;          char      achDest;
;;          char      achCabPath;
;;          BOOL      fContinuationCabinet;
;;          BOOL      fShowReserveInfo;
;;          BOOL      fNextCabCalled;
;;          CABINET   acab[2];
;;          char      achZap[cbFILE_NAME_MAX];
;;          char      achCabinetFile[cbFILE_NAME_MAX];
;;          int    cArgv;
;;          char      **pArgv;
;;          int    fDestructive;
;;          USHORT    iCurrentFolder;
;;        } SESSION, *PSESSION;
;;
;;    Members
;;        act
;;            The action to perform. This member can be one of the values from the following enumerated type.
;;                typedef enum {
;;                    actBAD,        // Invalid action
;;                    actHELP,      // Show help
;;                    actDEFAULT,    // Perform default action based on command line arguments
;;                    actDIRECTORY,   // Force display of cabinet directory
;;                    actEXTRACT,    // Force file extraction
;;                    actCOPY,      // Do single file-to-file copy
;;                } ACTION;
;;        hflist
;;            The handle to a list of files specified on the command line. This datatype is declared as follows:
;;            typedef void *HFILELIST;
;;        fAllCabinets
;;            A flag that indicates whether more than one cabinet file should be processed. If this value is TRUE, continuation cabinets are processed.
;;        fOverwrite
;;            A flag that indicates whether existing files should be overwritten. If this value is TRUE, existing files are overwritten.
;;        fNoLineFeed
;;            A flag that indicates whether the last printf call has the newline (\n) characters. If this value is TRUE, the last printf call did not include the newline characters.
;;        fSelfExtract
;;            A flag that indicates whether a cabinet is self extracting. If this value is TRUE, the cabinet is self extracting.
;;        cbSelfExtractSize
;;            The length of the executable (.exe) portion of a self-extracting cabinet.
;;        cbSelfExtractSize
;;            The length of the CAB portion of a self-extracting cabinet.
;;        ahfSelf
;;            The file handles to the cabinet.
;;            #define cMAX_CAB_FILE_OPEN 2
;;        cErrors
;;            The count of errors encountered during the extraction session.
;;        hfdi
;;            A handle to the FDI context. This datatype is declared as follows:
;;            typedef void FAR *HFDI;
;;        erf
;;            The FDI error structure. See ERF.
;;        cFiles
;;            The count of files processed.
;;        cbTotalBytes
;;            The total number of bytes extracted.
;;        perr
;;            The pass through FDI.
;;        se
;;            The spill file error. This member can be one of the values from the following enumerated type.
;;                typedef enum {
;;                    seNONE,                    // No error
;;                    seNOT_ENOUGH_MEMORY,      // Not enough RAM
;;                    seCANNOT_CREATE,          // Cannot create spill file
;;                    seNOT_ENOUGH_SPACE,        // Not enough space for spill file
;;                } SPILLERR;
;;        cbSpill
;;            The size of the spill file requested.
;;        achSelf
;;            The name of the executable (.exe) file.
;;            #define cbFILE_NAME_MAX 256
;;        achMsg
;;            The message formatting buffer.
;;            #define cbMAX_LINE 256
;;        achLine
;;            The line formatting buffer.
;;        achLocation
;;            The output directory.
;;        achFile
;;            The current file name being extracted.
;;        achDest
;;            The forced destination file name.
;;        achCabPath
;;            The path to look at for a cabinet file.
;;        fContinuationCabinet
;;            A flag that indicates whether the current cabinet is the first one processed. If set to TRUE, it is not the first cabinet processed.
;;        fShowReserveInfo
;;            A flag that indicates whether reserve information should be provided. If set to TRUE, the information is made available.
;;        fNextCabCalled
;;            This member provides a way to determine which of the acab entries to use if we are processing all files in a cabinet set (fAllCabinet is set to TRUE).
;;        acab
;;            The last two entries in the cabinet set. This structure is defined as follows:
;;                typedef struct {
;;                    char    achCabPath[cbFILE_NAME_MAX];   // Cabinet file path
;;                    char    achCabFilename[cbFILE_NAME_MAX]; // Cabinet file name.ext
;;                    char    achDiskName[cbFILE_NAME_MAX];    // User readable disk label
;;                    USHORT  setID;
;;                    USHORT  iCabinet;
;;                } CABINET;
;;                typedef CABINET *PCABINET;
;;        achZap
;;            The prefix to strip from the file name.
;;            #define cbFILE_NAME_MAX 256
;;        achCabinetFile
;;            The current cabinet file.
;;            #define cbFILE_NAME_MAX 256
;;        cArgv
;;            The default self-extracting argc.
;;        pArgv
;;            A pointer to a pointer to the default self-extracting argv[].
;;        fDestructive
;;            A flag that minimizes the disk space needed when set to TRUE.
;;        iCurrentFolder
;;            If fDestructive is set to TRUE, extract only the current folder.
;;
Global Const $tds_SESSION = "" & _   ; The SESSION structure contains information about the current session.
    "int    act;" & _                 ; The action to perform.
    "HWND   hflist;" & _               ; The handle to a list of files specified on the command line
    "BOOL   fAllCabinets;" & _       ; A flag that indicates whether more than one cabinet file should be processed. If this value is TRUE, continuation cabinets are processed.
    "BOOL   fOverwrite;" & _           ; A flag that indicates whether existing files should be overwritten. If this value is TRUE, existing files are overwritten.
    "BOOL   fNoLineFeed;" & _         ; A flag that indicates whether the last printf call has the newline (\n) characters. If this value is TRUE, the last printf call did not include the newline characters.
    "BOOL   fSelfExtract;" & _       ; A flag that indicates whether a cabinet is self extracting. If this value is TRUE, the cabinet is self extracting.
    "long   cbSelfExtractSize;" & _    ; The length of the executable (.exe) portion of a self-extracting cabinet.
    "long   cbSelfExtractSize;" & _    ; The length of the CAB portion of a self-extracting cabinet.
    "int    ahfSelf[2];" & _           ; The file handles to the cabinet.
    "int    cErrors;" & _             ; The count of errors encountered during the extraction session.
    "HWND   hfdi;" & _               ; A handle to the FDI context
    "int    erf;" & _                 ; The FDI error structure. See ERF.
    "long   cFiles;" & _               ; The count of files processed.
    "long   cbTotalBytes;" & _       ; The total number of bytes extracted.
    "int    perr;" & _               ; The pass through FDI.
    "long   se;" & _                   ; The spill file error
    "long   cbSpill;" & _             ; The size of the spill file requested.
    "char   achSelf[256];" & _       ; The name of the executable (.exe) file.
    "char   achMsg[512];" & _         ; The message formatting buffer.
    "ptr    achLine;" & _             ; The line formatting buffer.
    "ptr    achLocation;" & _         ; The output directory.
    "ptr    achFile;" & _             ; The current file name being extracted.
    "ptr    achDest;" & _             ; The forced destination file name.
    "ptr    achCabPath;" & _           ; The path to look at for a cabinet file.
    "BOOL   fContinuationCabinet;" & _ ; A flag that indicates whether the current cabinet is the first one processed. If set to TRUE, it is not the first cabinet processed.
    "BOOL   fShowReserveInfo;" & _   ; A flag that indicates whether reserve information should be provided. If set to TRUE, the information is made available.
    "BOOL   fNextCabCalled;" & _       ; This member provides a way to determine which of the acab entries to use if we are processing all files in a cabinet set (fAllCabinet is set to TRUE).
    $tds_CABINET&";"&$tds_CABINET & ";" & _ ; The last two entries in the cabinet set
    "char   achZap[256];" & _         ; The prefix to strip from the file name.
    "char   achCabinetFile[256];" & _  ; The current cabinet file.
    "int    cArgv;" & _             ; The default self-extracting argc.
    "ptr    pArgv;" & _             ; A pointer to a pointer to the default self-extracting argv[]
    "int    fDestructive;" & _       ; A flag that minimizes the disk space needed when set to TRUE.
    "USHORT iCurrentFolder"         ; If fDestructive is set to TRUE, extract only the current folder.

#EndRegion ;Cabinet API Structures


#Region ;FCI Functions
;;    The FCI (File Compression Interface) library provides the ability to create cabinets (also known as "CAB files"). Additionally,
;;      the library provides compression to reduce the size of the file data stored in cabinets.

;; The FCIAddFile adds a file to the cabinet under construction.
;;    Parameters
;;        hfci [in]
;;            A valid FCI context handle returned by the FCICreate function.
;;        pszSourceFile [in]
;;            The name of the file to add; this value should include path information.
;;        pszFileName [in]
;;            The name under which to store the file in the cabinet.
;;        fExecute [in]
;;            If set TRUE, the file will be executed when extracted.
;;        GetNextCab [in]
;;            Pointer to an application-defined callback function to obtain specifications on the next cabinet to create. The function should be declared using the FNFCIGETNEXTCABINET macro.
;;        pfnProgress [in]
;;            Pointer to an application-defined callback function to update the progress information available to the user. The function should be declared using the FNFCISTATUS macro.
;;        pfnOpenInfo [in]
;;            Pointer to an application-defined callback function to open a file and retrieve the file date, time, and attributes. The function should be declared using the FNFCIGETOPENINFO macro.
;;        typeCompress [in]
;;            The compression type to use.
;;            Note  To indicate LZX compression, use the TCOMPfromLZXWindow macro.
;;            Value                -  Meaning
;;            tcompTYPE_NONE  0x0000 - No compression.
;;            tcompTYPE_MSZIP 0x0001 - Microsoft ZIP compression.
;;
;;    Return value
;;        If the function succeeds, it returns TRUE; otherwise, FALSE.
;;        Extended error information is provided in the ERF structure used to create the FCI context.
;;
;;    Remarks
;;        When set, the _A_EXEC attribute is added to the file entry in the CAB. This mechanism is used in some Microsoft self-extracting executables,
;;          and could be used for this purpose in any custom extraction application.
;;
;; Syntax
;;      BOOL FCIAddFile(
;;        _In_  HFCI hfci,
;;        _In_  LPSTR pszSourceFile,
;;        _In_  LPSTR pszFileName,
;;        _In_  BOOL fExecute,
;;        _In_  PFNFCIGETNEXTCABINET GetNextCab,
;;        _In_  PFNFCISTATUS pfnProgress,
;;        _In_  PFNFCIGETOPENINFO pfnOpenInfo,
;;        _In_  TCOMP typeCompress
;;      );


;; The FCICreate function creates an FCI context.
;;    Parameters
;;        perf [in, out]
;;            Pointer to an ERF structure that receives the error information.
;;        pfnfiledest [in]
;;            Pointer to an application-defined callback function to notify when a file is placed in the cabinet. The function should be declared using the FNFCIFILEPLACED macro.
;;        pfnalloc [in]
;;            Pointer to an application-defined callback function to allocate memory. The function should be declared using the FNFCIALLOC macro.
;;        pfnfree [in]
;;            Pointer to an application-defined callback function to free previously allocated memory. The function should be delcared using the FNFCIFREE macro.
;;        pfnopen [in]
;;            Pointer to an application-defined callback function to open a file. The function should be declared using the FNFCIOPEN macro.
;;        pfnread [in]
;;            Pointer to an application-defined callback function to read data from a file. The function should be declared using the FNFCIREAD macro.
;;        pfnwrite [in]
;;            Pointer to an application-defined callback function to write data to a file. The function should be declared using the FNFCIWRITE macro.
;;        pfnclose [in]
;;            Pointer to an application-defined callback function to close a file. The function should be declared using the FNFCICLOSE macro.
;;        pfnseek [in]
;;            Pointer to an application-defined callback function to move a file pointer to the specific location. The function should be declared using the FNFCISEEK macro.
;;        pfndelete [in]
;;            Pointer to an application-defined callback function to delete a file. The function should be declared using the FNFCIDELETE macro.
;;        pfnfcigtf [in]
;;            Pointer to an application-defined callback function to retrieve a temporary file name. The function should be declared using the FNFCIGETTEMPFILE macro.
;;        pccab [in]
;;            Pointer to a CCAB structure that contains the parameters for creating a cabinet.
;;        pv [in, optional]
;;            Pointer to an application-defined value that is passed to callback functions.
;;
;;    Return value
;;        If the function succeeds, it returns a non-NULL HFCI context pointer; otherwise, NULL.
;;        Extended error information is provided in the ERF structure.
;;
;;    Remarks
;;        FCI supports multiple simultaneous contexts. As a result it is possible to create or extract multiple cabinets at the same time within the same application.
;;          If the application is multithreaded, it is also possible to run a different context in each thread; however, an application cannot use the same context
;;          simultaneously in multiple threads. For example, FCIAddFile cannot be called from two different threads, using the same FCI context.
;;
;; Syntax
;;      HFCI FCICreate(
;;        _Inout_   PERF perf,
;;        _In_    PFNFCIFILEPLACED pfnfiledest,
;;        _In_    PFNFCIALLOC pfnalloc,
;;        _In_    PFNFCIFREE pfnfree,
;;        _In_    PFNFCIOPEN pfnopen,
;;        _In_    PFNFCIREAD pfnread,
;;        _In_    PFNFCIWRITE pfnwrite,
;;        _In_    PFNFCICLOSE pfnclose,
;;        _In_    PFNFCISEEK pfnseek,
;;        _In_    PFNFCIDELETE pfndelete,
;;        _In_    PFNFCIGETTEMPFILE pfnfcigtf,
;;        _In_    PCCAB pccab,
;;        _In_opt_  void FAR *pv
;;      );


;; The FCIDestroy function deletes an open FCI context, freeing any memory and temporary files associated with the context.
;;    Parameters
;;        hfci [in]
;;            A valid FCI context handle returned by the FCICreate function.
;;
;;    Return value
;;        If the function succeeds, it returns TRUE; otherwise, FALSE.
;;        Extended error information is provided in the ERF structure used to create the FCI context.
;;
;; Syntax
;;      BOOL FCIDestroy(
;;        _In_  HFCI hfci
;;      );


;; The FCIFlushCabinet function completes the current cabinet.
;;    Parameters
;;        hfci [in]
;;            A valid FCI context handle returned by theFCICreate function.
;;        fGetNextCab [in]
;;            Specifies whether the function pointed to by the supplied GetNextCab parameter will be called.
;;        GetNextCab [in]
;;            Pointer to an application-defined callback function to obtain specifications on the next cabinet to create. The function should be declared using the FNFCIGETNEXTCABINET macro.
;;        pfnProgress [in]
;;            Pointer to an application-defined callback function to update the user. The function should be declared using the FNFCISTATUS macro.
;;
;;    Return value
;;        If the function succeeds, it returns TRUE; otherwise, FALSE.
;;        Extended error information is provided in the ERF structure used to create the FCI context.
;;
;;    Remarks
;;        The FCIFlushCabinet API forces the current cabinet under construction to be completed immediately and then written to disk. Further calls to FCIAddFile
;;          will result in files being added to another cabinet.
;;
;;        In the event the current cabinet has reached the application-specified media size limit, the pending data within an FCI's internal buffers will
;;          be placed into another cabinet.
;;
;;        The fGetNextCab flag determines whether the function pointed to by the GetNextCab parameter will be called. If fGetNextCab is set TRUE,
;;          GetNextCab is called to obtain continuation information. If FALSE, then GetNextCab is called only in the event the cabinet overflows.
;;
;;  Syntax
;;      BOOL FCIFlushCabinet(
;;        _In_  HFCI hfci,
;;        _In_  BOOL fGetNextCab,
;;        _In_  PFNFCIGETNEXTCABINET GetNextCab,
;;        _In_  PFNFCISTATUS pfnProgress
;;      );

;; The FCIFlushFolder function forces the current folder under construction to be completed immediately.
;;    Parameters
;;        hfci [in]
;;            A valid FCI context handle returned by the FCICreate function.
;;        GetNextCab [in]
;;            Pointer to an application-defined callback function to obtain specifications on the next cabinet to create. The function should be declared using the FNFCIGETNEXTCABINET macro.
;;        pfnProgress [in]
;;            Pointer to an application-defined callback function to update the user. The function should be declared using the FNFCISTATUS macro.
;;
;;    Return value
;;        If the function succeeds, it returns TRUE; otherwise, FASLE.
;;        Extended error information is provided in the ERF structure used to create the FCI context.
;;
;;    Remarks
;;        The FCIFlushFolder API forces the folder currently under construction to be completed immediately; effectively resetting the compression history if a compression method is in use.
;;
;;        The callback function indicated by GetNextCab will be called if the cabinet overflows, which occurs if the pending data buffered inside an FCI causes the application-specified cabinet media size to be exceeded.
;;
;; Syntax
;;      BOOL FCIFlushFolder(
;;        _In_  HFCI hfci,
;;        _In_  PFNFCIGETNEXTCABINET GetNextCab,
;;        _In_  PFNFCISTATUS pfnProgress
;;      );


;; The FCIErrorToString
;;            An FCI error code. Possible values include:
;;            Value                      - Meaning
;;            FCIERR_NONE            0x00 - No Error.
;;            FCIERR_OPEN_SRC        0x01 - Failure opening the file to be stored in the cabinet.
;;            FCIERR_READ_SRC        0x02 - Failure reading the file to be stored in the cabinet.
;;            FCIERR_ALLOC_FAIL    0x03 - Out of memory in FCI.
;;            FCIERR_TEMP_FILE      0x04 - Could not create a temporary file.
;;            FCIERR_BAD_COMPR_TYPE   0x05 - Unknown compression type.
;;            FCIERR_CAB_FILE        0x06 - Could not create the cabinet file.
;;            FCIERR_USER_ABORT    0x07 - FCI aborted.
;;            FCIERR_MCI_FAIL        0x08 - Failure compressing data.
;;            FCIERR_CAB_FORMAT_LIMIT 0x09 - Data-size or file-count exceeded CAB format limits.
Func _FCIErrorToString($FCIERROR)
    Switch $FCIERROR
        Case $FCIERR_NONE
            Return "No error";
        Case $FCIERR_OPEN_SRC
            Return "Failure opening file to be stored in cabinet";
        Case $FCIERR_READ_SRC
            Return "Failure reading file to be stored in cabinet";
        Case $FCIERR_ALLOC_FAIL
            Return "Insufficient memory in FCI";
        Case $FCIERR_TEMP_FILE
            Return "Could not create a temporary file";
        Case $FCIERR_BAD_COMPR_TYPE
            Return "Unknown compression type";
        Case $FCIERR_CAB_FILE
            Return "Could not create cabinet file";
        Case $FCIERR_USER_ABORT
            Return "Client requested abort";
        Case $FCIERR_MCI_FAIL
            Return "Failure compressing data";
        Case $FCIERR_CAB_FORMAT_LIMIT
            Return "Data-size or file-count exceeded CAB format limits";
        Case Else
            Return "Unknown error";
    EndSwitch
EndFunc


#EndRegion ;FCI Functions


#Region ;FDI Functions
;;    The FDI (File Decompression Interface) library provides the ability to extract files from cabinets.


;; The FDICopy function extracts files from cabinets.
;;    Parameters
;;        hfdi [in]
;;            A valid FDI context handle returned by the FDICreate function.
;;        pszCabinet [in]
;;            The name of the cabinet file, excluding any path information, from which to extract files. If a file is split over multiple cabinets, FDICopy allows for subsequent cabinets to be opened.
;;        pszCabPath [in]
;;            The pathname of the cabinet file, but not including the name of the file itself. For example, "C:\MyCabs\".
;;            The contents of pszCabinet are appended to pszCabPath to create the full pathname of the cabinet.
;;        flags [in]
;;            No flags are currently defined and this parameter should be set to zero.
;;        pfnfdin [in]
;;            Pointer to an application-defined callback notification function to update the application on the status of the decoder. The function should be declared using the FNFDINOTIFY macro.
;;        pfnfdid [in]
;;            Not currently used by FDI. This parameter should be set to NULL.
;;        pvUser [in, optional]
;;            Pointer to an application-specified value to pass to the notification function.
;;
;;        Return value
;;        If the function succeeds, it returns TRUE; otherwise, FALSE.
;;        Extended error information is provided in the ERF structure used to create the FDI context.
;;
;; Syntax
;;      BOOL FDICopy(
;;        _In_   HFDI hfdi,
;;        _In_   LPSTR pszCabinet,
;;        _In_   LPSTR pszCabPath,
;;        _In_   INT flags,
;;        _In_   PFNFDINOTIFY pfnfdin,
;;        _In_   PFNFDIDECRYPT pfnfdid,
;;          _In_opt_  void FAR pvUser
;;      );
Func _FDICopy($HFDI, $pszCabinet, $pszCabPath, $pvUser = 0, $pfnfdin = $PFNFDINOTIFY)
    ;;;;    $pszCabinet = _WinAPI_WideCharToMultiByte($pszCabinet, 65001, 0)
    ;;;;    $pszCabPath = _WinAPI_WideCharToMultiByte($pszCabPath, 65001, 0)
    ;; Local $aFDICopy = DllCall($h_Kernel32DLL, "int", "WideCharToMultiByte", "uint", $CP_UTF8, "dword", 0, "wstr", $pszCabinet, "int", -1, "ptr", 0, "int", 0, "ptr", 0, "ptr", 0)
    ;; If @Error Then Return SetError(-1, @Error, 0)
    ;; $pszCabinet = DllStructCreate("char[" & $aFDICopy[0] & "]")
    ;; $aFDICopy = DllCall($h_Kernel32DLL, "int", "WideCharToMultiByte", "uint", $CP_UTF8, "dword", 0, "wstr", $aFDICopy[3], "int", -1, "struct*", $pszCabinet, "int", $aFDICopy[0], "ptr", 0, "ptr", 0)
    ;; If @Error Then Return SetError(-1, @Error, 0)
    ;; $aFDICopy = DllCall($h_Kernel32DLL, "int", "WideCharToMultiByte", "uint", $CP_UTF8, "dword", 0, "wstr", $pszCabPath, "int", -1, "ptr", 0, "int", 0, "ptr", 0, "ptr", 0)
    ;; If @Error Then Return SetError(-1, @Error, 0)
    ;; $pszCabPath = DllStructCreate("char[" & $aFDICopy[0] & "]")
    ;; $aFDICopy = DllCall($h_Kernel32DLL, "int", "WideCharToMultiByte", "uint", $CP_UTF8, "dword", 0, "wstr", $aFDICopy[3], "int", -1, "struct*", $pszCabPath, "int", $aFDICopy[0], "ptr", 0, "ptr", 0)
    ;; If @Error Then Return SetError(-1, @Error, 0)

    Local $aFDICopy = Binary(StringToBinary($pszCabinet, 4))
    $pszCabinet = DllStructCreate("byte[" & BinaryLen($aFDICopy) + 1 & "]")
    DllStructSetData($pszCabinet, 1, $aFDICopy)
    $aFDICopy = Binary(StringToBinary($pszCabPath, 4))
    $pszCabPath = DllStructCreate("byte[" & BinaryLen($aFDICopy) + 1 & "]")
    DllStructSetData($pszCabPath, 1, $aFDICopy)

    ;;$aFDICopy = DllCall($h_CabiNetDLL, "BOOL:cdecl", "FDICopy", "ptr", $HFDI, "ptr", DllStructGetPtr($pszCabinet, 1), "ptr", DllStructGetPtr($pszCabPath, 1), "int", 0, "ptr", $pfnfdin, "ptr", 0, "ptr", $pvUser)
    $aFDICopy = DllCall($h_CabiNetDLL, "BOOL:cdecl", "FDICopy", "ptr", $HFDI, "struct*", $pszCabinet, "struct*", $pszCabPath, "int", 0, "ptr", $pfnfdin, "ptr", 0, "ptr", $pvUser)
    If @Error Or Not $aFDICopy[0] Then Return SetError(-1, DllStructGetData($ERF, "erfOper"), 0)
    Return $aFDICopy[0]
EndFunc


;; The FDICreate function creates an FDI context.
;;    Parameters
;;        pfnalloc [in]
;;            Pointer to an application-defined callback function to allocate memory. The function should be declared using the FNALLOC macro.
;;        pfnfree [in]
;;            Pointer to an application-defined callback function to free previously allocated memory. The function should be declared using the FNFREE macro.
;;        pfnopen [in]
;;            Pointer to an application-defined callback function to open a file. The function should be declared using the FNOPEN macro.
;;        pfnread [in]
;;            Pointer to an application-defined callback function to read data from a file. The function should be declared using the FNREAD macro.
;;        pfnwrite [in]
;;            Pointer to an application-defined callback function to write data to a file. The function should be declared using the FNWRITE macro.
;;        pfnclose [in]
;;            Pointer to an application-defined callback function to close a file. The function should be declared using the FNCLOSE macro.
;;        pfnseek [in]
;;            Pointer to an application-defined callback function to move a file pointer to the specified location. The function should be declared using the FNSEEK macro.
;;        cpuType [in]
;;            In the 16-bit version of FDI, specifies the CPU type and can be any of the following values.
;;            Note  Expressing the cpuUNKNOWN value is recommended.
;;            Value        - Meaning
;;            cpuUNKNOWN -1  - FDI should determine the CPU type.
;;            cpu80286    0  - Only 80286 instructions can be used.
;;            cpu80386    1  - 80386 instructions can be used.
;;        perf [in, out]
;;            Pointer to an ERF structure that receives the error information.
;;
;;    Return value
;;        If the function succeeds, it returns a non-NULL HFDI context pointer; otherwise, it returns NULL.
;;        Extended error information is provided in the ERF structure.
;;
;; Syntax
;;      HFDI FDICreate(
;;        _In_    PFNALLOC pfnalloc,
;;        _In_    PFNFREE pfnfree,
;;        _In_    PFNOPEN pfnopen,
;;        _In_    PFNREAD pfnread,
;;        _In_    PFNWRITE pfnwrite,
;;        _In_    PFNCLOSE pfnclose,
;;        _In_    PFNSEEK pfnseek,
;;        _In_    int cpuType,
;;          _Inout_  PERF perf
;;      );
Func _FDICreate()    ;$_PERF = $PERF
    Local $hFDI = DllCall($h_CabiNetDLL, "HWND:cdecl", "FDICreate", "ptr", $PFNALLOC, "ptr", $PFNFREE, "ptr", $PFNOPEN, "ptr", $PFNREAD,  "ptr", $PFNWRITE, "ptr", $PFNCLOSE, "ptr", $PFNSEEK, "int", -1, "ptr", $PERF)
    If @Error Or Not $hFDI[0] Then Return SetError(-1, @Error, 0)
    ;;;;    ConsoleWrite(("+> _FDICreate -  $PERF - " & $PERF & " - " & $hFDI[0] & @CRLF)
    ;;_ArrayDisplay($hFDI, DllStructGetData($ERF, "erfOper"))
    Return SetError(DllStructGetData($ERF, "fError"), DllStructGetData($ERF, "erfOper"), $hFDI[0])
EndFunc


;; The FDIDestroy function deletes an open FDI context.
;;    Parameters
;;        hfdi [in]
;;            A valid FDI context handle returned by the FDICreate function.
;;
;;    Return value
;;        If the function succeeds, it returns TRUE; otherwise, FALSE.
;;        Extended error information is provided in the ERF structure used to create the FDI context.
;;
;; Syntax
;;      BOOL FDIDestroy(
;;        _In_ BOOL hfdi
;;      );
Func _FDIDestroy($hFDI)
    Local $aFDIDestroy = DllCall($h_CabiNetDLL, "BOOL:cdecl", "FDIDestroy", "handle", $hFDI)
    If @Error Or Not $aFDIDestroy[0] Then Return SetError(1, DllStructGetData($ERF, "erfOper"), 0)
    Return $aFDIDestroy[0]
EndFunc


;; The FDIIsCabinet function determines whether a file is a cabinet and, if it is, returns information about it.
;;    Parameters
;;        hfdi [in]
;;            A valid FDI context handle returned by FDICreate.
;;        hf [in]
;;            An application-defined value to keep track of the opened file. This value must be of the same type as values used by the File I/O functions passed to FDICreate.
;;        pfdici [in, out]
;;            Pointer to an FDICABINETINFO structure that receives the cabinet details, in the event the file is actually a cabinet.
;;
;;    Return value
;;        If the file is a cabinet, the function returns TRUE ; otherwise, FALSE.
;;        Extended error information is provided in the ERF structure used to create the FDI context.
;;
;; Syntax
;;      BOOL FDIIsCabinet(
;;        _In_    HFDI hfdi,
;;        _In_    INT_PTR hf,
;;          _Inout_  PFDICABINETINFO pfdici
;;      );
Func _FDIIsCabinet($hFDI, $hf)
    Local $aFDIIsCabinet = DllCall($h_CabiNetDLL, "BOOL:cdecl", "FDIIsCabinet", "handle", $hFDI, "INT_PTR", $hf, "ptr", $PFDICABINETINFO)
    If @Error Or Not $aFDIIsCabinet[0] Then Return SetError(1, DllStructGetData($ERF, "erfOper"), 0)
    Return $FDICABINETINFO
EndFunc


;; The FDITruncateCabinet function truncates a cabinet file starting at the specified folder number.
;;    Parameters
;;        hfdi [in]
;;            A valid FDI context handle returned by the FDICreate function.
;;        pszCabinetName [in]
;;            The full cabinet filename.
;;        iFolderToDelete [in]
;;            The index of the first folder to delete.
;;
;;    Return value
;;        If the function succeeds, it returns TRUE; otherwise, FALSE.
;;        Extended error information is provided in the ERF structure used to create the FDI context.
;;
;; Syntax
;;      BOOL WINAPI FDITruncateCabinet(
;;        _In_ HFDI hfdi,
;;        _In_ LPSTR *pszCabinetName,
;;        _In_ USHORT iFolderToDelete
;;      );


;; The FDIErrorToString
;;            An FDI error code. Possible values include:
;;            Value                              - Meaning
;;            FDIERROR_NONE                 0x00 - No error.
;;            FDIERROR_CABINET_NOT_FOUND       0x01 - The cabinet file was not found.
;;            FDIERROR_NOT_A_CABINET           0x02 - The cabinet file does not have the correct format.
;;            FDIERROR_UNKNOWN_CABINET_VERSION 0x03 - The cabinet file has an unknown version number.
;;            FDIERROR_CORRUPT_CABINET       0x04 - The cabinet file is corrupt.
;;            FDIERROR_ALLOC_FAIL             0x05 - Insufficient memory.
;;            FDIERROR_BAD_COMPR_TYPE         0x06 - Unknown compression type used in the cabinet folder.
;;            FDIERROR_MDI_FAIL             0x07 - Failure decompressing data from the cabinet file.
;;            FDIERROR_TARGET_FILE           0x08 - Failure writing to the target file.
;;            FDIERROR_RESERVE_MISMATCH     0x09 - The cabinets within a set do not have the same RESERVE sizes.
;;            FDIERROR_WRONG_CABINET           0x0A - The cabinet returned by fdintNEXT_CABINET is incorrect.
;;            FDIERROR_USER_ABORT             0x0B - FDI aborted.
Func _FDIErrorToString($FDIERROR)
    Switch $FDIERROR
        Case $FDIERROR_NONE
            Return "No error";
        Case $FDIERROR_CABINET_NOT_FOUND
            Return "Cabinet not found";
        Case $FDIERROR_NOT_A_CABINET
            Return "Not a cabinet";
        Case $FDIERROR_UNKNOWN_CABINET_VERSION
            Return "Unknown cabinet version";
        Case $FDIERROR_CORRUPT_CABINET
            Return "Corrupt cabinet";
        Case $FDIERROR_ALLOC_FAIL
            Return "Memory allocation failed";
        Case $FDIERROR_BAD_COMPR_TYPE
            Return "Unknown compression type";
        Case $FDIERROR_MDI_FAIL
            Return "Failure decompressing data";
        Case $FDIERROR_TARGET_FILE
            Return "Failure writing to target file";
        Case $FDIERROR_RESERVE_MISMATCH
            Return "Cabinets in set have different RESERVE sizes";
        Case $FDIERROR_WRONG_CABINET
            Return "Cabinet returned on fdintNEXT_CABINET is incorrect";
        Case $FDIERROR_USER_ABORT
            Return "Application aborted";
        Case Else
            Return "Unknown error";
    EndSwitch
EndFunc


#EndRegion ;FDI Functions


#Region ;Deprecated Functions

;; The Extract function extracts files from a cabinet.
;;    Parameters
;;        ps
;;            Pointer to a SESSION structure that contains information about the current session.
;;        lpCabName
;;            Pointer to the name of the cabinet from which files are to be extracted.
;;
;;    Return value
;;        If the function succeeds, it returns S_OK; otherwise, it returns an error code.
;;
;;    Remarks
;;        This function has no associated import library or header file; you must call it using the LoadLibrary and GetProcAddress functions.
;;
;; Syntax
;;      HRESULT Extract(
;;          PSESSION ps,
;;          LPCSTR lpCabName
;;      );


;; The DeleteExtractedFiles function deletes the files that were extracted by the Extract function.
;;    Parameters
;;        ps
;;            A pointer to a SESSION structure that contains information about the current session.
;;            This function frees the memory in the pFileList member of this structure and sets pFileList to NULL.
;;
;;    Return value
;;        This function does not return a value.
;;
;;    Remarks
;;        This function has no associated import library or header file; you must call it using the LoadLibrary and GetProcAddress functions.
;;
;; Syntax
;;      VOID WINAPI DeleteExtractedFiles(
;;          PSESSION ps
;;      );


;; The DllGetVersion function retrieves the version number of Cabinet.dll using the CABINETDLLVERSIONINFO structure.
;;    Parameters
;;        pcdvi
;;            Pointer to the CABINETDLLVERSIONINFO structure that contains the version information.
;;
;;     Return value
;;        This function does not return a value.
;;
;;    Remarks
;;        This function has no associated import library or header file; you must call it using the LoadLibrary and GetProcAddress functions.
;;
;; Syntax
;;      VOID WINAPI DllGetVersion(
;;          PCABINETDLLVERSIONINFO pcdvi
;;      );


;; The GetDllVersion function retrieves the version number of Cabinet.dll.
;;    Parameters
;;        This function has no parameters.
;;
;;    Return value
;;        The version number of the file (see VERSIONINFO Resource).
;;
;;    Remarks
;;        This function has no associated import library or header file; you must call it using the LoadLibrary and GetProcAddress functions.
;;
;; Syntax
;;      LPCSTR WINAPI GetDllVersion(void);

#EndRegion ;Deprecated Functions


#Region ;FCI Macros - used by FCI
;;  The following macros are used by FCI:
;;      Macro               - Description
;;      FNFCIALLOC        - Used to allocate memory in an FCI context.
;;      FNFCICLOSE        - Used to close a file.
;;      FNFCIDELETE      - Used to delete a file.
;;      FNFCIFILEPLACED  - Used to notify when a file is placed in the cabinet.
;;      FNFCIFREE          - Used to free previously allocated memory in an FCI context.
;;      FNFCIGETNEXTCABINET - Used to request information for the next cabinet.
;;      FNFCIGETOPENINFO    - Used to open a file and retrieve file date, time, and attributes.
;;      FNFCIGETTEMPFILE    - Used to obtain a temporary file name.
;;      FNFCIOPEN          - Used to open a file in an FCI context.
;;      FNFCIREAD          - Used to read data from a file.
;;      FNFCISEEK          - Used to move a file pointer to a specified location.
;;      FNFCISTATUS      - Used to update the user.
;;      FNFCIWRITE        - Used to write data to a file.
;;      TCOMPfromLZXWindow  - Converts windows size into an LXZ TCOMP value for FCIAddFile.


;;    The FNFCIALLOC provides the declaration for the application-defined callback function to allocate memory within an FCI context.
;;    Parameters
;;        cb
;;            The number of bytes to allocate.
;;
;;    Return value
;;        The indicated callback function returns a void pointer to the allocated space, or NULL, if there is insufficient memory available.
;;
;;    Remarks
;;        The function accepts parameters similar to malloc.
;;
;; Syntax
;;      VOID HUGE * FAR FNFCIALLOC(
;;          ULONG cb
;;      );


;;    The FNFCICLOSE macro provides the declaration for the application-defined callback function to close a file in an FCI context.
;;    Parameters
;;        hf
;;            Specifies an application-defined value that identifies an open file.
;;        err
;;            Pointer to the error code value. This value is used to provide extended error information in the ERF structure used to create the FCI context.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The indicated callback function returns 0 if successful; otherwise -1.
;;
;;    Remarks
;;        The function accepts parameters similar to _close, with the addition of err and pv.
;;
;; Syntax
;;      void FNFCICLOSE(
;;          INT_PTR hf,
;;          int FAR *err,
;;          void FAR *pv
;;      );


;;    The FNFCIDELETE macro provides the declaration for the application-defined callback function to delete a file in the FCI context.
;;    Parameters
;;        pszFile [in]
;;            The name of the file to be deleted.
;;        err
;;            Pointer to the error code value. This value will be used to provide extended error information in the ERF structure used to create the FCI context.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The indicated callback function returns 0 if successful; otherwise -1.
;;
;;    Remarks
;;        The function accepts parameters similar to remove, with the addition of err and pv.
;;
;; Syntax
;;      void FNFCIDELETE(
;;          [in]  LPSTR pszFile,
;;          int FAR *err,
;;          void FAR *pv
;;      );



;;    The FNFCIFILEPLACED macro provides the declaration for the application-defined callback function to notify when a file is placed in the cabinet.
;;    Parameters
;;        pccab
;;            Pointer to the CCAB structure containing the parameters of the cabinet on which the file has been stored.
;;        pszFile [in]
;;            The name of the file in the cabinet.
;;        cbFile
;;            The length of the file in bytes.
;;        fContinuation
;;            A boolean value that is TRUE if the data added is a segment of a continued file.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The indicated callback function returns an application-defined value. However, a value of -1 indicates an error.
;;
;; Syntax
;;      void FNFCIFILEPLACED(
;;          PCCAB *pccab,
;;          [in]  LPSTR pszFile,
;;          long cbFile,
;;          BOOL fContinuation,
;;          void FAR *pv
;;      );


;;    The FNFCIFREE macro provides the declaration for the application-defined callback function to free previously allocated memory in an FCI context.
;;    Parameters
;;        memory
;;            Pointer to the allocated memory block to free.
;;
;;    Return value
;;        This macro does not return a value.
;;
;;    Remarks
;;        The function accepts parameters similar to free.
;;
;; Syntax
;;      void FNFCIFREE(
;;          void HUGE *memory
;;      );


;;    The FNFCIGETNEXTCABINET macro provides the declaration for the application-defined callback function to request information for the next cabinet.
;;    Parameters
;;        pccab
;;            Pointer to a CCAB structure to provide the parameters for the creation of a new cabinet.
;;        cbPrevCab
;;            Size, in bytes, of the previous cabinet.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The indicated callback function returns TRUE if successful; otherwise FALSE.
;;
;;    Remarks
;;        The CCAB structure referenced by this function is relevant to the most recently completed cabinet. However, with each successful operation
;;          the iCab field contained within this structure will have incremented by 1. Additionally, the next cabinet will be created using the
;;          fields in this structure. The szCab, in particular, should be modified as necessary. In particular, the szCab field, which specifies
;;          the cabinet name, should be changed for each cabinet.
;;
;;        When creating multiple cabinets, typically the iCab field is used to create the name.
;;
;; Syntax
;;      BOOL FNFCIGETNEXTCABINET(
;;          PCCAB pccab,
;;          ULONG cbPrevCab,
;;          void FAR *pv
;;      );



;;    The FNFCIGETOPENINFO macro provides the declaration for the application-defined callback function to open a file and retrieve file date, time, and attribute.
;;    Parameters
;;        pszName [in]
;;            The complete filename.
;;        pdate
;;            The MS-DOS date. The date is a packed value with the following format:
;;            Bits    - Description
;;            0-4        - Day of the Month (1-31)
;;            5-8    - Month (1 = January, 2 = Feburary, etc.)
;;            9-15    - Year Offset from 1980 (add 1980 to value to get current date)
;;        ptime
;;            The MS-DOS time. The time is a packed value with the following format:
;;            Bits    - Description
;;            0-4        - Second divided by 2
;;            5-8        - Minute (0-59)
;;            9-15    - Hour (0-23 on a 24-hour clock)
;;        pattribs
;;            The file attributes. For possible values and their descriptions, see File Attributes.
;;        err
;;            Pointer to the error code value. This value will be used to provide extended error information in the ERF structure used to create the FCI context.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The return value is application-defined and used to keep track of the opened file. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function should open the file using the file open function compatible with those passed into FCICreate.
;;
;; Syntax
;;      void FNFCIGETOPENINFO(
;;          [in]  LPSTR pszName,
;;          USHORT *pdate,
;;          USHORT *ptime,
;;          USHORT *pattribs,
;;          int FAR *err,
;;          void FAR *pv
;;      );


;;    The FNFCIGETTEMPFILE macro provides the declaration for the application-defined callback function to obtain a temporary file name.
;;    Parameters
;;        pszTempName [out]
;;            Pointer to a buffer to receive the complete temporary file name.
;;        cbTempName [in]
;;            Size, in bytes, of the pszTempName buffer.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The indicated callback function returns TRUE if successful; otherwise FALSE.
;;
;;    Remarks
;;        The function can return a filename that already exists by the time it is opened. For this reason, the caller should be prepared to make several
;;          attempts to create temporary files.
;;
;; Syntax
;;      void FNFCIGETTEMPFILE(
;;          [out]  char *pszTempName[bcount(cbTempName)],
;;          [in]   int cbTempName[range(>=, MAX_PATH)],
;;          void FAR *pv
;;      );


;;    The FNFCIOPEN macro provides the declaration for the application-defined callback function to open a file in an FCI context.
;;    Parameters
;;        pszFile [in]
;;            The name of the file.
;;        oflag
;;            Specifies the type of operations allowed.
;;        pmode
;;            Specifies the permission mode.
;;        err
;;            Pointer to the error code value.
;;            This value will be used to provide extended error information in the ERF structure used to create the FCI context.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The return value is application-defined and used to keep track of the opened file. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _open.
;;
;; Syntax
;;      void FNFCIOPEN(
;;          [in]  LPSTR pszFile,
;;          int oflag,
;;          int pmode,
;;          int FAR *err,
;;          void FAR *pv
;;      );


;;    The FNFCIREAD macro provides the declaration for the application-defined callback function to read data from a file in an FCI context.
;;    Parameters
;;        hf
;;            An application-defined value used to identify the open file.
;;        memory
;;            Pointer to the buffer that receives the data read from a file.
;;        cb
;;            The maximum number of bytes to read.
;;        err
;;            Pointer to the error code value. This value will be used to provide extended error information in the ERF structure used to create the FCI context.
;;        pv
;;            Pointer to an application-defined value
;;
;;    Return value
;;        The return value is application-defined and used to keep track of the opened file. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _read with the addition to err and pv.
;;
;; Syntax
;;      void FNFCIREAD(
;;          INT_PTR hf,
;;          void FAR *memory,
;;          UINT cb,
;;          int FAR *err,
;;          void FAR *pv
;;      );


;;    The FNFCISEEK macro provides the declaration for the application-defined callback function to move a file pointer to the specified location in an FCI context.
;;    Parameters
;;        hf
;;            An application-defined value used to identify the open file.
;;        dist
;;            The number of bytes to move the file pointer.
;;        seektype
;;            The starting point for the file pointer to move.
;;        err
;;            Pointer to the error code value. This value will be used to provide extended error information in the ERF structure used to create the FCI context.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The return value is application-defined and used to keep track of the opened file. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _lseek with the addition to err and pv.
;;
;; Syntax
;;      void FNFCISEEK(
;;          INT_PTR hf,
;;          long dist,
;;          int seektype,
;;          int FAR *err,
;;          void FAR *pv
;;      );


;;    The FNFCISTATUS macro provides the declaration for the application-defined callback function to update the user.
;;    Parameters
;;        typeStatus
;;            Indicates the type of status update. Possible values include:
;;            Value            - Meaning
;;            statusFile    0x00 - Compressing a block into a folder.
;;            statusFolder  0x01 - Adding a folder to a cabinet.
;;            statusCabinet 0x02 - Writing out a complete cabinet.
;;        cb1
;;            Indicates a status specific value. Possible values include:
;;            Value           - Meaning
;;            statusFile    0x00 - Size of the compressed block.
;;            statusFolder  0x01 - Amount of a folder copied to a cabinet thus far.
;;            statusCabinet 0x02 - Estimated cabinet size.
;;        cb2
;;            Specifies a status specific value. Possible values include:
;;            Value            - Meaning
;;            statusFile    0x00 - Size of the uncompressed block.
;;            statusFolder  0x01 - Total size of the folder.
;;            statusCabinet 0x02 - Actual cabinet size.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The function returns an application-defined value. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        If typeStatus equals statusCabinet the returned value indicates the desired size for the cabinet file. FCI updates the maximum cabinet size remaining
;;          using this returned value. This allows a client to generate multiple cabinets per disk, and have FCI limit the size accordingly.
;;
;; Syntax
;;      void FNFCISTATUS(
;;          UINT typeStatus,
;;          ULONG cb1,
;;          ULONG cb2,
;;          void FAR *pv
;;      );


;;    The FNFCIWRITE macro provides the declaration for the application-defined callback function to write data to a file in an FCI context.
;;    Parameters
;;        hf
;;            An application-defined value used to identify the open file.
;;        memory
;;            Pointer to the buffer containing the data to be written.
;;        cb
;;            The maximum number of bytes to be written.
;;        err
;;            Pointer to the error code value. This value is used when providing extended error information in the ERF structure used to create the FCI context.
;;        pv
;;            Pointer to an application-defined value.
;;
;;    Return value
;;        The indicated callback function returns the number of bytes written. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _write.
;;
;; Syntax
;;      void FNFCIWRITE(
;;          INT_PTR hf,
;;          void FAR *memory,
;;          UINT cb,
;;          int FAR *err,
;;          void FAR *pv
;;      );


;;    The TCOMPfromLZXWindow macro converts window size into an LXZTCOMP value for FCIAddFile.
;;    Parameters
;;        window_size
;;            The LZX window size. Possible value range is 15-21.
;;
;;    Return value
;;        The return value is a TCOMP value.
;;
;; Syntax
;;      TCOMP TCOMPfromLZXWindow(
;;          INT window_size
;;      );



#EndRegion ;FCI Macros - used by FCI


#Region ;FDI Macros - used by FDI
;;  The following macros are used by FDI:
;;      Macro        - Description
;;      FNALLOC  - Used to allocate memory in an FDI context.
;;      FNCLOSE  - Used to close a file in an FDI context.
;;      FNFDINOTIFY - Used to update the application on the status of the decoder.
;;      FNFREE    - Used to free previously allocated memory in an FDI context.
;;      FNOPEN    - Used to open a file in an FDI context.
;;      FNREAD    - Used to read data from a file in an FDI context.
;;      FNSEEK    - Used to move a file pointer to the specified location in an FDI context.
;;      FNWRITE  - Used to write data to a file in an FDI context.


;;    The FNALLOC provides the declaration for the application-defined callback function to allocate memory in an FDI context.
;;    Parameters
;;        cb
;;            The number of bytes to allocate.
;;
;;    Return value
;;        The indicated callback function returns a void pointer to the allocated space, or NULL, if there is insufficient memory available.
;;
;;    Remarks
;;        The function accepts parameters similar to malloc.
;;
;; Syntax
;;      void FNALLOC(
;;          ULONG cb
;;      );
;;
;;
;;    Examples - C++
;;            FNALLOC(fnMemAlloc)
;;            {
;;                return malloc(cb);
;;            }
;;
Func _FNALLOC($cb)
    #ForceRef $cb
    ;;$acMacros = DllCall($h_Kernel32DLL, "HANDLE", "GlobalAlloc", "UINT", $GPTR, "ULONG_PTR", $cb)
    ;;If @Error Or Not $acMacros[0] Then Return SetError(1, 0, 0)
    ;;;;    ConsoleWrite("+> _FNALLOC -  $cb - " & $cb & @CRLF)
    $acMacros = DllCall($h_Kernel32DLL, "ptr", "HeapAlloc", "HANDLE", $hDefaultProcessHeap, "dword", 8, "ULONG_PTR", $cb)
    If @Error Or Not $acMacros[0] Then Return SetError(1, 0, 0)
    ;;;;    ConsoleWrite(("+> _FNALLOC -  $cb - " & $cb & " - " & $acMacros[0] & @CRLF)
    Return $acMacros[0]
EndFunc


;;    The FNCLOSE macro provides the declaration for the application-defined callback function to close a file in an FDI context.
;;    Parameters
;;        hf [in]
;;            An application-defined value used to identify the open file.
;;
;;    Return value
;;        On success, the indicated callback function returns 0; otherwise -1.
;;
;;    Remarks
;;        The function accepts parameters similar to _close.
;;
;; Syntax
;;      void FNCLOSE(
;;          [in]  INT_PTR hf
;;      );
;;
;;
;;    Examples - C++
;;            FNCLOSE(fnFileClose)
;;            {
;;                return ( CloseHandle((HANDLE)hf) == TRUE ) ? 0 : -1;
;;            }
;;
Func _FNCLOSE($hf)
    #ForceRef $hf
    ;;;;    ConsoleWrite(("+> _FNCLOSE - $hf - " & $hf & @CRLF)
    $acMacros = DllCall($h_Kernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hf)
    If @Error Or Not $acMacros[0] Then Return SetError(1, 0, -1)
    ;;;;    ConsoleWrite(("+> _FNCLOSE - $hf - " & $hf & @CRLF)
    Return 0
EndFunc


;;    The FNFDINOTIFY macro provides the declaration for the application-defined callback notification function to update the application on the status of the decoder.
;;    Parameters
;;        fdint
;;            The type of notification.
;;            Value                   - Meaning
;;            fdintCABINET_INFO    0x00 - General information about the cabinet.
;;                                      When this value is set, the FDINOTIFICATION structure is populated with the following information:
;;                                            psz1   will point to the name of the next cabinet (excluding path information)
;;                                            psz2   will point to the name of the next disk
;;                                            psz3   will point to the cabinet path name
;;                                            setID    will equal the set ID of the current cabinet
;;                                            iCabinet will equal the cabinet number within the cabinet set (0 for the first cabinet, 1 for the second cabinet, etc.)
;;                                      The application should return 0 to indicate success, or -1 to indicate failure, which will abort FDICopy. An fdintCABINET_INFO
;;                                      notification will be provided once for each cabinet opened by FDICopy; this includes continuation cabinets opened due to files
;;                                      spanning cabinet boundaries.
;;            fdintPARTIAL_FILE    0x01 - First file in the cabinet is a continuation of a file from previous cabinet.
;;                                      When this value is set, the FDINOTIFICATION structure is populated with the following information:
;;                                            psz1 will point to the name of the file continued from a previous cabinet
;;                                            psz2 will point to the name of the cabinet on which the first segment of the file exists
;;                                            psz3 will point to the name of the disk on which the first segment of the file exists
;;                                      The fdintPARTIAL_FILE notification is called for files at the beginning of a cabinet that have continued from a previous cabinet.
;;                                      This notification will occur only when FDICopy is started on the second or subsequent cabinet in a series, which has files
;;                                      continued from a previous cabinet. The application should return 0 for success, or -1 to indicate failure.
;;            fdintCOPY_FILE       0x02 - Information identifying the file to be copied.
;;                                      When this value is set, the FDINOTIFICATION structure is populated with the following information:
;;                                            psz1   will point to the name of a file in the cabinet
;;                                            cb       will equal the uncompressed size of the file
;;                                            date   will equal the file's 16-bit MS-DOS date
;;                                            time   will equal the file's 16-bit MS-DOS time
;;                                            attrib   will equal the file's 16-bit MS-DOS attributes
;;                                      The application should return one of three values; 0 to skip (i.e. not copy) the file; -1 (negative one) to abort FDICopy; or a
;;                                      nonzero (and non-negative-one) file handle that indicates where to write the file. The file handle must be compatible with the
;;                                      PFNCLOSE function supplied to FDICreate. The fdintCOPY_FILE notification is called for each file that starts within the current
;;                                      cabinet, providing the opportunity for the application to request that the file be copied or skipped.
;;            fdintCLOSE_FILE_INFO 0x03 - Close the file, set relevant information.
;;                                      When this value is set, the FDINOTIFICATION structure is populated with the following information:
;;                                            psz1will point to the name of a file in the cabinet
;;                                            hf       will be a file handle (which originated from fdintCOPY_FILE)
;;                                            date   date will equal the file's 16-bit MS-DOS date
;;                                            time   time will equal the file's 16-bit MS-DOS time
;;                                            attrib   attributes will equal the file's 16-bit MS-DOS attributes (minus the _A_EXEC bit)
;;                                            cb       will equal either 0 or 1, indicating whether the file should be executed after extract (1), or not (0)
;;                                      It is the responsibility of the application to execute the file if cb equals 1. The fdintCLOSE_FILE_INFO notification is called
;;                                      after all of the data has been written to a target file. The application must close the file (using the provided hf handle), and
;;                                      set the file date, time, and attributes. The application should return TRUE for success, and FALSE or -1 to abort FDICopy. FDI
;;                                      assumes that the target file was closed, even if this callback returns failure; FDI will not attempt to use PFNCLOSE to close the file.
;;            fdintNEXT_CABINET    0x04 - File continued to next cabinet.
;;                                      When this value is set, the FDINOTIFICATION structure is populated with the following information:
;;                                            psz1will point to the name of the next cabinet on which the current file is continued
;;                                            psz2   will be a file handle (which originated from fdintCOPY_FILE)
;;                                            psz3   will point to the cabinet path information
;;                                            fdie   will equal a success or error value
;;                                      This notification is called only if fdintCOPY_FILE is instructed to copy a file, which is continued from a subsequent cabinet,
;;                                      to the current cabinet . Since it is possible for the application to modify the cabinet name, it is important that the cabinet
;;                                      path name, indicated by psz3, be validated before it is returned. Additionally, the application should ensure that the cabinet
;;                                      exists and is readable before returning; if necessary, the application should issue a disk change prompt to confirm.
;;                                      When this function returns to FDI, FDI will verify that the setID and iCabinet fields of the supplied cabinet match the expected
;;                                      values for that cabinet. If not, FDI will continue to send fdintNEXT_CABINET notification messages with the fdie field set to
;;                                      FDIERROR_WRONG_CABINET, until the correct cabinet file is specified, or until this function returns -1 and aborts the FDICopy call.
;;                                      If, after returning from this function, the cabinet file is not present, readable, or has been damaged, then the fdie field will
;;                                      equal one of the following values:
;;                                            FDIERROR_CABINET_NOT_FOUND
;;                                            FDIERROR_NOT_A_CABINET
;;                                            FDIERROR_UNKNOWN_CABINET_VERSION
;;                                            FDIERROR_CORRUPT_CABINET
;;                                            FDIERROR_BAD_COMPR_TYPE
;;                                            FDIERROR_RESERVE_MISMATCH
;;                                            FDIERROR_WRONG_CABINET
;;                                      If there was no error, fdie will equal FDIERROR_NONE. The application should return 0 to indicate success, or -1 to
;;                                      indicate failure, which will abort FDICopy.
;;            fdintENUMERATE       0x05 - Enumeration status.
;;        pfdin
;;            Pointer to an FDINOTIFICATION structure that contains notification information.
;;
;;    Return value
;;        This macro does not return a value.
;;
;; Syntax
;;      void FNFDINOTIFY(
;;          FDINOTIFICATIONTYPE fdint,
;;          PFDINOTIFICATION pfdin
;;      );
;;
;;
;;    Examples - C++
;;            FNFDINOTIFY(fnNotify)
;;            {
;;                INT_PTR iResult = 0;
;;
;;                switch(fdint)
;;                {
;;                  case fdintCOPY_FILE:
;;                  {
;;                      CHAR cResponse;
;;                      CHAR pszNewFileName[MAX_PATH];
;;                      LPSTR pszFileName;
;;                      HRESULT hr = S_OK;
;;
;;                  //TODO Validate if file name contains characters
;;                      //that are not allowed by the file system.
;;
;;                      //Remove any directory structure from the file name in cabinet
;;
;;                      pszFileName = strrchr(pfdin->psz1, '\\');
;;
;;                      if ( pszFileName == NULL )
;;                      {
;;                          pszFileName = pfdin->psz1;
;;                      }
;;
;;                      //Append the destination directory to the file name.
;;
;;                      hr = StringCchPrintfA(pszNewFileName,
;;                                            ARRAYSIZE(pszNewFileName),
;;                                            "%s\\%s",
;;                                            pfdin->pv,    //Destination directory provided by user
;;                                            pszFileName);
;;
;;                      if ( SUCCEEDED(hr) )
;;                      {
;;                          printf("Extract File \"%s\" (Size: %d bytes) -> \"%s\"? (Yes/No/Quit): ",
;;                                 pfdin->psz1,
;;                                 pfdin->cb,
;;                                 pszNewFileName); //uncompressed size of file
;;
;;                          do
;;                          {
;;                              cResponse = (CHAR)_getch();
;;                              cResponse = (CHAR)toupper(cResponse);
;;                          } while ( cResponse != 'Y' && cResponse != 'N' && cResponse != 'Q');
;;                          printf("\n");
;;
;;                          if ( cResponse == 'Y' )
;;                          {
;;                              iResult = fnFileOpen(pszNewFileName, _O_WRONLY | _O_CREAT, 0);
;;                          }
;;                          else if ( cResponse == 'Q' )
;;                          {
;;                              iResult = -1;
;;                          }
;;                      }
;;                      else
;;                      {
;;                          printf("Failed to append file name \"%s\" to destination directory \"%s\"\n",
;;                                 pszFileName,
;;                                 pfdin->pv);
;;                          iResult = -1;
;;                      }
;;
;;                      break;
;;                  }
;;                  case fdintCLOSE_FILE_INFO:
;;                  {
;;                      FILETIME fileTime;
;;                      FILETIME fileTimeLocal;
;;                      FILE_BASIC_INFO fbi;
;;
;;                      //Converts MS-DOS date and time values to a file time
;;
;;                      if ( DosDateTimeToFileTime(pfdin->date, pfdin->time, &fileTime) == TRUE &&
;;                           LocalFileTimeToFileTime(&fileTime, &fileTimeLocal) == TRUE )
;;                      {
;;                          fbi.CreationTime.LowPart = fileTimeLocal.dwLowDateTime;
;;                          fbi.CreationTime.HighPart = fileTimeLocal.dwHighDateTime;
;;                          fbi.LastWriteTime.QuadPart = -1;
;;                          fbi.ChangeTime.QuadPart = -1;
;;                          fbi.LastAccessTime.QuadPart = -1;
;;
;;                          //Retrieve the file attributes.
;;
;;                          fbi.FileAttributes = pfdin->attribs;
;;                          fbi.FileAttributes &= ( _A_RDONLY | _A_HIDDEN |
;;                                                  _A_SYSTEM | _A_ARCH  );
;;
;;                          //Set the date, time and attributes
;;
;;                          SetFileInformationByHandle((HANDLE)pfdin->hf,
;;                                                     FileBasicInfo,
;;                                                     &fbi,
;;                                                     sizeof(FILE_BASIC_INFO));
;;                      }
;;
;;                      iResult = !fnFileClose(pfdin->hf);
;;
;;                      break;
;;                  }
;;                  case fdintNEXT_CABINET:
;;                      if ( pfdin->fdie != FDIERROR_NONE )
;;                      {
;;                          printf("Failed to process the spanned cabinet file \"%s\""
;;                                 "with error code %d: %s\n",
;;                                 pfdin->psz1,
;;                                 pfdin->fdie,
;;                                 FDIErrorToString(pfdin->fdie));
;;                          iResult = -1;
;;                      }
;;                      break;
;;                  case fdintPARTIAL_FILE:
;;                      iResult = 0;
;;                      break;
;;                  case fdintCABINET_INFO:
;;                      iResult = 0;
;;                      break;
;;                  case fdintENUMERATE:
;;                      iResult = 0;
;;                      break;
;;                  default:
;;                      iResult = -1;
;;                      break;
;;                }
;;
;;                return iResult;
;;            }
;;
Func _FNFDINOTIFY($fdint, $pfdin)
    #ForceRef $fdint, $pfdin
    Local $iResult = 1, $FDINOTIFICATION = DllStructCreate($tds_FDINOTIFICATION, $pfdin)
    If @Error Then Return 0
    Switch $fdint
        ;;/***    FDINOTIFICATIONTYPE - FDICopy notification types
        ;; *
        ;; *  The notification function for FDICopy can be called with the following
        ;; *  values for the fdint parameter.  In all cases, the pfdin->pv field is
        ;; *  filled in with the value of the pvUser argument passed in to FDICopy().
        ;; *
        ;; *  A typical sequence of calls will be something like this:
        ;; *      fdintCABINET_INFO  // Info about the cabinet
        ;; *      fdintENUMERATE        // Starting enumeration
        ;; *      fdintPARTIAL_FILE  // Only if this is not the first cabinet, and
        ;; *                            // one or more files were continued from the
        ;; *                            // previous cabinet.
        ;; *      ...
        ;; *      fdintPARTIAL_FILE
        ;; *      fdintCOPY_FILE        // The first file that starts in this cabinet
        ;; *      ...
        ;; *      fdintCOPY_FILE        // Now let's assume you want this file...
        ;; *      // PFNWRITE called multiple times to write to this file.
        ;; *      fdintCLOSE_FILE_INFO  // File done, set date/time/attributes
        ;; *
        ;; *      fdintCOPY_FILE        // Now let's assume you want this file...
        ;; *      // PFNWRITE called multiple times to write to this file.
        ;; *      fdintNEXT_CABINET  // File was continued to next cabinet!
        ;; *      fdintCABINET_INFO  // Info about the new cabinet
        ;; *      // PFNWRITE called multiple times to write to this file.
        ;; *      fdintCLOSE_FILE_INFO  // File done, set date/time/attributes
        ;; *      ...
        ;; *      fdintENUMERATE        // Ending enumeration
        ;; *
        Case $fdintCABINET_INFO  ; 0x00 - General information about cabinet
            ;; *        Called exactly once for each cabinet opened by FDICopy(), including
            ;; *        continuation cabinets opened due to file(s) spanning cabinet
            ;; *        boundaries. Primarily intended to permit EXTRACT.EXE to
            ;; *        automatically select the next cabinet in a cabinet sequence even if
            ;; *        not copying files that span cabinet boundaries.
            ;; *      Entry:
            ;; *          pfdin->psz1    = name of next cabinet
            ;; *          pfdin->psz2    = name of next disk
            ;; *          pfdin->psz3    = cabinet path name
            ;; *          pfdin->setID    = cabinet set ID (a random 16-bit number)
            ;; *          pfdin->iCabinet = Cabinet number within cabinet set (0-based)
            ;; *      Exit-Success:
            ;; *          Return anything but -1
            ;; *      Exit-Failure:
            ;; *          Returns -1 => Abort FDICopy() call
            ;; *      Notes:
            ;; *          This call is made *every* time a new cabinet is examined by
            ;; *          FDICopy().  So if "foo2.cab" is examined because a file is
            ;; *          continued from "foo1.cab", and then you call FDICopy() again
            ;; *          on "foo2.cab", you will get *two* fdintCABINET_INFO calls all
            ;; *          told.
            ;; *
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCABINET_INFO - " & "pfdin->psz1   = name of next cabinet                     - " & DllStructGetData($FDINOTIFICATION, "psz1") & " - " & DllStructGetData(DllStructCreate("CHAR[260]", DllStructGetData($FDINOTIFICATION, "psz1")), 1) & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCABINET_INFO - " & "pfdin->psz2   = name of next disk                           - " & DllStructGetData($FDINOTIFICATION, "psz2") & " - " & DllStructGetData(DllStructCreate("CHAR[260]", DllStructGetData($FDINOTIFICATION, "psz2")), 1) & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCABINET_INFO - " & "pfdin->psz3   = cabinet path name                           - " & DllStructGetData($FDINOTIFICATION, "psz3") & " - " & DllStructGetData(DllStructCreate("CHAR[260]", DllStructGetData($FDINOTIFICATION, "psz3")), 1) & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCABINET_INFO - " & "pfdin->setID    = cabinet set ID (a random 16-bit number)     - " & DllStructGetData($FDINOTIFICATION, "setID") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCABINET_INFO - " & "pfdin->iCabinet = Cabinet number within cabinet set (0-based) - " & DllStructGetData($FDINOTIFICATION, "iCabinet") & @CRLF)
        Case $fdintCOPY_FILE        ; 0x02 - File to be copied
            ;; *        Called for each file that *starts* in the current cabinet, giving
            ;; *        the client the opportunity to request that the file be copied or
            ;; *        skipped.
            ;; *      Entry:
            ;; *          pfdin->psz1    = file name in cabinet
            ;; *          pfdin->cb   = uncompressed size of file
            ;; *          pfdin->date    = file date
            ;; *          pfdin->time    = file time
            ;; *          pfdin->attribs = file attributes
            ;; *          pfdin->iFolder = file's folder index
            ;; *      Exit-Success:
            ;; *          Return non-zero file handle for destination file; FDI writes
            ;; *          data to this file use the PFNWRITE function supplied to FDICreate,
            ;; *          and then calls fdintCLOSE_FILE_INFO to close the file and set
            ;; *          the date, time, and attributes.  NOTE: This file handle returned
            ;; *          must also be closeable by the PFNCLOSE function supplied to
            ;; *          FDICreate, since if an error occurs while writing to this handle,
            ;; *          FDI will use the PFNCLOSE function to close the file so that the
            ;; *          client may delete it.
            ;; *      Exit-Failure:
            ;; *          Returns 0  => Skip file, do not copy
            ;; *          Returns -1 => Abort FDICopy() call
            ;; *
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintCOPY_FILE - " & $fdintCOPY_FILE & " - " & $fdintCOPY_FILE & @CRLF)
            Local $pszFile = DllCall($h_Kernel32DLL, "int", "lstrlen", "ptr", DllStructGetData($FDINOTIFICATION, "psz1"))
            If @Error Then Return SetError(1, 0, -1)
            $pszFile = BinaryToString(DllStructGetData(DllStructCreate("byte["& $pszFile[0] & "]", $pszFile[1]), 1), 4)
            If $hLabel Then GUICtrlSetData($hLabel, $pszFile)
            ;;    Local $pszFile = DllStructGetData($FDINOTIFICATION, "psz1")
            ;;    $acMacros = DllCall($h_Kernel32DLL, "int", "MultiByteToWideChar", "uint", $CP_UTF8, "dword", 0, "ptr", $pszFile,"int", -1, "ptr", 0, "int", 0)
            ;;    If @Error Then Return SetError(1, 0, -1)
            ;;    $pszFile = DllStructCreate("wchar[" & $acMacros[0] & "]")
            ;;    $acMacros = DllCall($h_Kernel32DLL, "int", "MultiByteToWideChar", "uint", $CP_UTF8, "dword", 0, "ptr", $acMacros[3], "int", -1, "struct*", $pszFile, "int", $acMacros[0])
            ;;    If @Error Then Return SetError(1, 0, -1)
            ;;    $pszFile = DllStructGetData($pszFile, 1)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintCOPY_FILE - " & "pfdin->psz1    = file name in cabinet    - " & $pszFile & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintCOPY_FILE - " & "pfdin->cb    = uncompressed size of file - " & DllStructGetData($FDINOTIFICATION, "cb") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintCOPY_FILE - " & "pfdin->date    = file date              - " & DllStructGetData($FDINOTIFICATION, "date") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintCOPY_FILE - " & "pfdin->time    = file time              - " & DllStructGetData($FDINOTIFICATION, "time") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintCOPY_FILE - " & "pfdin->attribs = file attributes          - " & DllStructGetData($FDINOTIFICATION, "attribs") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintCOPY_FILE - " & "pfdin->iFolder = file's folder index      - " & DllStructGetData($FDINOTIFICATION, "iFolder") & @CRLF)
            Return _FNOPEN(DllStructGetData(DllStructCreate("WCHAR[260]", DllStructGetData($FDINOTIFICATION, "pv")), 1) & $pszFile, DllStructGetData($FDINOTIFICATION, "attribs"), 0)
        Case $fdintCLOSE_FILE_INFO  ; 0x03 - close the file, set relevant info
            ;; *        Called after all of the data has been written to a target file.
            ;; *        This function must close the file and set the file date, time,
            ;; *        and attributes.
            ;; *      Entry:
            ;; *          pfdin->psz1    = file name in cabinet
            ;; *          pfdin->hf   = file handle
            ;; *          pfdin->date    = file date
            ;; *          pfdin->time    = file time
            ;; *          pfdin->attribs = file attributes
            ;; *          pfdin->iFolder = file's folder index
            ;; *          pfdin->cb   = Run After Extract (0 - don't run, 1 Run)
            ;; *      Exit-Success:
            ;; *          Returns TRUE
            ;; *      Exit-Failure:
            ;; *          Returns FALSE, or -1 to abort;
            ;; *
            ;; *              IMPORTANT NOTE IMPORTANT:
            ;; *                  pfdin->cb is overloaded to no longer be the size of
            ;; *                  the file but to be a binary indicated run or not
            ;; *
            ;; *              IMPORTANT NOTE:
            ;; *                  FDI assumes that the target file was closed, even if this
            ;; *                  callback returns failure.  FDI will NOT attempt to use
            ;; *                  the PFNCLOSE function supplied on FDICreate() to close
            ;; *                  the file!
            ;; *
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCLOSE_FILE_INFO - " & "pfdin->psz1    = file name in cabinet                  - " & DllStructGetData($FDINOTIFICATION, "psz1") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCLOSE_FILE_INFO - " & "pfdin->hf   = file handle                           - " & DllStructGetData($FDINOTIFICATION, "hf") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCLOSE_FILE_INFO - " & "pfdin->date    = file date                                - " & DllStructGetData($FDINOTIFICATION, "date") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCLOSE_FILE_INFO - " & "pfdin->time    = file time                                - " & DllStructGetData($FDINOTIFICATION, "time") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCLOSE_FILE_INFO - " & "pfdin->attribs = file attributes                        - " & DllStructGetData($FDINOTIFICATION, "attribs") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCLOSE_FILE_INFO - " & "pfdin->iFolder = file's folder index                    - " & DllStructGetData($FDINOTIFICATION, "iFolder") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintCLOSE_FILE_INFO - " & "pfdin->cb   = Run After Extract (0 - don't run, 1 Run) - " & DllStructGetData($FDINOTIFICATION, "cb") & @CRLF)
            $acMacros = DllCall($h_Kernel32DLL, "bool", "DosDateTimeToFileTime", "word", DllStructGetData($FDINOTIFICATION, "date"), "word", DllStructGetData($FDINOTIFICATION, "time"), "ptr", $lpLocalFileTime)
            If Not @Error Then
                $acMacros = DllCall($h_Kernel32DLL, "bool", "LocalFileTimeToFileTime", "ptr", $lpLocalFileTime, "ptr", $lpFileTime)
                If Not @Error Then
                    ;;DllCall($h_Kernel32DLL, "none", "GetSystemTimeAsFileTime", "ptr", $lpLocalFileTime)
                    ;;$acMacros = DllCall($h_Kernel32DLL, "bool", "SetFileTime", "handle", DllStructGetData($FDINOTIFICATION, "hf"), "ptr", $lpLocalFileTime, "ptr", 0, "ptr", $lpFileTime)
                    $acMacros = DllCall($h_Kernel32DLL, "bool", "SetFileTime", "handle", DllStructGetData($FDINOTIFICATION, "hf"), "ptr", 0, "ptr", 0, "ptr", $lpFileTime)
                EndIf
            EndIf
            _FNCLOSE(DllStructGetData($FDINOTIFICATION, "hf"))
            Return 1
        Case $fdintPARTIAL_FILE  ; 0x01 - First file in cabinet is continuation
            ;; *        Called for files at the front of the cabinet that are CONTINUED
            ;; *        from a previous cabinet.  This callback occurs only when FDICopy is
            ;; *        started on second or subsequent cabinet in a series that has files
            ;; *        continued from a previous cabinet.
            ;; *      Entry:
            ;; *          pfdin->psz1 = file name of file CONTINUED from a PREVIOUS cabinet
            ;; *          pfdin->psz2 = name of cabinet where file starts
            ;; *          pfdin->psz3 = name of disk where file starts
            ;; *      Exit-Success:
            ;; *          Return anything other than -1; enumeration continues
            ;; *      Exit-Failure:
            ;; *          Returns -1 => Abort FDICopy() call
            ;; *
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintPARTIAL_FILE - " & "pfdin->psz1 = file name of file CONTINUED from a PREVIOUS cabinet - " & DllStructGetData($FDINOTIFICATION, "psz1") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintPARTIAL_FILE - " & "pfdin->psz2 = name of cabinet where file starts - " & DllStructGetData($FDINOTIFICATION, "psz2") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintPARTIAL_FILE - " & "pfdin->psz3 = name of disk where file starts    - " & DllStructGetData($FDINOTIFICATION, "psz3") & @CRLF)
            $iResult = 0
        Case $fdintENUMERATE        ; 0x05 - Enumeration status
            ;; *        Called once after a call to FDICopy() starts scanning a CAB's
            ;; *        CFFILE entries, and again when there are no more CFFILE entries.
            ;; *        If CAB spanning occurs, an additional call will occur after the
            ;; *        first spanned file is completed.  If the pfdin->iFolder value is
            ;; *        changed from zero, additional calls will occur next time it reaches
            ;; *        zero.  If iFolder is changed to zero, FDICopy will terminate, as if
            ;; *        there were no more CFFILE entries.  Primarily intended to allow an
            ;; *        application with it's own file list to help FDI advance quickly to
            ;; *        a CFFILE entry of interest.  Can also be used to allow an
            ;; *        application to determine the cb values for each file in the CAB.
            ;; *      Entry:
            ;; *        pfdin->cb       = current CFFILE position
            ;; *        pfdin->iFolder   = number of files remaining
            ;; *        pfdin->setID     = current CAB's setID value
            ;; *      Exit-Don't Care:
            ;; *        Don't change anything.
            ;; *        Return anything but -1.
            ;; *      Exit-Forcing a skip:
            ;; *        pfdin->cb       = desired CFFILE position
            ;; *        pfdin->iFolder   = desired # of files remaining
            ;; *        Return anything but -1.
            ;; *      Exit-Stop:
            ;; *        pfdin->iFolder    = set to 0
            ;; *        Return anything but -1.
            ;; *      Exit-Failure:
            ;; *        Return -1 => Abort FDICopy call ("user aborted".)
            ;; *      Notes:
            ;; *        This call can be ignored by applications which want normal file
            ;; *        searching.  The application can adjust the supplied values to
            ;; *        force FDICopy() to continue it's search at another location, or
            ;; *        to force FDICopy() to terminate the search, by setting iFolder to 0.
            ;; *        (FDICopy() will report no error when terminated this way.)
            ;; *        FDI has no means to verify the supplied cb or iFolder values.
            ;; *        Arbitrary values are likely to cause undesirable results.  An
            ;; *        application should cross-check pfdin->setID to be certain the
            ;; *        external database is in sync with the CAB.  Reverse-skips are OK
            ;; *        (but may be inefficient) unless fdintNEXT_CABINET has been called.
            ;; *
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintENUMERATE - " & "pfdin->cb    = current CFFILE position   - " & DllStructGetData($FDINOTIFICATION, "cb") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintENUMERATE - " & "pfdin->iFolder = number of files remaining - " & DllStructGetData($FDINOTIFICATION, "iFolder") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  $fdintENUMERATE - " & "pfdin->setID   = current CAB's setID value - " & DllStructGetData($FDINOTIFICATION, "setID") & @CRLF)
        Case $fdintNEXT_CABINET  ; 0x04 - File continued to next cabinet
            ;; *        This function is *only* called when fdintCOPY_FILE was told to copy
            ;; *        a file in the current cabinet that is continued to a subsequent
            ;; *        cabinet file.  It is important that the cabinet path name (psz3)
            ;; *        be validated before returning!  This function should ensure that
            ;; *        the cabinet exists and is readable before returning.  So, this
            ;; *        is the function that should, for example, issue a disk change
            ;; *        prompt and make sure the cabinet file exists.
            ;; *
            ;; *        When this function returns to FDI, FDI will check that the setID
            ;; *        and iCabinet match the expected values for the next cabinet.
            ;; *        If not, FDI will continue to call this function until the correct
            ;; *        cabinet file is specified, or until this function returns -1 to
            ;; *        abort the FDICopy() function.  pfdin->fdie is set to
            ;; *        FDIERROR_WRONG_CABINET to indicate this case.
            ;; *
            ;; *        If you *haven't* ensured that the cabinet file is present and
            ;; *        readable, or the cabinet file has been damaged, pfdin->fdie will
            ;; *        receive other appropriate error codes:
            ;; *
            ;; *              FDIERROR_CABINET_NOT_FOUND
            ;; *              FDIERROR_NOT_A_CABINET
            ;; *              FDIERROR_UNKNOWN_CABINET_VERSION
            ;; *              FDIERROR_CORRUPT_CABINET
            ;; *              FDIERROR_BAD_COMPR_TYPE
            ;; *              FDIERROR_RESERVE_MISMATCH
            ;; *              FDIERROR_WRONG_CABINET
            ;; *
            ;; *      Entry:
            ;; *          pfdin->psz1 = name of next cabinet where current file is continued
            ;; *          pfdin->psz2 = name of next disk where current file is continued
            ;; *          pfdin->psz3 = cabinet path name; FDI concatenates psz3 with psz1
            ;; *                          to produce the fully-qualified path for the cabinet
            ;; *                          file.  The 256-byte buffer pointed at by psz3 may
            ;; *                          be modified, but psz1 may not!
            ;; *          pfdin->fdie = FDIERROR_WRONG_CABINET if the previous call to
            ;; *                        fdintNEXT_CABINET specified a cabinet file that
            ;; *                        did not match the setID/iCabinet that was expected.
            ;; *      Exit-Success:
            ;; *          Return anything but -1
            ;; *      Exit-Failure:
            ;; *          Returns -1 => Abort FDICopy() call
            ;; *      Notes:
            ;; *          This call is almost always made when a target file is open and
            ;; *          being written to, and the next cabinet is needed to get more
            ;; *          data for the file.
            ;; */
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintNEXT_CABINET - " & "pfdin->psz1 = name of next cabinet where current file is continued - " & DllStructGetData($FDINOTIFICATION, "psz1") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintNEXT_CABINET - " & "pfdin->psz2 = name of next disk where current file is continued    - " & DllStructGetData($FDINOTIFICATION, "psz2") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintNEXT_CABINET - " & "pfdin->psz3 = cabinet path name; FDI concatenates psz3 with psz1   - " & DllStructGetData($FDINOTIFICATION, "psz3") & @CRLF)
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY - $fdintNEXT_CABINET - " & "pfdin->fdie = FDIERROR_WRONG_CABINET                            - " & DllStructGetData($FDINOTIFICATION, "fdie") & @CRLF)
            $iResult = - 1
            ;; *              ; $fdintNEXT_CABINET will not have to ever happen, so set to return error -1 - Abort FDICopy() call,
            ;; *              ;   or use FileOpenDialog(), example FileOpenDialog("Cab Files", @DesktopDir & "\", "Cab Files (*.cab;*.*_;*.*$)", 1)
            ;; *              $NewPath = FileOpenDialog("Cab Files", $CabinetPath, "Cab Files (*.cab;*.*_;*.*$)", 1)
            ;; *              If @Error Then Return -1 - Abort FDICopy() call, The system cannot find the path specified.
            ;; *              DllStructSetData(DllStructCreate("WCHAR[260]", $Param2), 1, $NewPath)
            ;; *              Return 0 ;NO_ERROR
        Case Else
            ;;;;    ConsoleWrite(("+> _FNFDINOTIFY -  Else - " & $fdint & " - " & $fdint & @CRLF)
            $iResult = 0        ;- 1
    EndSwitch
    Return $iResult
EndFunc

;;    The FNFREE macro provides the declaration for the application-defined callback function to free previously allocated memory in an FDI context.
;;    Parameters
;;        pv [in, optional]
;;            Pointer to the allocated memory block to free.
;;
;;    Return value
;;        This macro does not return a value.
;;
;;    Remarks
;;        The function accepts parameters similar to free.
;;
;; Syntax
;;      void FNFREE(
;;          [in, optional]  void HUGE *pv
;;      );
;;
;;
;;    Examples - C++
;;            FNFREE(fnMemFree)
;;            {
;;                free(pv);
;;            }
;;
Func _FNFREE($pv)
    #ForceRef $pv
    ;;;;    ConsoleWrite(("+> _FNFREE - $pv - " & $pv & @CRLF)
    $acMacros = DllCall($h_Kernel32DLL, "BOOL", "HeapFree", "HANDLE", $hDefaultProcessHeap, "dword", 0, "ptr", $pv)
    If @Error Or Not $acMacros[0] Then SetError(1)
    ;;;;    ConsoleWrite(("+> _FNFREE - $pv - " & $pv & @CRLF)
EndFunc


;;    The FNOPEN macro provides the declaration for the application-defined callback function to open a file in an FDI context.
;;    Parameters
;;        pszFile [in]
;;            The name of the file.
;;        oflag
;;            Specifies the type of operations allowed.
;;        pmode
;;            Specifies the permission mode.
;;
;;    Return value
;;        The return value is application-defined and used to identify the open file. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _open.
;;
;; Syntax
;;      void FNOPEN(
;;          [in]  LPSTR pszFile,
;;          int oflag,
;;          int pmode
;;      );
;;
;;
;;    Examples - C++
;;            FNOPEN(fnFileOpen)
;;            {
;;                HANDLE hFile = NULL;
;;                DWORD dwDesiredAccess = 0;
;;                DWORD dwCreationDisposition = 0;
;;
;;                UNREFERENCED_PARAMETER(pmode);
;;
;;                if ( oflag & _O_RDWR )
;;                {
;;                    dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
;;                }
;;                else if ( oflag & _O_WRONLY )
;;                {
;;                    dwDesiredAccess = GENERIC_WRITE;
;;                }
;;                else
;;                {
;;                    dwDesiredAccess = GENERIC_READ;
;;                }
;;
;;                if ( oflag & _O_CREAT )
;;                {
;;                    dwCreationDisposition = CREATE_ALWAYS;
;;                }
;;                else
;;                {
;;                    dwCreationDisposition = OPEN_EXISTING;
;;                }
;;
;;                hFile = CreateFileA(pszFile,
;;                                    dwDesiredAccess,
;;                                    FILE_SHARE_READ,
;;                                    NULL,
;;                                    dwCreationDisposition,
;;                                    FILE_ATTRIBUTE_NORMAL,
;;                                    NULL);
;;
;;                return (INT_PTR)hFile;
;;            }
;;
Func _FNOPEN($pszFile, $oflag, $pmode)
    If IsString($pszFile) Then
        ;;;;    ConsoleWrite(("+> _FNOPEN1 - $pszFile - " & $pszFile & "  - $oflag - " & $oflag & "  - $pmode- " & $pmode & @CRLF)
        ;;Local $dwDesiredAccess = $GENERIC_READ_WRITE, $dwCreationDisposition = $CREATE_ALWAYS, $dwShareMode = $FILE_SHARE_READ, $dwFlagsAndAttributes = $oflag
        ;;$pszFile = DllCall($h_Kernel32DLL, "HANDLE", "CreateFileW", "wstr", $pszFile, "dword", $dwDesiredAccess, "dword", $dwShareMode, "ptr", 0, "dword", $dwCreationDisposition, "dword", $dwFlagsAndAttributes, "ptr", 0)
        $pszFile = DllCall($h_Kernel32DLL, "HANDLE", "CreateFileW", "wstr", $pszFile, "dword", $GENERIC_READ_WRITE, "dword", $FILE_SHARE_READ, "ptr", 0, "dword", $CREATE_ALWAYS, "dword", $oflag, "ptr", 0)
    Else
        ;;;;    ConsoleWrite(("+> _FNOPEN2 - $pszFile - " & $pszFile & "  - $oflag - " & $oflag & "  - $pmode- " & $pmode & @CRLF)
        ;;;;    $pszFile = _WinAPI_MultiByteToWideChar($pszFile, 65001, 0, 1)
        ;;    $acMacros = DllCall($h_Kernel32DLL, "int", "MultiByteToWideChar", "uint", $CP_UTF8, "dword", 0, "ptr", $pszFile,"int", -1, "ptr", 0, "int", 0)
        ;;    If @Error Then Return SetError(1, 0, -1)
        ;;    $pszFile = DllStructCreate("wchar[" & $acMacros[0] & "]")
        ;;    $acMacros = DllCall($h_Kernel32DLL, "int", "MultiByteToWideChar", "uint", $CP_UTF8, "dword", 0, "ptr", $acMacros[3], "int", -1, "struct*", $pszFile, "int", $acMacros[0])
        ;;    If @Error Then Return SetError(1, 0, -1)
        ;;    $pszFile = DllStructGetData($pszFile, 1)
        $pszFile = DllCall($h_Kernel32DLL, "int", "lstrlen", "ptr", $pszFile)
        If @Error Then Return SetError(1, 0, -1)
        $pszFile = BinaryToString(DllStructGetData(DllStructCreate("byte["& $pszFile[0] & "]", $pszFile[1]), 1), 4)
        Local $dwDesiredAccess = $GENERIC_READ, $dwCreationDisposition = $OPEN_EXISTING, $dwShareMode = $FILE_SHARE_READ, $dwFlagsAndAttributes = $FILE_ATTRIBUTE_NORMAL
        If BitAND($oflag, $_O_RDWR) Then
            $dwDesiredAccess = $GENERIC_READ_WRITE
        ElseIf BitAND($oflag, $_O_WRONLY) Then
            $dwDesiredAccess = $GENERIC_WRITE
        EndIf
        If BitAND($oflag, $_O_CREAT) Then $dwCreationDisposition = $CREATE_ALWAYS
        $pszFile = DllCall($h_Kernel32DLL, "HANDLE", "CreateFileW", "wstr", $pszFile, "dword", $dwDesiredAccess, "dword", $dwShareMode, "ptr", 0, "dword", $dwCreationDisposition, "dword", $dwFlagsAndAttributes, "ptr", 0)
    EndIf
    If @Error Then Return SetError(1, 0, -1) ; INVALID_HANDLE_VALUE
    If $pszFile[0] <> Ptr(-1) Then Return $pszFile[0]
    If Not DirCreate(StringLeft($pszFile[1], StringInStr($pszFile[1], "\", 1, -1))) Then Return SetError(1, 0, -1) ; INVALID_HANDLE_VALUE
    $pszFile = DllCall($h_Kernel32DLL, "HANDLE", "CreateFileW", "wstr", $pszFile[1], "dword", $pszFile[2], "dword", $pszFile[3], "ptr", 0, "dword", $pszFile[5], "dword", $pszFile[6], "ptr", 0)
    If @Error Or $pszFile[0] = Ptr(-1) Then Return SetError(1, 0, -1) ; INVALID_HANDLE_VALUE
    Return $pszFile[0]
EndFunc


;;    The FNREAD macro provides the declaration for the application-defined callback function to read data from a file in an FDI context.
;;    Parameters
;;        hf [in]
;;            An application-defined value used to identify the open file.
;;        pv [out]
;;            Pointer to the buffer that receives the data read from a file.
;;        cb
;;            The maximum number of bytes to be read.
;;
;;    Return value
;;        The indicated callback function returns the number of bytes read. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _read.
;;
;; Syntax
;;      void FNREAD(
;;          [in]   INT_PTR hf,
;;          [out]  void FAR *pv[bcount(cb)],
;;          UINT cb
;;      );
;;
;;
;;    Examples - C++
;;            FNREAD(fnFileRead)
;;            {
;;                DWORD dwBytesRead = 0;
;;
;;                if ( ReadFile((HANDLE)hf, pv, cb, &dwBytesRead, NULL) == FALSE )
;;                {
;;                  dwBytesRead = (DWORD)-1L;
;;                }
;;
;;                return dwBytesRead;
;;            }
;;
Func _FNREAD($hf, $pv, $cb)
    #ForceRef $hf, $pv, $cb
    ;;;;;;;;$acMacros = DllCall($h_Kernel32DLL, "BOOL", "ReadFile", "HANDLE", $hFile, "ptr", $lpBuffer, "dword", $nNumberOfBytesToRead, "dword*", 0, "ptr", $lpOverlapped)
    ;;;;    ConsoleWrite(("+> _FNREAD - $hf - " & $hf & " - $pv - " & $pv & " - $cb - " & $cb & @CRLF)
    $acMacros = DllCall($h_Kernel32DLL, "BOOL", "ReadFile", "HANDLE", $hf, "ptr", $pv, "dword", $cb, "dword*", 0, "ptr", 0)
    If @Error Or Not $acMacros[4] Then Return SetError(1, 0, -1)
    ;;;;    ConsoleWrite(("+> _FNREAD - $hf - " & $hf & " - $pv - " & $pv & " - $cb - " & $cb & " - " & $acMacros[4] & @CRLF)
    Return $acMacros[4]    ;$lpNumberOfBytesRead
EndFunc


;;    The FNSEEK macro provides the declaration for the application-defined callback function to move a file pointer to the specified location in an FDI context.
;;    Parameters
;;        hf [in]
;;            An application-defined value used to identify the open file.
;;        dist
;;            The number of bytes to move the file pointer.
;;        seektype
;;            The starting point for the file pointer move.
;;
;;    Return value
;;        The indicated callback function returns the offset, in bytes, of the new position from the beginning of the file. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _lseek.
;;
;; Syntax
;;      void FNSEEK(
;;          [in]  INT_PTR hf,
;;          long dist,
;;          int seektype
;;      );
;;
;;
;;    Examples - C++
;;            FNSEEK(fnFileSeek)
;;            {
;;                return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
;;            }
;;
Func _FNSEEK($hf, $dist, $seektype)
    #ForceRef $hf, $dist, $seektype
    ;;;;$acMacros = DllCall($h_Kernel32DLL, "DWORD", "SetFilePointer", "HANDLE", $hFile, "LONG", $lDistanceToMove, "LONG*", $lpDistanceToMoveHigh, "LONG", $dwMoveMethod)
    ;;;;    ConsoleWrite(("+> _FNSEEK - $hf - " & $hf & " - $dist - " & $dist & " - $seektype - " & $seektype & @CRLF)
    $acMacros = DllCall($h_Kernel32DLL, "INT", "SetFilePointer", "HANDLE", $hf, "LONG", $dist, "ptr", 0, "LONG", $seektype)
    ;;;;    ConsoleWrite(("+> _FNSEEK - $hf - " & $hf & " - $dist - " & $dist & " - $seektype - " & $seektype & @CRLF)
    If @Error Then Return SetError(1, 0, -1)    ;INVALID_SET_FILE_POINTER (-1)
    Return $acMacros[0]
EndFunc


;;    The FNWRITE macro provides the declaration for the application-defined callback function to write data to a file in an FDI context.
;;    Parameters
;;        hf [in]
;;            An application-defined value used to identify the open file.
;;        pv [in]
;;            Pointer to the buffer containing the data to be written.
;;        cb
;;            The maximum number of bytes to be written.
;;
;;    Return value
;;        The indicated callback function returns the number of bytes written. However, a value of -1 indicates an error.
;;
;;    Remarks
;;        The function accepts parameters similar to _write.
;;
;; Syntax
;;      void FNWRITE(
;;          [in]  INT_PTR hf,
;;          [in]  void FAR *pv[bcount(cb)],
;;          UINT cb
;;      );
;;
;;
;;    Examples - C++
;;            FNWRITE(fnFileWrite)
;;            {
;;                DWORD dwBytesWritten = 0;
;;
;;                if ( WriteFile((HANDLE)hf, pv, cb, &dwBytesWritten, NULL) == FALSE )
;;                {
;;                  dwBytesWritten = (DWORD)-1;
;;                }
;;
;;                return dwBytesWritten;
;;            }
;;
Func _FNWRITE($hf, $pv, $cb)
    #ForceRef $hf, $pv, $cb
    ;;;;;;;;$acMacros = DllCall($h_Kernel32DLL, "BOOL", "WriteFile", "HANDLE", $hFile, "ptr", $lpBuffer, "dword", $nNumberOfBytesToWrite, "dword*", 0, "ptr", $lpOverlapped)
    ;;;;    ConsoleWrite(("+> _FNWRITE - $hf - " & $hf & " - $pv - " & $pv & " - $cb - " & $cb & @CRLF)
    $acMacros = DllCall($h_Kernel32DLL, "BOOL", "WriteFile", "HANDLE", $hf, "ptr", $pv, "dword", $cb, "dword*", 0, "ptr", 0)
    If @Error Or Not $acMacros[4] Then Return SetError(1, 0, -1)
    Return $acMacros[4]    ;$lpNumberOfBytesWritten
EndFunc

#EndRegion ;FDI Macros - used by FDI

Global $hFDI, $cFDI, $ExtractDir, $tExtractDir, $sCabName, $sCabPath, $hFDIIsCabinet, $Timer, $sFilePath, $ExitWhile

$hGui = GUICreate("Test", 531, 312)
GUISetBkColor(0xFFFFFF)
$hFilePathButton = GUICtrlCreateButton("  ....  ", 464, 64, 57, 25, $BS_CENTER)
$hFilePathInput = GUICtrlCreateInput("", 15, 64, 441, 24)
GUICtrlSetFont(-1, 10, 400, 0, "Tahoma")
$hStartButton = GUICtrlCreateButton("Start", 213, 160, 105, 25)
$hExtractDirInput = GUICtrlCreateInput("", 15, 107, 441, 24)
GUICtrlSetFont(-1, 10, 400, 0, "Tahoma")
$hExtractDirButton = GUICtrlCreateButton("  ....  ", 464, 107, 57, 25, $BS_CENTER)
$hLabel = GUICtrlCreateLabel("", 8, 208, 512, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 400, 0, "Tahoma")
;$hProgress = GUICtrlCreateProgress(8, 232, 512, 25)
GUISetState(@SW_SHOW)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $hFilePathButton
            $sFilePath = FileOpenDialog("Cab Files", @DesktopDir, "Cab Files (*.cab;*.*_;*.*$)", 1)
            If FileExists($sFilePath) Then
                GUICtrlSetData($hFilePathInput, $sFilePath)
                GUICtrlSetData($hExtractDirInput, StringLeft($sFilePath, StringInStr($sFilePath, ".", 1, -1) - 1))
                ;;If Not StringInStr(FileGetAttrib(GUICtrlRead($hExtractDirInput)), "D") Then GUICtrlSetData($hExtractDirInput, StringLeft($sFilePath, StringInStr($sFilePath, ".", 1, -1) - 1))
            EndIf
        Case $hExtractDirButton
            $ExtractDir = FileSelectFolder("Destination Dir.", "")
            GUICtrlSetData($hExtractDirInput, $ExtractDir)
        Case $hStartButton
            Local $Timer = TimerInit()
            _CabExtract(GUICtrlRead($hFilePathInput), GUICtrlRead($hExtractDirInput))
            $Timer = TimerDiff($Timer)
            MsgBox(0, 111, $Timer)
    EndSwitch
WEnd

Func _CabExtract($sFilePath, $sDestDir = "")
    $sFilePath = StringRegExpReplace($sFilePath, "[\\/]+", "\\")
    If Not FileExists($sFilePath) Then Return SetError(1, 0, 0)
    Local $hFDI = _FDICreate()
    If @Error Then Return SetError(2, @Extended, _FDIErrorToString(@Extended))
    Local $hFDIIsCabinet = DllCall($h_Kernel32DLL, "HANDLE", "CreateFileW", "wstr", $sFilePath, "dword", $GENERIC_READ, "dword", $FILE_SHARE_READ, "ptr", 0, "dword", $OPEN_EXISTING, "dword", $FILE_ATTRIBUTE_ARCHIVE, "ptr", 0)
    If @Error Or $hFDIIsCabinet[0] = Ptr(-1) Then Return SetError(3, 0, 0)
    Local $aFDIIsCabinet = _FDIIsCabinet($hFDI, $hFDIIsCabinet[0])
    If @Error Then Return SetError(4, @Extended, _FNCLOSE($hFDIIsCabinet[0]))
    $cFiles = DllStructGetData($aFDIIsCabinet, "cFiles")
    _FNCLOSE($hFDIIsCabinet[0])
    Local $sCabName = StringTrimLeft($sFilePath, StringInStr($sFilePath, "\", 1, -1))
    Local $sCabPath = StringLeft($sFilePath, StringInStr($sFilePath, "\", 1, -1))
    If Not $sDestDir Then $sDestDir = $sCabPath & StringRegExpReplace($sCabName & " ", "(\.[^\.\\]*)?(\h)$", "\\")
    $sDestDir = StringRegExpReplace($sDestDir & "\", "[\/\\]+", "\\")
    If Not DirCreate($sDestDir) Then Return SetError(5, 0, 0)
    Local $pDestDir, $tDestDir = DllStructCreate("wchar[" & StringLen($sDestDir) + 1 & "]")
    DllStructSetData($tDestDir, 1, $sDestDir)
    $pDestDir = DllStructGetPtr($tDestDir, 1)
    $cFDI = _FDICopy($hFDI, $sCabName, $sCabPath, $pDestDir, $PFNFDINOTIFY)
    If @Error Then SetError(6, @Extended, _FDIErrorToString(@Extended) & _FDIDestroy($hFDI))
    _FDIDestroy($hFDI)
    Return 1
EndFunc
Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Link to comment
Share on other sites

It's the problem with AutoIt, yes.

Some time ago I added volatile keyword function modifier that you can use when defining functions that do this to AutoIt. So with newer versions of AutoIt it would be, for example:

volatile Func _FNWRITE($hf, $pv, $cb)
;...
EndFunc

But I'm not developer any more so don't take my word for it.

Link to comment
Share on other sites

Hi trancexx, Thank You, I understand

I just wanted to know if it was a problem with autoit or not, because it was always the doubt that error could be in the script, so I lost a lot of time to try and try again

we hope that in the future will solve the problem

Ciao.

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Link to comment
Share on other sites

  • 3 months later...

It's the problem with AutoIt, yes.

Some time ago I added volatile keyword function modifier that you can use when defining functions that do this to AutoIt. So with newer versions of AutoIt it would be, for example:

volatile Func _FNWRITE($hf, $pv, $cb)
;...
EndFunc
But I'm not developer any more so don't take my word for it.

 

already tried with the AutoIt v3.3.9.6, everything works OK

Thanks again

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...