Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.80/41: Рейтинг темы: голосов - 41, средняя оценка - 4.80
Вопрощающий

Создание (+распаковка) CAB архива

11.10.2009, 19:26. Показов 10678. Ответов 130

Студворк — интернет-сервис помощи студентам
Обращаясь к cabinet.dll, без использования *.exe
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
11.10.2009, 19:26
Ответы с готовыми решениями:

Создание архива
Есть такая строка .AddAttachment "C:\logfiles.rar" При выполнении кода на ней ошибка. Как создать программно этот архив?

Программное создание архива.
Добрый день! Можноли программно сделать архив, например, ZIP или rar, не важно и добавить в него файлы? Заранее спасибо.

Создание архива с паролем
Private Declare Sub Sleep Lib "kernel32" (ByVal milliseconds As Long) Private Declare Function OpenProcess Lib "Kernel32.dll" (ByVal...

130
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
09.11.2024, 04:33
Очень интересная тема, жаль, что никто так и не ответил за 15 лет... Сейчас в интернете можно легко найти только код на Дельфи, на VB не видел

Добавлено через 4 часа 38 минут
Там, скорее всего, все API-функции к cabinet.dll такие как FCICreate имеют соглашение CDecl поэтому в стандартных VB-кодах просто так этого никто не смог бы написать раньше конечно.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
09.11.2024, 16:44
Самое интересное что 10 функций обратного вызова тоже все CDecl...

Добавлено через 2 минуты
Не удивительно конечно что никто так и не дал ответа. Это очень сложный код.
0
Эксперт по электронике
6506 / 3136 / 331
Регистрация: 28.10.2011
Сообщений: 12,323
Записей в блоге: 7
09.11.2024, 18:35
Если в VB такие жесткие ограничения которые обойти не получается, напишите код на другом ЯП (на упомянутом Дельфи или др.), скомпилируйте dll и подключите к проекту VB.
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
10.11.2024, 15:47
CDecl можно сейчас вызывать без проблем.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
10.11.2024, 22:08
Цитата Сообщение от The trick Посмотреть сообщение
CDecl можно сейчас вызывать без проблем
Да я знаю, но там всё равно слишком сложный код. Можно неделю переписывать с Дельфи.

Добавлено через 4 часа 25 минут
Я тут случайно узнал о недокументированной в MSDN функции ExtractFiles это функции ExtractFilesA и ExtractFilesW которые занимаются распаковкой CAB-файлов. Эта функция ExtractFiles является как раз красивой оболочкой для работы с распаковкой обращаясь к cabinet.dll.

Есть ещё способ распаковки через SetupIterateCabinet из setupapi.dll который тоже в свою очередь обращается к cabinet.dll, но с функцией SetupIterateCabinet ещё попыхтеть надо тоже, там тоже коллбаки и много чего нужно написать.

А вот недокументированную функцию ExtractFiles из advpack.dll, входящий в стандартную поставку Windows, я рассматриваю как оптимальный вариант. Это и есть та самая красивая обёртка которую нужно было написать обращаясь к cabinet.dll.

Добавлено через 13 минут
Фантастика! Всего одна строка кода!!! А создавать сложный модуль обращаясь к cabinet.dll можно целую неделю и там придётся написать 500 строк кода...

А тут всё так просто!

Visual Basic
1
2
3
4
5
Private Declare Function ExtractFiles Lib "advpack.dll" Alias "ExtractFilesA" (ByVal CabName As String, ByVal ExpandDir As String, ByVal Flags As Long, ByVal FileList As String, ByVal LReserved As Long, ByVal Reserved As Long) As Long
 
Private Sub Command1_Click()
    ExtractFiles App.Path & "\CabFile1.cab", App.Path, 0, "nemiro.ico", 0, 0 ' Просто здесь пишешь полный путь и имя архива и потом какой файл выдернуть из архива и всё! Вуаля! Всю сложную работу за нас уже давно написали в этой библиотеке advpack.dll
End Sub
Добавлено через 10 минут
Почему эту функцию не документировали в MSDN если она такая идеальная, я просто понять не могу...

Добавлено через 9 минут
Или вот например извлечь все файлы из архива (тогда оставляем vbNullString):

Visual Basic
1
2
3
4
5
6
7
Private Sub Command3_Click()
    If ExtractFiles(App.Path & "\CabFile1.cab", App.Path, 0, vbNullString, 0, 0) = 0 Then
        Print "Архив успешно извлечён"
    Else
        Print "Ошибка"
    End If
End Sub
1
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
11.11.2024, 01:24
Лучший ответ Сообщение было отмечено testuser2 как решение

Решение

Написал сегодня небольшой проектик для чтения и распаковки файлов из CAB-архивов, программным кодом на VB6.

Модуль:
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
Option Explicit
'////////////////////////////////////////////
'// Модуль для чтения CAB-архивов          //
'// Copyright (c) 11.11.2024 by HackerVlad //
'// e-mail: vladislavpeshkov@yandex.ru     //
'// Версия 1.0                             //
'////////////////////////////////////////////
 
Private Declare Function SetupIterateCabinet Lib "setupapi" Alias "SetupIterateCabinetA" (ByVal CabinetFile As String, ByVal Reserved As Long, ByVal MsgHandler As Long, ByVal Context As Long) As Long
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, ByVal Source As Long, ByVal Length As Long)
 
Private Const MAXPATH = 260
Private Const NO_ERROR = 0
'
' Notification messages, handled in the callback
' procedure. This class doesn't handle them all.
'
Private Const SPFILENOTIFY_FILEINCABINET = &H11
Private Const SPFILENOTIFY_NEEDNEWCABINET = &H12
Private Const SPFILENOTIFY_FILEEXTRACTED = &H13
 
