Что нового

[Файловая система] Cabinet File API - Работа с CAB архивами

Astel064

Помог мой пост, ставь +!
Сообщения
276
Репутация
51
Здравствуйте, как с помощью cabinet.dll (или cabview.dll) создать CAB архив, редактировать его, или извлечь из него файлы?
Кто-нибудь сталкивался с этим?

На оф. форуме нашел такой скрипт, но он не работает, поэтому обратился за помощью к Вам.

Еще наткнулся на эти варианты: 1, 2, но что-то не очень получается, то не хочет создавать CAB, то вылет с нестандартной ошибкой. Причем, на vbs все работает...
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Код:
makecab.exe file.dll
Код:
makecab.exe -?
pause
 

damien2008

Осваивающий
Сообщения
178
Репутация
34
вот нашел такой скрипт, только надо проверить:

Код:
;===================================================================================================
#include <Array.au3>
#include <File.au3>

;===================================================================================================


; Function Name:    _MakeDff()
; Description:      Create a dff file containing the directives to create a cabinet.
; Remarks:          To create a *.cab, a dff file containing the directives must be create. Such file
;                   contains information about how the cabinet is to be built (i.e., cabinet file name, the
;                   directory where the dff is to be stored, the target media (floppy, cdrom, etc) and maximum
;                   file size, etc.) as well as a list of files to store in the cabinet.
; Usage:            1.-The $pFiles parameter can either be a 1Dim array with each element containing a full path
;                   to a file, or a path to a directory, or to a single file. If $pExtis an array, try to
;                   group files according to their type to help compression. If $pExt is a path to a directory,
;                   you can use the $pExtto specify file types, wildcards allowed.
;                   2.-You may modify the settings that define the directives for the dff with the $pSettings
;                   parameter, substituting the default values.
; Parameter(s):     $pDffFile       - Compulsory:   FileName for dff file
;                   $pFiles         - Compulsory:   Files array or path to directory
;                   $pCabDirName    - Compulsory:   Subdirectory of $pDffDest where
;                                                   the cabinet will be stored
;                   $pCabName       - Compulsory:   Name for the cabinet file
;                   $pDffDest       - Optional:     Path to $pDffFile
;                                       -1      =   (Default) Current directory
;                                       String  =   path to output directory, no trailing slash. If the directory
;                                                   doesn't already exist, the script will attempt to create it.
;                   $pFileIndex     - Optional:     specifies index to start logging the $pFiles array
;                                       1       =   (Default) start with element 1 of the $pFiles array
;                   $pSettings      - Optional:     Directives for the dff file, see the $lSettings array
;                                       -1      =   (Default) directives as set in the $lSettings array
;                                       if modified, make sure your directives start at element 1 of the array
;                   $pExt           - Optional:     Specifies filetypes in $pFiles directory to be included in the dff,
;                                                   only relevant if $pFiles is a path pointing to a directory.
;                                                   WildCards allowed i.e, *.* or *.h?ml, etc.
; Requirement(s):   AutoIt3 V3.2 or higher
; Return Value(s):  On Success  - returns 1 and createsthe file
;                  On Failure   - Returns 0 and sets @ERROR
;                   @ERROR          = 1 Invalid Parameters, see extended
;                                   @Extended   =   1 when not using default $pDffDest and dff destination dir is not a string
;                                               =   2 when not using default $pDffDest and dff destination dir could not be created
;                                               =   3 dff file is invalid or already exists
;                                               =   4 $pCabDirName is not a valid directory name
;                                               =   5 $pCabName already exists or is not a valid filename
;                                               =   6 wrong type for $pFiles (neither array nor string)
;                                               =   7 invalid $pSettings neither array nor default value=-1
;                                               =   8 invalid $pFileIndex in $pFiles array
;                   @ERROR          = 2 $pFiles array error
;                                   @Extended   =   1 unable to generate files in $pFiles dir
;                   @ERROR          = 3 file in $pFiles array error
;                                   @Extended   =   1 file in $pFiles array does not exist
; NOTE:             Subdirectories are omitted from cabinet when $pFiles is a path to a directory
; TODO:             CHECK $pExt for errors
; Date:             11/9/2007
; Author:           Ivan Perez
;===================================================================================================


