Создание CAB-архива

Dragokas

Angry & Scary Developer
Команда форума
Супер-Модератор
Разработчик
Клуб переводчиков
Сообщения
7,814
Реакции
6,593
Создание CAB-архива через командную строку
(в т.ч. самораспаковующихся EXE), а также распаковка CAB.

Автор: Alex Averchenkoff
CMD/BATCH:
@echo **************************************************
@echo ((((((((((((((((((((((((((((((((((((((((((((((((((
@echo Name: CabMaker.exe
@echo Description: A program for creating cab archives
@echo Version: v. 1.0.0.0
@echo Copyright: @[USER=8310]Alex[/USER] Averchenkoff
@echo Create: 2011
@echo ))))))))))))))))))))))))))))))))))))))))))))))))))
@echo **************************************************

@echo off

set SaveName=""

rem ******************************************************
rem СТАРТОВЫЙ БЛОК - ВЫБИРАЕМ ДЕЙСТВИЕ:ПРОСМОТР\РАСПАКОВКА\СОЗДАНИЕ АРХИВА
rem ******************************************************
:start
echo.
set /p action=VIEW-1^|EXPAND-2^|CREATE-3:
if /i "%action%"=="1" (goto view)
if /i "%action%"=="2" (goto extract)
if /i "%action%"=="3" (goto create)
exit

rem ******************************************************
rem ПРОСМОТР CAB АРХИВА
rem ******************************************************
:view
set /p name=ENTER NAME ARCHIVE:
if "%SaveName%"=="" ( set SaveName=%name%)
if "%name%"=="" ( set name=%SaveName%)
if not "%name%"=="" (expand -D %name%.cab) else ( goto view)

if errorlevel 0 (goto action)
if errorlevel 1 (@echo An error occurred, try again)

rem ******************************************************
rem РАСПАКОВКА CAB АРХИВА - ФАЙЛЫ РАСПАКОВЫВАЮТСЯ В ДИРЕКТОРИЮ ОДНОИМЕННУЮ С ИМЕНЕМ АРХИВА
rem ******************************************************
:extract
set /p name=ENTER NAME ARCHIVE:
if "%SaveName%"=="" ( set SaveName=%name%)
if "%name%"=="" ( set name=%SaveName%)
if not "%name%"=="" (md "%~dp0%name%" && expand %name%.cab /F:* .\%name%) else ( goto extract)


if errorlevel 0 (@echo Archive successfully unzipped! & goto action)
if errorlevel 1 (@echo An error occurred, try again)

:action
echo You want to continue or exit the program?
set /p action=TO CONTINUE OR EXIT? [Y\N]:
if /i "%action%"=="Y" (goto start) else exit

rem ******************************************************
rem СОЗДАНИЕ НОВОГО CAB АРХИВА - СОЗДАЕТСЯ В ПАПКЕ РАСПОЛОЖЕНИЯ БАТНИКА
rem ******************************************************
:create
set /p name=ENTER NAME FOR ARCHIVE:
if "%SaveName%"=="" ( set SaveName=%name%)
if "%name%"=="" ( set name=%SaveName%)
if "%name%"=="" ( goto create)

rem ******************************************************
rem БУДЕМ ЛИ СОЗДАВАТЬ РАСПАКОВЫВАЮЩИЙСЯ АРХИВ
rem ******************************************************
set /p sfx=CREATE SFX?[Y\N]:

if /i "%sfx%"=="Y" (@echo Initiated the creation of self-extracting archive)
echo.
rem ******************************************************
rem СОЗДАЕМ СПИСОК ФАЙЛОВ И ФАЙЛ ОТВЕТОВ ДЛЯ MAKECAB
rem ******************************************************
@echo .Set CabinetNameTemplate=%name%.cab>make.ddf
@echo .Set CompressionType=MSZIP>>make.ddf
@echo .Set MaxDiskSize=CDROM>>make.ddf
@echo .Set ReservePerCabinetSize=6144>>make.ddf
@echo .Set Compress=on>>make.ddf
@echo .Set CompressionMemory=21>>make.ddf
@echo .Set DiskDirectoryTemplate=".">>make.ddf
@echo .Set Cabinet=ON>>make.ddf
@echo .Set MaxCabinetSize=999999999>>make.ddf
@echo .Set CompressionLevel=^7>>make.ddf