Private Const sicList = 568
Private Const sicCount = 569
 
Dim mstrFileToExtract As String
Dim mstrOutputPath As String
Dim mstrOutputFile As String
Dim mlngCount As Long
Dim mlngcnt As Long
Dim arrListFilesCab() As CabInfo
 
Public Type CabInfo
    cabFileName As String
    cabFileSize As Long
End Type
 
Private Type FileInCabinetInfo
    NameInCabinet As Long
    FileSize      As Long
    Win32Error    As Long
    DosDate       As Integer
    DosTime       As Integer
    DosAttribs    As Integer
    FullTargetName(0 To MAXPATH - 1) As Byte
End Type
 
Private Enum FILEOP
    FILEOP_ABORT = 0
    FILEOP_DOIT = 1
    FILEOP_SKIP = 2
End Enum
 
Private Function CabinetCallback(ByVal Context As Long, ByVal Notification As Long, ByRef Param1 As FileInCabinetInfo, ByVal Param2 As Long) As Long
    Select Case Notification
        Case SPFILENOTIFY_NEEDNEWCABINET
            CabinetCallback = NO_ERROR
            
        Case SPFILENOTIFY_FILEINCABINET
            Select Case Context
                Case sicCount
                    mlngCount = mlngCount + 1
                    CabinetCallback = FILEOP_SKIP
                    
               Case sicList
                    ' Добавить позицию в массив UDT
                    ReDim Preserve arrListFilesCab(mlngcnt)
                    arrListFilesCab(mlngcnt).cabFileName = fStringFromPointer(Param1.NameInCabinet)
                    arrListFilesCab(mlngcnt).cabFileSize = Param1.FileSize
                    mlngcnt = mlngcnt + 1
                    
                    CabinetCallback = FILEOP_SKIP ' Перебирать список файлов дальше
            End Select
    End Select
End Function
 
Private Function fStringFromPointer(ByVal ptr As Long) As String
    Dim lngLen   As Long
    Dim strBuffer As String
    '
    ' Given a string pointer, copy the value
    ' of the string into a new, safe location.
    '
    lngLen = lstrlen(ptr)
    strBuffer = Space$(lngLen)
    
    CopyMemory ByVal strBuffer, ptr, lngLen
    fStringFromPointer = strBuffer
End Function
 
' Получить список файлов внутри архива CAB
Public Function GetFilesListInCab(ByVal FileName As String, arrCabInfo() As CabInfo) As Long
    mlngcnt = 0
    
    If SetupIterateCabinet(FileName, 0, AddressOf CabinetCallback, sicList) Then
        arrCabInfo = arrListFilesCab
        GetFilesListInCab = mlngcnt
        
        Erase arrListFilesCab
    End If
End Function
 
' Узнать количество файлов внутри архива CAB
Public Function GetFilesCountInCab(ByVal FileName As String) As Long
    mlngCount = 0
    
    If SetupIterateCabinet(FileName, 0, AddressOf CabinetCallback, sicCount) Then
        GetFilesCountInCab = mlngCount
    End If
End Function
Форма:

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
Option Explicit
Private Declare Function ExtractFiles Lib "advpack.dll" Alias "ExtractFilesA" (ByVal CabName As String, ByVal ExpandDir As String, ByVal Flags As Long, ByVal FileList As String, lpReserved As Any, ByVal Reserved As Long) As Long
Private Declare Function SafeArrayGetDim Lib "oleaut32.dll" (arr() As Any) As Long
 
Private Sub Command1_Click()
    Dim arrListCab() As CabInfo
    Dim i As Long
    
    If GetFilesListInCab(Text1.Text, arrListCab) > 0 Then
        If SafeArrayGetDim(arrListCab) > 0 Then
            If List1.ListCount > 0 Then List1.Clear
            
            For i = 0 To UBound(arrListCab)
                List1.AddItem arrListCab(i).cabFileName & "    " & arrListCab(i).cabFileSize & " bytes"
            Next
            
            If List1.ListCount > 0 Then
                List1.Selected(0) = True
                List1.SetFocus
                
                Me.Caption = "UnCab 1.0 by HackerVlad    (" & List1.ListCount & " files)"
            End If
        End If
    Else
        Beep ' err
    End If
End Sub
 
Private Sub Command2_Click()
    Dim str As String
    
    str = Left$(List1.Text, InStr(1, List1.Text, "    ") - 1)
    
    If ExtractFiles(Text1.Text, Text2.Text, 0, str, 0, 0) = 0 Then
        Me.Cls
        Print "Файл из архива успешно извлечён"
    Else
        Me.Cls
        Print "Ошибка"
    End If
End Sub
 
Private Sub Command3_Click()
    If ExtractFiles(Text1.Text, Text2.Text, 0, vbNullString, 0, 0) = 0 Then
        Me.Cls
        Print "Архив полностью успешно извлечён"
    Else
        Me.Cls
        Print "Ошибка"
    End If
End Sub
 
Private Sub Form_DblClick()
    MsgBox GetFilesCountInCab(Text1.Text), vbInformation
End Sub
 
Private Sub Form_Load()
    Text1.Text = App.Path & "\CabFile.cab"
    Text2.Text = App.Path & "\TestUnpacked"
    
    On Error Resume Next
    MkDir App.Path & "\TestUnpacked"
End Sub
 
Private Sub Text1_KeyPress(KeyAscii As Integer)
    If KeyAscii = 13 Then
        KeyAscii = 0
        Command1_Click
    End If
