home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 5_2007-2008.ISO / data / Zips / Multiple_C208148912007.psc / MyCapture / Client / cDIBSectionSave.cls < prev    next >
Text File  |  2003-11-12  |  20KB  |  565 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "cDIBSectionSave"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
  17.     lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
  18.  
  19. Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
  20. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
  21. Private Declare Function CreateDCAsNull Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, lpDeviceName As Any, lpOutput As Any, lpInitData As Any) As Long
  22. Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
  23. Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
  24.  
  25. Private Type RGBQUAD
  26.     rgbBlue As Byte
  27.     rgbGreen As Byte
  28.     rgbRed As Byte
  29.     rgbReserved As Byte
  30. End Type
  31. Private Type BITMAPINFOHEADER '40 bytes
  32.     biSize As Long
  33.     biWidth As Long
  34.     biHeight As Long
  35.     biPlanes As Integer
  36.     biBitCount As Integer
  37.     biCompression As Long
  38.     biSizeImage As Long
  39.     biXPelsPerMeter As Long
  40.     biYPelsPerMeter As Long
  41.     biClrUsed As Long
  42.     biClrImportant As Long
  43. End Type
  44. Private Type BITMAPINFO2
  45.     bmiHeader As BITMAPINFOHEADER
  46.     bmiColors(0 To 1) As RGBQUAD
  47. End Type
  48. Private Type BITMAPINFO16
  49.     bmiHeader As BITMAPINFOHEADER
  50.     bmiColors(0 To 15) As RGBQUAD
  51. End Type
  52. Private Type BITMAPINFO256
  53.     bmiHeader As BITMAPINFOHEADER
  54.     bmiColors(0 To 255) As RGBQUAD
  55. End Type
  56.  
  57. Private Const BI_RGB = 0&
  58. Private Const BI_RLE4 = 2&
  59. Private Const BI_RLE8 = 1&
  60. Private Const DIB_RGB_COLORS = 0 '  color table in RGBs
  61.  
  62. Private Declare Function CreateDIBSection2 Lib "gdi32" Alias "CreateDIBSection" _
  63.     (ByVal hdc As Long, _
  64.     pBitmapInfo As BITMAPINFO2, _
  65.     ByVal un As Long, _
  66.     lplpVoid As Long, _
  67.     ByVal handle As Long, _
  68.     ByVal dw As Long) As Long
  69. Private Declare Function CreateDIBSection16 Lib "gdi32" Alias "CreateDIBSection" _
  70.     (ByVal hdc As Long, _
  71.     pBitmapInfo As BITMAPINFO16, _
  72.     ByVal un As Long, _
  73.     lplpVoid As Long, _
  74.     ByVal handle As Long, _
  75.     ByVal dw As Long) As Long
  76. Private Declare Function CreateDIBSection256 Lib "gdi32" Alias "CreateDIBSection" _
  77.     (ByVal hdc As Long, _
  78.     pBitmapInfo As BITMAPINFO256, _
  79.     ByVal un As Long, _
  80.     lplpVoid As Long, _
  81.     ByVal handle As Long, _
  82.     ByVal dw As Long) As Long
  83.  
  84. Private Const BITMAPTYPE As Integer = &H4D42
  85. Private Type BITMAPFILEHEADER
  86.    bfType As Integer '- type  ="BM" i.e &H4D42 - 2
  87.    bfSize As Long ' - size in bytes of file - 6
  88.    bfReserved1 As Integer ' - reserved, must be 0 - 8
  89.    bfReserved2 As Integer ' - reserved, must be 0 - 10
  90.    bfOffBits As Long ' offset from this structure to the bitmap bits - 14
  91. End Type
  92.  
  93. Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, 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
  94. Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
  95. Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
  96. Private Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
  97. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
  98. Private Const INVALID_HANDLE_VALUE = -1
  99. Private Const CREATE_ALWAYS = 2
  100. Private Const GENERIC_READ = &H80000000
  101. Private Const GENERIC_WRITE = &H40000000
  102. Private Const FILE_ATTRIBUTE_ARCHIVE = &H20
  103. Private Const FILE_ATTRIBUTE_COMPRESSED = &H800
  104. Private Const FILE_ATTRIBUTE_DIRECTORY = &H10
  105. Private Const FILE_ATTRIBUTE_HIDDEN = &H2
  106. Private Const FILE_ATTRIBUTE_NORMAL = &H80
  107. Private Const FILE_ATTRIBUTE_READONLY = &H1
  108. Private Const FILE_ATTRIBUTE_SYSTEM = &H4
  109. Private Const FILE_ATTRIBUTE_TEMPORARY = &H100
  110. Private Const FILE_BEGIN = 0
  111. Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  112. Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
  113. Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
  114. Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  115. Private Const GMEM_FIXED = &H0
  116. Private Const GMEM_ZEROINIT = &H40
  117. Private Const GPTR = (GMEM_FIXED Or GMEM_ZEROINIT)
  118. Private Const FORMAT_MESSAGE_ALLOCATE_BUFFER = &H100
  119. Private Const FORMAT_MESSAGE_ARGUMENT_ARRAY = &H2000
  120. Private Const FORMAT_MESSAGE_FROM_HMODULE = &H800
  121. Private Const FORMAT_MESSAGE_FROM_STRING = &H400
  122. Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
  123. Private Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200
  124. Private Const FORMAT_MESSAGE_MAX_WIDTH_MASK = &HFF
  125. Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Long) As Long
  126.  
  127. Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Long, lpBI As BITMAPINFO256, ByVal wUsage As Long) As Long
  128. Private Declare Function CreateDIBitmap Lib "gdi32" (ByVal hdc As Long, lpInfoHeader As BITMAPINFOHEADER, ByVal dwUsage As Long, lpInitBits As Any, lpInitInfo As BITMAPINFO256, ByVal wUsage As Long) As Long
  129.  
  130.  
  131. Public Enum EDSSColourDepthConstants
  132.    edss2Colour
  133.    edss16Colour
  134.    edss256Colour
  135.    edssTrueColour
  136. End Enum
  137.  
  138. Public Enum EDSSColourReductionConstants
  139.    edssSystemDefault
  140.    edssUsePalette
  141.    edssGeneratePalette
  142. End Enum
  143.  
  144. Public Function Save( _
  145.       ByVal sFileName As String, _
  146.       ByRef cDIB As cDIBSection, _
  147.       Optional ByRef cPal As cPalette = Nothing, _
  148.       Optional ByVal eOutputColourDepth As EDSSColourDepthConstants = edss256Colour, _
  149.       Optional ByVal eColourReductionMethod As EDSSColourReductionConstants = edssSystemDefault _
  150.    ) As Boolean
  151. Dim tBIH As BITMAPINFOHEADER
  152.  
  153.    If eOutputColourDepth = edssTrueColour Then
  154.       ' Just directly save the DIBSection as is:
  155.       Save = cDIB.SavePicture(sFileName)
  156.       
  157.    Else
  158.       ' We must create a new DIBSection of the correct colour depth to save.
  159.       ' Also, we may need to perform a colour depth reduction before saving
  160.       
  161.       ' First create the DIBSection
  162.       Dim tBI2 As BITMAPINFO2, tBI16 As BITMAPINFO16, tBI256 As cDIBSectionSave.BITMAPINFO256
  163.       Dim hDib As Long, lptr As Long, bSuccess As Boolean
  164.       Dim lHDC As Long, hBmpOld As Long, lHDCWOrk As Long, i As Long
  165.       Dim cDIBWork As cDIBSection
  166.       Dim cColReduce As New cColourReduceDIB
  167.       Dim bBltIn As Boolean
  168.                
  169.       ' Do any colour reduction as required:
  170.       Select Case eColourReductionMethod
  171.       Case edssSystemDefault
  172.          bBltIn = True
  173.          
  174.       Case edssUsePalette
  175.          Set cDIBWork = New cDIBSection
  176.          cDIBWork.Create cDIB.Width, cDIB.Height
  177.          cColReduce.ApplyPalette cDIB, cDIBWork, cPal
  178.       
  179.       Case edssGeneratePalette
  180.          Select Case eOutputColourDepth
  181.          Case edss256Colour
  182.             ' Create optimal palette using octree quantisation:
  183.             Set cPal = New cPalette
  184.             cPal.CreateOptimal cDIB
  185.             Set cDIBWork = New cDIBSection
  186.             cDIBWork.Create cDIB.Width, cDIB.Height
  187.             cColReduce.ApplyPalette cDIB, cDIBWork, cPal, False
  188.             
  189.          Case edss16Colour
  190.             ' Use a default palette
  191.             Set cPal = New cPalette
  192.             cPal.Create16Colour
  193.             Set cDIBWork = New cDIBSection
  194.             cDIBWork.Create cDIB.Width, cDIB.Height
  195.             cColReduce.ApplyPalette cDIB, cDIBWork, cPal
  196.             
  197.          Case edss2Colour
  198.             ' Use a default palette
  199.             Set cDIBWork = New cDIBSection
  200.             cDIBWork.Create cDIB.Width, cDIB.Height
  201.             cColReduce.BlackAndWhite cDIB, cDIBWork
  202.          
  203.          End Select
  204.       End Select
  205.                               
  206.       ' Create our output DIB section (with appropriate palette):
  207.       Select Case eOutputColourDepth
  208.       Case edss2Colour
  209.          pbCreate2ColourDIBSection hDib, tBI2, lptr, cDIB.Width, cDIB.Height
  210.       Case edss16Colour
  211.          pbCreate16ColourDIBSection hDib, tBI16, lptr, cDIB.Width, cDIB.Height
  212.       Case edss256Colour
  213.          pbCreate256ColourDIBSection hDib, tBI256, lptr, cDIB.Width, cDIB.Height, cPal
  214.       End Select
  215.       
  216.       If Not hDib = 0 Then
  217.                               
  218.          ' Blit the appropriate true colour DIB into our DIB:
  219.          lHDC = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&)
  220.          lHDCWOrk = CreateCompatibleDC(lHDC)
  221.          DeleteDC lHDC
  222.          hBmpOld = SelectObject(lHDCWOrk, hDib)
  223.          cDIB.PaintPicture lHDCWOrk
  224.          
  225.          If bBltIn Then
  226.             cDIB.LoadPictureBlt lHDCWOrk
  227.          End If
  228.          
  229.          SelectObject lHDCWOrk, hBmpOld
  230.          DeleteDC lHDCWOrk
  231.                   
  232.                   
  233.          ' Save the bitmap we created:
  234.          Select Case eOutputColourDepth
  235.          Case edss2Colour
  236.             bSuccess = SaveToBitmap2(tBI2, lptr, sFileName)
  237.          Case edss16Colour
  238.             bSuccess = SaveToBitmap16(tBI16, lptr, sFileName)
  239.          Case edss256Colour
  240.             bSuccess = SaveToBitmap256(tBI256, lptr, sFileName)
  241.          End Select
  242.       
  243.          DeleteObject hDib
  244.       End If
  245.       
  246.    End If
  247.    
  248. End Function
  249. Private Function pbCreate2ColourDIBSection(ByRef hDib As Long, ByRef tBI As BITMAPINFO2, ByRef lptr As Long, ByVal lWidth As Long, ByVal lheight As Long) As Boolean
  250. Dim lScanSize As Long
  251. Dim lHDC As Long
  252.    lHDC = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&)
  253.    With tBI.bmiHeader
  254.        .biSize = Len(tBI.bmiHeader)
  255.        .biWidth = lWidth
  256.        .biHeight = lheight
  257.        .biPlanes = 1
  258.        .biBitCount = 1
  259.        .biCompression = BI_RGB
  260.        lScanSize = lWidth \ 8
  261.        lScanSize = lScanSize + lScanSize Mod 4
  262.        .biSizeImage = lScanSize * .biHeight
  263.    End With
  264.    With tBI.bmiColors(1)
  265.       .rgbBlue = &HFF: .rgbRed = &HFF: .rgbGreen = &HFF
  266.    End With
  267.    hDib = CreateDIBSection2( _
  268.            lHDC, _
  269.            tBI, _
  270.            DIB_RGB_COLORS, _
  271.            lptr, _
  272.            0, 0)
  273.    pbCreate2ColourDIBSection = (hDib <> 0)
  274.    DeleteDC lHDC
  275. End Function
  276. Private Function pbCreate16ColourDIBSection(ByRef hDib As Long, ByRef tBI As BITMAPINFO16, ByRef lptr As Long, ByVal lWidth As Long, ByVal lheight As Long) As Boolean
  277. Dim lScanSize As Long
  278. Dim lHDC As Long
  279. Dim i As Long
  280.    lHDC = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&)
  281.    With tBI.bmiHeader
  282.        .biSize = Len(tBI.bmiHeader)
  283.        .biWidth = lWidth
  284.        .biHeight = lheight
  285.        .biPlanes = 1
  286.        .biBitCount = 4
  287.        .biCompression = BI_RGB
  288.        lScanSize = lWidth \ 2
  289.        lScanSize = lScanSize + lScanSize Mod 4
  290.        .biSizeImage = lScanSize * .biHeight
  291.    End With
  292.    Dim cP As New cPalette
  293.    cP.Create16Colour
  294.    For i = 0 To 15
  295.       With tBI.bmiColors(i)
  296.          .rgbBlue = cP.Red(i + 1)
  297.          .rgbGreen = cP.Green(i + 1)
  298.          .rgbRed = cP.Blue(i + 1)
  299.       End With
  300.    Next
  301.    hDib = CreateDIBSection16( _
  302.            lHDC, _
  303.            tBI, _
  304.            DIB_RGB_COLORS, _
  305.            lptr, _
  306.            0, 0)
  307.    pbCreate16ColourDIBSection = (hDib <> 0)
  308.    DeleteDC lHDC
  309. End Function
  310. Private Function pbCreate256ColourDIBSection(ByRef hDib As Long, ByRef tBI As BITMAPINFO256, ByRef lptr As Long, ByVal lWidth As Long, ByVal lheight As Long, Optional ByRef cP As cPalette = Nothing) As Boolean
  311. Dim lScanSize As Long
  312. Dim lHDC As Long
  313. Dim i As Long
  314. Dim iMax As Long
  315.    lHDC = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&)
  316.    With tBI.bmiHeader
  317.        .biSize = Len(tBI.bmiHeader)
  318.        .biWidth = lWidth
  319.        .biHeight = lheight
  320.        .biPlanes = 1
  321.        .biBitCount = 8
  322.        .biCompression = BI_RGB
  323.        lScanSize = (lWidth + lWidth Mod 4)
  324.        .biSizeImage = lScanSize * .biHeight
  325.    End With
  326.    ' Halftone palette:
  327.    If cP Is Nothing Then
  328.       Set cP = New cPalette
  329.       cP.CreateHalfTone
  330.    End If
  331.    iMax = 255
  332.    If iMax >= cP.Count Then
  333.       iMax = cP.Count - 1
  334.    End If
  335.    For i = 0 To iMax
  336.       With tBI.bmiColors(i)
  337.          .rgbBlue = cP.Blue(i + 1)
  338.          .rgbGreen = cP.Green(i + 1)
  339.          .rgbRed = cP.Red(i + 1)
  340.       End With
  341.    Next
  342.    hDib = CreateDIBSection256( _
  343.            lHDC, _
  344.            tBI, _
  345.            DIB_RGB_COLORS, _
  346.            lptr, _
  347.            0, 0)
  348.    pbCreate256ColourDIBSection = (hDib <> 0)
  349.    DeleteDC lHDC
  350. End Function
  351.       
  352.       
  353. Private Function SaveToBitmap256(ByRef tBI As cDIBSectionSave.BITMAPINFO256, ByVal lPtrBits As Long, ByVal sFileName As String)
  354. Dim tBH As BITMAPFILEHEADER
  355. Dim tRGBQ As RGBQUAD
  356. Dim hFile As Long
  357. Dim lBytesWritten As Long
  358. Dim lSize As Long
  359. Dim lR As Long
  360. Dim bErr As Boolean
  361. Dim hMem As Long, lptr As Long
  362. Dim lErr As Long
  363.  
  364.    ' Prepare the BITMAPFILEHEADER
  365.    With tBH
  366.       .bfType = BITMAPTYPE
  367.       .bfOffBits = 14 + Len(tBI)
  368.       .bfSize = .bfOffBits + tBI.bmiHeader.biSizeImage
  369.    End With
  370.    hFile = CreateFile(sFileName, _
  371.                  GENERIC_READ Or GENERIC_WRITE, _
  372.                   ByVal 0&, _
  373.                   ByVal 0&, _
  374.                   CREATE_ALWAYS, _
  375.                   FILE_ATTRIBUTE_NORMAL, _
  376.                   0)
  377.    lErr = Err.LastDllError
  378.    If (hFile = INVALID_HANDLE_VALUE) Then
  379.       ' error
  380.       Err.Raise 17, App.EXEName & ".cDIBSection256", ApiError(lErr)
  381.    Else
  382.       
  383.       ' Writing the BITMAPFILEINFOHEADER is somewhat painful
  384.       ' due to non-byte alignment of structure...
  385.       hMem = GlobalAlloc(GPTR, 14)
  386.       lptr = GlobalLock(hMem)
  387.       CopyMemory ByVal lptr, tBH.bfType, 2
  388.       CopyMemory ByVal lptr + 2, tBH.bfSize, 4
  389.       CopyMemory ByVal lptr + 6, 0&, 4
  390.       CopyMemory ByVal lptr + 10, tBH.bfOffBits, 4
  391.       lSize = 14
  392.       lR = WriteFile(hFile, ByVal lptr, lSize, lBytesWritten, ByVal 0&)
  393.       GlobalUnlock hMem
  394.       GlobalFree hMem
  395.       
  396.       ' Add the BITMAPINFOHEADER and colour palette:
  397.       bErr = FileErrHandler(lR, lSize, lBytesWritten)
  398.       If Not bErr Then
  399.          lSize = Len(tBI)
  400.          lR = WriteFile(hFile, tBI, lSize, lBytesWritten, ByVal 0&)
  401.          bErr = FileErrHandler(lR, lSize, lBytesWritten)
  402.       End If
  403.       
  404.       If Not bErr Then
  405.          ' Its easy to write the bitmap data, though...
  406.          lSize = tBI.bmiHeader.biSizeImage
  407.          lR = WriteFile(hFile, ByVal lPtrBits, lSize, lBytesWritten, ByVal 0&)
  408.          bErr = FileErrHandler(lR, lSize, lBytesWritten)
  409.       End If
  410.       
  411.       
  412.       CloseHandle hFile
  413.       SaveToBitmap256 = Not (bErr)
  414.    End If
  415.  
  416. End Function
  417.  
  418.       
  419. Private Function SaveToBitmap16(ByRef tBI As BITMAPINFO16, ByVal lPtrBits As Long, ByVal sFileName As String)
  420. Dim tBH As BITMAPFILEHEADER
  421. Dim tRGBQ As RGBQUAD
  422. Dim hFile As Long
  423. Dim lBytesWritten As Long
  424. Dim lSize As Long
  425. Dim lR As Long
  426. Dim bErr As Boolean
  427. Dim hMem As Long, lptr As Long
  428. Dim lErr As Long
  429.  
  430.    ' Prepare the BITMAPFILEHEADER
  431.    With tBH
  432.       .bfType = BITMAPTYPE
  433.       .bfOffBits = 14 + Len(tBI)
  434.       .bfSize = .bfOffBits + tBI.bmiHeader.biSizeImage
  435.    End With
  436.    hFile = CreateFile(sFileName, _
  437.                  GENERIC_READ Or GENERIC_WRITE, _
  438.                   ByVal 0&, _
  439.                   ByVal 0&, _
  440.                   CREATE_ALWAYS, _
  441.                   FILE_ATTRIBUTE_NORMAL, _
  442.                   0)
  443.    lErr = Err.LastDllError
  444.    If (hFile = INVALID_HANDLE_VALUE) Then
  445.       ' error
  446.       Err.Raise 17, App.EXEName & ".cDIBSection256", ApiError(lErr)
  447.    Else
  448.       
  449.       ' Writing the BITMAPFILEINFOHEADER is somewhat painful
  450.       ' due to non-byte alignment of structure...
  451.       hMem = GlobalAlloc(GPTR, 14)
  452.       lptr = GlobalLock(hMem)
  453.       CopyMemory ByVal lptr, tBH.bfType, 2
  454.       CopyMemory ByVal lptr + 2, tBH.bfSize, 4
  455.       CopyMemory ByVal lptr + 6, 0&, 4
  456.       CopyMemory ByVal lptr + 10, tBH.bfOffBits, 4
  457.       lSize = 14
  458.       lR = WriteFile(hFile, ByVal lptr, lSize, lBytesWritten, ByVal 0&)
  459.       GlobalUnlock hMem
  460.       GlobalFree hMem
  461.       
  462.       ' Add the BITMAPINFOHEADER and colour palette:
  463.       bErr = FileErrHandler(lR, lSize, lBytesWritten)
  464.       If Not bErr Then
  465.          lSize = Len(tBI)
  466.          lR = WriteFile(hFile, tBI, lSize, lBytesWritten, ByVal 0&)
  467.          bErr = FileErrHandler(lR, lSize, lBytesWritten)
  468.       End If
  469.       
  470.       If Not bErr Then
  471.          ' Its easy to write the bitmap data, though...
  472.          lSize = tBI.bmiHeader.biSizeImage
  473.          lR = WriteFile(hFile, ByVal lPtrBits, lSize, lBytesWritten, ByVal 0&)
  474.          bErr = FileErrHandler(lR, lSize, lBytesWritten)
  475.       End If
  476.       
  477.       
  478.       CloseHandle hFile
  479.       SaveToBitmap16 = Not (bErr)
  480.    End If
  481.  
  482. End Function
  483.  
  484. Private Function SaveToBitmap2(ByRef tBI As BITMAPINFO2, ByVal lPtrBits As Long, ByVal sFileName As String)
  485. Dim tBH As BITMAPFILEHEADER
  486. Dim tRGBQ As RGBQUAD
  487. Dim hFile As Long
  488. Dim lBytesWritten As Long
  489. Dim lSize As Long
  490. Dim lR As Long
  491. Dim bErr As Boolean
  492. Dim hMem As Long, lptr As Long
  493. Dim lErr As Long
  494.  
  495.    ' Prepare the BITMAPFILEHEADER
  496.    With tBH
  497.       .bfType = BITMAPTYPE
  498.       .bfOffBits = 14 + Len(tBI)
  499.       .bfSize = .bfOffBits + tBI.bmiHeader.biSizeImage
  500.    End With
  501.    hFile = CreateFile(sFileName, _
  502.                  GENERIC_READ Or GENERIC_WRITE, _
  503.                   ByVal 0&, _
  504.                   ByVal 0&, _
  505.                   CREATE_ALWAYS, _
  506.                   FILE_ATTRIBUTE_NORMAL, _
  507.                   0)
  508.    lErr = Err.LastDllError
  509.    If (hFile = INVALID_HANDLE_VALUE) Then
  510.       ' error
  511.       Err.Raise 17, App.EXEName & ".cDIBSection256", ApiError(lErr)
  512.    Else
  513.       
  514.       ' Writing the BITMAPFILEINFOHEADER is somewhat painful
  515.       ' due to non-byte alignment of structure...
  516.       hMem = GlobalAlloc(GPTR, 14)
  517.       lptr = GlobalLock(hMem)
  518.       CopyMemory ByVal lptr, tBH.bfType, 2
  519.       CopyMemory ByVal lptr + 2, tBH.bfSize, 4
  520.       CopyMemory ByVal lptr + 6, 0&, 4
  521.       CopyMemory ByVal lptr + 10, tBH.bfOffBits, 4
  522.       lSize = 14
  523.       lR = WriteFile(hFile, ByVal lptr, lSize, lBytesWritten, ByVal 0&)
  524.       GlobalUnlock hMem
  525.       GlobalFree hMem
  526.       
  527.       ' Add the BITMAPINFOHEADER and colour palette:
  528.       bErr = FileErrHandler(lR, lSize, lBytesWritten)
  529.       If Not bErr Then
  530.          lSize = Len(tBI)
  531.          lR = WriteFile(hFile, tBI, lSize, lBytesWritten, ByVal 0&)
  532.          bErr = FileErrHandler(lR, lSize, lBytesWritten)
  533.       End If
  534.       
  535.       If Not bErr Then
  536.          ' Its easy to write the bitmap data, though...
  537.          lSize = tBI.bmiHeader.biSizeImage
  538.          lR = WriteFile(hFile, ByVal lPtrBits, lSize, lBytesWritten, ByVal 0&)
  539.          bErr = FileErrHandler(lR, lSize, lBytesWritten)
  540.       End If
  541.       
  542.       
  543.       CloseHandle hFile
  544.       SaveToBitmap2 = Not (bErr)
  545.    End If
  546.  
  547. End Function
  548. Private Function ApiError(ByVal e As Long) As String
  549.     Dim s As String, c As Long
  550.     s = String(256, 0)
  551.     c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
  552.                       FORMAT_MESSAGE_IGNORE_INSERTS, _
  553.                       0, e, 0&, s, Len(s), ByVal 0)
  554.     If c Then ApiError = Left$(s, c)
  555. End Function
  556.  
  557. Private Function FileErrHandler(ByVal lR As Long, ByVal lSize As Long, ByVal lBytes As Long) As Boolean
  558.    If (lR = 0) Or Not (lSize = lBytes) Then
  559.       'Err.Raise
  560.       FileErrHandler = True
  561.    End If
  562. End Function
  563.  
  564.  
  565.