rem ******************************************************
rem СОЗДАЕМ ОБЫЧНЫЙ АРХИВ
rem ******************************************************
chcp 1251>nul
FOR /R %%f IN (*.*) DO (
If not "%%~nxf"=="make.ddf" (
@If not "%%~nxf"=="CabMaker.bat" (@echo "%%f">>make.ddf))
)
makecab /F make.ddf
if /i "%sfx%"=="Y" (goto create_sfx) else ( goto clear)

:clear
del setup.inf
del setup.rpt
del make.ddf
chcp 866 > nul
echo.
echo Creating a backup is successfully completed!
goto action


rem ******************************************************
rem МАГИЕЙ ПРЕВРАЩАЕМ ОБЫЧНЫЙ АРХИВ В САМРАСПАКОВЫВАЮЩИЙСЯ :-)
rem ******************************************************
:create_sfx
copy /b %windir%\system32\extrac32.exe+%name%.cab %name%.exe
del setup.inf
del setup.rpt
del make.ddf
del %name%.cab
chcp 866 > nul
echo.
echo Create self-extracting archive completed successfully!
goto action
Также перевод на VB6 от меня, созданный на основе кода от Alex Averchenkoff с правками от Dark_Timur.
VB.NET / VBA:
Option Explicit

' Alex Averchenkoff принадлежит оригинальный код BAT программы MakeCab.
' Dragokas перевел программу на язык Visual Basic 6.
' Dark_Timur исправил и дополнил программу.
' И затем Dragokas еще раз подправил :)
' Версия: 1.1.1

