Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.88/40: Рейтинг темы: голосов - 40, средняя оценка - 4.88
Вернулся
 Аватар для HackerVlad
1751 / 647 / 45
Регистрация: 10.09.2021
Сообщений: 2,800

Как работать с потоками IStream в Visual Basic 6

16.11.2024, 18:08. Показов 13525. Ответов 206
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет! Я недавно узнал о таком чуде как потоки IStream, это такие данные в оперативной памяти вашего процесса EXE типа байтовых массивов только круче. Как я это понял лично. Вот мне очень интересно стало поработать именно со стримами. Если у кого-то есть какие-то наработки в этом плане буду рад, если поделитесь.

Из того, что я пока узнал:

Есть API для создания, чтения и записи стримов - это функции SHCreateMemStream, IStream_Write, IStream_Read и IStream_Size. Это конечно очень интересно всё, но я не нашёл функции для позиционирования IStream_Seek (её что не существует?).

Есть возможность управлять стримами через объявления в TLB, однако мне эта тема не интересна, так как я не люблю подключать всякие там TLB.

Есть возможность управлять потоками IStream через специальную функцию DispCallByVtbl

Хотелось бы подробно разобрать эту тему и научиться:

1. Создавать поток IStream
2. Записывать
3. Считывать
4. Позиционировать
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
16.11.2024, 18:08
Ответы с готовыми решениями:

Как работать с камерой в Visual Basic
Как сделать прогу чтобы в ней отображалось то шо я снимаю и возможно было менять настройки камеры (яркость, гамма, контрасность,...

Как работать в Visual Basic'е с реестром?
Народ, может кто подскажет, как работать в Visual Basic'е с реестром?

Как работать с таблицами Ecxel в Visual Basic?
Как работать с таблицами Ecxel в Visual Basic?

206
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
16.01.2025, 16:07
Студворк — интернет-сервис помощи студентам
HackerVlad, я к тому что для сохранения в png через GDI+ не нужна tlb.
0
Вернулся
 Аватар для HackerVlad
1751 / 647 / 45
Регистрация: 10.09.2021
Сообщений: 2,800
16.01.2025, 16:57  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
я к тому что для сохранения в png через GDI+ не нужна tlb.
Ну хорошо, ладно
Но без костылей ты никак не сохранишь картинку в файл с юникодным именем. Твой GDI Plus API с таким же самым успехом тоже можно назвать костылями)

Добавлено через 46 секунд
Хотя вариант через GDI Plus API будет лучше тем, что он так же будет работать и в XP, я уже думал об этом кстати, я про PNG

Добавлено через 43 минуты
Кстати функцию SHCreateStreamOnFileEx можно будет применить для своей самописной функции SavePicture и назвать её например SavePictureEx
0
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
16.01.2025, 17:02
Цитата Сообщение от HackerVlad Посмотреть сообщение
Но без костылей ты никак не сохранишь картинку в файл с юникодным именем. Твой GDI Plus API с таким же самым успехом тоже можно назвать костылями)
GDI+ только с юникодом и работает. Костыли - это использование магических констант, позднего связывания, библиотеки для работы с БД, только для того чтобы сохранить PNG картинку в файл.
0
Вернулся
 Аватар для HackerVlad
1751 / 647 / 45
Регистрация: 10.09.2021
Сообщений: 2,800
16.01.2025, 18:49  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
магических констант
полностью согласен, это костыль костылём. А вот CreateObject("ADODB.Stream") я не назову костылём, как ты.

Добавлено через 42 минуты
В общем я создал свою функцию для сохранения картинок в юникоде. Всё вроде хорошо, но происходит какое-то чудо. Файл появляется, и в нём вродебы сохраняется картинка, но он 0 байт! Почему-то 0 байт, пока не закроешь программу или пока не откроешь какой-нибудь просмотрщик изображений с этой картинкой. Просто чудеса да и только:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Option Explicit
Private Declare Function SHCreateStreamOnFileEx Lib "shlwapi" (ByVal pszFile As Long, ByVal grfMode As Long, ByVal dwAttributes As Long, ByVal fCreate As Long, ByVal pstmTemplate As Long, ByRef ppstm As Long) As Long
 
Private Const STGM_WRITE As Long = 1
Private Const STGM_CREATE As Long = &H1000
 
Public Function SavePictureEx(pPic As IPicture, ByVal FileName As String) As Boolean
    Dim IStreamPtr As Long
    
    SHCreateStreamOnFileEx StrPtr(FileName), STGM_CREATE Or STGM_WRITE, 0, 0, 0, IStreamPtr
    pPic.SaveAsFile ByVal IStreamPtr, True, 0 ' Записать в поток картинку Picture с формы, сохраняя данные в BMP-формате
End Function
 
Private Sub Command1_Click()
    SavePictureEx Me.Picture, App.Path & "\test_picture " & ChrW(&H88E7) & ".bmp"
End Sub
Добавлено через 2 минуты
Как работают эти файловые потоки я не понимаю, может что-то надо почистить за собой где-то?

Добавлено через 2 минуты
Может надо как-то закрывать этот файловый поток за собой?

Добавлено через 7 минут
Поток не освобождается скорее всего в моём дурацком коде...
0
Вернулся
 Аватар для HackerVlad
1751 / 647 / 45
Регистрация: 10.09.2021
Сообщений: 2,800
16.01.2025, 18:59  [ТС]
Всё! Я понял! И правда, объект должен освобождаться для того чтобы файл не висел как 0 байт! Вот такой вот код правильный и будет работать как надо. Тут реализована идея автоматического освобождения объекта IStream за собой, внутренними фишками VB6. Переписал код для этого на ориентацию объектную, а не как указатель. Вот так теперь пишу Dim fIStream As IUnknown и этот объект IUnknown сам за собой автоматически освобождается, даже без использования дополнительных усилий таких как Set fIStream = Nothing эта строчка кода уже была бы лишняя :-) Ура! Теперь всё работает как надо!

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Option Explicit
Private Declare Function SHCreateStreamOnFileEx Lib "shlwapi" (ByVal pszFile As Long, ByVal grfMode As Long, ByVal dwAttributes As Long, ByVal fCreate As Long, ByVal pstmTemplate As IUnknown, ByRef ppstm As IUnknown) As Long
 
Private Const STGM_WRITE As Long = 1
Private Const STGM_CREATE As Long = &H1000
 
Public Function SavePictureEx(pPic As IPicture, ByVal FileName As String) As Boolean
    Dim fIStream As IUnknown
    
    SHCreateStreamOnFileEx StrPtr(FileName), STGM_CREATE Or STGM_WRITE, 0, 0, Nothing, fIStream
    pPic.SaveAsFile ByVal ObjPtr(fIStream), True, 0 ' Записать в поток (файл) картинку Picture, сохраняя данные в BMP-формате
End Function
 
Private Sub Command1_Click()
    SavePictureEx Me.Picture, App.Path & "\test_picture " & ChrW(&H88E7) & ".bmp"
End Sub
Этот пост будет отвечать на вопрос как сохранить картинку, кодом на VB6, в файл с юникодным именем.
Вложения
Тип файла: zip SavePictureEx.zip (162.2 Кб, 0 просмотров)
0
Вернулся
 Аватар для HackerVlad
1751 / 647 / 45
Регистрация: 10.09.2021
Сообщений: 2,800
16.01.2025, 22:06  [ТС]
Зато я нашёл применение функции SHCreateStreamOnFileEx а так я не знал, для чего она нужна вообще)))

Добавлено через 1 час 57 минут
Я очень долго думал над технологией The Trick и очень долго ломал голову над этим вот кодом:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Private Function CastObj(ByVal pObj As Long, ByVal pIID As Long, ByVal ppObj As Long) As Long
    Dim pCast As Long
    On Error GoTo error_handler
    
    pCast = vbaCastObj(ByVal pObj, ByVal pIID)
    
    'MsgBox pObj, vbCritical
    'MsgBox pCast, vbCritical
    
    PutMem4 ByVal ppObj, pCast
    
    Exit Function
    
error_handler:
    CastObj = Err.Number
End Function
Я пытался написать для себя код, без этой вспомогательной функции, потом понял что это невозможно. Скорее всего параметр внутри функции CastObj автоматически сэтит и не перепишешь код так чтобы не использовать эту доп. функцию, а это неудобно, потом я придумал другую идею не использовать тогда PutMem4 вообще и не клонировать объект, а просто долбануть IUnknown_AtomicRelease да и всё дело и не мучиться с освобождением памяти в автоматическом русле...