End Sub
Миниатюры
Создание (+распаковка) CAB архива  
Вложения
Тип файла: zip UnCab.zip (27.4 Кб, 7 просмотров)
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
11.11.2024, 01:33
Фактически функцию SetupIterateCabinet я использую только для получения списка файлов внутри архива. Да и сам модуль нужен только для этого. А так, на самом деле, распаковка CAB-архивов идёт одной строчкой кода из формы, с помощью функции ExtractFiles из библиотеки advpack.dll.

Добавлено через 5 минут
То что я написал - это самый лёгкий и самый упрощённый вариант для данной темы. Файлы CAB, конечно, можно распаковывать и с помощью функции SetupIterateCabinet , но честно сказать это не лучший вариант, так как можно заколебаться всё это описывать, много строк кода пришлось бы написать. Но есть класс CabFile.cls, который лежит у меня как раз в тестовом архиве CabFile.cab, так вот этот класс он действительно может распаковывать файлы из CAB только лишь кодом функции SetupIterateCabinet , однако там написано очень много строк кода, очень много дополнительных пользовательских функций, больше чем 800 строк кода там... А оно нам надо? И тем более, я тестировал этот класс - он глючный, некоторые архивы неправильно распаковывает.

А тут у меня получается всё просто и красиво, и строк кода мало и всё работает правильно. В конечном итоге всё равно все эти функции, конечно, вызывают cabinet.dll однако нам не надо теперь париться с разбирательством с этим кодом для cabinet.dll, так как там очень сложный код.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
15.11.2024, 20:25
Кстати я написал упаковку CAB, две недели писал, уйма ошибок было у меня так как это очень-очень сложный код оказался, но мне просто было интересно смогу я это написать или нет. Спортивный интерес так сказать.
2
sleep
 Аватар для I can
4914 / 4553 / 837
Регистрация: 13.04.2015
Сообщений: 9,677
15.11.2024, 20:55
Цитата Сообщение от HackerVlad Посмотреть сообщение
две недели писал
Мне этого наверное вообще никогда не понять. Потратить две недели своей жизни на какую-то хрень, которая за 15 лет никому не понадобилась, и скорее всего и не понадобится больше, для меня непостижимо.

Но тебе конечно плюс за такое дело.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
15.11.2024, 21:07
Цитата Сообщение от I can Посмотреть сообщение
которая за 15 лет никому не понадобилась
За 15 лет, уверен, этот код много кому нужен был, просто из-за того что его очень сложно написать, из-за этого никто и не писал.

Добавлено через 40 секунд
Плюс на других форумах видел, много кто пытался написать этот код и не у кого не получалось. А у меня получилось.
1
1381 / 837 / 89
Регистрация: 08.02.2017
Сообщений: 3,506
Записей в блоге: 1
16.11.2024, 05:21
HackerVlad, выкладывай свой код. Я в ближайшее время хочу доделть супер-конвертер кода в x64 compatible и попытаюсь его преобразовать в x64.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.11.2024, 14:28
testuser2, там есть ошибки у меня, одну ошибку до сих пор не знаю как исправить
тебе нужен глючный код?

Добавлено через 2 минуты
я так и не смог устранить одну ошибку, сейчас у меня работает через "заплатку" но надо думать как исправить эту ошибку без заплатки пока не получается

Добавлено через 25 минут
testuser2, ты бы только знал, насколько сложный это код вообще, мало того что там 4 API-функции к cabinet.dll и 13 пользовательских call-back функций обратного вызова, так ещё и самые большие сложности это с описанием самих этих функций, особенно самые большие сложности с пониманием где ставить ByVal а где ByRef это самое сложное вообще, поставишь только вместо ByVal например ByRef или наоборот вместо ByRef поставишь ByVal и сразу идёт вылет из среды VB6 с необратимым исключением.
Вообще у меня VB6 вылетал, в процессе написания этого кода, больше ста раз наверное... Одно необратимое исключение я не мог исправить целый день не понимал почему вылетает. Помог TwinBasic кстати он подсказывает где на какой строке кода примерно происходит необратимое исключение...

Добавлено через 3 минуты
Несколько раз я даже про себя сдавался и думал что это написать невозможно и думал про себя всё больше не буду заниматься этой ерундой

Добавлено через 3 минуты
Но русские не сдаются, как всем известно и я продолжал идти дальше...
Меня путал даже Фафалон со своими неправильными советами где ставить ByVal а где ByRef
0
1381 / 837 / 89
Регистрация: 08.02.2017
Сообщений: 3,506
Записей в блоге: 1
16.11.2024, 15:01
Цитата Сообщение от HackerVlad Посмотреть сообщение
я так и не смог устранить одну ошибку, сейчас у меня работает через "заплатку" но надо думать как исправить эту ошибку без заплатки пока не получается
Можешь описать здесь ситуацию и возможно найдется ответ