Function CreateCab(Source As String, SourceType As String, ArchName As String, Destination As String, Compress As Boolean, _
    CompressLvl As Byte, SubFolders As Boolean, Ext As String, SFX As Boolean, Silent As Boolean) As Long

    Dim AddData As String, DDF As String

    If LCase(SourceType) = "d" Or LCase(SourceType) = "dir" Or LCase(SourceType) = "directory" Then
        AddData = GetData(Source, True, LCase(Ext), Silent)
    ElseIf LCase(SourceType) = "f" Or LCase(SourceType) = "file" Then
        AddData = """" & Source & """" & vbCrLf
    Else
        If Not Silent Then MsgBox "Неправильно задан тип исходных данных", vbCritical
        CreateCab = 272
        Exit Function
    End If

    If (Err <> 0) Then Exit Function
    DDF = GetTempFile() 'DDF будет во временной папке Windows
    CreateDDF DDF, ArchName, AddData, Destination, IIf(Compress, "ON", "OFF"), CompressLvl

    With CreateObject("WScript.Shell")

        CreateCab = .Run("makecab.exe /F """ & DDF & """", 0, True)
        If (CreateCab <> 0) Then
            If Not Silent Then MsgBox "Ошибка создания архива (" & CreateCab & ")", vbCritical
            Dim ExecObj As Object
            If Not Silent Then
                Set ExecObj = CreateObject("WScript.Shell").Exec("cmd /c makecab.exe /F """ & DDF & """")
                MsgBox "Ошибка создания архива (" & CreateCab & ")" & vbCrLf & ExecObj.StdOut.ReadAll(), vbCritical
                Set ExecObj = Nothing
            End If
            Exit Function
        End If

        If SFX Then 'Превращаем обычный архив в SFX
            .Run "cmd /x /c ""copy /b """ & Environ("windir") & "\system32\extrac32.exe""+""" & _
                Destination & "\" & ArchName & ".cab"" """ & Destination & "\" & ArchName & ".exe""""", 0, True
            Kill Destination & "\" & ArchName & ".cab"
        End If
    End With
 
    Call Clear(DDF)
    If Not Silent Then MsgBox "Готово.", vbInformation
End Function

Function GetData(fold As String, SubFolders As Boolean, Ext As String, Silent As Boolean) As String
    On Error Resume Next 'Пропуск папок/файлов, защищенных правами
    Dim myfiles As Object, mydirs As Object
    Dim fil As Object, dir As Object

    With CreateObject("Scripting.FileSystemObject").GetFolder(fold)
        Set myfiles = .Files
        Set mydirs = .SubFolders
    End With

    For Each fil In myfiles
        If Trim(Ext) = "*" Or Trim(Ext) = "*.*" Or Trim(Ext) = "" Or (LCase(Right(fil.Name, Len(Ext)))) = Ext Then
            GetData = GetData & """" & fil.Path & """" & vbCrLf
        End If
    Next

    If SubFolders Then
        For Each dir In mydirs
            GetData = GetData & ".Set DestinationDir=" & Chr(34) & dir.Name & Chr(34) & vbCrLf & _
            GetData(dir.Path, True, Ext, Silent) & vbCrLf
        Next
    End If

    GetData = Left(GetData, Len(GetData) - 2) 'CrLf
    Set myfiles = Nothing: Set mydirs = Nothing
End Function

Function GetTempFile() 'Получить временный незанятый файл
    Dim FSO As Object, FN As String
 
    Set FSO = CreateObject("Scripting.FileSystemObject")
 
    FN = FSO.GetTempName()
    FN = Environ("temp") & "\" & FN
 
    If dir(FN) <> vbNullString Then FN = GetTempFile()

    GetTempFile = FN
    Set FSO = Nothing
End Function

Function CreateDDF(DDF$, ArchName, GetData$, Out, SetCom As String, SetComLvl As Byte)
    Dim ff As Integer
    ff = FreeFile()

    'Подготовим DDF-файл ответов для архиватора CAB
    Open DDF For Output As #ff
 
        Print #ff, ".Set CabinetNameTemplate=" & ArchName & ".cab"
        Print #ff, ".Set CompressionType=MSZIP"
        Print #ff, ".Set MaxDiskSize=CDROM"
        Print #ff, ".Set ReservePerCabinetSize=6144"
        Print #ff, ".Set Compress=" & SetCom
        Print #ff, ".Set CompressionMemory=21"
        Print #ff, ".Set DiskDirectoryTemplate=""."""
        Print #ff, ".Set Cabinet=ON"
        Print #ff, ".Set UniqueFiles=ON"
        If LCase(SetCom) = "on" Then Print #ff, ".Set CompressionLevel=" & CStr(SetComLvl)
        Print #ff, ".Set DiskDirectory1=" & Out
        Print #ff, GetData
 
    Close #ff

End Function

Sub Clear(DDF$)
On Error Resume Next
    Kill Environ("temp") & "\setup.inf"
    Kill Environ("temp") & "\setup.rpt"
    Kill DDF
End Sub
Source - путь до исходного файла/папки.

SourceType - тип исходных данных. Значения: "d", "dir", "directory" означают, что исходными данными является папка, а Значения: "f", "file" означают, что исходными данными является файл. Регистр значения SourceType не важен. Остальные значения завершают функцию с ошибкой 272.

ArchName - имя будущего архива без расширения. Расширение выбирается компьютером, так что смысла его вводить в ArchName нет.

Destination - путь до папки, где будет создан архив.

Compress - флаг, устанавливающий, использовать сжатие (True) или не использовать (False).

CompressLvl - если используется сжатие, то устанавливает уровень сжатия. Диопазон: 1...7 включительно. При отключенном сжатии важности не представляет.

SubFolders - если архивируется папка и там есть подпапки, то этот флаг устанавливает, архивировать подпапки (True) или не архивировать (False). При архивировании файла важности не представляет.

Ext - если архивируется папка, то устанавливает разрешенное расширение файлов для архивирования. Файлы с неправильным расширением архивированы не будут. Если вы хотите, чтоб архивировались все файлы, то оставьте переменную пустой ("") или введите звездочку ("*" или "*.*"). Также действует и на подпапки, если они архивируются. При архивировании файла важности не представляет.

SFX - устанавливает тип архива. Обычный архив с расширением CAB будет создан, если SFX = False. Иначе, если SFX = True, будет создан SFX (самораспаковывающийся) архив с расширением EXE.

Silent - включает или отключает тихий режим. Если Silent = False, то на экран будут выводиться сообщения. Иначе, если Silent = True, на экран ничего выводиться не будет.
 

Вложения

  • CabMaker.zip
    1.4 KB · Просмотры: 15
Последнее редактирование:
Код:
rem СОЗДАЕМ ОБЫЧНЫЙ АРХИВ
rem ******************************************************
chcp 1251>nul
FOR /R %%f IN (*.*) DO (
If not "%%~nxf"=="make.ddf" (
@If not "%%~nxf"=="CabMaker.bat" (@echo "%%f">>make.ddf))
)
makecab /F make.ddf
А что и где он создаст ? Даже для демо не понятно.
 
Все претензии к автору.
Вечером постараюсь объяснить принцип работы. Если нужно - модифицировать скрипт.
 
Разобрался. Вот так работает (/v 1..3 - verbosity level) :cigar:
Код:
chcp 1251>nul
FOR /R %%f IN (*.*) DO  (
    If not "%%~nxf"=="make.ddf" (
       @If not "%%~nxf"=="CabMaker.bat" (@echo "%%f">>make.ddf))
    )
makecab /F make.ddf /V2
chcp 866
Не удается найти C:\Users\..\setup.inf
Не удается найти C:\Users\..\setup.rpt
 
С помощью CAB-архиватора можно вытягивать информацию о версии файла и CRC32.

Получение сведений о версии файла и CRC32 нативными средствами [через makecab]

Способ найден на просторах Интернета.
Мною упрощен и превращен в функцию.
Демо:

CMD/BATCH:
@echo off
SetLocal EnableExtensions
:: Полный путь к файлу
set file=h:\_CMD рус\FileVersion\Units_Compile_helper.exe

call :GetFileInfo "%file%" "*ver*" FileVer
echo Версия файла: %FileVer%

call :GetFileInfo "%file%" "*vers*" ProductVer
echo Версия продукта: %ProductVer%

call :GetFileInfo "%file%" "*csum*" CheckSum
echo CRC32: %CheckSum%

call :GetFileInfo "%file%" "*lang*" Language
echo Язык: %Language%

pause
exit /B

:GetFileInfo [_in_ FullFileName] [_in_ Type of Information] [_out_ Variable, that receive a bufer]
  pushd "%~dp1" & echo "%~nx1"> "%TEMP%\file.path"
  (echo .set DoNotCopyFiles=on&echo .Set Cabinet=off&echo .Set Compress=off&echo .Set InfFileLineFormat="%~2") > "%TEMP%\cab.inf"
  makecab /d InfFileName="%TEMP%\file.inf" /d "DiskDirectory1=%TEMP%" /f "%TEMP%\cab.inf" /f "%TEMP%\file.path" /v0 >NUL
  for /f "usebackq skip=4 delims=" %%f in ("%TEMP%\file.inf") do set "%~3=%%f"
  (del /f "%TEMP%\file.inf" & del /f "%TEMP%\file.path" & del /f "%TEMP%\cab.inf") 2>NUL & popd
exit /B
 
Phoenix, на каком файле проверял? У меня все показывает. А в свойствах этого файла данная инфа имеется?
 
Назад
Сверху Снизу