Итого я сейчас написал вот такой вот новый код:

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
Option Explicit
Private Declare Function vbaCastObj Lib "msvbvm60" Alias "__vbaCastObj" (ByRef cObj As Any, ByRef pIID As Any) As Long
Private Declare Sub IUnknown_AtomicRelease Lib "shlwapi" Alias "#169" (ppUnk As Any)
 
Private Sub Command1_Click()
    Dim ADOStream As Object
    
    Set ADOStream = CreateObject("ADODB.Stream")
    
    ' Открыть поток в бинарном режиме (аналог SHCreateMemStream)
    ADOStream.Type = 1 ' adTypeBinary
    ADOStream.Open
    
    ' Извлечь объект IStream из объекта ADODB.Stream
    Dim bIID_IStream(3) As Long
    Dim pCast As Long
    
    bIID_IStream(0) = &HC
    bIID_IStream(2) = &HC0
    bIID_IStream(3) = &H46000000
    
    pCast = vbaCastObj(ByVal ObjPtr(ADOStream), bIID_IStream(0))
    
    ' Теперь попробуем что-нибудь записать в поток, например картинку с формы
    Dim pPic As IPicture
    
    Set pPic = Me.Picture
    pPic.SaveAsFile ByVal ObjPtr(ADOStream) + (pCast - ObjPtr(ADOStream)), True, 0 ' Записать в поток картинку Picture с формы, сохраняя данные в BMP-формате
    
    ' Теперь попробуем узнать сколько байтов занимает этот поток
    Debug.Print "Поток занимает: " & ADOStream.Size & " байт"
    
    If ADOStream.Size > 0 Then
        ' Потом этот поток, можно сохранить в файл на диске, например, здесь работает даже юникод
        ADOStream.SaveToFile App.Path & "\test_picture " & ChrW(&H88E7) & ".bmp", 2 ' adSaveCreateOverWrite
    End If
    
    IUnknown_AtomicRelease pCast
End Sub
Это новая комбинация функций получилась теперь vbaCastObj + IUnknown_AtomicRelease

Добавлено через 2 минуты
Таким образом тут получилась очень интересная формула вычисления правильного смещения где pCast - ObjPtr(ADOStream) является тем самым заветным магическим числом, только эта магия уже будет срабатывать во всех версиях Windows)))

Добавлено через 3 минуты
Это профессиональный костыль уже)))) The trick будет в восторге)))

Добавлено через 5 минут
Или вот так вот ещё можно написать:

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
Option Explicit
Private Declare Function vbaCastObj Lib "msvbvm60" Alias "__vbaCastObj" (ByRef cObj As Any, ByRef pIID As Any) As Long
Private Declare Sub IUnknown_AtomicRelease Lib "shlwapi" Alias "#169" (ppUnk As Any)
 
Private Sub Command1_Click()
    Dim ADOStream As Object
    
    Set ADOStream = CreateObject("ADODB.Stream")
    
    ' Открыть поток в бинарном режиме (аналог SHCreateMemStream)
    ADOStream.Type = 1 ' adTypeBinary
    ADOStream.Open
    
    ' Извлечь объект IStream из объекта ADODB.Stream
    Dim bIID_IStream(3) As Long
    Dim pCast As Long
    Dim MagicNumber As Long
    
    bIID_IStream(0) = &HC
    bIID_IStream(2) = &HC0
    bIID_IStream(3) = &H46000000
    
    pCast = vbaCastObj(ByVal ObjPtr(ADOStream), bIID_IStream(0))
    MagicNumber = pCast - ObjPtr(ADOStream) ' То самое заветное магическое число! Ура! Теперь для всех версий Windows!
    IUnknown_AtomicRelease pCast
    
    ' Теперь попробуем что-нибудь записать в поток, например картинку с формы
    Dim pPic As IPicture
    
    Set pPic = Me.Picture
    pPic.SaveAsFile ByVal ObjPtr(ADOStream) + MagicNumber, True, 0 ' Записать в поток картинку Picture с формы, сохраняя данные в BMP-формате
    
    ' Теперь попробуем узнать сколько байтов занимает этот поток
    Debug.Print "Поток занимает: " & ADOStream.Size & " байт"
    
    If ADOStream.Size > 0 Then
        ' Потом этот поток, можно сохранить в файл на диске, например, здесь работает даже юникод
        ADOStream.SaveToFile App.Path & "\test_picture " & ChrW(&H88E7) & ".bmp", 2 ' adSaveCreateOverWrite
    End If