Добавлено через 13 минут
Я, кстати, как раз хочу сделать парсер С-деклараций, чтобы их перегонят в VB-декларации. Я кое что кстати, уже сделал, но не уерен, на сколько правильно работает.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.11.2024, 15:44
testuser2, сейчас пока выкладывать сырой код смысла нет, вряд ли мне кто-то поможет исправить ошибку так как это долго вникать надо, и нужно много знаний
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
18.11.2024, 23:54
testuser2, основной код, который я переписывал с Delphi там он основан на временных файлах, в результате создавалась куча разных TMP-файлов, а мне это не нравится конечно же, зачем создавать много TMP-файлов в системной папке на диске, по моему это пережитки прошлого, а-ля Windows 98, сейчас у людей оперативки хватает можно спокойно выполнять все основные процессы в оперативной памяти компьютера, не создавая при этом огромную кучу TMP-файлов. Поэтому я сейчас переписываю этот код на технологию стримов, чтобы ни одна тээмпэшка на диске больше никогда не создавалась. Не люблю TMP. Но технология такая достаточно хакерская, я тебе скажу, чтобы вместо файлов TMP у нас были стримы в памяти для работы основной по созданию CAB.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
20.11.2024, 20:44
Здесь так же стоит отметить, что моя технология, основанная на работе в оперативной памяти, без временных файлов на диске, работает по скорости быстрее, чем стандартная технология основанная на временных файлах. Я создал два проекта.
1. Упаковка CAB с использованием временного файла
2. Упаковка CAB без временных файлов, все операции только в оперативке

Сравнил по скоростям два эти проекта, и второй проект, без временных файлов оказался конечно же быстрее! В среднем быстрее на 100млск относительна обработки 100Кб данных
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
20.11.2024, 23:19
Представляю вашему вниманию первую версию модуля упаковки CAB-архивов. Я написал этот модуль полностью на VB6, поэтому пока будет работать только в VB6. Это первая версия модуля, который работает без ошибок уже теперь точно.

Пока функция CabinetAddFile принимает в качестве параметра только FileName одного файла, который нужно упаковать, а так же на выходе получается файл CAB. Это самая первая версия, потом можно будет придумать как заглатывать сразу списки файлов.

Все вычислительные процессы производит и работает полностью в оперативке, без временных файлов, что очень важно для убыстрения работы скрипта. Пока только сжимает в MSZIP. Ещё не разобрался как установить другой метод сжатия.

Самое главное это то, что я осуществил мечту! Написал код, который многие люди думали, что невозможно написать на VB6. Однако конечно будет зависимость в виде надстройки CDeclFix от The Trick для установки патча для работы CDecl функций. Как и где скачать эту надстройку надеюсь найдёте на этом форуме.

Модуль:

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
Option Explicit
'/////////////////////////////////////////////
'// Модуль упаковки CAB-архивов             //
'// Copyright (c) 20.11.2024 by HackerVlad  //
'// e-mail: vladislavpeshkov@yandex.ru      //
'// Версия 1.0                              //
'/////////////////////////////////////////////
 
' Декларации API ...
Private Declare Function FCICreate CDecl Lib "cabinet.dll" (perf As TERF, ByVal fnFilePlaced As Long, ByVal fnAlloc As Long, ByVal fnFree As Long, ByVal fnOpen As Long, ByVal fnRead As Long, ByVal fnWrite As Long, ByVal fnClose As Long, ByVal fnSeek As Long, ByVal fnDelete As Long, ByVal fnFciGTF As Long, ByVal ccab As Long, Optional ByVal pv As Long) As Long
Private Declare Function FCIAddFile CDecl Lib "cabinet.dll" (ByVal hfci As Long, ByVal pszSourceFile As Long, ByVal pszFileName As Long, ByVal fExecute As BOOL, ByVal pfnGetNextCabinet As Long, ByVal pfnProgress As Long, ByVal pfnOpenInfo As Long, ByVal typeCompress As Long) As Long
Private Declare Function FCIFlushCabinet CDecl Lib "cabinet.dll" (ByVal hfci As Long, ByVal fGetNextCab As BOOL, ByVal pfnfcignc As Long, ByVal pfnfcis As Long) As BOOL
Private Declare Function FCIDestroy CDecl Lib "cabinet.dll" (ByVal hfci As Long) As BOOL
Private Declare Function SHCreateMemStream Lib "shlwapi.dll" Alias "#12" (ByVal pInit As Long, ByVal cbInit As Long) As Long
Private Declare Function PathStripPathW Lib "shlwapi.dll" (ByVal pszPath As Long) As Long
Private Declare Function PathRemoveFileSpecW Lib "shlwapi.dll" (ByVal pszPath As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (Destination As Any, ByVal Length As Long)
Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" (ByVal lpFileName As Long) As Long
Private Declare Function GetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long
Private Declare Function FileTimeToDosDateTime Lib "kernel32" (lpFileTime As FILETIME, lpFatDate As Integer, lpFatTime As Integer) As Long
Private Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, ByVal lpBuffer As Long, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Any) As BOOL
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, ByVal lpBuffer As Long, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Any) As BOOL
Private Declare Function OpenFile Lib "kernel32" (ByVal lpFileName As Long, lpReOpenBuff As OFSTRUCT, ByVal wStyle As Long) As Long
Private Declare Function CreateFileA Lib "kernel32" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function CreateFileW Lib "kernel32" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
 
' Константы ...
Private Const CB_MAX_DISK_NAME = 256
Private Const CB_MAX_CABINET_NAME = 256
Private Const CB_MAX_CAB_PATH = 256
Private Const OFS_MAXPATHNAME = 128
Private Const tcompTYPE_MSZIP = &H1
Private Const GENERIC_READ As Long = &H80000000
Private Const GENERIC_WRITE As Long = &H40000000
Private Const FILE_SHARE_READ = &H1
Private Const OPEN_EXISTING As Long = 3
Private Const FILE_ATTRIBUTE_ARCHIVE = &H20
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const INVALID_HANDLE_VALUE As Long = -1
Private Const CREATE_ALWAYS = 2
Private Const MAX_PATH As Long = 260
 
