Модератор: Mikle
arthur2 писал(а):Я так понимаю, что в спрайте не предусмотрена загрузка картинок из массива. Как бы её прикрутить?
Изначально была задача - ну хоть как-нибудь Хотя, конечно, лучше первоеMikle писал(а):А он прочитан как целый файл (с заголовком, кодированием и т. п.), или как готовые данные ARGB?
Public Sub LoadFromBytes(Bytes() As Byte, Optional ByVal Trans As SR2D_Transform = TrNone, Optional ByVal W As Long = 0, Optional ByVal H As Long = 0, Optional ByVal cKey As Long = -1)
Dim Res As Long
Dim Stream As IUnknown
Dim tSI As GdiplusStartupInput
Dim GDIP As Long
Dim Bmp As Long
Dim lData As BitmapData
Dim R As RECTL
Dim x As Long, y As Long
Dim Sp As SR2D_Sprite
If Trans <> TrNone Or W > 0 Or H > 0 Then
Set Sp = New SR2D_Sprite
Sp.LoadFromBytes Bytes
LoadFromSprite Sp, Trans, W, H, cKey
Else
tSI.GdiplusVersion = 1
Res = GdiplusStartup(GDIP, tSI)
If Res = 0 Then
CreateStreamOnHGlobal Bytes(0), False, Stream
Res = GdipLoadImageFromStream(Stream, Bmp)
If Res = 0 Then
GdipGetImageWidth Bmp, x
GdipGetImageHeight Bmp, y
R.Left = 0
R.Right = x
R.Top = 0
R.Bottom = y
Res = GdipBitmapLockBits(Bmp, R, ImageLockModeRead, PixelFormat32bppARGB, lData)
If Res = 0 Then
Init x, y, OpPaint
CopyMemory ByVal lData.Scan0, cBuf(0), x * y * 4
GdipBitmapUnlockBits Bmp, lData
If cKey >= 0 Then AddColorKey cKey: Op = OpAlphaTest
End If
GdipDisposeImage Bmp
End If
Set Stream = Nothing
GdiplusShutdown GDIP
End If
End If
End Sub
всё ли правильно
Собственно, я тут и не писал ничего - функция твоя, вставка вместе с названием - из кирпича от Andrey Fedorov.Mikle писал(а):только это я бы и назвал LoadFromFileInMemory
Но ведь код работает. Почему, если передано не то? А чем проще SHCreateMemStream?The trick писал(а): Если нужно передать указатель то проще вызвать SHCreateMemStream.
В эту часть я не вникал - код из оригинала. КопиМемери тоже оригинальная - из SR2D.dllThe trick писал(а):GdipBitmapLockBits позволяет передать буфер, так что можно обойтись без CopyMemory (кстати в котором тоже ошибка - перепутаны dst/src).
The trick писал(а):CopyMemory (кстати в котором тоже ошибка - перепутаны dst/src)
arthur2 писал(а):Но ведь код работает. Почему, если передано не то? А чем проще SHCreateMemStream?
arthur2 писал(а):В эту часть я не вникал - код из оригинала. КопиМемери тоже оригинальная - из SR2D.dll
' //
' // Load picture from memory
' //
Public Function LoadPictureFromMemory( _
ByVal pData As Long, _
ByVal lSize As Long) As StdPicture
Dim hMem As Long
Dim pLocData As Long
Dim pIStream As IUnknown
Dim hGdipImg As Long
Dim hDib As Long
Dim tRC As RECT
Dim tBI As BITMAPINFO
Dim hdc As Long
Dim pBitsData As Long
Dim tBmpData As BitmapData
Dim IID_IPicture As UUID
Dim tPicDesc As PICTDESC
Dim cIPicture As IPicture
If Not InitializeGDIPlus() Then Exit Function
hMem = GlobalAlloc(GMEM_MOVEABLE, lSize)
If hMem = 0 Then GoTo CleanUp
pLocData = GlobalLock(hMem)
If pLocData = 0 Then GoTo CleanUp
CopyMemory ByVal pLocData, ByVal pData, lSize
GlobalUnlock hMem
If CreateStreamOnHGlobal(hMem, True, pIStream) Then GoTo CleanUp
If GdipLoadImageFromStream(pIStream, hGdipImg) Then GoTo CleanUp
If GdipGetImageWidth(hGdipImg, tRC.iRight) Then GoTo CleanUp
If GdipGetImageHeight(hGdipImg, tRC.iBottom) Then GoTo CleanUp
With tBI.bmiHeader
.biBitCount = 32
.biHeight = -tRC.iBottom
.biWidth = tRC.iRight
.biPlanes = 1
.biSize = Len(tBI.bmiHeader)
End With
hdc = GetDC(0)
If hdc = 0 Then GoTo CleanUp
hDib = CreateDIBSection(hdc, tBI, 0, tBmpData.scan0, 0, 0)
If hDib = 0 Then GoTo CleanUp
With tBmpData
.height = tRC.iBottom
.width = tRC.iRight
.PixelFormat = PixelFormat32bppPARGB
.stride = .width * 4
End With
If GdipBitmapLockBits(hGdipImg, tRC, ImageLockModeUserInputBuf Or _
ImageLockModeRead, PixelFormat32bppPARGB, tBmpData) Then GoTo CleanUp
If GdipBitmapUnlockBits(hGdipImg, tBmpData) Then GoTo CleanUp
IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID_IPicture
tPicDesc.cbSizeofstruct = Len(tPicDesc)
tPicDesc.hbitmap = hDib
tPicDesc.picType = vbPicTypeBitmap
If OleCreatePictureIndirect(tPicDesc, IID_IPicture, True, cIPicture) Then GoTo CleanUp
Set LoadPictureFromMemory = cIPicture
CleanUp:
If hdc Then ReleaseDC 0, hdc
If hGdipImg Then GdipDisposeImage hGdipImg
If Not pIStream Is Nothing Then
Set pIStream = Nothing
Else
GlobalFree hMem
End If
If LoadPictureFromMemory Is Nothing Then
If hDib Then DeleteObject hDib
End If
UninitializeGDIPlus
End Function
Но я ведь передаю не SA, а просто указатель на первый байт? Причем, нигде даже не передаю длину массива? Почему это работает?The trick писал(а):Нет никакой гарантии что SA память под массив будет корректно работать в качестве HGLOBAL
У тебя в коде ты выделяешь память, копируешь туда массив и передаёшь-таки в CreateStreamOnHGlobal именно HGLOBAL. Почему же не сделать проще с SHCreateMemStream? А можно как-то получить HGLOBAL на уже существующий блок памяти?The trick писал(а):Проще тем что сразу задает возможность задать правильную инициализацию.
Кстати, аналогичная функция есть и в MSVBVM60:Mikle писал(а):Тут CopyMemory из SR2D.dll. Я когда-то сделал и оставил потому, что, вроде бы, было быстрее, чем RtlMoveMemory.
Declare Sub CopyBytes Lib "MSVBVM60.DLL" Alias "__vbaCopyBytes" _
(ByVal Size As Long, Dest As Any, Source As Any) 'Аналогично RtlMoveMemory, но только для неперекрывающихся блоков
CreateStreamOnHGlobal ByVal LocalHandle(Bytes(0)), False, Stream
arthur2 писал(а):Но я ведь передаю не SA, а просто указатель на первый байт? Причем, нигде даже не передаю длину массива? Почему это работает?
The trick писал(а):У тебя в коде ты выделяешь память, копируешь туда массив и передаёшь-таки в CreateStreamOnHGlobal именно HGLOBAL. Почему же не сделать проще с SHCreateMemStream? А можно как-то получить HGLOBAL на уже существующий блок памяти?
arthur2 писал(а):Заменил на:Теперь правильно?
- Код: Выделить всё
CreateStreamOnHGlobal ByVal LocalHandle(Bytes(0)), False, Stream
Но мы ведь говорим не о произвольном блоке, а о массиве, выделенном бейсиком. Разве это не значит, что бейсик при создании массива уже все как нужно выделил а залочил?The trick писал(а):Произвольный блок может не принадлежать какой-либо куче.
Почему?The trick писал(а):Теперь правильно?
Нет.
arthur2 писал(а):Почему ты выделяешь именно перемещаемую память, а не фиксированную?
arthur2 писал(а):почему разлочиваешь блок до того, как перестал его использовать?
arthur2 писал(а):Но мы ведь говорим не о произвольном блоке, а о массиве, выделенном бейсиком. Разве это не значит, что бейсик при создании массива уже все как нужно выделил а залочил?
arthur2 писал(а):Почему?
Разве то, что LocalHandle/GlobalHandle вернула ненулевое значение, не означает, что блок, о котором речь, уже как нужно выделен и залочен? Ведь если передать не первый, а второй байт, они вернут-таки ноль. И если GlobalHandle почему-то возвращает недействительный хендл, то откуда тогда система при создании стрима знает длину блока?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 23