📄 modparsers.bas
字号:
If Not rtnRegion = 0& Then DeleteObject rtnRegion
Err.Clear
Else
iparseCreateShapedRegion = rtnRegion
End If
End Function
Private Function CreatePartialRegion(rgnRects() As RECT, lIndex As Long, uIndex As Long, leftOffset As Long, cX As Long) As Long
' Helper function for CreateShapedRegion & CreateWin98Region
' Called to create a region in its entirety or stepped (see CreateWin98Region)
On Error Resume Next
' Note: Ideally contiguous rectangles of equal height & width should be combined
' into one larger rectangle. However, thru trial & error I found that Windows
' does this for us and taking the extra time to do it ourselves
' is too cumbersome & slows down the results.
' the first 32 bytes of a region is the header describing the region.
' Well, 32 bytes equates to 2 rectangles (16 bytes each), so I'll
' cheat a little & use rectangles to store the header
With rgnRects(lIndex - 2) ' bytes 0-15
.Left = 32& ' length of region header in bytes
.Top = 1& ' required cannot be anything else
.Right = uIndex - lIndex + 1& ' number of rectangles for the region
.Bottom = .Right * 16& ' byte size used by the rectangles; can be zero
End With
With rgnRects(lIndex - 1&) ' bytes 16-31 bounding rectangle identification
.Left = leftOffset ' left
.Top = rgnRects(lIndex).Top ' top
.Right = leftOffset + cX ' right
.Bottom = rgnRects(uIndex).Bottom ' bottom
End With
' call function to create region from our byte (RECT) array
CreatePartialRegion = ExtCreateRegion(ByVal 0&, (rgnRects(lIndex - 2&).Right + 2&) * 16&, rgnRects(lIndex - 2&))
If Err Then Err.Clear
End Function
Private Function CreateWin98Region(rgnRects() As RECT, rectCount As Long, leftOffset As Long, cX As Long) As Long
' Fall-back routine when a very large region fails to be created.
' Win98 has problems with regional rectangles over 4000
' So, we'll try again in case this is the prob with other systems too.
' We'll step it at 2000 at a time which is stil very quick
Dim X As Long, Y As Long ' loop counters
Dim win98Rgn As Long ' partial region
Dim rtnRegion As Long ' combined region & return value of this function
Const RGN_OR As Long = 2&
Const scanSize As Long = 2000&
' we start with 2 'cause first 2 RECTs are the header
For X = 2& To rectCount Step scanSize
If X + scanSize > rectCount Then
Y = rectCount
Else
Y = X + scanSize
End If
' attempt to create partial region, scanSize rects at a time
win98Rgn = CreatePartialRegion(rgnRects(), X, Y, leftOffset, cX)
If win98Rgn = 0& Then ' failure
' cleaup combined region if needed
If Not rtnRegion = 0& Then DeleteObject rtnRegion
Exit For ' abort; system won't allow us to create the region
Else
If rtnRegion = 0& Then ' first time thru
rtnRegion = win98Rgn
Else ' already started
' use combineRgn, but only every scanSize times
CombineRgn rtnRegion, rtnRegion, win98Rgn, RGN_OR
DeleteObject win98Rgn
End If
End If
Next
' done; return result
CreateWin98Region = rtnRegion
End Function
Public Function iparseIsArrayEmpty(FarPointer As Long) As Long
' test to see if an array has been initialized
CopyMemory iparseIsArrayEmpty, ByVal FarPointer, 4&
End Function
Public Function iparseByteAlignOnWord(ByVal bitDepth As Byte, ByVal Width As Long) As Long
' function to align any bit depth on dWord boundaries
iparseByteAlignOnWord = (((Width * bitDepth) + &H1F&) And Not &H1F&) \ &H8&
End Function
Public Function iparseArrayToPicture(inArray() As Byte, Offset As Long, Size As Long) As IPicture
' function creates a stdPicture from the passed array
' Note: The array was already validated as not empty when calling class' LoadStream was called
Dim o_hMem As Long
Dim o_lpMem As Long
Dim aGUID(0 To 3) As Long
Dim IIStream As IUnknown
aGUID(0) = &H7BF80980 ' GUID for stdPicture
aGUID(1) = &H101ABF32
aGUID(2) = &HAA00BB8B
aGUID(3) = &HAB0C3000
o_hMem = GlobalAlloc(&H2&, Size)
If Not o_hMem = 0& Then
o_lpMem = GlobalLock(o_hMem)
If Not o_lpMem = 0& Then
CopyMemory ByVal o_lpMem, inArray(Offset), Size
Call GlobalUnlock(o_hMem)
If CreateStreamOnHGlobal(o_hMem, 1&, IIStream) = 0& Then
Call OleLoadPicture(ByVal ObjPtr(IIStream), 0&, 0&, aGUID(0), iparseArrayToPicture)
End If
End If
End If
End Function
Public Function iparseHandleToStdPicture(ByVal hImage As Long, ByVal imgType As Long) As IPicture
' function creates a stdPicture object from a image handle (bitmap or icon)
Dim lpPictDesc As PictDesc, aGUID(0 To 3) As Long
With lpPictDesc
.Size = Len(lpPictDesc)
.Type = imgType
.hHandle = hImage
.hPal = 0
End With
' IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
aGUID(0) = &H7BF80980
aGUID(1) = &H101ABF32
aGUID(2) = &HAA00BB8B
aGUID(3) = &HAB0C3000
' create stdPicture
Call OleCreatePictureIndirect(lpPictDesc, aGUID(0), True, iparseHandleToStdPicture)
End Function
Public Function iparseReverseLong(ByVal inLong As Long) As Long
' fast function to reverse a long value from big endian to little endian
' PNG files contain reversed longs
Dim b1 As Long
Dim b2 As Long
Dim b3 As Long
Dim b4 As Long
Dim lHighBit As Long
lHighBit = inLong And &H80000000
If lHighBit Then
inLong = inLong And Not &H80000000
End If
b1 = inLong And &HFF
b2 = (inLong And &HFF00&) \ &H100&
b3 = (inLong And &HFF0000) \ &H10000
If lHighBit Then
b4 = inLong \ &H1000000 Or &H80&
Else
b4 = inLong \ &H1000000
End If
If b1 And &H80& Then
iparseReverseLong = ((b1 And &H7F&) * &H1000000 Or &H80000000) Or _
b2 * &H10000 Or b3 * &H100& Or b4
Else
iparseReverseLong = b1 * &H1000000 Or _
b2 * &H10000 Or b3 * &H100& Or b4
End If
End Function
Public Function iparseValidateDLL(ByVal DllName As String, ByVal dllProc As String) As Boolean
' PURPOSE: Test a DLL for a specific function.
Dim LB As Long, pa As Long
'attempt to open the DLL to be checked
LB = LoadLibrary(DllName)
If LB Then
'if so, retrieve the address of one of the function calls
pa = GetProcAddress(LB, dllProc)
' free references
FreeLibrary LB
End If
iparseValidateDLL = (Not (LB = 0 Or pa = 0))
End Function
Public Function iparseValidateZLIB(ByRef DllName As String, ByRef Version As Long, _
ByRef isCDECL As Boolean, ByRef hasCompression2 As Boolean, _
Optional ByVal bTestOnly As Boolean) As Boolean
' PURPOSE: Test ZLib availability and calling convention.
' About zLIB. There are several versions ranging from v1.2.3 (latest) to v1.0.? (earliest).
' Zlib is used to compress/decompress PNG files, among other things.
' However, zLIB is written with C calling convention (cdecl) which is unusable with VB. There
' are other modified versions out there that were converted to stdcall calling convention which
' is what VB expects. But, we don't know the calling convention of the zLIB in advance, do we?
' Allowing VB to call cdecl directly results in crashes or invalid function returns. The class
' cCDECL is one created by Paul Caton that uses assembly to "wrap" the cdecl call into a stdcall.
' But we still need to know the calling convention so we know to use cCDECL or simple API calls.
Dim LB As Long, pa As Long
Dim asmVal As Integer
DllName = "zlib1.dll" ' test for newer version first
For Version = 2& To 1& Step -1&
LB = LoadLibrary(DllName) 'attempt to open the DLL to be checked
If LB Then
hasCompression2 = Not (GetProcAddress(LB, "compress2") = 0)
pa = GetProcAddress(LB, "crc32") ' retrieve the address of the "crc32" exported function
If Not pa = 0& Then
If bTestOnly Then Exit For
Do
' Note: this method will not work for every DLL, nor every function within a DLL.
' I have analyzed 5 versions of zlib (some cdecl, some stdcall) using disassemblers
' and am confident this will work for the crc32 function in all versions from v1.2.3 down.
' Looking for an exit code:
CopyMemory asmVal, ByVal pa, 1&
Select Case asmVal
Case &HC3 ' exit code, no stack clean up
CopyMemory asmVal, ByVal iparseSafeOffset(pa, -1&), 1&
If Not asmVal = &H33 Then ' else 0x33C3 is an XOR function, not exit code
isCDECL = True ' DLL uses cdecl calling convention, we use cCDECL
Exit For
End If
Case &HC2
CopyMemory asmVal, ByVal iparseSafeOffset(pa, 1&), 2&
If asmVal = &HC Then ' exit code with clean up of 12 bytes (the 3 crc32 parameters)
isCDECL = False ' DLL uses stdcall calling convention, we use APIs
Exit For
Else
asmVal = 0
End If
End Select
pa = iparseSafeOffset(pa, 1&)
Loop
End If
' unmap library
FreeLibrary LB
LB = 0&
hasCompression2 = False
End If
DllName = "zlib.dll" ' test for older version next, if necessary
Next Version
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -