Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1463

[VB6] Code Snippet: Converting an hIcon to an hBitmap

$
0
0
So this isn't a full on project (although it will be part of an upcoming one), just some code- doing this conversion in VB turned out to be very difficult for someone unfamiliar with graphics APIs. Found tons of other people having the same question with mostly incomplete answers, and I couldn't find anywhere showing it done in VB.. spent hours figuring it out from other codes, which turned the issue into something far more complicated than the ultimate solution I found turned out to be.

The use case this was developed as a response to was to be able to use take hIcon's extracted from files and be able to use them as a value for MENUITEMINFO.hbmpItem.
Code:


'Declares
Private Type BITMAPINFOHEADER
  biSize                  As Long
  biWidth                  As Long
  biHeight                As Long
  biPlanes                As Integer
  biBitCount              As Integer
  biCompression            As Long
  biSizeImage              As Long
  biXPelsPerMeter          As Long
  biYPelsPerMeter          As Long
  biClrUsed                As Long
  biClrImportant          As Long
End Type

Private Type BITMAPINFO
  bmiHeader                As BITMAPINFOHEADER
  bmiColors(3)            As Byte
End Type

Private Const DIB_RGB_COLORS = 0&
Private Const DI_NORMAL = 3&

Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As Long, pBitmapInfo As BITMAPINFO, ByVal un As Long, ByRef lplpVoid As Any, ByVal Handle As Long, ByVal dw As Long) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, ByVal XLeft As Long, ByVal YTop As Long, ByVal hIcon As Long, ByVal CXWidth As Long, ByVal CYWidth As Long, ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, ByVal diFlags As Long) As Long

'Functions
Public Function HBitmapFromHIcon(hIcon As Long, cx As Long, cy As Long) As Long
        Dim hdc As Long
        Dim hBackDC As Long
        Dim hBitmap As Long
        Dim hBackSV As Long

        hdc = GetDC(0)
        hBackDC = CreateCompatibleDC(hdc)
        hBitmap = Create32BitHBITMAP(hBackDC, cx, cy)
       
        hBackSV = SelectObject(hBackDC, hBitmap)
        DrawIconEx hBackDC, 0, 0, hIcon, cx, cy, 0, 0, DI_NORMAL
       
        Call SelectObject(hBackDC, hBackSV)
        Call ReleaseDC(0, hdc)
        Call DeleteDC(hBackDC)
HBitmapFromHIcon = hBitmap
End Function
Public Function Create32BitHBITMAP(hdc As Long, cx As Long, cy As Long) As Long
Dim bmi As BITMAPINFO
Dim hdcUsed As Long
    bmi.bmiHeader.biSize = Len(bmi.bmiHeader)
    bmi.bmiHeader.biPlanes = 1
    bmi.bmiHeader.biCompression = 0

    bmi.bmiHeader.biWidth = cx
    bmi.bmiHeader.biHeight = cy
    bmi.bmiHeader.biBitCount = 32
    Create32BitHBITMAP = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, ByVal 0&, 0, 0)
   
End Function

The initial hIcon can be from any source that has that type returned; e.g. ExtractIcon[Ex], LoadImage, etc.

EDIT - KNOWN ISSUES
**The above code only works for 24-bit icons with an alpha channel.**
For 24-bit icons without an alpha channel, and icons with 256 or fewer colors:
Code:

Public Function HBitmapFromHIconNoAlpha(hIcon As Long) As Long
Dim himg As Long
Dim hb As Long
GdipCreateBitmapFromHICON hIcon, himg
GdipCreateHBITMAPFromBitmap himg, hb, &HFF000000
GdipDisposeImage himg
HBitmapFromHIconNoAlpha = hb
End Function

(note that this requires gdiplus to be initialized, so use the entire module below which includes it)

This of course requires knowing which one to use, I'm working on one without GDIPlus, in the mean time there's this one from Leandro Ascierto's clsMenuImage:
Code:

Option Explicit
'If you are using this don't just copy the main function, note the startup and shutdown of gdiplus
Public gInitToken As Long
Private Const PixelFormat32bppRGB  As Long = &H22009
Private Type GdiplusStartupInput
    GdiplusVersion          As Long
    DebugEventCallback      As Long
    SuppressBackgroundThread As Long
    SuppressExternalCodecs  As Long
End Type
Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type
Private Type ARGB
    Blue            As Byte
    Green          As Byte
    Red            As Byte
    Alpha          As Byte
End Type
Private Type BitmapData
    Width          As Long
    Height          As Long
    Stride          As Long
    PixelFormat    As Long
    Scan0          As Long
    Reserved        As Long
End Type
Private Enum ImageLockMode
    ImageLockModeRead = &H1
    ImageLockModeWrite = &H2
    ImageLockModeUserInputBuf = &H4