' Типы ...
Private Type TCCAB
    cb As Long ' size available for cabinet on this media
    cbFolderThresh As Long ' Thresshold for forcing a new Folder
    cbReserveCFHeader As Long ' Space to reserve in CFHEADER
    cbReserveCFFolder As Long ' Space to reserve in CFFOLDER
    cbReserveCFData As Long ' Space to reserve in CFDATA
    iCab As Long ' sequential numbers for cabinets
    iDisk As Long ' Disk number
    fFailOnIncompressible As Long ' TRUE => Fail if a block is incompressible
    setID As Integer ' Cabinet set ID
    szDisk(0 To (CB_MAX_DISK_NAME - 1)) As Byte ' current disk name
    szCab(0 To (CB_MAX_CABINET_NAME - 1)) As Byte ' current cabinet name
    szCabPath(0 To (CB_MAX_CAB_PATH - 1)) As Byte ' path for creating cabinet
End Type
 
Private Type TERF
    erfOper As Long
    erfType As Long
    fError As Byte
End Type
 
Private Type OFSTRUCT
    cBytes As Byte
    fFixedDisk As Byte
    nErrCode As Integer
    Reserved1 As Integer
    Reserved2 As Integer
    szPathName(0 To (OFS_MAXPATHNAME - 1)) As Byte
End Type
 
Private Type FILETIME
  dwLowDateTime As Long
  dwHighDateTime As Long
End Type
 
' Переменные для временного хранения данных ...
Dim fh As Long
Dim fh_cab As Long
Dim cabFileName As String
 
' Енумы ...
Private Enum BOOL
    cFalse
    cTrue
End Enum
 
Private Enum Stream_Seek
    STREAM_SEEK_SET
    STREAM_SEEK_CUR
    STREAM_SEEK_END
End Enum
 
' Для совместимости с TwinBasic и VBA7
#If (VBA7 <> 0) Or (TWINBASIC <> 0) Then
    Private Declare PtrSafe Function DispCallFunc Lib "oleaut32" (ByVal pvInstance As LongPtr, ByVal oVft As LongPtr, ByVal lCc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, prgVt As Any, prgpVarg As Any, pvargResult As Variant) As Long
#Else
    Private Declare Function DispCallFunc Lib "oleaut32" (ByVal pvInstance As LongPtr, ByVal oVft As LongPtr, ByVal lCc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, prgVt As Any, prgpVarg As Any, pvargResult As Variant) As Long
    
    Private Enum LongPtr
        [_]
    End Enum
#End If
 
Private Function DispCallByVtbl(ByVal pUnk As LongPtr, ByVal lIndex As Long, ParamArray A() As Variant) As Variant
    Const CC_STDCALL    As Long = 4
#If Win64 Then
    Const PTR_SIZE      As Long = 8
#Else
    Const PTR_SIZE      As Long = 4
#End If
    Dim lIdx            As Long
    Dim vParam()        As Variant
    Dim vType(0 To 63)  As Integer
    Dim vPtr(0 To 63)   As LongPtr
    Dim hResult         As Long
    
    vParam = A
    For lIdx = 0 To UBound(vParam)
        vType(lIdx) = VarType(vParam(lIdx))
        vPtr(lIdx) = VarPtr(vParam(lIdx))
    Next
    hResult = DispCallFunc(pUnk, lIndex * PTR_SIZE, CC_STDCALL, vbLong, lIdx, vType(0), vPtr(0), DispCallByVtbl)
    If hResult < 0 Then
        Err.Raise hResult, "DispCallFunc"
    End If
End Function
 
Private Function IStream_Read(ByVal ptrIStream As Long, ByVal pv As Long, ByVal BytesRead As Long) As Long
    Dim BytesReaded As Long
    
    DispCallByVtbl ptrIStream, 3, pv, BytesRead, VarPtr(BytesReaded)
    IStream_Read = BytesReaded
End Function
 
Private Function IStream_Write(ByVal ptrIStream As Long, ByVal pv As Long, ByVal BytesWrite As Long) As Long
    Dim BytesWritten As Long
    
    DispCallByVtbl ptrIStream, 4, pv, BytesWrite, VarPtr(BytesWritten)
    IStream_Write = BytesWritten
End Function
 
Private Function IStream_Seek(ByVal ptrIStream As Long, ByVal Offset As Currency, ByVal Origin As Stream_Seek) As Long
    Dim NewPosition As Currency
    
    DispCallByVtbl ptrIStream, 5, Offset, Origin, VarPtr(NewPosition)
    IStream_Seek = NewPosition * 10000@
End Function
 
Private Sub IStream_Release(ByVal ptrIStream As Long)
    DispCallByVtbl ptrIStream, 2
End Sub
 
' +++ FCICreate CallBack's +++
 
' 1. Выделение памяти
' Описание макроса: https://learn.microsoft.com/en-us/windows/win32/api/fdi/nf-fdi-fnalloc
' Delphi: function fnAlloc(Size: ULONG): Pointer; cdecl;
Private Function fnAlloc CDecl(ByVal lngSize As Long) As Long
    fnAlloc = GlobalAlloc(0, lngSize)
End Function
 
' 2. Создание временного файла (потока)
' Delphi: function fnFciGTF(pszTempName: PAnsiChar; cbTempName: Integer; pv: Pointer): BOOL; cdecl;
Private Function fnFciGTF CDecl(ByRef pszTempName As Long, ByVal cbTempName As Long, ByVal pv As Long) As BOOL
    ' Специальный хак:
    ' Обманываем операционную систему, которая будет "думать", что работает с TMP-файлами на диске
    ' Вместо временного файла на диске, мы будем создавать поток IStream в оперативной памяти своего процесса
    Dim hStream As Long
    
    hStream = SHCreateMemStream(0, 0) ' Создать новый поток IStream для временного файла
    pszTempName = hStream ' Здесь мы будем использовать хак: засовываем в переменную String значение Long
    fnFciGTF = 1