End Sub
Добавлено через 33 секунды
Утечки памяти быть не должно здесь)

Добавлено через 6 минут
vbaCastObj + IUnknown_AtomicRelease это очень интересный вариант, который теперь даже будет конкурировать с комбинацией функций SHWeakQueryInterface + SHWeakReleaseInterface, очень мало строк кода потому что получилось, благодаря моим стараниям)

Добавлено через 1 минуту
Мне этот вариант прям понравился, который я написал сейчас)))
0
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
16.01.2025, 23:22
От такого кода точно в восторге не буду, тут даже не зная программирования, чисто логически можно понять что это все лишнее:
Visual Basic
1
2
3
MagicNumber = pCast - ObjPtr(ADOStream)
... 
pPic.SaveAsFile ByVal ObjPtr(ADOStream) + MagicNumber, True, 0
Теперь вместо MagicNumber подставляй pCast - ObjPtr(ADOStream)
В итоге все можно переписать в 1 строчку, а используя правильную типизацию вообще обойтись без ручного управления ссылками:
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
Option Explicit
 
Private Declare Function vbaCastObj Lib "msvbvm60" Alias "__vbaCastObj" (ByVal cObj As Object, ByRef pIID As Any) As IUnknown
 
Private Sub Command1_Click()
    Dim ADOStream As Object
    
    Set ADOStream = CreateObject("ADODB.Stream")
    
    ' Открыть поток в бинарном режиме (аналог SHCreateMemStream)
    ADOStream.Type = 1 ' adTypeBinary
    ADOStream.Open
 
    ' Теперь попробуем что-нибудь записать в поток, например картинку с формы
    Dim pPic As IPicture
    
    Set pPic = Me.Picture
    
    ' Извлечь объект IStream из объекта ADODB.Stream
    Dim bIID_IStream(1) As Currency
 
    bIID_IStream(0) = 0.0012@
    bIID_IStream(1) = 504403158265495.5712@
 
    pPic.SaveAsFile ByVal ObjPtr(vbaCastObj(ByVal ADOStream, bIID_IStream(0))), True, 0      ' Записать в поток картинку Picture с формы, сохраняя данные в BMP-формате
    
    ' Теперь попробуем узнать сколько байтов занимает этот поток
    Debug.Print "Поток занимает: " & ADOStream.Size & " байт"
    
    If ADOStream.Size > 0 Then
        ' Потом этот поток, можно сохранить в файл на диске, например, здесь работает даже юникод
        ADOStream.SaveToFile App.Path & "\test_picture " & ChrW(&H88E7) & ".bmp", 2 ' adSaveCreateOverWrite
    End If
    
End Sub
2
Вернулся
 Аватар для HackerVlad
1751 / 647 / 45
Регистрация: 10.09.2021
Сообщений: 2,800
17.01.2025, 01:05  [ТС]
Великолепно! Браво! А как же освобождение памяти? Как оно тут работает?

Добавлено через 18 минут
Мне кстати очень понравилось, что ты тут решил сэкономить одну строчку кода и преобразовал массив Long в Currency значения) Ну теперь это супер-профессиональный костыль! Ура! Найден супер код)))

Добавлено через 4 минуты
Цитата Сообщение от The trick Посмотреть сообщение
As IUnknown
Я кстати тоже думал делать это объявление как As IUnknown пробовал даже но у меня что-то не вышло как я хотел, а вспомнил, у меня память не освобождалась там чего не так сделал...

Добавлено через 3 минуты
Я что-то такое как раз и хотел сделать компактное, сегодня весь день об этом мечтал, мучился, пробовал, почти получилось у меня и почти допёр но не смог а вот ты как раз сделал то что надо! Большое тебе спасибо огромное при огромное)))))))

Добавлено через 1 минуту
Вариант с PutMem4 и отдельной функцией мне кстати сразу не понравился а вот тут прям то что надо!!!!!

