Что нового

Данные, строки Ошибочное чтение данных из структуры

musicstashall

Знающий
Сообщения
310
Репутация
5
Доброго.
Необходимо было получить данные об иконке в файле, для чего я написал такой скрипт, согласно документации. В скрипте переменная $sByte — это считанные данные из файла, в которых содержится информация о количестве изображений в иконке (count), размеры изображений (width, height), количество битов на пиксель (bpp), размер изображения в байтах (size) и индекс изображения (index). $tagICONS_HEADER — это заголовок данных, в котором узнаем количество иконок. $tagICONS_INFO — каталог информации об изображении, представляет собой последовательные записи фиксированного размера 14 байт (в документации почему-то указано 16 байт), следующие одна за другой. Количество записей определяется полем count заголовка.

Первая строка ($sByte) содержит информацию о десяти изображениях с индексами от 1 до 10. Вторая короткая строка бинарных данных ($sByte) содержит информацию об одной иконке, ее индекс (index) равен 11.

Вроде бы не сложно, но возникает баг при чтении — каждая нечетная запись содержит ошибку в последних двух числах (size и index), что вы можете наблюдать в итоговом массиве. Прошу помощи.

Код:
#include <WinAPIGdi.au3>
#include <APIResConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <StaticConstants.au3>
#include <WinAPIIcons.au3>
#include <WinAPIRes.au3>
#include <Array.au3>

Local $tagICONS_HEADER = 'word;word type;word count'
Local $tagICONS_INFO = 'byte width;byte height;byte colors;byte;word planes;word bpp;dword size;word index'

Local $sByte = '0x0000'&'0100'&'0A00'& _
               '00'&'00'&'00'&'00'&'0100'&'2000'&'28200400'&'0100'& _
               '80'&'80'&'00'&'00'&'0100'&'2000'&'28080100'&'0200'& _
               '60'&'60'&'00'&'00'&'0100'&'2000'&'A8940000'&'0300'& _
               '50'&'50'&'00'&'00'&'0100'&'2000'&'E8670000'&'0400'& _
               '48'&'48'&'00'&'00'&'0100'&'2000'&'88540000'&'0500'& _
               '40'&'40'&'00'&'00'&'0100'&'2000'&'28420000'&'0600'& _
               '30'&'30'&'00'&'00'&'0100'&'2000'&'A8250000'&'0700'& _
               '20'&'20'&'00'&'00'&'0100'&'2000'&'A8100000'&'0800'& _
               '18'&'18'&'00'&'00'&'0100'&'2000'&'88090000'&'0900'& _
               '10'&'10'&'00'&'00'&'0100'&'2000'&'68040000'&'0A00'
Local $sByte = '0x0000'&'0100'&'0100'& _
               '10'&'10'&'00'&'00'&'0100'&'2000'&'68040000'&'0B00'

Local $tModify = DllStructCreate("byte[" & BinaryLen($sByte) & "]")
DllStructSetData($tModify, 1, $sByte)
Local $pData = DllStructGetPtr($tModify, 1)

_ArrayDisplay(_Icon_GetCountSize($pData))

Func _Icon_GetCountSize($pData)
    Local $tIcon, $tData = DllStructCreate($tagICONS_HEADER, $pData)
    Local $aData[1][5] = [[$tData.count]]
    For $i = 0 To $tData.count -1
        $tIcon = DllStructCreate('byte[' & 6 + 14 * $i & '];' & $tagICONS_INFO, $pData)
        _ArrayAdd($aData, $tIcon.width & '|' & $tIcon.height & '|' & $tIcon.bpp & '|' & $tIcon.size & '|' & $tIcon.index)
    Next
    Return $aData
EndFunc


Снимок экрана 2022-03-01 200001.png
 
Последнее редактирование:

Prog

Продвинутый
Сообщения
454
Репутация
55
В структуре поле index должно быть типа dword, а не word.
 
Автор
M

musicstashall

Знающий
Сообщения
310
Репутация
5
должно быть типа dword
Во-первых, это ничего не меняет, а во-вторых, посчитайте сами, например, в короткой бинарной строке, может ли там быть dword.

Вот, раскладываю длинную строку по записям:

Код:
0000 0100 0A00 — заголовок
00 00 00 00 0100 2000 28200400 0100 — первая запись
80 80 00 00 0100 2000 28080100 0200 — вторая запись
60 60 00 00 0100 2000 A8940000 0300 — третья запись
50 50 00 00 0100 2000 E8670000 0400 — четвертая запись
48 48 00 00 0100 2000 88540000 0500 — пятая
40 40 00 00 0100 2000 28420000 0600 — шестая
30 30 00 00 0100 2000 A8250000 0700 — седьмая
20 20 00 00 0100 2000 A8100000 0800 — восьмая
18 18 00 00 0100 2000 88090000 0900 — девятая
10 10 00 00 0100 2000 68040000 0A00 — десятая

Как видим, не 16, а 14 байт в каждой записи
Попробовал отрезать заголовок и извлечь данные — без заголовка всё извлекается корректно. Волшебство)
 
Последнее редактирование:
Сообщения
142
Репутация
-3
Что показывает
Код:
_ArrayDisplay($pData)

до заброса в функцию?
Сообщение автоматически объединено:

Local $tagICONS_HEADER = 'word;word type;word count'
Local $tIcon, $tData = DllStructCreate($tagICONS_HEADER, $pData)
Эм... Если это работает, то можно и #pData в функцию не передавать.
 
Последнее редактирование:
Автор
M

musicstashall

Знающий
Сообщения
310
Репутация
5
Получилось только таким образом. Я как понял, тут какие-то нюансы с памятью.

Код:
#include <WinAPIGdi.au3>
#include <APIResConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <StaticConstants.au3>
#include <WinAPIIcons.au3>
#include <WinAPIRes.au3>
#include <Array.au3>
#include <Binary.au3>

Local $tagICONS_HEADER = 'STRUCT;word;word type;word count;ENDSTRUCT'
Local $tagICONS_INFO = 'byte width;byte height;byte colors;byte;word planes;word bpp;dword size;word index'

Local $sByte = '0x0000'&'0100'&'0A00'& _
               '00'&'00'&'00'&'00'&'0100'&'2000'&'28200400'&'0100'& _
               '80'&'80'&'00'&'00'&'0100'&'2000'&'28080100'&'0200'& _
               '60'&'60'&'00'&'00'&'0100'&'2000'&'A8940000'&'0300'& _
               '50'&'50'&'00'&'00'&'0100'&'2000'&'E8670000'&'0400'& _
               '48'&'48'&'00'&'00'&'0100'&'2000'&'88540000'&'0500'& _
               '40'&'40'&'00'&'00'&'0100'&'2000'&'28420000'&'0600'& _
               '30'&'30'&'00'&'00'&'0100'&'2000'&'A8250000'&'0700'& _
               '20'&'20'&'00'&'00'&'0100'&'2000'&'A8100000'&'0800'& _
               '18'&'18'&'00'&'00'&'0100'&'2000'&'88090000'&'0900'& _
               '10'&'10'&'00'&'00'&'0100'&'2000'&'68040000'&'0A00'
;Local $sByte = '0x0000'&'0100'&'0100'& _
;               '10'&'10'&'00'&'00'&'0100'&'2000'&'68040000'&'0B00'


Local $pData = __BinaryCodeBufferAlloc($sByte)
_ArrayDisplay(_Icon_GetCountSize($pData))

Func _Icon_GetCountSize($pData)
    Local $tIcon, $tData = DllStructCreate($tagICONS_HEADER, $pData)
    Local $aData[1][5] = [[$tData.count]]
    Local $iSize = 14 * $tData.count
    Local $sBinary = _BinaryRight(_BinaryFromMemory($pData, 6 + $iSize), $iSize)
    For $i = 0 To $tData.count -1
        $pData = __BinaryCodeBufferAlloc(_BinaryRight($sBinary, $iSize - 14 * $i))
        $tIcon = DllStructCreate($tagICONS_INFO, $pData)
        _ArrayAdd($aData, $tIcon.width & '|' & $tIcon.height & '|' & $tIcon.bpp & '|' & $tIcon.size & '|' & $tIcon.index)
    Next
    Return $aData
EndFunc

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

можно и #pData в функцию не передавать.
У меня pData читается из файла с ресурсами, поэтому только так.
 

Вложения

  • Binary.au3
    26.1 КБ · Просмотры: 3

Prog

Продвинутый
Сообщения
454
Репутация
55
Почему проверяете на строке данных, а не на реальном значке? Может допустили ошибку в строке?
У меня на значке все работает и поле index типа dword.
 

Вложения

  • Icon.zip
    3.7 КБ · Просмотры: 1
  • img.png
    img.png
    54.2 КБ · Просмотры: 5
Автор
M

musicstashall

Знающий
Сообщения
310
Репутация
5
Может допустили ошибку в строке?
ну вот, извлеченные бинарники, проверьте. Большой и маленький (ICO.zip)
Сообщение автоматически объединено:

Почему проверяете на строке данных, а не на реальном значке?
Извлекаю иконку со всеми изображениями

Код:
Func _Icon_SaveToFile($hInstance, $aData, $sFileTarget)
    Local $iSize, $hResource
    Local $aIcons[$aData[0][0]]
    For $i = 1 To $aData[0][0]
        $hResource = _WinAPI_FindResource($hInstance, $RT_ICON, Int($aData[$i][4]))
        $aIcons[$i -1] = _WinAPI_CreateIconFromResourceEx(_WinAPI_LockResource(_WinAPI_LoadResource($hInstance, $hResource)), Int($aData[$i][3]))
    Next
    Local $Ret = _WinAPI_SaveHICONToFile($sFileTarget, $aIcons)
    For $i = 0 To UBound($aIcons) - 1
        _WinAPI_DestroyIcon($aIcons[$i])
    Next
    Return $Ret
EndFunc
 

Вложения

  • ICO.zip
    424 байт · Просмотры: 1
Последнее редактирование:
Автор
M

musicstashall

Знающий
Сообщения
310
Репутация
5
Возьми, загрузи данные из любого файла, содержазщего пождобные ресусы
 

Prog

Продвинутый
Сообщения
454
Репутация
55
Я загружал файлы значков. Верно считывает информацию.
В вики пишут про значки, а не ресурсы. Или причина проще. В какой-то из функций есть ошибка из-за которой неправильно извлекаются данные.
 
Верх