modParsers.bas
上传用户:jnjasmy
上传日期:2015-01-04
资源大小:637k
文件大小:34k
源码类别:

GDI/图象编程

开发平台:

Visual Basic

  1. Attribute VB_Name = "modParsers"
  2. Option Explicit
  3. ' Module contains functions that are required by two or more classes.
  4. ' No APIs are declared public. This is to prevent possibly, differently
  5. ' declared APIs or different versions, of the same API, from conflciting
  6. ' with any APIs you declared in your project. Same rule for UDTs.
  7. Private Type SafeArrayBound
  8.     cElements As Long
  9.     lLbound As Long
  10. End Type
  11. Private Type SafeArray        ' used as DMA overlay on a DIB
  12.     cDims As Integer
  13.     fFeatures As Integer
  14.     cbElements As Long
  15.     cLocks As Long
  16.     pvData As Long
  17.     rgSABound(0 To 1) As SafeArrayBound
  18. End Type
  19. Private Type PictDesc
  20.     Size As Long
  21.     Type As Long
  22.     hHandle As Long
  23.     hPal As Long
  24. End Type
  25. Private Type RECT
  26.     Left As Long
  27.     Top As Long
  28.     Right As Long
  29.     Bottom As Long
  30. End Type
  31. Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (ByRef Ptr() As Any) As Long
  32. Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
  33. ' used to create a stdPicture from a byte array
  34. Private Declare Function CreateStreamOnHGlobal Lib "ole32" (ByVal hGlobal As Long, ByVal fDeleteOnRelease As Long, ppstm As Any) As Long
  35. Private Declare Function GlobalAlloc Lib "kernel32" (ByVal uFlags As Long, ByVal dwBytes As Long) As Long
  36. Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  37. Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  38. Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
  39. Private Declare Function OleLoadPicture Lib "olepro32" (pStream As Any, ByVal lSize As Long, ByVal fRunmode As Long, riid As Any, ppvObj As Any) As Long
  40. Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (lpPictDesc As PictDesc, riid As Any, ByVal fPictureOwnsHandle As Long, iPic As IPicture) As Long
  41. ' used to see if DLL exported function exists
  42. Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
  43. Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
  44. Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
  45. ' GDI32 APIs
  46. Private Declare Function CombineRgn Lib "gdi32.dll" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
  47. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
  48. Private Declare Function ExtCreateRegion Lib "gdi32" (lpXform As Any, ByVal nCount As Long, lpRgnData As Any) As Long
  49. Private Declare Function GetRegionData Lib "gdi32.dll" (ByVal hRgn As Long, ByVal dwCount As Long, ByRef lpRgnData As Any) As Long
  50. Private Declare Function GetRgnBox Lib "gdi32.dll" (ByVal hRgn As Long, ByRef lpRect As RECT) As Long
  51. Private Declare Function CreateRectRgn Lib "gdi32.dll" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
  52. ' User32 APIs
  53. Private Declare Function SetRect Lib "user32" (lpRect As RECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
  54. ' Kernel32/User32 APIs for Unicode Filename Support
  55. Private Declare Function CreateFileW Lib "kernel32" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
  56. Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
  57. Private Declare Function DeleteFileW Lib "kernel32.dll" (ByVal lpFileName As Long) As Long
  58. Private Declare Function DeleteFile Lib "kernel32.dll" Alias "DeleteFileA" (ByVal lpFileName As String) As Long
  59. Private Declare Function SetFileAttributesW Lib "kernel32.dll" (ByVal lpFileName As Long, ByVal dwFileAttributes As Long) As Long
  60. Private Declare Function SetFileAttributes Lib "kernel32.dll" Alias "SetFileAttributesA" (ByVal lpFileName As String, ByVal dwFileAttributes As Long) As Long
  61. Private Declare Function GetFileAttributesW Lib "kernel32.dll" (ByVal lpFileName As Long) As Long
  62. Private Declare Function GetFileAttributes Lib "kernel32.dll" Alias "GetFileAttributesA" (ByVal lpFileName As String) As Long
  63. Private Declare Function GetDesktopWindow Lib "user32.dll" () As Long
  64. Private Declare Function IsWindowUnicode Lib "user32.dll" (ByVal hwnd As Long) As Long
  65. Private Const FILE_ATTRIBUTE_NORMAL = &H80&
  66. Public Function iparseCreateShapedRegion(cHost As c32bppDIB, regionStyle As eRegionStyles) As Long
  67.     '*******************************************************
  68.     ' FUNCTION RETURNS A HANDLE TO A REGION IF SUCCESSFUL.
  69.     ' If unsuccessful, function retuns zero.
  70.     ' The fastest region from bitmap routines around, custom
  71.     ' designed by LaVolpe. This version modified to create
  72.     ' regions from alpha masks.
  73.     '*******************************************************
  74.     ' Note: See c32bppDIB.CreateRegion for description of the regionStyle parameter
  75.     
  76.     ' declare bunch of variables...
  77.     Dim rgnRects() As RECT ' array of rectangles comprising region
  78.     Dim rectCount As Long ' number of rectangles & used to increment above array
  79.     Dim rStart As Long ' pixel that begins a new regional rectangle
  80.     
  81.     Dim X As Long, Y As Long, Z As Long ' loop counters
  82.     
  83.     Dim bDib() As Byte  ' the DIB bit array
  84.     Dim tSA As SafeArray ' array overlay
  85.     Dim rtnRegion As Long ' region handle returned by this function
  86.     Dim Width As Long, Height As Long
  87.     Dim lScanWidth As Long ' used to size the DIB bit array
  88.     
  89.     ' Simple sanity checks
  90.     If cHost.Alpha = False Then
  91.         iparseCreateShapedRegion = CreateRectRgn(0&, 0&, cHost.Width, cHost.Height)
  92.         Exit Function
  93.     End If
  94.     
  95.     Width = cHost.Width
  96.     If Width < 1& Then Exit Function
  97.     Height = cHost.Height
  98.     If Height < 1& Then Exit Function
  99.     
  100.     On Error GoTo CleanUp
  101.       
  102.     lScanWidth = Width * 4& ' how many bytes per bitmap line?
  103.     With tSA                ' prepare array overlay
  104.         .cbElements = 1     ' byte elements
  105.         .cDims = 2          ' two dim array
  106.         .pvData = cHost.BitsPointer  ' data location
  107.         .rgSABound(0).cElements = Height
  108.         .rgSABound(1).cElements = lScanWidth
  109.     End With
  110.     ' overlay now
  111.     CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4&
  112.     
  113.     If regionStyle = regionShaped Then
  114.         
  115.         ReDim rgnRects(0 To Width * 3&) ' start with an arbritray number of rectangles
  116.         
  117.         ' begin pixel by pixel comparisons
  118.         For Y = Height - 1 To 0& Step -1&
  119.             ' the alpha byte is every 4th byte
  120.             For X = 3& To lScanWidth - 1& Step 4&
  121.             
  122.                 ' test to see if next pixel is 100% transparent
  123.                 If bDib(X, Y) = 0 Then
  124.                     If Not rStart = 0& Then ' we're currently tracking a rectangle,
  125.                         ' so let's close it, but see if array needs to be resized
  126.                         If rectCount + 1& = UBound(rgnRects) Then _
  127.                             ReDim Preserve rgnRects(0 To UBound(rgnRects) + Width * 3&)
  128.                          
  129.                          ' add the rectangle to our array
  130.                          SetRect rgnRects(rectCount + 2&), rStart  4, Height - Y - 1&, X  4 + 1&, Height - Y
  131.                          rStart = 0&                    ' reset flag
  132.                          rectCount = rectCount + 1&     ' keep track of nr in use
  133.                     End If
  134.                 
  135.                 Else
  136.                     ' non-transparent, ensure start value set
  137.                     If rStart = 0& Then rStart = X  ' set start point
  138.                 End If
  139.             Next X
  140.             If Not rStart = 0& Then
  141.                 ' got to end of bitmap without hitting another transparent pixel
  142.                 ' but we're tracking so we'll close rectangle now
  143.                
  144.                ' see if array needs to be resized
  145.                If rectCount + 1& = UBound(rgnRects) Then _
  146.                    ReDim Preserve rgnRects(0 To UBound(rgnRects) + Width * 3&)
  147.                    
  148.                 ' add the rectangle to our array
  149.                 SetRect rgnRects(rectCount + 2&), rStart  4, Height - Y - 1&, Width, Height - Y
  150.                 rStart = 0&                     ' reset flag
  151.                 rectCount = rectCount + 1&      ' keep track of nr in use
  152.             End If
  153.         Next Y
  154.     ElseIf regionStyle = regionEnclosed Then
  155.         
  156.         ReDim rgnRects(0 To Width * 3&) ' start with an arbritray number of rectangles
  157.         
  158.         ' begin pixel by pixel comparisons
  159.         For Y = Height - 1 To 0& Step -1&
  160.             ' the alpha byte is every 4th byte
  161.             For X = 3& To lScanWidth - 1& Step 4&
  162.             
  163.                 ' test to see if next pixel has any opaqueness
  164.                 If Not bDib(X, Y) = 0 Then
  165.                     ' we got the left side of the scan line, check the right side
  166.                     For Z = lScanWidth - 1 To X + 4& Step -4&
  167.                         ' when we hit a non-transparent pixel, exit loop
  168.                         If Not bDib(Z, Y) = 0 Then Exit For
  169.                     Next
  170.                     ' see if array needs to be resized
  171.                     If rectCount + 1& = UBound(rgnRects) Then _
  172.                         ReDim Preserve rgnRects(0 To UBound(rgnRects) + Width * 3&)
  173.                      
  174.                      ' add the rectangle to our array
  175.                      SetRect rgnRects(rectCount + 2&), X  4, Height - Y - 1&, Z  4 + 1&, Height - Y
  176.                      rectCount = rectCount + 1&     ' keep track of nr in use
  177.                      Exit For
  178.                 End If
  179.             Next X
  180.         Next Y
  181.         
  182.     ElseIf regionStyle = regionBounds Then
  183.         
  184.         ReDim rgnRects(0 To 0) ' we will only have 1 regional rectangle
  185.         
  186.         ' set the min,max bounding parameters
  187.         SetRect rgnRects(0), Width * 4, Height, 0, 0
  188.         With rgnRects(0)
  189.             ' begin pixel by pixel comparisons
  190.             For Y = Height - 1 To 0& Step -1&
  191.                 ' the alpha byte is every 4th byte
  192.                 For X = 3& To lScanWidth - 1& Step 4&
  193.                 
  194.                     ' test to see if next pixel has any opaqueness
  195.                     If Not bDib(X, Y) = 0 Then
  196.                         ' we got the left side of the scan line, check the right side
  197.                         For Z = lScanWidth - 1 To X + 4& Step -4&
  198.                             ' when we hit a non-transparent pixel, exit loop
  199.                             If Not bDib(Z, Y) = 0 Then Exit For
  200.                         Next
  201.                         rStart = 1& ' flag indicating we have opaqueness on this line
  202.                         ' resize our bounding rectangle's left/right as needed
  203.                         If X < .Left Then .Left = X
  204.                         If Z > .Right Then .Right = Z
  205.                         Exit For
  206.                     End If
  207.                 Next X
  208.                 If rStart = 1& Then
  209.                     ' resize our bounding rectangle's top/bottom as needed
  210.                     If Y < .Top Then .Top = Y
  211.                     If Y > .Bottom Then .Bottom = Y
  212.                     rStart = 0& ' reset flag indicating we do not have any opaque pixels
  213.                 End If
  214.             Next Y
  215.         End With
  216.         If rgnRects(0).Right > rgnRects(0).Left Then
  217.             rtnRegion = CreateRectRgn(rgnRects(0).Left  4, Height - rgnRects(0).Bottom - 1&, rgnRects(0).Right  4 + 1&, _
  218.                                      (rgnRects(0).Bottom - rgnRects(0).Top) + (Height - rgnRects(0).Bottom))
  219.         End If
  220.     End If
  221.     ' remove the array overlay
  222.     CopyMemory ByVal VarPtrArray(bDib()), 0&, 4&
  223.         
  224.     On Error Resume Next
  225.     ' check for failure & engage backup plan if needed
  226.     If Not rectCount = 0 Then
  227.         ' there were rectangles identified, try to create the region in one step
  228.         rtnRegion = CreatePartialRegion(rgnRects(), 2&, rectCount + 1&, 0&, Width)
  229.         
  230.         ' ok, now to test whether or not we are good to go...
  231.         ' if less than 2000 rectangles, region should have been created & if it didn't
  232.         ' it wasn't due O/S restrictions -- failure
  233.         If rtnRegion = 0& Then
  234.             If rectCount > 2000& Then
  235.                 ' Win98 has limitation of approximately 4000 regional rectangles
  236.                 ' In cases of failure, we will create the region in steps of
  237.                 ' 2000 vs trying to create the region in one step
  238.                 rtnRegion = CreateWin98Region(rgnRects, rectCount + 1&, 0&, Width)
  239.             End If
  240.         End If
  241.     End If
  242. CleanUp:
  243.     Erase rgnRects()
  244.     
  245.     If Err Then ' failure; probably low on resources
  246.         If Not rtnRegion = 0& Then DeleteObject rtnRegion
  247.         Err.Clear
  248.     Else
  249.         iparseCreateShapedRegion = rtnRegion
  250.     End If
  251. End Function
  252. Private Function CreatePartialRegion(rgnRects() As RECT, lIndex As Long, uIndex As Long, leftOffset As Long, cX As Long) As Long
  253.     ' Helper function for CreateShapedRegion & CreateWin98Region
  254.     ' Called to create a region in its entirety or stepped (see CreateWin98Region)
  255.     On Error Resume Next
  256.     ' Note: Ideally contiguous rectangles of equal height & width should be combined
  257.     ' into one larger rectangle. However, thru trial & error I found that Windows
  258.     ' does this for us and taking the extra time to do it ourselves
  259.     ' is too cumbersome & slows down the results.
  260.     
  261.     ' the first 32 bytes of a region is the header describing the region.
  262.     ' Well, 32 bytes equates to 2 rectangles (16 bytes each), so I'll
  263.     ' cheat a little & use rectangles to store the header
  264.     With rgnRects(lIndex - 2) ' bytes 0-15
  265.         .Left = 32&                     ' length of region header in bytes
  266.         .Top = 1&                       ' required cannot be anything else
  267.         .Right = uIndex - lIndex + 1&   ' number of rectangles for the region
  268.         .Bottom = .Right * 16&          ' byte size used by the rectangles; can be zero
  269.     End With
  270.     With rgnRects(lIndex - 1&) ' bytes 16-31 bounding rectangle identification
  271.         .Left = leftOffset                  ' left
  272.         .Top = rgnRects(lIndex).Top         ' top
  273.         .Right = leftOffset + cX            ' right
  274.         .Bottom = rgnRects(uIndex).Bottom   ' bottom
  275.     End With
  276.     ' call function to create region from our byte (RECT) array
  277.     CreatePartialRegion = ExtCreateRegion(ByVal 0&, (rgnRects(lIndex - 2&).Right + 2&) * 16&, rgnRects(lIndex - 2&))
  278.     If Err Then Err.Clear
  279. End Function
  280. Private Function CreateWin98Region(rgnRects() As RECT, rectCount As Long, leftOffset As Long, cX As Long) As Long
  281.     ' Fall-back routine when a very large region fails to be created.
  282.     ' Win98 has problems with regional rectangles over 4000
  283.     ' So, we'll try again in case this is the prob with other systems too.
  284.     ' We'll step it at 2000 at a time which is stil very quick
  285.     Dim X As Long, Y As Long ' loop counters
  286.     Dim win98Rgn As Long     ' partial region
  287.     Dim rtnRegion As Long    ' combined region & return value of this function
  288.     Const RGN_OR As Long = 2&
  289.     Const scanSize As Long = 2000&
  290.     ' we start with 2 'cause first 2 RECTs are the header
  291.     For X = 2& To rectCount Step scanSize
  292.     
  293.         If X + scanSize > rectCount Then
  294.             Y = rectCount
  295.         Else
  296.             Y = X + scanSize
  297.         End If
  298.         
  299.         ' attempt to create partial region, scanSize rects at a time
  300.         win98Rgn = CreatePartialRegion(rgnRects(), X, Y, leftOffset, cX)
  301.         
  302.         If win98Rgn = 0& Then    ' failure
  303.             ' cleaup combined region if needed
  304.             If Not rtnRegion = 0& Then DeleteObject rtnRegion
  305.             Exit For ' abort; system won't allow us to create the region
  306.         Else
  307.             If rtnRegion = 0& Then ' first time thru
  308.                 rtnRegion = win98Rgn
  309.             Else ' already started
  310.                 ' use combineRgn, but only every scanSize times
  311.                 CombineRgn rtnRegion, rtnRegion, win98Rgn, RGN_OR
  312.                 DeleteObject win98Rgn
  313.             End If
  314.         End If
  315.     Next
  316.     ' done; return result
  317.     CreateWin98Region = rtnRegion
  318.     
  319. End Function
  320. Public Function iparseIsArrayEmpty(FarPointer As Long) As Long
  321.   ' test to see if an array has been initialized
  322.   CopyMemory iparseIsArrayEmpty, ByVal FarPointer, 4&
  323. End Function
  324. Public Function iparseByteAlignOnWord(ByVal bitDepth As Byte, ByVal Width As Long) As Long
  325.     ' function to align any bit depth on dWord boundaries
  326.     iparseByteAlignOnWord = (((Width * bitDepth) + &H1F&) And Not &H1F&)  &H8&
  327. End Function
  328. Public Function iparseArrayToPicture(inArray() As Byte, Offset As Long, Size As Long) As IPicture
  329.     
  330.     ' function creates a stdPicture from the passed array
  331.     ' Note: The array was already validated as not empty when calling class' LoadStream was called
  332.     
  333.     Dim o_hMem  As Long
  334.     Dim o_lpMem  As Long
  335.     Dim aGUID(0 To 3) As Long
  336.     Dim IIStream As IUnknown
  337.     
  338.     aGUID(0) = &H7BF80980    ' GUID for stdPicture
  339.     aGUID(1) = &H101ABF32
  340.     aGUID(2) = &HAA00BB8B
  341.     aGUID(3) = &HAB0C3000
  342.     
  343.     o_hMem = GlobalAlloc(&H2&, Size)
  344.     If Not o_hMem = 0& Then
  345.         o_lpMem = GlobalLock(o_hMem)
  346.         If Not o_lpMem = 0& Then
  347.             CopyMemory ByVal o_lpMem, inArray(Offset), Size
  348.             Call GlobalUnlock(o_hMem)
  349.             If CreateStreamOnHGlobal(o_hMem, 1&, IIStream) = 0& Then
  350.                   Call OleLoadPicture(ByVal ObjPtr(IIStream), 0&, 0&, aGUID(0), iparseArrayToPicture)
  351.             End If
  352.         End If
  353.     End If
  354. End Function
  355. Public Function iparseHandleToStdPicture(ByVal hImage As Long, ByVal imgType As Long) As IPicture
  356.     ' function creates a stdPicture object from a image handle (bitmap or icon)
  357.     
  358.     Dim lpPictDesc As PictDesc, aGUID(0 To 3) As Long
  359.     With lpPictDesc
  360.         .Size = Len(lpPictDesc)
  361.         .Type = imgType
  362.         .hHandle = hImage
  363.         .hPal = 0
  364.     End With
  365.     ' IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
  366.     aGUID(0) = &H7BF80980
  367.     aGUID(1) = &H101ABF32
  368.     aGUID(2) = &HAA00BB8B
  369.     aGUID(3) = &HAB0C3000
  370.     ' create stdPicture
  371.     Call OleCreatePictureIndirect(lpPictDesc, aGUID(0), True, iparseHandleToStdPicture)
  372.     
  373. End Function
  374. Public Function iparseReverseLong(ByVal inLong As Long) As Long
  375.     ' fast function to reverse a long value from big endian to little endian
  376.     ' PNG files contain reversed longs
  377.     Dim b1 As Long
  378.     Dim b2 As Long
  379.     Dim b3 As Long
  380.     Dim b4 As Long
  381.     Dim lHighBit As Long
  382.     
  383.     lHighBit = inLong And &H80000000
  384.     If lHighBit Then
  385.       inLong = inLong And Not &H80000000
  386.     End If
  387.     
  388.     b1 = inLong And &HFF
  389.     b2 = (inLong And &HFF00&)  &H100&
  390.     b3 = (inLong And &HFF0000)  &H10000
  391.     If lHighBit Then
  392.       b4 = inLong  &H1000000 Or &H80&
  393.     Else
  394.       b4 = inLong  &H1000000
  395.     End If
  396.     
  397.     If b1 And &H80& Then
  398.       iparseReverseLong = ((b1 And &H7F&) * &H1000000 Or &H80000000) Or _
  399.           b2 * &H10000 Or b3 * &H100& Or b4
  400.     Else
  401.       iparseReverseLong = b1 * &H1000000 Or _
  402.           b2 * &H10000 Or b3 * &H100& Or b4
  403.     End If
  404. End Function
  405. Public Function iparseValidateDLL(ByVal DllName As String, ByVal dllProc As String) As Boolean
  406.     
  407.     ' PURPOSE: Test a DLL for a specific function.
  408.     
  409.     Dim LB As Long, pa As Long
  410.     
  411.     'attempt to open the DLL to be checked
  412.     LB = LoadLibrary(DllName)
  413.     If LB Then
  414.         'if so, retrieve the address of one of the function calls
  415.         pa = GetProcAddress(LB, dllProc)
  416.         ' free references
  417.         FreeLibrary LB
  418.     End If
  419.     iparseValidateDLL = (Not (LB = 0 Or pa = 0))
  420.     
  421. End Function
  422. Public Function iparseValidateZLIB(ByRef DllName As String, ByRef Version As Long, _
  423.                                 ByRef isCDECL As Boolean, ByRef hasCompression2 As Boolean, _
  424.                                 Optional ByVal bTestOnly As Boolean) As Boolean
  425.     
  426.     ' PURPOSE: Test ZLib availability and calling convention.
  427.     
  428.     ' About zLIB.  There are several versions ranging from v1.2.3 (latest) to v1.0.? (earliest).
  429.     ' Zlib is used to compress/decompress PNG files, among other things.
  430.     
  431.     ' However, zLIB is written with C calling convention (cdecl) which is unusable with VB.  There
  432.     ' are other modified versions out there that were converted to stdcall calling convention which
  433.     ' is what VB expects. But, we don't know the calling convention of the zLIB in advance, do we?
  434.     
  435.     ' Allowing VB to call cdecl directly results in crashes or invalid function returns. The class
  436.     ' cCDECL is one created by Paul Caton that uses assembly to "wrap" the cdecl call into a stdcall.
  437.     ' But we still need to know the calling convention so we know to use cCDECL or simple API calls.
  438.     
  439.     Dim LB As Long, pa As Long
  440.     Dim asmVal As Integer
  441.     
  442.     DllName = "zlib1.dll"       ' test for newer version first
  443.     For Version = 2& To 1& Step -1&
  444.         LB = LoadLibrary(DllName) 'attempt to open the DLL to be checked
  445.         If LB Then
  446.             hasCompression2 = Not (GetProcAddress(LB, "compress2") = 0)
  447.             pa = GetProcAddress(LB, "crc32") ' retrieve the address of the "crc32" exported function
  448.             If Not pa = 0& Then
  449.                 
  450.                 If bTestOnly Then Exit For
  451.                 Do
  452.                     ' Note: this method will not work for every DLL, nor every function within a DLL.
  453.                     ' I have analyzed 5 versions of zlib (some cdecl, some stdcall) using disassemblers
  454.                     ' and am confident this will work for the crc32 function in all versions from v1.2.3 down.
  455.                     
  456.                     ' Looking for an exit code:
  457.                     CopyMemory asmVal, ByVal pa, 1&
  458.                     Select Case asmVal
  459.                         Case &HC3               ' exit code, no stack clean up
  460.                             CopyMemory asmVal, ByVal iparseSafeOffset(pa, -1&), 1&
  461.                             If Not asmVal = &H33 Then   ' else 0x33C3 is an XOR function, not exit code
  462.                                 isCDECL = True      ' DLL uses cdecl calling convention, we use cCDECL
  463.                                 Exit For
  464.                             End If
  465.                         Case &HC2
  466.                             CopyMemory asmVal, ByVal iparseSafeOffset(pa, 1&), 2&
  467.                             If asmVal = &HC Then ' exit code with clean up of 12 bytes (the 3 crc32 parameters)
  468.                                 isCDECL = False  ' DLL uses stdcall calling convention, we use APIs
  469.                                 Exit For
  470.                             Else
  471.                                 asmVal = 0
  472.                             End If
  473.                     End Select
  474.                     pa = iparseSafeOffset(pa, 1&)
  475.                 Loop
  476.             End If
  477.             ' unmap library
  478.             FreeLibrary LB
  479.             LB = 0&
  480.             hasCompression2 = False
  481.         End If
  482.         DllName = "zlib.dll"    ' test for older version next, if necessary
  483.     Next Version
  484.     
  485.     If Not LB = 0& Then FreeLibrary LB
  486.     iparseValidateZLIB = (Not (Version = 0&))
  487.     
  488. End Function
  489. Public Sub iparseValidateAlphaChannel(inStream() As Byte, bPreMultiply As Boolean, bIsAlpha As Boolean, imgType As Long)
  490.     ' Purpose: Modify 32bpp DIB's alpha bytes depending on whether or not they are used
  491.     
  492.     ' Parameters
  493.     ' inStream(). 2D array overlaying the DIB to be checked
  494.     ' bPreMultiply. If true, image will be premultiplied if not already
  495.     ' bIsAlpha. Returns whether or not the image contains transparency
  496.     ' imgType. If passed as -1 then image is known to be not alpha, but will have its alpha values set to 255
  497.     '          When routine returns, imgType is either imgBmpARGB, imgBmpPARGB or imgBitmap
  498.     Dim X As Long, Y As Long
  499.     Dim lPARGB As Long, zeroCount As Long, opaqueCount As Long
  500.     Dim bPARGB As Boolean, bAlpha As Boolean
  501.     ' see if the 32bpp is premultiplied or not and if it is alpha or not
  502.     If Not imgType = -1 Then
  503.         For Y = 0 To UBound(inStream, 2)
  504.             For X = 3 To UBound(inStream, 1) Step 4
  505.                 Select Case inStream(X, Y)
  506.                 Case 0
  507.                     If lPARGB = 0 Then
  508.                         ' zero alpha, if any of the RGB bytes are non-zero, then this is not pre-multiplied
  509.                         If Not inStream(X - 1, Y) = 0 Then
  510.                             lPARGB = 1 ' not premultiplied
  511.                         ElseIf Not inStream(X - 2, Y) = 0 Then
  512.                             lPARGB = 1
  513.                         ElseIf Not inStream(X - 3, Y) = 0 Then
  514.                             lPARGB = 1
  515.                         End If
  516.                         ' but don't exit loop until we know if any alphas are non-zero
  517.                     End If
  518.                     zeroCount = zeroCount + 1 ' helps in decision factor at end of loop
  519.                 Case 255
  520.                     ' no way to indicate if premultiplied or not, unless...
  521.                     If lPARGB = 1 Then
  522.                         lPARGB = 2    ' not pre-multiplied because of the zero check above
  523.                         Exit For
  524.                     End If
  525.                     opaqueCount = opaqueCount + 1
  526.                 Case Else
  527.                     ' if any Exit For's below get triggered, not pre-multiplied
  528.                     If lPARGB = 1 Then
  529.                         lPARGB = 2: Exit For
  530.                     ElseIf inStream(X - 3, Y) > inStream(X, Y) Then
  531.                         lPARGB = 2: Exit For
  532.                     ElseIf inStream(X - 2, Y) > inStream(X, Y) Then
  533.                         lPARGB = 2: Exit For
  534.                     ElseIf inStream(X - 1, Y) > inStream(X, Y) Then
  535.                         lPARGB = 2: Exit For
  536.                     End If
  537.                 End Select
  538.             Next
  539.             If lPARGB = 2 Then Exit For
  540.         Next
  541.         
  542.         ' if we got all the way thru the image without hitting Exit:For then
  543.         ' the image is not alpha unless the bAlpha flag was set in the loop
  544.         
  545.         If zeroCount = (X  4) * (UBound(inStream, 2) + 1) Then ' every alpha value was zero
  546.             bPARGB = False: bAlpha = False ' assume RGB, else 100% transparent ARGB
  547.             ' also if lPARGB=0, then image is completely black
  548.         ElseIf opaqueCount = (X  4) * (UBound(inStream, 2) + 1) Then ' every alpha is 255
  549.             bPARGB = False: bAlpha = False
  550.         Else
  551.             Select Case lPARGB
  552.                 Case 2: bPARGB = False: bAlpha = True ' 100% positive ARGB
  553.                 Case 1: bPARGB = False: bAlpha = True ' now 100% positive ARGB
  554.                 Case 0: bPARGB = True: bAlpha = True
  555.             End Select
  556.         End If
  557.     End If
  558.     
  559.     ' see if caller wants the non-premultiplied alpha channel premultiplied
  560.     If bAlpha = True Then
  561.         If bPARGB Then ' else force premultiplied
  562.             imgType = imgBmpPARGB
  563.         Else
  564.             imgType = imgBmpARGB
  565.             If bPreMultiply = True Then
  566.                 For Y = 0 To UBound(inStream, 2)
  567.                     For X = 3 To UBound(inStream, 1) Step 4
  568.                         If inStream(X, Y) = 0 Then
  569.                             CopyMemory inStream(X - 3, Y), 0&, 4&
  570.                         ElseIf Not inStream(X, Y) = 255 Then
  571.                             For lPARGB = X - 3 To X - 1
  572.                                 inStream(lPARGB, Y) = ((0& + inStream(lPARGB, Y)) * inStream(X, Y))  &HFF
  573.                             Next
  574.                         End If
  575.                     Next
  576.                 Next
  577.                 bAlpha = True
  578.             End If
  579.         End If
  580.     Else
  581.         imgType = imgBitmap
  582.         If bPreMultiply = True Then
  583.             For Y = 0 To UBound(inStream, 2)
  584.                 For X = 3 To UBound(inStream, 1) Step 4
  585.                     inStream(X, Y) = 255
  586.                 Next
  587.             Next
  588.         End If
  589.     End If
  590.     bIsAlpha = bAlpha
  591. End Sub
  592. Public Sub iparseGrayScaleRatios(Formula As eGrayScaleFormulas, R As Single, G As Single, B As Single)
  593.         Select Case Formula ' note: when adding your own formulas, ensure they add up to 1.0 or less
  594.         Case gsclNone   ' no grayscale
  595.             R = 1: G = 1: B = 1
  596.         Case gsclNTSCPAL
  597.             R = 0.299: G = 0.587: B = 0.114 ' standard weighted average
  598.         Case gsclSimpleAvg
  599.             R = 0.333: G = 0.334: B = R     ' pure average
  600.         Case gsclCCIR709
  601.             R = 0.213: G = 0.715: B = 0.072 ' Formula.CCIR 709, Default
  602.         Case gsclRedMask
  603.             R = 0.8: G = 0.1: B = G     ' personal preferences: could be r=1:g=0:b=0 or other weights
  604.         Case gsclGreenMask
  605.             R = 0.1: G = 0.8: B = R     ' personal preferences: could be r=0:g=1:b=0 or other weights
  606.         Case gsclBlueMask
  607.             R = 0.1: G = R: B = 0.8     ' personal preferences: could be r=0:g=0:b=1 or other weights
  608.         Case gsclBlueGreenMask
  609.             R = 0.1: G = 0.45: B = G    ' personal preferences: could be r=0:g=.5:b=.5 or other weights
  610.         Case gsclRedGreenMask
  611.             R = 0.45: G = R: B = 0.1    ' personal preferences: could be r=.5:g=.5:b=0 or other weights
  612.         Case Else
  613.             R = 0.299: G = 0.587: B = 0.114 ' use gsclNTSCPAL
  614.         End Select
  615. End Sub
  616. Public Function iparseSafeOffset(ByVal Ptr As Long, Offset As Long) As Long
  617.     ' ref http://support.microsoft.com/kb/q189323/ ' unsigned math
  618.     ' Purpose: Provide a valid pointer offset
  619.     
  620.     ' If a pointer +/- the offset wraps around the high bit of a long, the
  621.     ' pointer needs to change from positive to negative or vice versa.
  622.     
  623.     ' A return of zero indicates the offset exceeds the min/max unsigned long bounds
  624.     
  625.     Const MAXINT_4NEG As Long = -2147483648#
  626.     Const MAXINT_4 As Long = 2147483647
  627.     
  628.     If Offset = 0 Then
  629.         iparseSafeOffset = Ptr
  630.     Else
  631.     
  632.         If Offset < 0 Then ' subtracting from pointer
  633.             If Ptr < MAXINT_4NEG - Offset Then
  634.                 ' wraps around high bit (backwards) & changes to Positive from Negative
  635.                 iparseSafeOffset = MAXINT_4 - ((MAXINT_4NEG - Ptr) - Offset - 1)
  636.             ElseIf Ptr > 0 Then ' verify pointer does not wrap around 0 bit
  637.                 If Ptr > -Offset Then iparseSafeOffset = Ptr + Offset
  638.             Else
  639.                 iparseSafeOffset = Ptr + Offset
  640.             End If
  641.         Else    ' Adding to pointer
  642.             If Ptr > MAXINT_4 - Offset Then
  643.                 ' wraps around high bit (forward) & changes to Negative from Positive
  644.                 iparseSafeOffset = MAXINT_4NEG + (Offset - (MAXINT_4 - Ptr) - 1)
  645.             ElseIf Ptr < 0 Then ' verify pointer does not wrap around 0 bit
  646.                 If Ptr < -Offset Then iparseSafeOffset = Ptr + Offset
  647.             Else
  648.                 iparseSafeOffset = Ptr + Offset
  649.             End If
  650.         End If
  651.     End If
  652. End Function
  653. Public Function iparseGetFileHandle(ByVal FileName As String, bOpen As Boolean, Optional ByVal useUnicode As Boolean = False) As Long
  654.     ' Function uses APIs to read/create files with unicode support
  655.     Const GENERIC_READ As Long = &H80000000
  656.     Const OPEN_EXISTING = &H3
  657.     Const FILE_SHARE_READ = &H1
  658.     Const GENERIC_WRITE As Long = &H40000000
  659.     Const FILE_SHARE_WRITE As Long = &H2
  660.     Const CREATE_ALWAYS As Long = 2
  661.     Const FILE_ATTRIBUTE_ARCHIVE As Long = &H20
  662.     Const FILE_ATTRIBUTE_HIDDEN As Long = &H2
  663.     Const FILE_ATTRIBUTE_READONLY As Long = &H1
  664.     Const FILE_ATTRIBUTE_SYSTEM As Long = &H4
  665.     
  666.     Dim Flags As Long, Access As Long
  667.     Dim Disposition As Long, Share As Long
  668.     
  669.     If useUnicode = False Then useUnicode = (Not (IsWindowUnicode(GetDesktopWindow) = 0&))
  670.     If bOpen Then
  671.         Access = GENERIC_READ
  672.         Share = FILE_SHARE_READ
  673.         Disposition = OPEN_EXISTING
  674.         Flags = FILE_ATTRIBUTE_ARCHIVE Or FILE_ATTRIBUTE_HIDDEN Or FILE_ATTRIBUTE_NORMAL _
  675.                 Or FILE_ATTRIBUTE_READONLY Or FILE_ATTRIBUTE_SYSTEM
  676.     Else
  677.         Access = GENERIC_READ Or GENERIC_WRITE
  678.         Share = 0&
  679.         If useUnicode Then
  680.             Flags = GetFileAttributesW(StrPtr(FileName))
  681.         Else
  682.             Flags = GetFileAttributes(FileName)
  683.         End If
  684.         If Flags < 0& Then Flags = FILE_ATTRIBUTE_NORMAL
  685.         ' CREATE_ALWAYS will delete previous file if necessary
  686.         Disposition = CREATE_ALWAYS
  687.     End If
  688.     
  689.     If useUnicode Then
  690.         iparseGetFileHandle = CreateFileW(StrPtr(FileName), Access, Share, ByVal 0&, Disposition, Flags, 0&)
  691.     Else
  692.         iparseGetFileHandle = CreateFile(FileName, Access, Share, ByVal 0&, Disposition, Flags, 0&)
  693.     End If
  694. End Function
  695. Public Function iparseDeleteFile(FileName As String, Optional ByVal useUnicode As Boolean = False) As Boolean
  696.     ' Function uses APIs to delete files with unicode support
  697.     If useUnicode = False Then useUnicode = (Not (IsWindowUnicode(GetDesktopWindow) = 0&))
  698.     If useUnicode Then
  699.         If Not (SetFileAttributesW(StrPtr(FileName), FILE_ATTRIBUTE_NORMAL) = 0&) Then
  700.             iparseDeleteFile = Not (DeleteFileW(StrPtr(FileName)) = 0&)
  701.         End If
  702.     Else
  703.         If Not (SetFileAttributes(FileName, FILE_ATTRIBUTE_NORMAL) = 0&) Then
  704.             iparseDeleteFile = Not (DeleteFile(FileName) = 0&)
  705.         End If
  706.     End If
  707. End Function
  708. Public Function iparseFileExists(FileName As String, Optional ByVal useUnicode As Boolean) As Boolean
  709.     ' test to see if a file exists
  710.     Const INVALID_HANDLE_VALUE = -1&
  711.     If useUnicode = False Then useUnicode = (Not (IsWindowUnicode(GetDesktopWindow) = 0&))
  712.     If useUnicode Then
  713.         iparseFileExists = Not (GetFileAttributesW(StrPtr(FileName)) = INVALID_HANDLE_VALUE)
  714.     Else
  715.         iparseFileExists = Not (GetFileAttributes(FileName) = INVALID_HANDLE_VALUE)
  716.     End If
  717. End Function