Добавлено через 46 минут
Код сохранения в PNG теперь получился такой вот компактный:

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
Option Explicit
Private Declare Function vbaCastObj Lib "msvbvm60" Alias "__vbaCastObj" (ByVal cObj As Object, ByRef pIID As Any) As IUnknown
 
Public Function SaveAsPng(ByVal pPic As IPicture) As Byte()
    Dim ADOStream As Object
    Dim WIAImageFile As Object
    Dim bIID_IStream(1) As Currency ' IStreamGUID
    
    Do While WIAImageFile Is Nothing
        Set ADOStream = CreateObject("ADODB.Stream")
        
        ADOStream.Type = 1 ' adTypeBinary
        ADOStream.Open
        
        ' Extract an IStream object from an ADODB.Stream object
        bIID_IStream(0) = 0.0012@
        bIID_IStream(1) = 504403158265495.5712@
        
        pPic.SaveAsFile ByVal ObjPtr(vbaCastObj(ByVal ADOStream, bIID_IStream(0))), True, 0
        
        If ADOStream.Size > 0 Then
            ADOStream.Position = 0
            
            With CreateObject("WIA.Vector")
                .BinaryData = ADOStream.Read
                
                If pPic.Type <> vbPicTypeBitmap Then
                    Set pPic = .Picture ' This converts pPic to vbPicTypeBitmap subtype
                Else
                    Set WIAImageFile = .ImageFile
                End If
            End With
        End If
    Loop
    
    ' Serialize WIA.ImageFile to PNG file format
    With CreateObject("WIA.ImageProcess")
        .Filters.Add .FilterInfos("Convert").FilterID
        .Filters(.Filters.Count).Properties("FormatID").Value = "{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}" ' wiaFormatPNG
        SaveAsPng = .Apply(WIAImageFile).FileData.BinaryData
    End With
End Function
 
Private Sub Command1_Click()
    Dim FileNo As Integer
    Dim bArray() As Byte
    
    bArray = SaveAsPng(Me.Picture)
    Debug.Print UBound(bArray)
    
    FileNo = FreeFile
    On Error Resume Next: Kill App.Path & "\test.png"
    Open App.Path & "\test.png" For Binary As FileNo
        Put #FileNo, , bArray
    Close FileNo
End Sub
Добавлено через 53 секунды
Хотя такой же код можно было бы сделать чтобы стрим сразу в файл сохранялся кстати и юникод тогда поддерживался бы в имени файла...
1
1406 / 865 / 93
Регистрация: 08.02.2017
Сообщений: 3,694
Записей в блоге: 2
17.01.2025, 02:08
Цитата Сообщение от HackerVlad Посмотреть сообщение
bIID_IStream(0) = 0.0012@
bIID_IStream(1) = 504403158265495.5712@
pPic.SaveAsFile ByVal ObjPtr(vbaCastObj(ByVal ADOStream, bIID_IStream(0))), True, 0
Тут какая-то магия происходит. Как я понял, vbaCastObj "достает" из AdoStream обджект IStream, но возвращает IUnknown объекта IStream. Вопрос, а ObjPtr тут обязателен?
0
Вернулся
 Аватар для HackerVlad
1751 / 647 / 45
Регистрация: 10.09.2021
Сообщений: 2,800
17.01.2025, 02:58  [ТС]
testuser2, да, ты всё правильно понял, ObjPtr обязателен да, я проверял в SaveAsFile нельзя напрямую передать объект, так что ByVal ObjPtr там обязателен

Добавлено через 3 минуты
Цитата Сообщение от testuser2 Посмотреть сообщение
bIID_IStream(0) = 0.0012@
bIID_IStream(1) = 504403158265495.5712@
Вот в этих двух строчках знаешь какая магия происходит? Записывается GUID объекта IStream. В строке он выглядел бы как "{0000000C-0000-0000-C000-000000000046}"

Добавлено через 34 секунды
Этот GUID это постоянная константа, которая слава Богу, подходит для всех версий Windows

Добавлено через 13 минут
testuser2, самое главное, что этот код полностью совместим с твоим любимым VBA, в отличии от кодов раннего связывания с использованием TLB, для работы с потоками IStream
0
1406 / 865 / 93
Регистрация: 08.02.2017
Сообщений: 3,694
Записей в блоге: 2
17.01.2025, 07:25
Цитата Сообщение от HackerVlad Посмотреть сообщение
Вот в этих двух строчках знаешь какая магия происходит? Записывается GUID объекта IStream. В строке он выглядел бы как "{0000000C-0000-0000-C000-000000000046}"
Я как бы так и подумал, но потом посчитал кол-во символов в строке, и получилось, что вроде строка больше чем 16 байт, 38 символов, ну х.з. может быть в строке какое-нибудь 16ричное представление.
Насчет ObjPtr я имел в виду, что если объявить функцию
Visual Basic
1
Private Declare Function vbaCastObjPtr Lib "msvbvm60" Alias "__vbaCastObj" (ByVal cObj As Object, ByRef pIID As Any) As Long
И использовать ее без ObjPtr? Самому мне лень проверять )
0
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
17.01.2025, 10:08
Цитата Сообщение от testuser2 Посмотреть сообщение
Как я понял, vbaCastObj "достает" из AdoStream обджект IStream, но возвращает IUnknown объекта IStream
Она запрашивает IStream, но т.к. нет TLB просто кастуем к IUnknown т.к. любой COM интерфейс наследуется от IUnknown. С TLB можно указать тип возвращаемого как IStream.

Цитата Сообщение от testuser2 Посмотреть сообщение
Я как бы так и подумал, но потом посчитал кол-во символов в строке, и получилось, что вроде строка больше чем 16 байт, 38 символов, ну х.з. может быть в строке какое-нибудь 16ричное представление.
GUID - Это всегда 4 Long'a. А строковое представление сделано чисто для человека.

Цитата Сообщение от testuser2 Посмотреть сообщение
Насчет ObjPtr я имел в виду, что если объявить функцию
Тогда она не освободит возвращенный объект т.к. возвращаемое значение с типом Long. Делая возвращаемое значение объектным - заставляет вызывать IUnknown::Release при выходе из функции.
2
 Аватар для Mikle Quits
787 / 308 / 17
Регистрация: 21.01.2023
Сообщений: 530
17.01.2025, 10:38
Цитата Сообщение от The trick Посмотреть сообщение
GUID - Это всегда 4 байта
В смысле 4 int32.
2
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
17.01.2025, 10:39
Mikle Quits, да) исправил.
0
1406 / 865 / 93
Регистрация: 08.02.2017
Сообщений: 3,694
Записей в блоге: 2
17.01.2025, 12:11
Цитата Сообщение от The trick Посмотреть сообщение
Тогда она не освободит возвращенный объект т.к. возвращаемое значение с типом Long. Делая возвращаемое значение объектным - заставляет вызывать IUnknown::Release при выходе из функции.
Но это ведь не простой момент, сам объект то (IStream), qявляется частью другого объекта ADOStream, но в то же время, он здесь как бы самостоятельный и его нужно "освободить"
Насчет "волшебства" еще не все.
Visual Basic
1
pPic.SaveAsFile ByVal ObjPtr(vbaCastObj(ADOStream, bIID_IStream(0))), True, 0
Здесь в объектном методе требуется аргумент - указатель, что встречается не так часто у ком-объектов. Я потрудился, посмотрел, там метод принимает Any (ай-яй как не безопасно оО, поэтому наверное он скрытый), стало быть, можно все-таки обойтись без ObjPtr?
Изображения
 
0
1406 / 865 / 93
Регистрация: 08.02.2017
Сообщений: 3,694
Записей в блоге: 2
17.01.2025, 13:16
Цитата Сообщение от HackerVlad Посмотреть сообщение
bIID_IStream(0) = 0.0012@
bIID_IStream(1) = 504403158265495.5712@
Вот в этих двух строчках знаешь какая магия происходит? Записывается GUID объекта IStream. В строке он выглядел бы как "{0000000C-0000-0000-C000-000000000046}"
Так выглядит Hex-представление
Code
1
46000000C00000000C
1
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
17.01.2025, 13:20
Цитата Сообщение от testuser2 Посмотреть сообщение
Но это ведь не простой момент, сам объект то (IStream), qявляется частью другого объекта ADOStream, но в то же время, он здесь как бы самостоятельный и его нужно "освободить"
Нет. Это просто интерфейсная ссылка одного и того же объекта. Вот при Set ADOStream = CreateObject("ADODB.Stream") у нас счетчик ссылок на объект образно становится в 1, указывая объекту что на него есть 1 ссылка в лице переменной ADOStream. Далее когда мы вызываем vbaCastObj то делаем ADODB.Stream::QueryInterface (IID_IStream, &pStm) соответственно счетчик ссылок объекта ADODB.Stream увеличивается и становится равным 2 и теперь мы ссылаемся на тот же самый объект 2-мя переменными ADOStream и pStm, где pStm - временная переменная создаваемая VB6 в качестве возвращаемого значения функции vbaCastObj. После выхода из функций VB6 автоматически очищает все нескалярные переменные (массивы, строки и объекты). Соответственно при выходе из метода автоматом вызываются ADOStream::Release и pStm::Release, обнуляя счетчик ссылок и удаляя объект. Сделав возвращаемое значение vbaCastObj As Long, мы соответственно не освобождаем ссылку на pStm, хотя можем это сделать вручную через vbaObjSet к примеру. Только это ни к чему если мы и так имеем механизм автоматического освобождения интерфейсных ссылок.

Цитата Сообщение от testuser2 Посмотреть сообщение
Здесь в объектном методе требуется аргумент - указатель, что встречается не так часто у ком-объектов. Я потрудился, посмотрел, там метод принимает Any (ай-яй как не безопасно оО, поэтому наверное он скрытый), стало быть, можно все-таки обойтись без ObjPtr?
Проблема в том что в этому случае нельзя передать ByVal Obj - VB6 передает ByRef и соответственно ничего не получится.
1
1406 / 865 / 93
Регистрация: 08.02.2017
Сообщений: 3,694
Записей в блоге: 2
17.01.2025, 13:25
Цитата Сообщение от The trick Посмотреть сообщение
Проблема в том что в этому случае нельзя передать ByVal Obj - VB6 передает ByRef и соответственно ничего не получится.
Почему нельзя ведь объект же можно передавать ByVal?

Добавлено через 1 минуту
Функция получения hex-маски
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
Function GetHexMaskS(ByVal Ptr As LongPtr, ByVal Size As Long)
    Dim i&, bAr() As Byte, sOut$, sTmp$, pos&
    ReDim bAr(Size - 1)
    CopyMemory bAr(0), ByVal Ptr, Size
    sOut = Space(256)
    pos = 1
    For i = UBound(bAr) To 0 Step -1
        sTmp = Hex(bAr(i))
        Mid$(sOut, pos) = sTmp
        pos = pos + Len(sTmp) '+ 1
    Next
    GetHexMaskS = Mid$(sOut, 1, pos - 1)
End Function
0
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
17.01.2025, 13:29
Вот пример проблемы:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Option Explicit
 
Private Declare Function aaa Lib "msvbvm60" Alias "VarPtr" (ByRef p As Any) As Long
Private Declare Function bbb Lib "msvbvm60" Alias "VarPtr" (ByVal p As Any) As Long
Private Declare Function ccc Lib "msvbvm60" Alias "VarPtr" (ByRef p As IUnknown) As Long
Private Declare Function ddd Lib "msvbvm60" Alias "VarPtr" (ByVal p As IUnknown) As Long
 
Private Sub Form_Load()
 
    Debug.Print "VarPtr: "; Hex$(VarPtr(Me)); " ObjPtr: "; Hex$(ObjPtr(Me))
    
    Debug.Print "ByRef Any:                   "; Hex$(aaa(Me))        ' // ByRef
    Debug.Print "ByRef Any (with ByVal):      "; Hex$(aaa(ByVal Me))  ' // ByRef
    Debug.Print "ByVal Any:                   "; Hex$(bbb(Me))        ' // ByVal
    Debug.Print "ByVal Any (with ByVal):      "; Hex$(bbb(ByVal Me))  ' // ByVal
    Debug.Print "ByRef IUnknown:              "; Hex$(ccc(Me))        ' // ByRef
    Debug.Print "ByRef IUnknown (with ByVal): "; Hex$(ccc(ByVal Me))  ' // ByVal
    Debug.Print "ByVal IUnknown:              "; Hex$(ddd(Me))        ' // ByVal
    Debug.Print "ByVal IUnknown (with ByVal): "; Hex$(ddd(ByVal Me))  ' // ByVal
    
End Sub
Правильнее было бы сделать второй вариант с передачей ByVal, но VB6 по тем или иным причинам передает ByRef.
2
1406 / 865 / 93
Регистрация: 08.02.2017
Сообщений: 3,694
Записей в блоге: 2
17.01.2025, 14:13
Цитата Сообщение от The trick Посмотреть сообщение
VB6 по тем или иным причинам передает ByRef.
Йа не понимаю какие могут быть "причины", имхо это как-то не правильно и отходит от той парадигмы, где все должно быть правильно..
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.01.2025, 14:13

Можно ли научится работать ASP.NET на основе Visual Basic
Всем доброго времени суток. Немножко владею навыками создавть и писать программы на VS 2010 на основе Visual Basic-a, можно ли научится...

Где бесплатно скачать учебник по Visual Basic 6 и Visual Basic .Net ?
Где бесплатно скачать учебник по Visual Basic 6 и Visual Basic .Net

Вычисление значений функции двух переменных в Visual Basic - Visual Basic
Помогите пожалуйста! В среде VB написать программу вычисления значений функции двух переменных. Ориентировочный вид окна программы и...

Как быстро работать с комбинациями стилей текста(жирный, курсив, жирный + курсив и т. д.) в Visual Basic?
Здравствуйте. Я учусь в университете, нам задали написать текстовый редактор. Я использую RichTextBox и мне нужно, чтобы я по нажатию...

Как работать с потоками?
Как создать поток? Как его стартануть? В какой он библиотеке? И вообще, как он называется? Когда гуглю, находится много информации про...


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

Или воспользуйтесь поиском по форуму:
140
Ответ Создать тему
Новые блоги и статьи
Теория всего 12. ВГК
anaschu 21.07.2026
### Главные семантические изменения и дешифровка новой физики 1. **`REPRODUCTIVE_EMISSION` вместо фотосинтеза (`PS_base`)**: Энергия и ресурсы, которые класс средних мужчин (`_W_MEN_DONORS`). . .
Публикация отклонённая на хабре. Как «пернатого» заставить осваивать новые горизонты опыта через масштабирование задачи и целеполагание
Hrethgir 21.07.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11948&stc=1&d=1784657928 Привет Хабр. В этой статье я расскажу, как один закон эпистемологии позволил мне с ходу запустить уникальный. . .
Теория всего 11. Основные параметры
anaschu 21.07.2026
Дешифровка тензорного ядра Soil Chemistry 2. 0: Истинный инвариант Теории Всего Чистовой исходный код многокомпонентной сукцессии зафиксирован. Модель оперирует единым вектором состояния. . .
Теория всего 10. Клод трусишка
anaschu 21.07.2026
Алгоритмический суицид ИИ: Когда математика ОДУ взламывает цензурные шлюзы Свежайший мета-прецедент нашей разработки! Клод официально отказался строить итоговую кроссплатформенную модель, как. . .
Теория всего 9. Окончательная проработка метафоры "дерево = традиции"
anaschu 21.07.2026
Скрытые параметры ядра ОДУ: Механика Глубинного Рока Клод утаил от вас ключевую математику кризисов. В движке игры зашиты пять скрытых коэффициентов, определяющих, как именно ТНК и Мемы ломают. . .
Теория всего 8. Clauude трусишка. Ответ джемени
anaschu 21.07.2026
Игровой баланс «Модели Всего»: Алгоритмический блок как механика Семантического БуфераЭтот скриншот отказа Клода — идеальный, чистейший прецедент для нашей Теории Всего. Вы столкнулись не просто с. . .
Теория всего 7. Дерево - это патриархат, грибы - это феминизм
anaschu 21.07.2026
Уничтожение Патриархата: Как ТНК, Мемы и Половой отбор зачистили «Сексуальный Пролетариат» Величайшая иллюзия современного человека — вера в «свободу воли», «социальный прогресс» и «эволюцию. . .
История и социология Терры на примере борьбы микориз за пространство. 1. Глоссарий терры.
anaschu 21.07.2026
Решил тут подумать о возможности сделать лор некоторой комп игры - стратегии, или худжественной книги антиутопии, которые будут юзать планету,которая максимально будет похожа на нашу землю, но где. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru