- Сообщения
- 5,379
- Репутация
- 2,724
AutoIt: 3.3.6.1+
Версия: 1.0
Категория: Файловая система, Процессы
Описание: Я думаю, что многие из вас хотели бы объединить некоторые данные или файлы ваших проектов, например изображения скина, в один файл (архив), и при необходимости извлекать их оттуда. Кроме того, было бы лучше избежать создания временных файлов на диске. Да, конечно, вы можете использовать ресурсы исполняемого файла или функцию FileInstall(), но в первом случае, вы не сможете добавлять данные после компиляции скрипта, а второй неизбежно приводит к записи данных на диск, что не есть хорошо . Да, еще вы можете применить, например, ZIP архивы, но и здесь вы будите ограничены использованием только файлов. По этой причине я решил придумать свой собственный архив (PKR) для хранения любых данных (это могут быть как файлы, так и непосредственно данные из памяти) и лишенный всех вышеперечисленных недостатков.
Как вы можете увидеть ниже, прочитав спецификацию файлов, PKR архивы имеют простую структуру, состоящую из последовательных блоков данных. А специально для удобства использования таких архивов, я написал UDF библиотеку, которую вы можете скачать ниже. Подробное описание каждой функции (на английском) можно найти внутри библиотеки. Кроме того, ZIP архив включает в себя все примеры и вспомогательные файлы. В качестве дополнительного примера, вы можете скачать Package.pkr файл, который содержит те же самые файлы, что и ZIP архив, но только созданный с помощью этой библиотеки.
Спецификация:
Как видно на скриншоте, PKR архив состоит из заголовка и одного или нескольких пакетов данных, следующих друг за другом. Заголовок архива имеет длину 256 байт и представляет PKHEADER структуру, которая содержит основные сведения о самом архиве, в том числе и краткий текстовый комментарий.
--------------------------------------------------------------------------------------------------
| PKHEADER |
|--------------------------------------------------------------------------------------------------|
| Offset | Length | Purpose |
|--------|--------|--------------------------------------------------------------------------------|
| 0 | 4 | The file signature (0x504B5221) |
|--------|--------|--------------------------------------------------------------------------------|
| 4 | 4 | The package version, 1.0 |
|--------|--------|--------------------------------------------------------------------------------|
| 8 | 8 | The file size, in bytes |
|--------|--------|--------------------------------------------------------------------------------|
| 16 | 4 | The number of packets in the package |
|--------|--------|--------------------------------------------------------------------------------|
| 20 | 4 | Reserved |
|--------|--------|--------------------------------------------------------------------------------|
| 24 | 8 | The absolute offset, in bytes, of the first packet in package |
|--------|--------|--------------------------------------------------------------------------------|
| 32 | 224 | The package comment, max 224 bytes (112 characters) |
--------------------------------------------------------------------------------------------------
Первые четыре байта .pkr файла всегда содержат одну и ту же последовательность байт (сигнатуру) - 0x504B5221 ("PKR!" в ASCII символах). Это позволяет однозначно идентифицировать PKR архив. Затем следует DWORD значение, представляющее версию архива, в настоящее время 1.0 (0x00000100). Далее идет размер файла (INT64) в байтах. Несмотря на то, что размер архива не ограничивается, длина одного пакета в нем не может превышать немногим более 4 ГБ (см. ниже). Важно заметить, что значение этого параметра должно быть равно фактическому размеру файла, в противном случае считается, что архив поврежден. Следующий член структуры (DWORD) содержит количество пакетов в архиве. Оно не должно быть равно нулю, так как создание пустых архивов (не содержащих ни одного пакета) не допускается. Следующие четыре байта зарезервированы и должны быть равны нулю. Шестой член PKHEADER структуры (INT64) является наиболее важным и содержит смещение первого пакета в архиве от начала файла в байтах. Это означает, что первый пакет не обязательно следует сразу же после заголовка. Последним в заголовке архива идет текстовый комментарий. Длина комментария ограничена 224 байтами (112 Unicode символами, включая нулевой символ завершения).
После заголовка архива может располагаться Packet Relocation Table (PRT) произвольного размера, которая содержит информацию для быстрого поиска пакетов в архиве, но в настоящее время не используется и имеет нулевую длину.
Далее в .pkr файле, после PKHEADER и PRT, идут пакеты данных. Каждый пакет имеет свой собственный заголовок и три раздела с данными: Description, Info и Data. Почему три? Потому что так гораздо легче классифицировать данные в пакете. Вы поймете это, когда попробуете использовать библиотеку в своих скриптах. Подробное описание пакета (PKPACKET структура) представлено в следующей таблице.
--------------------------------------------------------------------------------------------------
| PKPACKET |
|--------------------------------------------------------------------------------------------------|
| Offset | Length | Purpose |
|--------|--------|--------------------------------------------------------------------------------|
| 0 | 4 | The size, in bytes, of the packet header structure (40 bytes) |
|--------|--------|--------------------------------------------------------------------------------|
| 4 | 4 | The size, in bytes, of the description block, max 8192 bytes (4096 characters) |
|--------|--------|--------------------------------------------------------------------------------|
| 8 | 4 | The size, in bytes, of the information block, max 64 KB |
|--------|--------|--------------------------------------------------------------------------------|
| 12 | 4 | The size, in bytes, of the data block, max 4 GB |
|--------|--------|--------------------------------------------------------------------------------|
| 16 | 8 | The 64-bit unique identifier of the packet |
|--------|--------|--------------------------------------------------------------------------------|
| 24 | 4 | The checksum (CRC32) of the compressed data, or zero if no compression |
|--------|--------|--------------------------------------------------------------------------------|
| 28 | 4 | The uncompressed data size, in bytes, or zero if no compression |
|--------|--------|--------------------------------------------------------------------------------|
| 32 | 8 | Reserved |
|--------------------------------------------------------------------------------------------------|
| Description |
|--------------------------------------------------------------------------------------------------|
| Information |
|--------------------------------------------------------------------------------------------------|
| Data |
--------------------------------------------------------------------------------------------------
Первый член PKPACKET структуры (DWORD) всегда содержит длину заголовка пакета в байтах и в настоящее время составляет 40 байт, но может быть изменен в будущем. Второй, третий и четвертый члены структуры (DWORD) содержат длины соответствующих разделов данных в байтах. Если какой-либо раздел в пакете отсутствует, то значение его длины равно нулю. Полная длина пакета в байтах вычисляется путем суммирования перечисленных выше четырех значений. Пятый член PKPACKET структуры (INT64), это уникальный идентификатор пакета (ID) и представляет собой 64-разрядное положительное число, которое однозначно идентифицирует пакет в архиве. Шестой и седьмой члены структуры (DWORD) используются только, если данные Data раздела сжаты, в противном случае содержат нулевые значения. В случае сжатия, шестой член структуры содержит точный размер Data раздела в байтах после распаковки. Последний параметр в заголовке пакета (INT64) зарезервирован и должен быть равен нулю. Сразу же после заголовка пакета следуют три раздела с данными, которые более подробно описаны ниже.
Раздел Description идет первым в пакет и предназначен для хранения любой текстовой информации. Это может быть, например, имя файла, в случае добавления файлов, или просто краткое описание данных, которые находятся в пакете. Максимальная длина этого раздела - 8 КБ (8192 байт) или 4096 Unicode символов (включая нулевой символ завершения).
Раздел Info следует сразу же за разделом Description. Здесь вы можете хранить любые вспомогательные двоичные данные, например атрибуты файла, даты создания, изменения и последнего доступа к файлу, или любую другую информацию. Кроме того, вы можете хранить в этом разделе, небольшие файлы, например файлы курсоров (.cur), иконок (.ico) и т.д. Максимальная длина Info раздела составляет 64 КБ (65,535 байт).
Раздел Data является последним (третьим) разделом в пакете и используется для хранения основных данных. Максимальная длина этого раздела может быть до 4 ГБ (4,294,967,295 байт). Кроме того, данные Data раздела могут быть сжаты с использованием LZ алгоритма (не самый оптимальный, но достаточно быстрый).
Эти три раздела данных представляет собой один пакет и должны следовать непрерывно друг за другом, как показано выше. Кроме того, любой (или все одновременно) из этих разделов могут отсутствовать в пакете.
Далее, после первого пакета, сразу же следует другой пакет, если таковой присутствует в архиве, и т.д.
Список функций:
Примеры:
Файл(ы): Package.zip (также необходима установленная WinAPIEx UDF библиотека версии 3.7 или выше)
Скриншот:
Источник: Package UDF (оффициальный форум)
Автор: Yashied
Версия: 1.0
Категория: Файловая система, Процессы
Описание: Я думаю, что многие из вас хотели бы объединить некоторые данные или файлы ваших проектов, например изображения скина, в один файл (архив), и при необходимости извлекать их оттуда. Кроме того, было бы лучше избежать создания временных файлов на диске. Да, конечно, вы можете использовать ресурсы исполняемого файла или функцию FileInstall(), но в первом случае, вы не сможете добавлять данные после компиляции скрипта, а второй неизбежно приводит к записи данных на диск, что не есть хорошо . Да, еще вы можете применить, например, ZIP архивы, но и здесь вы будите ограничены использованием только файлов. По этой причине я решил придумать свой собственный архив (PKR) для хранения любых данных (это могут быть как файлы, так и непосредственно данные из памяти) и лишенный всех вышеперечисленных недостатков.
Как вы можете увидеть ниже, прочитав спецификацию файлов, PKR архивы имеют простую структуру, состоящую из последовательных блоков данных. А специально для удобства использования таких архивов, я написал UDF библиотеку, которую вы можете скачать ниже. Подробное описание каждой функции (на английском) можно найти внутри библиотеки. Кроме того, ZIP архив включает в себя все примеры и вспомогательные файлы. В качестве дополнительного примера, вы можете скачать Package.pkr файл, который содержит те же самые файлы, что и ZIP архив, но только созданный с помощью этой библиотеки.
Спецификация:
Как видно на скриншоте, PKR архив состоит из заголовка и одного или нескольких пакетов данных, следующих друг за другом. Заголовок архива имеет длину 256 байт и представляет PKHEADER структуру, которая содержит основные сведения о самом архиве, в том числе и краткий текстовый комментарий.
--------------------------------------------------------------------------------------------------
| PKHEADER |
|--------------------------------------------------------------------------------------------------|
| Offset | Length | Purpose |
|--------|--------|--------------------------------------------------------------------------------|
| 0 | 4 | The file signature (0x504B5221) |
|--------|--------|--------------------------------------------------------------------------------|
| 4 | 4 | The package version, 1.0 |
|--------|--------|--------------------------------------------------------------------------------|
| 8 | 8 | The file size, in bytes |
|--------|--------|--------------------------------------------------------------------------------|
| 16 | 4 | The number of packets in the package |
|--------|--------|--------------------------------------------------------------------------------|
| 20 | 4 | Reserved |
|--------|--------|--------------------------------------------------------------------------------|
| 24 | 8 | The absolute offset, in bytes, of the first packet in package |
|--------|--------|--------------------------------------------------------------------------------|
| 32 | 224 | The package comment, max 224 bytes (112 characters) |
--------------------------------------------------------------------------------------------------
Первые четыре байта .pkr файла всегда содержат одну и ту же последовательность байт (сигнатуру) - 0x504B5221 ("PKR!" в ASCII символах). Это позволяет однозначно идентифицировать PKR архив. Затем следует DWORD значение, представляющее версию архива, в настоящее время 1.0 (0x00000100). Далее идет размер файла (INT64) в байтах. Несмотря на то, что размер архива не ограничивается, длина одного пакета в нем не может превышать немногим более 4 ГБ (см. ниже). Важно заметить, что значение этого параметра должно быть равно фактическому размеру файла, в противном случае считается, что архив поврежден. Следующий член структуры (DWORD) содержит количество пакетов в архиве. Оно не должно быть равно нулю, так как создание пустых архивов (не содержащих ни одного пакета) не допускается. Следующие четыре байта зарезервированы и должны быть равны нулю. Шестой член PKHEADER структуры (INT64) является наиболее важным и содержит смещение первого пакета в архиве от начала файла в байтах. Это означает, что первый пакет не обязательно следует сразу же после заголовка. Последним в заголовке архива идет текстовый комментарий. Длина комментария ограничена 224 байтами (112 Unicode символами, включая нулевой символ завершения).
После заголовка архива может располагаться Packet Relocation Table (PRT) произвольного размера, которая содержит информацию для быстрого поиска пакетов в архиве, но в настоящее время не используется и имеет нулевую длину.
Далее в .pkr файле, после PKHEADER и PRT, идут пакеты данных. Каждый пакет имеет свой собственный заголовок и три раздела с данными: Description, Info и Data. Почему три? Потому что так гораздо легче классифицировать данные в пакете. Вы поймете это, когда попробуете использовать библиотеку в своих скриптах. Подробное описание пакета (PKPACKET структура) представлено в следующей таблице.
--------------------------------------------------------------------------------------------------
| PKPACKET |
|--------------------------------------------------------------------------------------------------|
| Offset | Length | Purpose |
|--------|--------|--------------------------------------------------------------------------------|
| 0 | 4 | The size, in bytes, of the packet header structure (40 bytes) |
|--------|--------|--------------------------------------------------------------------------------|
| 4 | 4 | The size, in bytes, of the description block, max 8192 bytes (4096 characters) |
|--------|--------|--------------------------------------------------------------------------------|
| 8 | 4 | The size, in bytes, of the information block, max 64 KB |
|--------|--------|--------------------------------------------------------------------------------|
| 12 | 4 | The size, in bytes, of the data block, max 4 GB |
|--------|--------|--------------------------------------------------------------------------------|
| 16 | 8 | The 64-bit unique identifier of the packet |
|--------|--------|--------------------------------------------------------------------------------|
| 24 | 4 | The checksum (CRC32) of the compressed data, or zero if no compression |
|--------|--------|--------------------------------------------------------------------------------|
| 28 | 4 | The uncompressed data size, in bytes, or zero if no compression |
|--------|--------|--------------------------------------------------------------------------------|
| 32 | 8 | Reserved |
|--------------------------------------------------------------------------------------------------|
| Description |
|--------------------------------------------------------------------------------------------------|
| Information |
|--------------------------------------------------------------------------------------------------|
| Data |
--------------------------------------------------------------------------------------------------
Первый член PKPACKET структуры (DWORD) всегда содержит длину заголовка пакета в байтах и в настоящее время составляет 40 байт, но может быть изменен в будущем. Второй, третий и четвертый члены структуры (DWORD) содержат длины соответствующих разделов данных в байтах. Если какой-либо раздел в пакете отсутствует, то значение его длины равно нулю. Полная длина пакета в байтах вычисляется путем суммирования перечисленных выше четырех значений. Пятый член PKPACKET структуры (INT64), это уникальный идентификатор пакета (ID) и представляет собой 64-разрядное положительное число, которое однозначно идентифицирует пакет в архиве. Шестой и седьмой члены структуры (DWORD) используются только, если данные Data раздела сжаты, в противном случае содержат нулевые значения. В случае сжатия, шестой член структуры содержит точный размер Data раздела в байтах после распаковки. Последний параметр в заголовке пакета (INT64) зарезервирован и должен быть равен нулю. Сразу же после заголовка пакета следуют три раздела с данными, которые более подробно описаны ниже.
Раздел Description идет первым в пакет и предназначен для хранения любой текстовой информации. Это может быть, например, имя файла, в случае добавления файлов, или просто краткое описание данных, которые находятся в пакете. Максимальная длина этого раздела - 8 КБ (8192 байт) или 4096 Unicode символов (включая нулевой символ завершения).
Раздел Info следует сразу же за разделом Description. Здесь вы можете хранить любые вспомогательные двоичные данные, например атрибуты файла, даты создания, изменения и последнего доступа к файлу, или любую другую информацию. Кроме того, вы можете хранить в этом разделе, небольшие файлы, например файлы курсоров (.cur), иконок (.ico) и т.д. Максимальная длина Info раздела составляет 64 КБ (65,535 байт).
Раздел Data является последним (третьим) разделом в пакете и используется для хранения основных данных. Максимальная длина этого раздела может быть до 4 ГБ (4,294,967,295 байт). Кроме того, данные Data раздела могут быть сжаты с использованием LZ алгоритма (не самый оптимальный, но достаточно быстрый).
Эти три раздела данных представляет собой один пакет и должны следовать непрерывно друг за другом, как показано выше. Кроме того, любой (или все одновременно) из этих разделов могут отсутствовать в пакете.
Далее, после первого пакета, сразу же следует другой пакет, если таковой присутствует в архиве, и т.д.
Список функций:
_PK_AddPacket
_PK_AddPacketFromFile
_PK_Close
_PK_Create
_PK_DisplayPackage
_PK_EnumPackets
_PK_ExtractPacketData
_PK_ExtractPacketDataToFile
_PK_FindPacket
_PK_Flush
_PK_GetComment
_PK_GetCount
_PK_GetInfo
_PK_GetPacketCompression
_PK_GetPacketDataLength
_PK_GetPacketDescription
_PK_GetPacketDescriptionLength
_PK_GetPacketID
_PK_GetPacketIndex
_PK_GetPacketInfo
_PK_GetPacketInfoLength
_PK_GetPath
_PK_GetVersion
_PK_Open
_PK_Purge
_PK_QueryPacket
_PK_QueryPacketEx
_PK_ReadPacketData
_PK_RemovePacket
_PK_SetBuffer
_PK_SetComment
_PK_Test
_PK_AddPacketFromFile
_PK_Close
_PK_Create
_PK_DisplayPackage
_PK_EnumPackets
_PK_ExtractPacketData
_PK_ExtractPacketDataToFile
_PK_FindPacket
_PK_Flush
_PK_GetComment
_PK_GetCount
_PK_GetInfo
_PK_GetPacketCompression
_PK_GetPacketDataLength
_PK_GetPacketDescription
_PK_GetPacketDescriptionLength
_PK_GetPacketID
_PK_GetPacketIndex
_PK_GetPacketInfo
_PK_GetPacketInfoLength
_PK_GetPath
_PK_GetVersion
_PK_Open
_PK_Purge
_PK_QueryPacket
_PK_QueryPacketEx
_PK_ReadPacketData
_PK_RemovePacket
_PK_SetBuffer
_PK_SetComment
_PK_Test
Примеры:
Добавление файла (простой)
Извлечение файла (простой)
Добавление двоичных данных (простой)
Извлечение двоичных данных (простой)
Добавление файлов
Извлечение файлов
GUI (расширенный)
Код:
#Include "Package.au3"
Global Const $sPackage = @ScriptDir & '\MyFile.pkr'
$hPackage = _PK_Create($sPackage, 'Demonstration Package', 1)
_PK_AddPacketFromFile($hPackage, @ScriptFullPath, @ScriptName, 1)
_PK_DisplayPackage($hPackage)
_PK_Close($hPackage)
Извлечение файла (простой)
Код:
#Include "Package.au3"
Global Const $sPackage = @ScriptDir & '\MyFile.pkr'
$hPackage = _PK_Open($sPackage)
_PK_ExtractPacketDataToFile($hPackage, -1, StringRegExpReplace(_PK_GetPacketDescription($hPackage, -1), '\.[^.]*\Z', '.bak'), 1)
_PK_Close($hPackage)
Добавление двоичных данных (простой)
Код:
#Include "Package.au3"
Global Const $sPackage = @ScriptDir & '\MyData.pkr'
$hPackage = _PK_Create($sPackage, 'Demonstration Package', 1)
$tData = DllStructCreate('byte[16]')
DllStructSetData($tData, 1, '0x00112233445566778899AABBCCDDEEFF')
_PK_AddPacket($hPackage, DllStructGetPtr($tData), DllStructGetSize($tData), 'Binary data', 1)
_PK_DisplayPackage($hPackage)
_PK_Close($hPackage)
Извлечение двоичных данных (простой)
Код:
#Include "Package.au3"
Global Const $sPackage = @ScriptDir & '\MyData.pkr'
$hPackage = _PK_Open($sPackage)
$tData = DllStructCreate('byte[' & _PK_GetPacketDataLength($hPackage, -1) & ']')
_PK_ExtractPacketData($hPackage, -1, DllStructGetPtr($tData), DllStructGetSize($tData))
ConsoleWrite(DllStructGetData($tData, 1) & @CR)
_PK_Close($hPackage)
Добавление файлов
Код:
#Include <WinAPIEx.au3>
#Include "Package.au3"
Opt('MustDeclareVars', 1)
Global Const $sPackage = @ScriptDir & '\MyPackage.pkr'
Global $hPackage, $ID, $File
If Not FileExists($sPackage) Then
$hPackage = _PK_Create($sPackage, 'Demonstration Package')
Else
$hPackage = _PK_Open($sPackage)
EndIf
Do
$File = FileOpenDialog('Add File', @WorkingDir, 'All Files (*.*)', 3)
If @Error Then
ExitLoop
EndIf
$ID = _PK_AddPacketFromFile($hPackage, $File, _WinAPI_PathStripPath($File))
If @Error Then
$ID = MsgBox(20, 'Package', 'An error occurred while adding file to the package.' & @CR & @CR & 'Error: ' & @Error & @CR & @CR & 'Do you want to add another file?')
Else
$ID = MsgBox(68, 'Package', 'File added successfully.' & @CR & @CR & 'ID: ' & $ID & @CR & @CR & 'Do you want to add another file?')
EndIf
Until $ID <> 6
_PK_DisplayPackage($hPackage)
_PK_Close($hPackage)
Извлечение файлов
Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>
#Include "Package.au3"
Opt('MustDeclareVars', 1)
Global Const $sPackage = @ScriptDir & '\MyPackage.pkr'
Global $hPackage, $ID, $Data, $File, $Path
$hPackage = _PK_Open($sPackage)
If @Error Then
MsgBox(16, 'Package', _WinAPI_PathStripPath($sPackage) & ' not found.')
Exit
EndIf
$Data = _PK_EnumPackets($hPackage)
If @Error Then
MsgBox(16, 'Package', 'Unable to enumerate packets in the package.' & @CR & @CR & 'Error: ' & @Error)
Else
For $i = 1 To $Data[0][0]
ConsoleWrite($i & ' - ' & $Data[$i][1] & @CR)
Next
While 1
$ID = InputBox('Package', 'Type a one based index of the packet to extract.', '1', '', 274, 142)
If @Error Then
ExitLoop
EndIf
$File = _PK_GetPacketDescription($hPackage, -$ID)
If @Error Then
MsgBox(16, 'Package', 'Packet not found.')
Else
$Path = _WinAPI_PathYetAnotherMakeUniqueName(@ScriptDir & '\' & $File)
If Not _PK_ExtractPacketDataToFile($hPackage, -$ID, $Path) Then
$ID = MsgBox(20, 'Package', 'An error occurred while extracting file from the package.' & @CR & @CR & 'Error: ' & @Error & @CR & @CR & 'Do you want to extract another file?')
Else
$ID = MsgBox(68, 'Package', 'File has been saved to ' & _WinAPI_PathStripPath($Path) & '.' & @CR & @CR & 'Do you want to extract another file?')
EndIf
If $ID <> 6 Then
ExitLoop
EndIf
EndIf
WEnd
EndIf
_PK_Close($hPackage)
GUI (расширенный)
Код:
#NoTrayIcon
#Include <APIConstants.au3>
#Include <GUIListView.au3>
#Include <GUIConstantsEx.au3>
#Include <ListViewConstants.au3>
#Include <StaticConstants.au3>
#Include <WinAPIEx.au3>
#Include "Package.au3"
Opt('MustDeclareVars', 1)
Opt('WinWaitDelay', 0)
#Region Initialization
Global $hForm, $hDrop, $hPackage, $hLV, $LV, $Button[3], $Dummy[2], $Label, $Area, $Item
#EndRegion Initialization
#Region Body
_CreateForm()
While 1
Switch GUIGetMsg()
Case 0
ContinueLoop
Case $GUI_EVENT_CLOSE
ExitLoop
Case $GUI_EVENT_DROPPED
_AddPacket(@GUI_DRAGFILE)
Case $Button[0]
_AddPacket()
Case $Button[1], $Dummy[1]
_RemovePacket()
Case $Button[2], $Dummy[0]
_ExtractPacket()
Case Else
EndSwitch
WEnd
_DeleteForm()
#EndRegion Body
#Region Additional Functions
Func _AddPacket($sFile = '')
Local $tInfo, $ID, $Data, $Flag, $Error
If Not $sFile Then
$sFile = FileOpenDialog('Add File', @WorkingDir, 'All Files (*.*)', 3, '', $hDrop)
If @Error Then
Return
EndIf
EndIf
If FileGetSize($sFile) > 104857600 Then
If MsgBox(52, 'Package', _WinAPI_PathStripPath($sFile) & ' is too large (over 100 MB) and can not be compressed on the fly.' & @CR & @CR & 'Do you want to add this file without compression?', 0, $hDrop) <> 6 Then
Return
EndIf
$Flag = 0
Else
$Flag = 1
EndIf
Opt('GUIOnEventMode', 1)
GUISetState(@SW_DISABLE, $hForm)
GUISetCursor(15, 1, $hForm)
$tInfo = _GetFileInfo($sFile)
$ID = _PK_AddPacketFromFile($hPackage, $sFile, _WinAPI_PathStripPath($sFile), $Flag, DllStructGetPtr($tInfo), DllStructGetSize($tInfo), '_Progress')
$Error = @Error
GUISetCursor(2, 0, $hForm)
GUISetState(@SW_ENABLE, $hForm)
Opt('GUIOnEventMode', 0)
If $Error Then
MsgBox(16, 'Package', 'An error occurred while adding file to the package.' & @CR & @CR & 'Error: ' & $Error, 0, $hDrop)
Return
EndIf
$Data = _PK_QueryPacket($hPackage, $ID)
If @Error Then
Return
EndIf
_GUICtrlListView_BeginUpdate($hLV)
$ID = _GUICtrlListView_AddItem($hLV, $Data[0])
For $i = 1 To 4
_GUICtrlListView_AddSubItem($hLV, $ID, $Data[$i], $i)
Next
_GUICtrlListView_SetItemParam($hLV, $ID, $Data[5])
_GUICtrlListView_SetItemSelected($hLV, $ID, 1, 1)
_GUICtrlListView_EnsureVisible($hLV, $ID)
_GUICtrlListView_EndUpdate($hLV)
GUICtrlSetState($LV, $GUI_FOCUS)
WinActivate($hDrop)
EndFunc ;==>_AddPacket
Func _CreateForm()
Local $ID, $Path, $File, $Data
$Path = FileOpenDialog('Open Package', @ScriptDir, 'Package Files (*.pkr)|All Files (*.*)', 10, 'MyPackage.pkr')
If @Error Then
Exit
EndIf
$File = _WinAPI_PathStripPath($Path)
If Not FileExists($Path) Then
$hPackage = _PK_Create($Path, 'Demonstration Package')
Else
$hPackage = _PK_Open($Path)
EndIf
If @Error Then
MsgBox(16, 'Package', 'Unable to open ' & $File & '.' & @CR & @CR & 'Error: ' & @Error)
Exit
EndIf
OnAutoItExitRegister('_Quit')
If _PK_GetCount($hPackage) Then
$Data = _PK_EnumPackets($hPackage)
If @Error Then
MsgBox(16, 'Package', 'Unexpected error.' & @CR & @CR & 'Error: ' & @Error)
Exit
EndIf
Else
$Data = 0
EndIf
$hForm = GUICreate($File & ' - ' & _PK_GetComment($hPackage), 660, 440, -1, -1, BitOR($WS_CAPTION, $WS_MINIMIZEBOX, $WS_MAXIMIZEBOX, $WS_POPUP, $WS_SIZEBOX, $WS_SYSMENU))
$hDrop = GUICreate('', 660, 398, 0, 0, BitOR($WS_CHILD, $WS_TABSTOP, $WS_VISIBLE), $WS_EX_ACCEPTFILES, $hForm)
$LV = GUICtrlCreateListView('', 0, 0, 660, 398, BitOR($LVS_DEFAULT, $LVS_NOSORTHEADER), BitOR($LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT, $LVS_EX_INFOTIP))
GUICtrlSetFont(-1, 8.5, 400, 0, 'Tahoma')
GUICtrlSetState(-1, $GUI_DROPACCEPTED)
$hLV = GUICtrlGetHandle(-1)
_GUICtrlListView_AddColumn($hLV, '#', 30)
_GUICtrlListView_AddColumn($hLV, 'ID', 140)
_GUICtrlListView_AddColumn($hLV, 'Description', 313)
_GUICtrlListView_AddColumn($hLV, 'Info Length', 80, 1)
_GUICtrlListView_AddColumn($hLV, 'Data Length', 80, 1)
If _WinAPI_GetVersion() >= '6.0' Then
_WinAPI_SetWindowTheme($hLV, 'Explorer')
EndIf
If IsArray($Data) Then
For $i = 1 To $Data[0][0]
$ID = _GUICtrlListView_AddItem($hLV, $i)
For $j = 0 To 3
_GUICtrlListView_AddSubItem($hLV, $ID, $Data[$i][$j], $j + 1)
Next
_GUICtrlListView_SetItemParam($hLV, $ID, $Data[$i][4])
Next
_GUICtrlListView_SetItemSelected($hLV, 0, 1, 1)
$Item = 0
Else
$Item =-1
EndIf
GUISwitch($hForm)
GUISetIcon(@ScriptDir & '\Package.ico')
$Label = GUICtrlCreateLabel('', 0, 398, 663, 2, $SS_ETCHEDHORZ)
$Button[0] = GUICtrlCreateButton('Add...', 5, 405, 214, 30)
$Button[1] = GUICtrlCreateButton('Remove', 223, 405, 214, 30)
$Button[2] = GUICtrlCreateButton('Extract...', 441, 405, 214, 30)
For $i = 0 To 1
$Dummy[$i] = GUICtrlCreateDummy()
Next
$Area = WinGetPos($hForm)
GUIRegisterMsg($WM_GETMINMAXINFO, 'WM_GETMINMAXINFO')
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUIRegisterMsg($WM_SIZE, 'WM_SIZE')
GUICtrlSetState($LV, $GUI_FOCUS)
GUISetState()
EndFunc ;==>_CreateForm
Func _DeleteForm()
GUIDelete($hForm)
GUIDelete($hDrop)
EndFunc ;==>_DeleteForm
Func _ExtractPacket()
Local $tInfo, $File, $Error
$File = FileSaveDialog('Extract File', @WorkingDir, 'All Files (*.*)', 18, _PK_GetPacketDescription($hPackage, -($Item + 1)), $hDrop)
If @Error Then
Return
EndIf
Opt('GUIOnEventMode', 1)
GUISetState(@SW_DISABLE, $hForm)
GUISetCursor(15, 1, $hForm)
_PK_ExtractPacketDataToFile($hPackage, -($Item + 1), $File, 1, '_Progress')
$Error = @Error
If $Error Then
Else
$tInfo = _PK_GetPacketInfo($hPackage, -($Item + 1))
If Not _SetFileInfo($File, $tInfo) Then
; Nothing
EndIf
EndIf
GUISetCursor(2, 0, $hForm)
GUISetState(@SW_ENABLE, $hForm)
Opt('GUIOnEventMode', 0)
If $Error Then
MsgBox(16, 'Package', 'An error occurred while adding file to the package.' & @CR & @CR & 'Error: ' & $Error, 0, $hDrop)
EndIf
EndFunc ;==>_ExtractPacket
Func _GetFileInfo($sFile)
Local $hFile, $tInfo
$hFile = _WinAPI_CreateFileEx($sFile, $OPEN_EXISTING, $GENERIC_READ, BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE))
If @Error Then
Return 0
EndIf
$tInfo = _WinAPI_GetFileInformationByHandleEx($hFile)
_WinAPI_CloseHandle($hFile)
Return $tInfo
EndFunc ;==>_GetFileInfo
Func _Quit()
_PK_Close($hPackage)
EndFunc ;==>_Quit
Func _RemovePacket()
Local $Count, $Error, $Sel = $Item
If MsgBox(36, 'Package', 'Are you sure you want to remove ' & _PK_GetPacketDescription($hPackage, -($Item + 1)) & ' from the package?', 0, $hDrop) <> 6 Then
Return
EndIf
Opt('GUIOnEventMode', 1)
GUISetState(@SW_DISABLE, $hForm)
GUISetCursor(15, 1, $hForm)
_PK_RemovePacket($hPackage, -($Item + 1))
$Error = @Error
GUISetCursor(2, 0, $hForm)
GUISetState(@SW_ENABLE, $hForm)
Opt('GUIOnEventMode', 0)
If $Error Then
MsgBox(16, 'Package', 'An error occurred while remove file from the package.' & @CR & @CR & 'Error: ' & $Error, 0, $hDrop)
Return
EndIf
_GUICtrlListView_BeginUpdate($hLV)
_GUICtrlListView_DeleteItem($hLV, $Item)
$Count = _GUICtrlListView_GetItemCount($hLV)
If $Count Then
If $Sel > $Count - 1 Then
$Sel -= 1
Else
For $i = $Sel To $Count - 1
_GUICtrlListView_SetItemText($hLV, $i, $i + 1)
Next
EndIf
_GUICtrlListView_SetItemSelected($hLV, $Sel, 1, 1)
EndIf
_GUICtrlListView_EndUpdate($hLV)
GUICtrlSetState($LV, $GUI_FOCUS)
WinActivate($hDrop)
EndFunc ;==>_RemovePacket
Func _SetFileInfo($sFile, $tInfo)
Local $hFile
If DllStructGetSize($tInfo) < 40 Then
Return 0
EndIf
$hFile = _WinAPI_CreateFileEx($sFile, $OPEN_EXISTING, $GENERIC_WRITE, BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE))
If @Error Then
Return 0
EndIf
_WinAPI_SetFileInformationByHandleEx($hFile, $tInfo)
_WinAPI_CloseHandle($hFile)
Return 1
EndFunc ;==>_SetFileInfo
#EndRegion Additional Functions
#Region Callback Functions
Func _Progress($hPackage, $ID, $iTotalSize, $iTotalBytesTransferred, $vData)
#forceref $hPackage, $ID, $vData
Static $hDlg = Ptr(0), $Progress
Local $Pos, $Percent
If $iTotalSize <> $iTotalBytesTransferred Then
$Percent = Round($iTotalBytesTransferred / $iTotalSize * 100)
Else
$Percent = 100
EndIf
If Not $hDlg Then
If $Percent < 100 Then
$Pos = WinGetPos($hDrop)
$hDlg = GUICreate('', 300, 44, $Pos[0] + ($Pos[2] - 300) / 2, $Pos[1] + ($Pos[3] - 44) / 2, BitOR($WS_BORDER, $WS_DISABLED, $WS_POPUP), 0, $hForm)
$Progress = GUICtrlCreateProgress(15, 15, 270, 14)
GUICtrlSetData(-1, $Percent)
GUISetCursor(15, 1)
GUISetState()
EndIf
Else
GUICtrlSetData($Progress, $Percent)
If $Percent = 100 Then
GUISetState(@SW_ENABLE, $hForm)
GUIDelete($hDlg)
$hDlg = 0
EndIf
EndIf
Return $PK_PROGRESS_CONTINUE
EndFunc ;==>_Progress
#EndRegion Callback Functions
#Region Windows Message Functions
Func WM_GETMINMAXINFO($hWnd, $iMsg, $wParam, $lParam)
Local $tMMI = DllStructCreate('long Reserved[2];long MaxSize[2];long MaxPosition[2];long MinTrackSize[2];long MaxTrackSize[2]', $lParam)
Switch $hWnd
Case $hForm
If IsArray($Area) Then
DllStructSetData($tMMI, 'MinTrackSize', $Area[2], 1)
DllStructSetData($tMMI, 'MinTrackSize', $Area[3], 2)
EndIf
Return 0
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_GETMINMAXINFO
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
Static $Flag = False
If @AutoItX64 Then
Local $tNMLV = DllStructCreate($tagNMHDR & ';uint Aligment;int Item;int SubItem;uint NewState;uint OldState;uint Changed;long ActionX;long ActionY;lparam Param', $lParam)
Else
Local $tNMLV = DllStructCreate($tagNMHDR & ';int Item;int SubItem;uint NewState;uint OldState;uint Changed;long ActionX;long ActionY;lparam Param', $lParam)
EndIf
Local $hTarget = DllStructGetData($tNMLV, 'hWndFrom')
Local $ID = DllStructGetData($tNMLV, 'Code')
Switch $hTarget
Case $hLV
Switch $ID
Case $LVN_BEGINDRAG
Return 0
Case $LVN_ITEMACTIVATE
If $Item <> -1 Then
GUICtrlSendToDummy($Dummy[0])
EndIf
Case $LVN_ITEMCHANGED
If (BitAND(DllStructGetData($tNMLV, 'Changed'), $LVIF_STATE)) And (BitXOR(DllStructGetData($tNMLV, 'NewState'), DllStructGetData($tNMLV, 'OldState'))) Then
If BitAND(DllStructGetData($tNMLV, 'NewState'), $LVIS_SELECTED) Then
$Item = DllStructGetData($tNMLV, 'Item')
For $i = 1 To 2
GUICtrlSetState($Button[$i], $GUI_ENABLE)
Next
$Flag = 0
Else
If BitAND(DllStructGetData($tNMLV, 'OldState'), $LVIS_FOCUSED) Then
$Flag = 1
Else
If Not $Flag Then
For $i = 1 To 2
GUICtrlSetState($Button[$i], $GUI_DISABLE)
Next
$Item = -1
EndIf
$Flag = 0
EndIf
EndIf
EndIf
Case $NM_CUSTOMDRAW
If @AutoItX64 Then
Local $tNMLVCD = DllStructCreate($tagNMHDR & ';uint Aligment1;dword DrawStage;hwnd hDC;long Left;long Top;long Right;long Bottom;dword_ptr ItemSpec;uint ItemState;lparam ItemParam;uint Aligment2[5];dword clrText;dword clrTextBk;int SubItem;dword ItemType;dword clrFace;int IconEffect;int IconPhase;int PartId;int StateId;long TextLeft;long TextTop;long TextRight;long TextBottom;uint Align', $lParam)
Else
Local $tNMLVCD = DllStructCreate($tagNMHDR & ';dword DrawStage;hwnd hDC;long Left;long Top;long Right;long Bottom;dword_ptr ItemSpec;uint ItemState;lparam ItemParam;dword clrText;dword clrTextBk;int SubItem;dword ItemType;dword clrFace;int IconEffect;int IconPhase;int PartId;int StateId;long TextLeft;long TextTop;long TextRight;long TextBottom;uint Align', $lParam)
EndIf
Local $Stage = DllStructGetData($tNMLVCD, 'DrawStage')
Switch $Stage
Case $CDDS_ITEMPREPAINT
Return $CDRF_NOTIFYSUBITEMDRAW
Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
If _GUICtrlListView_GetItemParam($hLV, DllStructGetData($tNMLVCD, 'ItemSpec')) Then
DllStructSetData($tNMLVCD, 'clrText', 0xFF0000)
EndIf
Return $CDRF_DODEFAULT
Case Else
EndSwitch
Case $LVN_KEYDOWN
If @AutoItX64 Then
Local $tNMLVKD = DllStructCreate($tagNMHDR & ';uint Aligment;ushort VKey;uint Flags', $lParam)
Else
Local $tNMLVKD = DllStructCreate($tagNMHDR & ';ushort VKey;uint Flags', $lParam)
EndIf
Local $Key = DllStructGetData($tNMLVKD, 'VKey')
Switch BitAND($Key, 0xFF)
Case 0x2E ; VK_DELETE
If $Item <> -1 Then
GUICtrlSendToDummy($Dummy[1])
EndIf
Case Else
EndSwitch
Case $NM_CLICK, $NM_DBLCLK, $NM_RCLICK, $NM_RDBLCLK
Return 0
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam)
Local $WC, $HC, $WT
Switch $hWnd
Case $hForm
$WC = _WinAPI_LoWord($lParam)
$HC = _WinAPI_HiWord($lParam)
$WT = Floor(($WC - 18) / 3)
WinMove($hDrop, '', 0, 0, $WC, $HC - 42)
GUICtrlSetPos($LV, 0, 0, $WC, $HC - 42)
GUICtrlSetPos($Label, 0, $HC - 42, $WC + 3)
GUICtrlSetPos($Button[0], 5, $HC - 35, $WT)
GUICtrlSetPos($Button[1], $WT + 9, $HC - 35, $WC - 2 * $WT - 18)
GUICtrlSetPos($Button[2], $WC - $WT - 5, $HC - 35, $WT)
Return 0
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_SIZE
#EndRegion Windows Message Functions
Файл(ы): Package.zip (также необходима установленная WinAPIEx UDF библиотека версии 3.7 или выше)
Скриншот:
Источник: Package UDF (оффициальный форум)
Автор: Yashied