Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769

Функция RtlDecompressBuffer иногда обманывает и возвращает ложный успех

29.03.2023, 15:29. Показов 587. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Я написал для себя модуль для упаковки и распаковки данных, байтовых массивов. Всё бы хорошо, но очень редко, но иногда так бывает, что функция RtlDecompressBuffer возвращает ложный успех и беда в том, что заранее нельзя знать какой буфер потребуется при распаковке данных.

Вот мой модуль:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Private Declare Function RtlGetCompressionWorkSpaceSize Lib "ntdll" (ByVal CompressionFormatAndEngine As Integer, ByRef CompressBufferWorkSpaceSize As Long, ByRef CompressFragmentWorkSpaceSize As Long) As Long
Private Declare Function RtlCompressBuffer Lib "ntdll" (ByVal CompressionFormatAndEngine As Integer, ByRef UncompressedBuffer As Any, ByVal UncompressedBufferSize As Long, ByRef CompressedBuffer As Any, ByVal CompressedBufferSize As Long, ByVal UncompressedChunkSize As Long, ByRef FinalCompressedSize As Long, ByRef WorkSpace As Any) As Long
Private Declare Function RtlDecompressBuffer Lib "ntdll" (ByVal CompressionFormat As Integer, ByRef ptrDestBuffer As Any, ByVal DestBufferSize As Long, ByRef ptrSrceBuffer As Any, ByVal SceBufferSize As Long, ByRef pDestinationSize As Long) As Long
Private Declare Function RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal Length As Long) As Long
 
Private Const STATUS_SUCCESS As Long = 0
Private Const COMPRESSION_FORMAT_LZNT1 As Long = 2
Private Const STATUS_BAD_COMPRESSION_BUFFER As Long = &HC0000242
 
' Упаковать (сжать) данные байтового массива
Public Function Compress_NT(byteArray() As Byte) As Boolean
    On Error GoTo Quit
    
    Dim output() As Byte
    Dim WorkSpace() As Byte
    Dim szWorkSpace As Long
    Dim mSizeOfData As Long
    Dim OutPutSize As Long
    Dim returnedSize As Long
    
    If RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, szWorkSpace, 0) = STATUS_SUCCESS Then
        mSizeOfData = UBound(byteArray) + 1
        OutPutSize = mSizeOfData * 2
        ReDim WorkSpace(szWorkSpace - 1)
        ReDim output(OutPutSize - 1)
        
        If RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, byteArray(0), mSizeOfData, output(0), OutPutSize, 4096, returnedSize, WorkSpace(0)) = STATUS_SUCCESS Then
            ReDim byteArray(returnedSize - 1)
            RtlMoveMemory byteArray(0), output(0), returnedSize
            Compress_NT = True
        End If
    End If
Quit:
End Function
 
' Распаковать (извлечь) данные байтового массива
Public Function DeCompress_NT(byteArray() As Byte) As Boolean
    On Error GoTo Quit
    
    Dim output() As Byte
    Dim mSizeOfData As Long
    Dim OutPutSize As Long
    Dim returnedSize As Long
    Dim status As Long
    Dim cnt As Byte
    
    mSizeOfData = UBound(byteArray) + 1
    OutPutSize = mSizeOfData * 2
    ReDim output(OutPutSize - 1)
    
    Do
        status = RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, output(0), OutPutSize, byteArray(0), mSizeOfData, returnedSize)
        
        Debug.Print cnt & ", status: " & status ' Очень редко, но иногда так бывает, что функция обманывает и возвращает ложный успех
        
        If status = STATUS_BAD_COMPRESSION_BUFFER Then
            If cnt >= 19 Then Exit Function ' Предотвратить зависание программы, если файл так и не удастся распаковать после двадцатой попытки, предполагая что коэффициент сжатия не превысит размера в 20 раз
            
            OutPutSize = OutPutSize + mSizeOfData
            ReDim output(OutPutSize - 1)
            cnt = cnt + 1
        End If
    Loop While status = STATUS_BAD_COMPRESSION_BUFFER
    
    ReDim byteArray(returnedSize - 1)
    RtlMoveMemory byteArray(0), output(0), returnedSize
    DeCompress_NT = True