End Function
 
' 3. Открытие файла (потока)
' Описание макроса: https://learn.microsoft.com/en-us/windows/win32/api/fdi/nf-fdi-fnopen
' Delphi: function fnOpen(pszFile: PAnsiChar; oflag: Integer; pmode: Integer; err: PInteger; pv: Pointer): Integer; cdecl;
Private Function fnOpen CDecl(ByRef pszFile As Long, ByVal oFlag As Long, ByVal pMode As Long, ByRef ErrNo As Long, ByVal pv As Long) As Long
    If oFlag <> &H8302& Then ' Хак
        fnOpen = pszFile
    Else
        fh_cab = CreateFileW(StrPtr(cabFileName), GENERIC_WRITE, FILE_SHARE_READ, ByVal 0&, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, 0)
        
        If fh_cab <> INVALID_HANDLE_VALUE Then
            ErrNo = Err.LastDllError
            fnOpen = fh_cab
        Else
            ErrNo = Err.LastDllError
            fnOpen = -1
        End If
    End If
End Function
 
' 4. Чтение данных
' Описание макроса: https://learn.microsoft.com/en-us/windows/win32/api/fdi/nf-fdi-fnread
' Delphi: function fnRead(hf: Integer; memory: Pointer; cb: UINT; err: PInteger; pv: Pointer): UINT; cdecl;
Private Function fnRead CDecl(ByVal hf As Long, ByVal hMemory As Long, ByVal cbSize As Long, ByRef ErrNo As Long, ByVal pv As Long) As Long
    Dim dwBytesRead As Long
    
    If hf = fh Then ' Если открывается на чтение файл, который добавляется в архив
        If ReadFile(fh, hMemory, cbSize, dwBytesRead, ByVal 0&) = cFalse Then
            ErrNo = Err.LastDllError
            fnRead = -1
            Exit Function
        End If
    Else ' Если открывается на чтение временный поток IStream
        dwBytesRead = IStream_Read(hf, hMemory, cbSize)
    End If
    
    fnRead = dwBytesRead
End Function
 
' 5. Запись данных
' Описание макроса: https://learn.microsoft.com/en-us/windows/win32/api/fdi/nf-fdi-fnwrite
' Delphi: function fnWrite(hf: Integer; memory: Pointer; cb: UINT; err: PInteger; pv: Pointer): UINT; cdecl;
Private Function fnWrite CDecl(ByVal hf As Long, ByVal hMemory As Long, ByVal cbSize As Long, ByRef ErrNo As Long, ByVal pv As Long) As Long
    Dim dwBytesWritten As Long
    
    If hf = fh_cab Then ' Если открывается на запись файл архива
        If WriteFile(fh_cab, hMemory, cbSize, dwBytesWritten, ByVal 0&) = cFalse Then
            ErrNo = Err.LastDllError
            fnWrite = -1
            Exit Function
        End If
    Else ' Если открывается на запись временный поток IStream
        dwBytesWritten = IStream_Write(hf, hMemory, cbSize)
    End If
    
    fnWrite = dwBytesWritten
End Function
 
' 6. Освобождение памяти
' Описание макроса: https://learn.microsoft.com/en-us/windows/win32/api/fdi/nf-fdi-fnfree
' Delphi: procedure fnFree(memory: Pointer); cdecl;
Private Sub fnFree CDecl(ByVal lngMemory As Long)
    GlobalFree lngMemory
End Sub
 
' 7. Позиционирование указателя
' Описание макроса: https://learn.microsoft.com/en-us/windows/win32/api/fdi/nf-fdi-fnseek
' Delphi: function fnSeek(hf: Integer; dist: Longint; seektype: Integer; err: PInteger; pv: Pointer): Longint; cdecl;
Private Function fnSeek CDecl(ByVal hf As Long, ByVal dist As Long, ByVal seektype As Long, ByRef ErrNo As Long, pv As Long) As Long
    Dim newPos As Long
    
    If hf = fh Or hf = fh_cab Then ' Если открывается на позиционирование файл, который добавляется в архив, либо сам файл архива
        newPos = SetFilePointer(hf, dist, ByVal 0&, seektype)
        ErrNo = Err.LastDllError
    Else ' Позиционирование "временного файла" то есть потока
        newPos = IStream_Seek(hf, dist / 10000@, seektype)
    End If
    
    fnSeek = newPos
End Function
 
' 8. Закрытие файла (потока)
' Описание макроса: https://learn.microsoft.com/en-us/windows/win32/api/fdi/nf-fdi-fnclose
' Delphi: function fnClose(hf: Integer; err, pv: Pointer): Integer; cdecl;
Private Function fnClose CDecl(ByVal hf As Long, ErrNo As Long, pv As Long) As Long
    If hf = fh Or hf = fh_cab Then ' Если закрывать нужно файл, который добавляется в архив, либо нужно закрывать сам файл архива
        CloseHandle hf
    End If
    
    fnClose = 0
End Function
 
' 9. Удаление временного файла (потока)
' Delphi: function fnDelete(pszFile: PAnsiChar; err: PInteger; pv: Pointer): Integer; cdecl;
Private Function fnDelete CDecl(ByRef pszFile As Long, ErrNo As Long, pv As Long) As Long
    IStream_Release pszFile
    fnDelete = 0
End Function
 
' 10. Вызывается каждый раз при добавлении нового файла в архив
' Delphi: function fnFilePlaced(var ccab: TCCAB; pszFile: PAnsiChar; cbFile: Longint; fContinuation: BOOL; pv: Pointer): THandle; cdecl;
Private Function fnFilePlaced CDecl(ccab As TCCAB, ByVal pszFile As String, ByVal FileSize As Long, ByVal fContinuation As BOOL, ByVal pv As Long) As Long
    ' Здесь можно получить полезные данные:
    ' 1. FileSize
    ' 2. StrConv(ccab.szCabPath, vbUnicode)
    ' 3. StrConv(ccab.szCab, vbUnicode)
    
    fnFilePlaced = 0
End Function
 
' --- FCICreate CallBack's ---
 
' +++ FCIAddFile CallBack's +++
 
' 11. Устанавливаем атрибуты файла
' Delphi: function fnOpenInfo(pszName: PAnsiChar; var pDate: WORD; var pTime: WORD; var pAttrib: WORD; err: PInteger; pv: Pointer): Integer; cdecl;
' Syntax C++
' ;;    void FNFCIGETOPENINFO(
' ;;      [in]  LPSTR pszName,
' ;;      USHORT *pdate,
' ;;      USHORT *ptime,
' ;;      USHORT *pattribs,
' ;;      int FAR *err,
' ;;      void FAR *pv
' ;;    );
Private Function fnOpenInfo CDecl(ByVal pszName As String, pDate As Integer, pTime As Integer, pAttribs As Integer, ErrNo As Long, ByVal pv As Long) As Long
    Dim LocalTime As FILETIME
    Dim CreationTime As FILETIME
    Dim LastAccessTime As FILETIME
    Dim LastWriteTime As FILETIME
    
    pAttribs = GetFileAttributes(StrPtr(pszName))
    fh = CreateFileA(StrPtr(pszName), GENERIC_READ, FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
    
    If fh <> INVALID_HANDLE_VALUE Then
        GetFileTime fh, CreationTime, LastAccessTime, LastWriteTime
        FileTimeToLocalFileTime LastWriteTime, LocalTime
        FileTimeToDosDateTime LocalTime, pDate, pTime
        
        fnOpenInfo = fh
    Else
        ErrNo = Err.LastDllError
        fnOpenInfo = -1
    End If
End Function
 
' 12. Вызывается на нескольких этапах обработки файла: сжатие блока, добавление сжатого блока и запись архива
' Delphi: function fnStatus(typeStatus: UINT; cb1, cb2: ULONG; pv: Pointer): Longint; cdecl;
Private Function fnStatus CDecl(ByVal typeStatus As Long, ByVal cb1 As Long, ByVal cb2 As Long, ByVal pv As Long) As Long
    fnStatus = 0
End Function
 
' 13. Вызывается перед созданием нового тома архива
' Delphi: function fnGetNextCabinet(var ccab: TCCAB; cbPrevCab: ULONG; pv: Pointer): BOOL; cdecl;
Private Function fnGetNextCabinet CDecl(ccab As TCCAB, ByVal cbPrevCab As Long, ByVal pv As Long) As BOOL
    fnGetNextCabinet = 0
End Function
 
' --- FCIAddFile CallBack's ---
 
' Упаковать файл в архив CAB
Public Function CabinetAddFile(ByVal CabinetFullFileName As String, ByVal SourceFileName As String) As Boolean
    Dim ccab As TCCAB
    Dim erf As TERF
    Dim fci As Long
    Dim CabinetDisk As String
    Dim CabinetName As String
    Dim CabinetPath As String
    Dim AnsiSourceFileName As String
    Dim AnsiExtractFileName As String
    
    ZeroMemory ccab, LenB(ccab)
    ZeroMemory erf, LenB(erf)
    
    ' Прежде всего нужно взять FullFileName будущего архива и извлечь из него путь к папке и имя файла
    CabinetName = StrConv(CabinetExtractFileName(CabinetFullFileName), vbFromUnicode) ' Преобразовать в ANSI
    CabinetPath = StrConv(CabinetExtractFilePath(CabinetFullFileName), vbFromUnicode) ' Преобразовать в ANSI
    
    ' Определить значения структуры
    ccab.cb = &H7FFFFFFF ' The maximum size, in bytes, of a cabinet created by FCI
    ccab.iDisk = 1
    
    CabinetDisk = StrConv("DISK1", vbFromUnicode) ' Я не знаю почему, но надо писать "DISK1"
    
    CopyMemory VarPtr(ccab.setID) + 2, StrPtr(CabinetDisk), LenB(CabinetDisk) ' ccab.szDisk = CabinetDisk
    CopyMemory VarPtr(ccab.setID) + 2 + 256, StrPtr(CabinetName), LenB(CabinetName) ' ccab.szCab = CabinetName
    CopyMemory VarPtr(ccab.setID) + 2 + 512, StrPtr(CabinetPath), LenB(CabinetPath) ' ccab.szCabPath = CabinetPath
    
    cabFileName = CabinetFullFileName ' Запомнить FileName будущего архива
    AnsiSourceFileName = StrConv(SourceFileName, vbFromUnicode) ' Преобразовать в ANSI
    AnsiExtractFileName = StrConv(CabinetExtractFileName(SourceFileName), vbFromUnicode) ' Преобразовать в ANSI
    
    If InStrB(1, AnsiSourceFileName, ChrB(&H3F)) > 0 Then
        ' Cabinet.dll не поддерживает юникодные имена файлов для упаковки
        Exit Function
    End If
    
    fci = FCICreate(erf, AddressOf fnFilePlaced, AddressOf fnAlloc, AddressOf fnFree, AddressOf fnOpen, AddressOf fnRead, AddressOf fnWrite, AddressOf fnClose, AddressOf fnSeek, AddressOf fnDelete, AddressOf fnFciGTF, VarPtr(ccab))
    
    If fci <> 0 Then
        If FCIAddFile(fci, StrPtr(AnsiSourceFileName), StrPtr(AnsiExtractFileName), 0, AddressOf fnGetNextCabinet, AddressOf fnStatus, AddressOf fnOpenInfo, tcompTYPE_MSZIP) <> 0 Then
            If FCIFlushCabinet(fci, cFalse, AddressOf fnGetNextCabinet, AddressOf fnStatus) = cTrue Then
                CabinetAddFile = True
            End If
        End If
        
        FCIDestroy fci
    End If
    
    cabFileName = vbNullString
End Function
 
' Преобразовать полный путь кабинета в имя файла
Public Function CabinetExtractFileName(ByVal FileName As String) As String
    Dim lNullPos As Long
    Dim pszPath As String
    
    pszPath = FileName
    PathStripPathW StrPtr(pszPath)
    
    lNullPos = InStr(1, pszPath, vbNullChar)
    If lNullPos Then
        CabinetExtractFileName = Left$(pszPath, lNullPos - 1)
    Else
        CabinetExtractFileName = FileName
    End If
End Function
 
' Преобразовать полный путь кабинета в путь к папке (всегда возвращает на конце "\")
Public Function CabinetExtractFilePath(ByVal FileName As String) As String
    Dim lNullPos As Long
    Dim pszPath As String
    
    pszPath = FileName
    PathRemoveFileSpecW StrPtr(pszPath)
    
    lNullPos = InStr(1, pszPath, vbNullChar)
    If lNullPos Then
        pszPath = Left$(pszPath, lNullPos - 1)
        If Right$(pszPath, 1) <> "\" Then pszPath = pszPath & "\"
        CabinetExtractFilePath = pszPath
    Else
        CabinetExtractFilePath = FileName
    End If
End Function
Форма:

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
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
 
Private Sub Command1_Click()
    Dim tick As Long
    
    tick = GetTickCount
    
    Me.Cls
    Print CabinetAddFile(Text1.Text, Text2.Text)
    Print (GetTickCount - tick) & " ml"
End Sub
 
Private Sub Command2_Click()
    MsgBox Chr(34) & CabinetExtractFileName(Text1.Text) & Chr(34), vbInformation
End Sub
 
Private Sub Command3_Click()
    MsgBox Chr(34) & CabinetExtractFilePath(Text1.Text) & Chr(34), vbInformation
End Sub
 
Private Sub Form_Load()
    Text1.Text = App.Path & "\test.cab"
    Text2.Text = App.Path & "\test.txt"
End Sub
Миниатюры
Создание (+распаковка) CAB архива  
Вложения
Тип файла: zip modCabinet.zip (42.6 Кб, 11 просмотров)
1
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
20.11.2024, 23:55
А вы знаете, я только что проверил, в TwinBasic тоже работает оказывается. Так что Ура! Даже переписывать не надо и что-то менять специально для TwinBasic. Просто надо импортировать проект из vbp и сохранить обязательно проект в той же папке и всё.

Добавлено через 3 минуты
Но скорость абсолютно одинаковая, я проверил, что в VB6, что в TwinBasic для этого процесса упаковки файлов. Наверное потому что сам основной процесс упаковки выполняет cabinet.dll и от языка программирования тут уже скорость почти не зависит.

Добавлено через 1 минуту
20 мегабайт упаковывает за 670 млск. Это хорошая скорость кстати.
0
1381 / 837 / 89
Регистрация: 08.02.2017
Сообщений: 3,506
Записей в блоге: 1
21.11.2024, 01:50
Цитата Сообщение от HackerVlad Посмотреть сообщение
' Для совместимости с TwinBasic и VBA7
#If (VBA7 <> 0) Or (TWINBASIC <> 0) Then
Это походу не нужно, там же у тебя всюду CDecl - функции, я не помню в VB6/VBA такого
Цитата Сообщение от HackerVlad Посмотреть сообщение
Private Function fnOpen CDecl(ByRef pszFile As Long,
Добавлено через 7 минут
Цитата Сообщение от HackerVlad Посмотреть сообщение
Однако конечно будет зависимость в виде надстройки CDeclFix от The Trick
А понял
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
21.11.2024, 01:50
Помогаю со студенческими работами здесь

Создание установочного архива для своих любимых программ
Многие новички в программировании рано или поздно создают программы или игры, которыми хотят поделиться с другими пользователями или своими...

Распаковка архива rar без сохранения файла во временную папку
В архиве rar хранится сжатый (с паролем) файл txt, как его распаковать (пароль известен) чтобы файл не записывался на диск, а содержимому...

Создание архива с паролем средствами PB. Возможно?
Есть ли какая то библиотека что позволяет запихнуть PB кодом файлы в архив с паролем? Ну и соответственно извлекать из архива. Спасибо.

Создание cab архива
Здравствуйте! Помогите реализовать код создания cab архива с помощью CabinetAPI Код из msdn не получается скомпилировать, не понимаю...

Создание папки с датой в имени и распаковка в неё архива
Есть папка на диске С:\Arhiv в нем есть архивы по датам! надо что бы брал самый последний архив по дате и распаковывал в корень С:\Arhiv\...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
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