Func _MakeDff($pDffFile, $pFiles, $pCabDirName, $pCabName, $pDffDest = -1, $pFileIndex = 1, $pSettings = -1, $pExt = '*.*')
    Local $lFileAttr, $lDff, $lFileSearch, $lFileFound, $lDffHndl
    Dim $lFileList[1] = [0], $lFileArr[1] = [0], $lSettings[19]
    $lSettings[0] = 19
    $lSettings[1] = '.OPTION EXPLICIT'
    $lSettings[2] = '.Set InfDiskHeader="[disk list]"'
    $lSettings[3] = '.Set InfDiskHeader1=";<disk number>,<disk label>"'
    $lSettings[4] = '.Set InfDiskLineFormat="*disk#*,*label*"'
    $lSettings[5] = '.Set InfCabinetHeader="[cabinet list]"'
    $lSettings[6] = '.Set InfCabinetHeader1=";<cabinet number>,<disk number>,<cabinet file name>"'
    $lSettings[7] = '.Set InfCabinetLineFormat="*cab#*,*disk#*,*cabfile*"'
    $lSettings[8] = '.Set InfFileHeader=";*** File List ***"'
    $lSettings[9] = '.Set InfFileHeader1=";<disk number>,<cabinet number>,<filename>,<size>"'
    $lSettings[10] = '.Set InfFileHeader2=";Note: File is not in a cabinet if cab# is 0"'
    $lSettings[11] = '.Set InfFileHeader3=""'
    $lSettings[12] = '.Set InfFileLineFormat="*disk#*,*cab#*,*file*,*date*,*size*"'
    $lSettings[13] = '.Set GenerateInf=ON'
    $lSettings[14] = '.Set Compress=ON'
    $lSettings[15] = '.Set Cabinet=ON'
    $lSettings[16] = '.Set CompressionType=MSZIP'
    $lSettings[17] = '.Set DiskDirectoryTemplate=CDROM'
    $lSettings[18] = '.Set MaxDiskSize=CDROM'
    
; valid dff destination
    If $pDffDest <> -1 Then
        If Not IsString($pDffDest) Then
            SetError(1, 1, 0)
            Return
        EndIf
        If Not FileExists($pDffDest) Then DirCreate($pDffDest)
        If Not FileExists($pDffDest) Or Not StringInStr(FileGetAttrib($pDffDest), 'D') Then
            SetError(1, 2, 0)
            Return
        EndIf
    Else
        $pDffDest = @ScriptDir
    EndIf
    
