I've known about this method for quite some time and even use it in some of my projects. But haven't seen it applied elsewhere. So, I thought I'd make it more known with an example.
We know there are plenty of examples of loading a PNG file. Those typically use GDI+, WIA, or a custom control. However, since Vista, we can do this with basically one API call. The downside is that VB still won't display these correctly if PNG has alphablending, but we can draw them flawlessly to a DC while maintaining transparency within the PNG, if any.
Requirement: Vista or better
API: CreateIconFromResourceEx. Also needed is DrawIconEx to render the PNG to DC
Edited: My comments above are a bit misleading. Only if the PNG contains alphablending will you want to use DrawIconEx to draw the image. Otherwise, just assign the returned stdPicture to any control's Picture property or even the form's Picture property. Also, see post #2 for a possible workaround.
Recommend testing on some large PNGs. I am not sure what the limit of the API may be. I believe Vista topped out around 768x768. However, never really researched it and that may have been a soft-limit. In other words, this may not be a perfect solution for all PNGs. But on Win10, for example, no problem with typical 1024x768 PNGs.
Simply get the PNG data into a zero-bound byte array (from file or via LoadResData) and pass to this function. The function creates a stdPicture object wrapped around an icon created from the PNG. You don't have to worry about destroying the icon since VB will do it when the stdPicture is released or goes out of scope.
Example. Some error checking provided, tweak to your liking. Replace the bold blue text below with a valid file/path name of a PNG.
We know there are plenty of examples of loading a PNG file. Those typically use GDI+, WIA, or a custom control. However, since Vista, we can do this with basically one API call. The downside is that VB still won't display these correctly if PNG has alphablending, but we can draw them flawlessly to a DC while maintaining transparency within the PNG, if any.
Requirement: Vista or better
API: CreateIconFromResourceEx. Also needed is DrawIconEx to render the PNG to DC
Edited: My comments above are a bit misleading. Only if the PNG contains alphablending will you want to use DrawIconEx to draw the image. Otherwise, just assign the returned stdPicture to any control's Picture property or even the form's Picture property. Also, see post #2 for a possible workaround.
Recommend testing on some large PNGs. I am not sure what the limit of the API may be. I believe Vista topped out around 768x768. However, never really researched it and that may have been a soft-limit. In other words, this may not be a perfect solution for all PNGs. But on Win10, for example, no problem with typical 1024x768 PNGs.
Simply get the PNG data into a zero-bound byte array (from file or via LoadResData) and pass to this function. The function creates a stdPicture object wrapped around an icon created from the PNG. You don't have to worry about destroying the icon since VB will do it when the stdPicture is released or goes out of scope.
Code:
' APIs first
Private Declare Function CreateIconFromResourceEx Lib "user32.dll" (ByRef presbits As Any, ByVal dwResSize As Long, ByVal fIcon As Long, ByVal dwVer As Long, ByVal cxDesired As Long, ByVal cyDesired As Long, ByVal Flags As Long) As Long
Private Declare Function OleCreatePictureIndirect Lib "OleAut32.dll" (lpPictDesc As Any, riid As Any, ByVal fPictureOwnsHandle As Long, ipic As IPicture) As Long
Private Declare Function DestroyIcon Lib "user32.dll" (ByVal hIcon As Long) As Long
Public Function LoadPNGtoICO(pngData() As Byte) As IPicture
Dim hIcon As Long
Dim lpPictDesc(0 To 3) As Long, aGUID(0 To 3) As Long
hIcon = CreateIconFromResourceEx(pngData(0), UBound(pngData) + 1&, 1&, &H30000, 0&, 0&, 0&)
If hIcon Then
lpPictDesc(0) = 16&
lpPictDesc(1) = vbPicTypeIcon
lpPictDesc(2) = hIcon
' IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
aGUID(0) = &H7BF80980
aGUID(1) = &H101ABF32
aGUID(2) = &HAA00BB8B
aGUID(3) = &HAB0C3000
' create stdPicture
If OleCreatePictureIndirect(lpPictDesc(0), aGUID(0), True, LoadPNGtoICO) Then
DestroyIcon hIcon
End If
End If
End Function
Code:
' DrawIconEx API:
Private Declare Function DrawIconEx Lib "user32.dll" (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
Private Sub Command1_Click()
Dim tPicture As StdPicture
Dim imgData() As Byte, fnr As Integer, lSize As Long
fnr = FreeFile()
On Error Resume Next
Open [the file] For Binary As #fnr
If Err Then
MsgBox Err.Description
Exit Sub
End If
On Error GoTo 0
lSize = LOF(fnr)
If lSize = 0& Then
MsgBox "File does not exist", vbExclamation + vbOKOnly
Close #fnr
Exit Sub
End If
ReDim imgData(0 To lSize - 1&)
Get #fnr, 1, imgData()
Close #fnr
Set tPicture = LoadPNGtoICO(imgData())
Erase imgData()
If tPicture Is Nothing Then
MsgBox "Failed to load the file. May not be valid PNG format or pre-Vista operating system.", vbExclamation + vbOKOnly
Else
' change the 3rd & 4th 0& to destination width & height respectively. Zero = actual size
DrawIconEx Me.hDC, 0&, 0&, tPicture.Handle, 0&, 0&, 0&, 0&, &H3
End If
End Sub