End Enum
Private Declare Function GdiplusStartup Lib "GdiPlus.dll" (Token As Long, gdipInput As GdiplusStartupInput, GdiplusStartupOutput As Long) As Long
Private Declare Sub GdiplusShutdown Lib "GdiPlus.dll" (ByVal Token As Long)
Private Declare Function GdipCreateBitmapFromHBITMAP Lib "GdiPlus.dll" (ByVal hBmp As Long, ByVal hPal As Long, GpBitmap As Long) As Long
Private Declare Function GdipGetImagePixelFormat Lib "GDIplus" (ByVal Image As Long, ByRef PixelFormat As Long) As Long
Private Declare Function GdipGetImageDimension Lib "GDIplus" (ByVal Image As Long, ByRef Width As Single, ByRef Height As Single) As Long
Private Declare Function GdipBitmapLockBits Lib "GDIplus" (ByVal BITMAP As Long, ByRef RECT As RECT, ByVal Flags As ImageLockMode, ByVal PixelFormat As Long, ByRef LockedBitmapData As BitmapData) As Long
Private Declare Function GdipBitmapUnlockBits Lib "GDIplus" (ByVal BITMAP As Long, ByRef LockedBitmapData As BitmapData) As Long
Private Declare Function GdipDisposeImage Lib "GdiPlus.dll" (ByVal Image As Long) As Long

Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long


Public Sub InitGDIP()
    Static Token    As Long
    If Token = 0 Then
        Dim gdipInit As GdiplusStartupInput
        gdipInit.GdiplusVersion = 1
        GdiplusStartup Token, gdipInit, ByVal 0&
        gInitToken = Token
    End If
End Sub

Public Function pvIsAlphaIcon(ByVal IconHandle As Long) As Boolean

    Dim tARGB() As ARGB
    Dim tRECT As RECT
    Dim tICONINFO As ICONINFO
    Dim tBitmapData As BitmapData
    Dim lPixelFormat As Long
    Dim lngX As Long
    Dim lngY As Long
    Dim sngWidth As Single
    Dim sngHeight As Single
    Dim lngArgbBmp As Long
    Dim lngColorBmp As Long
    Dim bolRet As Boolean
    Dim hr As Long
   
On Error GoTo e0
If gInitToken = 0 Then InitGDIP
hr = GetIconInfo(IconHandle, tICONINFO)
If hr <> 0 Then
    If tICONINFO.hBMColor <> 0 Then
        If GdipCreateBitmapFromHBITMAP(tICONINFO.hBMColor, 0&, lngColorBmp) = 0 Then
            If GdipGetImagePixelFormat(lngColorBmp, lPixelFormat) = 0 Then
                If lPixelFormat <> PixelFormat32bppRGB Then
                    bolRet = False
                Else
                    If GdipGetImageDimension(lngColorBmp, sngWidth, sngHeight) = 0 Then
                        With tRECT
                            .Right = CLng(sngWidth)
                            .Bottom = CLng(sngHeight)
                        End With
                        ReDim tARGB(tRECT.Right - 1&, tRECT.Bottom - 1&)
                        With tBitmapData
                            .Scan0 = VarPtr(tARGB(0&, 0&))
                            .Stride = 4& * tRECT.Right
                        End With
                        If GdipBitmapLockBits(lngColorBmp, tRECT, ImageLockModeRead Or ImageLockModeUserInputBuf, lPixelFormat, tBitmapData) = 0 Then
                            For lngY = 0 To tBitmapData.Height - 1
                                For lngX = 0 To tBitmapData.Width - 1
                                    If tARGB(lngX, lngY).Alpha > 0 Then
                                        If tARGB(lngX, lngY).Alpha < 255 Then
                                            bolRet = True
                                            Exit For
                                        End If
                                    End If
                                Next lngX
                                If bolRet Then Exit For
                            Next lngY
                            Call GdipDisposeImage(lngArgbBmp)
                            Call GdipBitmapUnlockBits(lngColorBmp, tBitmapData)
                        End If
                    End If
                End If
            End If
            Call GdipDisposeImage(lngColorBmp)
        End If
        Call DeleteObject(tICONINFO.hBMColor)
    End If
    Call DeleteObject(tICONINFO.hBMMask)
Else
    bolRet = False
End If
pvIsAlphaIcon = bolRet
ReleaseGDIP
On Error GoTo 0
Exit Function

e0:
Debug.Print "modGDIP.pvIsAlphaIcon.Error->" & Err.Description & " (" & Err.Number & ")"
   
End Function
Public Function HBitmapFromHIconNoAlpha(hIcon As Long) As Long
Dim himg As Long
Dim hb As Long
GdipCreateBitmapFromHICON hIcon, himg
GdipCreateHBITMAPFromBitmap himg, hb, &HFF000000
GdipDisposeImage himg
HBitmapFromHIconNoAlpha = hb
End Function
Public Sub ReleaseGDIP()
GdiplusShutdown gInitToken
End Sub


Viewing all articles
Browse latest Browse all 1463

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>