; $pDffFile: valid filename and not exist
    If Not _IsValidFileName($pDffFile) Or FileExists($pDffDest & '\' & $pDffFile) Then
        SetError(1, 3, 0)
        Return
    EndIf
    
; check $pCabDirName
    If Not _IsValidFileName($pCabDirName) Then
        SetError(1, 4, 0)
        Return
    EndIf
; check $pCabName
    If Not _IsValidFileName($pCabName) Or FileExists($pDffDest & '\' & $pCabDirName & '\' & $pCabName) Then
        SetError(1, 5, 0)
        Return
    EndIf
    
; check type on parm $pFiles
    If Not (IsArray($pFiles) Or IsString($pFiles)) Then
        SetError(1, 6, 0)
        Return
    EndIf
    
; validate $pSettings
    If IsArray($pSettings) Then
        $lSettings = $pSettings
    ElseIf $pSettings <> -1 Then
        SetError(1, 7, 0)
        Return
    EndIf
    ReDim $lSettings[UBound($lSettings) + 1]
    $lSettings[UBound($lSettings) - 1] = '.Set DiskDirectory1=' & $pCabDirName
    ReDim $lSettings[UBound($lSettings) + 1]
    $lSettings[UBound($lSettings) - 1] = '.Set CabinetNameTemplate=' & $pCabName
    
; define $lFileList or set $pFiles array
    If IsString($pFiles) Then
    ; files exist
        If FileExists($pFiles) Then
        ; Just assign
            If Not StringInStr(FileGetAttrib($pFiles), 'D') Then
                ReDim $lFileList [UBound($lFileList) + 1]
                $lFileList[UBound($lFileList) - 1] = '"' & $pFiles & '"'
            ; build files in directory
            Else
                $lFileSearch = FileFindFirstFile($pFiles & '\' & $pExt)
                If $lFileSearch = -1 Then
                    SetError(2, 1, 0)
                    Return
                EndIf
                While 1
                    $lFileFound = FileFindNextFile($lFileSearch)
                    If @error Then ExitLoop
                    If FileExists($pFiles & '\' & $lFileFound) And Not StringInStr(FileGetAttrib($lFileFound), 'D') Then
                        ReDim $lFileArr[UBound($lFileArr) + 1]
                        $lFileArr[UBound($lFileArr) - 1] = $pFiles & '\' & $lFileFound
                    EndIf
                WEnd
                $lFileArr[0] = UBound($lFileArr) - 1
                FileClose($lFileSearch)
            ; reset for array procedure
                $pFiles = $lFileArr
                $pFileIndex = 1
            EndIf
        EndIf
    EndIf
; define $lFileList from $pFiles array
    If IsArray($pFiles) Then
    ; valid index on array
        If Not IsInt($pFileIndex) And $pFileIndex < 0 And $pFileIndex < UBound($pFiles) Then
            SetError(1, 8, 0)
            Return
        EndIf
    ; files exist
        For $i = $pFileIndex To UBound($pFiles) - 1 Step 1
            $lFileAttr = FileGetAttrib($pFiles[$i])
            If FileExists($pFiles[$i]) = 1 Then
                If Not StringInStr($lFileAttr, 'D') Then
                    ReDim $lFileList [UBound($lFileList) + 1]
                    $lFileList[UBound($lFileList) - 1] = '"' & $pFiles[$i] & '"';& @CRLF
                EndIf
            Else
                SetError(3, 1, 0)
                Return
            EndIf
        Next
        $lFileList[0] = UBound($lFileList) - 1
    EndIf
    
; build the text for the dff file
    $lDffHndl = FileOpen($pDffDest & '\' & $pDffFile, 2)
    For $i = 1 To UBound($lSettings) - 1 Step 1
        FileWriteLine($lDffHndl, $lSettings[$i])
    Next
    For $i = 1 To UBound($lFileList) - 1 Step 1
        FileWriteLine($lDffHndl, $lFileList[$i])
    Next
    FileClose($lDffHndl)
    Return 1
EndFunc  ;==>_MakeDff

;===================================================================================================


; Function Name:    _MakeCab()
; Description:      Create a cabinet file from a previously created (manually or with _MakeDff) dff file.
; Parameter(s):     $pDffFile       - Compulsory:   FileName of dff file
;                   $pDffPath       - Compulsory:   Path to $pDffFile
;                   $pCabDest       - Compulsory:   Path to cabinet directory
; Return Value(s):  On Success  - returns 1 and creates the cabinet file
;                  On Failure   - Returns 0 and sets @ERROR
;                   @ERROR          = 1 Invalid Parameters, see extended
;                                   @Extended   =   1 invalid $pDffFile or doesn't exist
;                                               =   2 invalid $pDffPath or doesn't exist
;                                               =   3 Cabinet dir couldn't be created
; Requirement(s):   AutoIt3 V3.2 or higher
; NOTE: Subdirectories are omitted from cabinet when $pFiles is a path to a directory
; Date:             9/9/2007
; Author:           Ivan Perez
;===================================================================================================


Func _MakeCab($pDffFile, $pDffPath, $pCabDest)
    Local $lCmd, $lWorkingDir, $lResult
; validate path to dff file
    If Not FileExists($pDffPath) Or Not StringInStr(FileGetAttrib($pDffPath), 'D') Then
        SetError(1, 1, 0)
        Return
    EndIf
; validate $pDffFile
    If Not (_IsValidFileName($pDffFile) Or FileExists($pDffPath & '\' & $pDffFile)) Then
        SetError(1, 2, 0)
        Return
    EndIf
; validate cabinet directory
    If Not FileExists($pCabDest) Then DirCreate($pCabDest)
    If Not FileExists($pCabDest) Or Not StringInStr(FileGetAttrib($pCabDest), 'D') Then
        SetError(1, 3, 0)
        Return
    EndIf
; create the command
    $lCmd = 'makecab  /F ' & '"' & $pDffPath & '\' & $pDffFile & '"'
; run the command
    $lResult = RunWait(@ComSpec & " /c " & $lCmd, $pCabDest, @SW_HIDE)
; delete the files created by makecab
    If FileExists($pCabDest &'\' &'setup.inf') Then FileDelete($pCabDest &'\' &'setup.inf')
    If FileExists($pCabDest &'\' &'setup.rpt') Then FileDelete($pCabDest &'\' &'setup.rpt')
    If $lResult = 0 Then Return 1
    Return 0
EndFunc  ;==>_MakeCab

;===================================================================================================


; Function Name:    _CabGetFiles()
; Description:      Generate a list of files in cabinet.
; Parameter(s):     $pCabFile       - Compulsory:   FileName of cabinet file
;                   $pDestDir       - Compulsory:   Path to $pCabFile
;                                       -1      =   (Default) Working directory
;                                       String  =   path to output directory, no trailing slash. If the directory
;                                                   doesn't already exist, the script will attempt to create it.
; Requirement(s):   AutoIt3 V3.2 or higher
; Return Value(s):  On Success  - returns 1 and creates the file
;                  On Failure   - Returns 0 and sets @ERROR
;                   @ERROR          = 1 Invalid Parameters, see extended
;                                   @Extended   =   1 when not using default $pDffDest and dff destination dir is not a string
;                                               =   2 when not using default $pDffDest and dff destination dir could not be created
;                                               =   3 dff file is invalid or already exists
; NOTE: Subdirectories are omitted from cabinet when $pFiles is a path to a directory
; TODO:             CHECK result (run exit code?)
; Date:             9/9/2007
; Author:           Ivan Perez
;===================================================================================================


Func _CabGetFiles($pCabFile, $pCabPath = -1)
    Local $lCmd, $lWorkingDir, $lResult, $lTmp, $lReadFileHndl, $lFile
    Dim $lFileArr[1] = [0]
    If $pCabPath <> -1 Then
        If Not IsString($pCabPath) Then
            SetError(1, 1, 0)
            Return
        EndIf
        If Not FileExists($pCabPath) Then DirCreate($pCabPath)
        If Not FileExists($pCabPath) Or Not StringInStr(FileGetAttrib($pCabPath), 'D') Then
            SetError(1, 2, 0)
            Return
        EndIf
    Else
        $pCabPath = @ScriptDir
    EndIf
; $pCabFile: valid filename and not exist
    If Not (_IsValidFileName($pCabFile) Or FileExists($pCabPath & '\' & $pCabFile)) Then
        SetError(1, 3, 0)
        Return
    EndIf
; create tmp file
    $lTmp = _TempFile($pCabPath)
    
    If IsNumber($pCabPath) And $pCabPath = 0 Then
        $lCmd = 'expand -D ' & '"' & $pCabFile & '"'
        $lWorkingDir = ''
    Else
        $lCmd = 'expand -D ' & '"' & $pCabPath & '\' & $pCabFile & '"'
        $lWorkingDir = $pCabPath
    EndIf
    $lCmd &= '>"'&$lTmp & '"'
; run the command to dump the file list to tmp file
    $lResult = RunWait(@ComSpec & " /c " & $lCmd, $lWorkingDir, @SW_HIDE)
    If $lResult = 0 And FileExists($lTmp) Then
    ; read file contents
        $lReadFileHndl = FileOpen($lTmp, 0)
        While 1
            $lLine = FileReadLine($lReadFileHndl)
            If @error = -1 Then ExitLoop; EOF
            $lFile = StringReplace($lLine, $pCabFile & ': ', '')
            If @extended > 0 Then
                ReDim $lFileArr[UBound($lFileArr) + 1]
                $lFileArr[UBound($lFileArr) - 1] = $lFile
            EndIf
        WEnd
        FileClose($lReadFileHndl)
        $lFileArr[0] = UBound($lFileArr) - 1
;~      If FileExists($lWorkingDir &'\' &$lTmp) Then FileDelete($lWorkingDir &'\' &$lTmp)
        FileDelete($lTmp)
        If FileExists($lTmp) Then MsgBox(0,'Tmp not deleted',$lTmp)
    Else
    ; file list could not be dumped
        SetError(2, 1, 0)
        Return
    EndIf
    Return $lFileArr
EndFunc  ;==>_CabGetFiles

; extract files to a directory
;~ Func _CabExtract($pCabFile, $pDest, $pCabPath = -1, $pMode = -1, $pFileList = -1, $pExt = '*.*')
Func _CabExtract($pCabFile, $pDest, $pCabPath = -1, $pMode = -1, $pExt = '*.*')
    Local $lCmd, $lCommand, $lWorkingDir, $lResult, $lTmp, $lReadFileHndl, $lFile
    Local $lFileList
    Dim $lFileArr[1] = [0], $lPaths[5]
    If $pCabPath <> -1 Then
        If Not IsString($pCabPath) Then
            SetError(1, 1, 0)
            Return
        EndIf
        If Not FileExists($pCabPath) Then DirCreate($pCabPath)
        If Not FileExists($pCabPath) Or Not StringInStr(FileGetAttrib($pCabPath), 'D') Then
            SetError(1, 2, 0)
            Return
        EndIf
    Else
        $pCabPath = @ScriptDir
    EndIf
; $pCabFile: valid filename and not exist
    If Not (_IsValidFileName($pCabFile) Or FileExists($pCabPath & '\' & $pCabFile)) Then
        SetError(1, 3, 0)
        Return
    EndIf
    
; $pCabFile: valid filename and not exist
    If Not FileExists($pDest) Then DirCreate($pDest)
    If Not FileExists($pDest) Or Not StringInStr(FileGetAttrib($pDest), 'D') Then
        SetError(1, 4, 0)
        Return
    EndIf
    
    If Not IsNumber($pMode) Or ($pMode < -1 And $pMode > 0) Then
        SetError(1, 5, 0)
        Return
    EndIf
    
    $lFileList = _CabGetFiles($pCabFile, $pCabPath)
    If @error Or Not IsArray($lFileList) Then
        SetError(1, 6, 0)
        Return
    EndIf
    If UBound($lFileList) - 1 = 1 Then; single file extraction
        $lPaths = _PathSplit($lFileList[1], $lPaths[0], $lPaths[1], $lPaths[2], $lPaths[3])
        $lCmd = 'expand ' & '"' & $pCabPath & '\' & $pCabFile & '" ' & '"' & $pDest & '\' & $lPaths[3] & $lPaths[4] & '"'
    ElseIf UBound($lFileList) - 1 > 1 Then; multiple file extraction
        Switch $pMode
        ; extract all
            Case - 1
                $lCmd = 'expand ' & '"' & $pCabPath & '\' & $pCabFile & '" -F:* ' & '"' & $pDest & '"'
            ; extract selected file types
            Case 0
                $lCmd = 'expand ' & '"' & $pCabPath & '\' & $pCabFile & '" -F:' & $pExt & ' ' & '"' & $pDest & '"'
        EndSwitch
    Else
        SetError(2, 1, 0)
        Return
    EndIf
    $lResult = RunWait(@ComSpec & " /c " & $lCmd, $lWorkingDir, @SW_HIDE)
    If $lResult <> 0 Then
        SetError(2, 1, 0)
        Return
    EndIf
    Return 1
EndFunc  ;==>_CabExtract

;;;;;;;;; support funcs
; won't accept filenames containing chr(0) or chr(127)
Func _IsValidFileName($pFileName)
    If StringRegExp($pFileName, '(["*/<>?\\|]|[[:cntrl:]])', 0) Then Return 0; ascii 0-31
    Return 1
EndFunc  ;==>_IsValidFileName
 
Автор
Astel064

Astel064

Помог мой пост, ставь +!
Сообщения
276
Репутация
51
AZJIO [?]
Код: [Выделить]makecab.exe file.dllКод: [Выделить]makecab.exe -?pause
damien2008 [?]
говорят, что нужен .NET FrameWork 2.0.а если попробовать взять 2 консольных утилиты cabarc.exe и extract.exe?

Про эти утилиты знаю, но не хотелось-бы, чтобы они в процессах висели во время упаковки или извлечения... К тому-же, cabarc.exe и extract.exe у меня отсутствуют. Ранее я пользовался утилитами makecab.exe и expand.exe.

В общем, пытаюсь найти рабочие для AutoIt варианты работы с ObjCreate('makecab.makecab.1'), сейчас на стадии: объект есть, а архив создавать не хочет... Если выполнить аналогичный код на VBScript, то все безупречно создает и даже файлы пакует, но это опять - лишние процессы.


Уважаемые гуру, никто из Вас не сталкивался с этим? ???


Добавлено:
Сообщение автоматически объединено:

Люди, проверьте кто-нибудь у себя этот скрипт:
Код:
$oCab = ObjCreate('makecab.makecab.1')
	If @error Or Not IsObj($oCab) Then 
	MsgBox(48,"Error","ObjCreate(1)")
	Exit
	EndIF

$oCreate = $oCab.CreateCab(@ScriptDir&"\Out.cab", False, False, False)
	If @error Or Not IsObj($oCreate) Then 
	MsgBox(48,"Error","CreateCab(1,2,3,4)")
	Exit
	EndIF

$oAdd =  $oCreate.AddFile(@ScriptFullPath, @ScriptName)
	If @error Or Not IsObj($oAdd) Then 
	MsgBox(48,"Error","AddFile(1,2)")
	Exit
	EndIF

$oCab.CloseCab()
MsgBox(64,"OK","OK")
Exit


Если эта ошибка только у меня, то Вы увидите сообщение OK и в папке скрипта появится архив Out.cab
Пожалуйста, отпишитесь в этой теме, кто проверит, у меня уже крыша едет от этой ошибки "CreateCab" на AutoIt и успехе на Vbs... :stars:
 

erlik

Продвинутый
Сообщения
317
Репутация
84
Astel064
У меня и твой скрипт (ошибка ObjCreate(1)) и вариант на vbs - оба выдают ошибку о невозможности создать объект. Система win7 32-бит.
--------------------------------------------------------
Если выполнить аналогичный код на VBScript, то все безупречно создает и даже файлы пакует
Похоже ты на XP сидишь - так как скрипт на vbs у меня только на XP пошел, а autoit-вариант выдал ошибку на стадии применения метода CreateCab.
 
Автор
Astel064

Astel064

Помог мой пост, ставь +!
Сообщения
276
Репутация
51
erlik [?]
У меня и твой скрипт (ошибка ObjCreate(1)) и вариант на vbs - оба выдают ошибку о невозможности создать объект. Система win7 32-бит.

Понятно, буду значит искать информацию про SetupAPI.dll
Спасибо за помощь :ok:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
А почему именно CAB? Есть ведь много других архиваторов.
 
Автор
Astel064

Astel064

Помог мой пост, ставь +!
Сообщения
276
Репутация
51
Yashied [?]
А почему именно CAB? Есть ведь много других архиваторов.

Потому-что CAB архив можно создать и извлечь средствами Windows, вывод: неплохое сжатие и не нужно таскать с собой, например, 7Zip.dll.
Изначально я пытался с Zip-ом разобраться, но всегда получается, что какое-нибудь окно от объекта Shell.Application да вываливается. Вот поэтому :smile:

И да, кстати, никто не знает про библиотеку "AdvPack.DLL": В каких версиях Windows она есть, а в каких может отсутствовать?
 
Автор
Astel064

Astel064

Помог мой пост, ставь +!
Сообщения
276
Репутация
51
Собственно то, от чего так долго бежал и решил прибегнуть из-за безысходности: CabArchive UDF - Работа с Microsoft CAB файлами

Если кто-нибудь найдет решения работы с CAB файлами с помощью родных для Windows DLL, пожалуйста, сообщите мне, можно в этой теме...
 
Верх