Quit:
End Function
Добавлено через 4 минуты
Я так и не понял почему функция не вернула STATUS_BAD_COMPRESSION_BUFFER как полагается. В результате у меня на выходе вышло лишь часть данных которая превышает только в два раза, размер упакованных данных. Хотя в 5 раз больше выходной буфер в моём случае, должен быть (но заранее я же этого не знаю).

Добавлено через 23 минуты
Каков максимальный коэффициент сжатия функции RtlDecompressBuffer? В 10 раз может сжать данные, в 20 раз? И что мне сразу выделять буфер в 20 раз больше что ли, чтобы уж точно функция правильно сработала без ошибок. Ну это скорее всего баг майкрософтовской функции конечно. При чём очень редкий.
1
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
29.03.2023, 15:29
Ответы с готовыми решениями:

Функция иногда возвращает ложные данные
Имеется web сервис для проверки статуса заказа, при тестировании всплыл баг, иногда функция запроса из базы выдает неверные данные. ...

Иногда функция возвращает значение NaN
Доброго времени суток. У меня следующая проблема. Не всегда, но в 70% случаев функция возвращает значение NaN. Никак не могу найти...

Почему программа иногда возвращает не нулевой результат, а иногда нуль?
С чем подобное может быть связана?

4
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
29.03.2023, 17:09
Проверяй returnedSize и если он равен OutPutSize то продолжай распаковывать.
1
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
29.03.2023, 22:54  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Проверяй returnedSize и если он равен OutPutSize то продолжай распаковывать
Хорошая идея, напиши пожалуйста код. Хотя и сам могу. Ну что убедился что это баг майкрософта?

Добавлено через 5 минут
Посмотреть бы на исходник функции RtlDecompressBuffer и найти бы там ошибку. Кстати вроде на гитхабе до сих пор лежит исходник XP.

Добавлено через 1 час 25 минут
Цитата Сообщение от The trick Посмотреть сообщение
Проверяй returnedSize и если он равен OutPutSize то продолжай распаковывать
Не прокатило, во втором случае returnedSize стал 4096 почему-то, сам посмотри идея не удалась

Добавлено через 1 минуту
И во втором прогоне вернуло уже STATUS_BAD_COMPRESSION_BUFFER

Добавлено через 21 минуту
Ну что, пофиксим майкрософтовский баг и напишем тогда новый алгоритм сравнения: либо STATUS_BAD_COMPRESSION_BUFFER либо returnedSize = OutPutSize. Добавлю так же в свою функцию Optional OutputBufferSize As Long на всякий случай для тех кто заранее знает размер буфера (так всё-таки надёжнее)

Добавлено через 1 час 7 минут
Вот я написал сам наконец-таки. Проверьте, надеюсь правильно всё написал.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Private Declare Function RtlGetCompressionWorkSpaceSize Lib "ntdll" (ByVal CompressionFormatAndEngine As Integer, ByRef CompressBufferWorkSpaceSize As Long, ByRef CompressFragmentWorkSpaceSize As Long) As Long
Private Declare Function RtlCompressBuffer Lib "ntdll" (ByVal CompressionFormatAndEngine As Integer, ByRef UncompressedBuffer As Any, ByVal UncompressedBufferSize As Long, ByRef CompressedBuffer As Any, ByVal CompressedBufferSize As Long, ByVal UncompressedChunkSize As Long, ByRef FinalCompressedSize As Long, ByRef WorkSpace As Any) As Long
Private Declare Function RtlDecompressBuffer Lib "ntdll" (ByVal CompressionFormat As Integer, ByRef ptrDestBuffer As Any, ByVal DestBufferSize As Long, ByRef ptrSrceBuffer As Any, ByVal SceBufferSize As Long, ByRef pDestinationSize As Long) As Long
Private Declare Function RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal Length As Long) As Long
 
Private Const STATUS_SUCCESS As Long = 0
Private Const COMPRESSION_FORMAT_LZNT1 As Long = 2
Private Const STATUS_BAD_COMPRESSION_BUFFER As Long = &HC0000242
 
' Упаковать (сжать) данные байтового массива
Public Function Compress_NT(byteArray() As Byte) As Boolean
    On Error GoTo Quit
    
    Dim output() As Byte
    Dim WorkSpace() As Byte
    Dim szWorkSpace As Long
    Dim mSizeOfData As Long
    Dim OutPutSize As Long
    Dim returnedSize As Long
    
    If RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, szWorkSpace, 0) = STATUS_SUCCESS Then
        mSizeOfData = UBound(byteArray) + 1
        OutPutSize = mSizeOfData * 2
        ReDim WorkSpace(szWorkSpace - 1)
        ReDim output(OutPutSize - 1)
        
        If RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, byteArray(0), mSizeOfData, output(0), OutPutSize, 4096, returnedSize, WorkSpace(0)) = STATUS_SUCCESS Then
            ReDim byteArray(returnedSize - 1)
            RtlMoveMemory byteArray(0), output(0), returnedSize
            Compress_NT = True
        End If
    End If
Quit:
End Function
 
' Распаковать (извлечь) данные байтового массива
Public Function DeCompress_NT(byteArray() As Byte, Optional OutputBufferSize As Long) As Boolean
    On Error GoTo Quit
    
    Dim output() As Byte
    Dim mSizeOfData As Long
    Dim OutPutSize As Long
    Dim returnedSize As Long
    Dim status As Long
    Dim oldcnt As Byte
    Dim cnt As Byte
    
    mSizeOfData = UBound(byteArray) + 1
    
    If OutputBufferSize > 0 Then
        OutPutSize = OutputBufferSize
    Else
        OutPutSize = mSizeOfData * 2
    End If
    ReDim output(OutPutSize - 1)
    
    Do
        status = RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, output(0), OutPutSize, byteArray(0), mSizeOfData, returnedSize)
        Debug.Print "cnt: " & cnt & " , status:" & status
        oldcnt = cnt
        
        If status = STATUS_BAD_COMPRESSION_BUFFER Or returnedSize = OutPutSize Then ' Эта фишка исправляет глюк майкрософта
            ' Предотвратить зависание программы, если данные так и не удастся распаковать после двадцатой попытки
            If cnt >= 19 Then Exit Function
            
            OutPutSize = OutPutSize + mSizeOfData
            ReDim output(OutPutSize - 1)
            cnt = cnt + 1
        End If
        
        If cnt = oldcnt Then Exit Do ' Если размер буфера был правильный то надо выходить из цикла
    Loop While status = STATUS_BAD_COMPRESSION_BUFFER Or returnedSize = (OutPutSize - mSizeOfData)
    
    ReDim byteArray(returnedSize - 1)
    RtlMoveMemory byteArray(0), output(0), returnedSize
    DeCompress_NT = True
Quit:
End Function
Этот код будет исправлять глюк майкрософта.
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
30.03.2023, 11:09
Цитата Сообщение от HackerVlad Посмотреть сообщение
Не прокатило, во втором случае returnedSize стал 4096 почему-то, сам посмотри идея не удалась
Странное утверждение если в итоге ты так и сделал
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
30.03.2023, 11:14  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
если в итоге ты так и сделал
ахаххахаха
я думал всё сравнивать на If returnedSize = OutPutSize Then
а надо было If status = STATUS_BAD_COMPRESSION_BUFFER Or returnedSize = OutPutSize Then

Добавлено через 1 минуту
Главное мы помогли людям, теперь эта страница на 1 месте по запросу "rtldecompressbuffer теряет байты"
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
30.03.2023, 11:14
Помогаю со студенческими работами здесь

В типе float иногда возвращает -0
Иногда на экран выводится -0,000, если точность 3 стоит. Тип float. о чем это может свидетельствовать? Неужто оо очень малом числе? ...

Now().DateString() иногда возвращает пустую строку
Добрый день! В программе предусмотен вывод информации о дате и времени Информацию получаю так TDateTime NowTime = Now(); ...

LAST_INSERT_ID() иногда возвращает ноль. Это не хорошо
Создается запись в БД. Сразу после этого пытаемся получить её ID: $SQL = ' SELECT LAST_INSERT_ID() AS last_id '; $st =...

Почему при работе мышкой иногда возвращает назад?
Купил новую мышку и теперь при работе ей,а особенно при вёрстке в Notepad++ и в инспекторе браузера периодически возвращает назад,на...

ExecuteScalar иногда не возвращает значения. В чем может быть причина?
Добрый день. Нужна ваша помощь. Проблема озвучена в названии темы - функция MySQL ExecuteScalar не всегда возвращает значение ID новой...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru