Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
I have a problem loading an icon from a resource.dll and the problem is that when I load it from the dll the image gets blurred, while if I add it to the form's Icon property it gets crispy and clear (for the small size).
To create the resource.dll I use Resource Builder 4, and I load it to an Icon resource.
The icon contains 3 sizes (48x48, 32x32 and 16x16) all 32 bits depth.
I have attached 2 screen shots below that show how it looks when loaded in the IDE and in code from the resource.
This is the code I use:
In the form Load
Code:
Private Sub Form_Load()
...
Icon = cLang.LoadGraphic(200, ICON_IMAGE)
....
cLang is an instance of a class I picked up online somewhere some years ago, which I to date mainly used for loading text. This is the code used and I have left out some of the more well known declarations as MoveMemory etc.
Code:
Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (PICDESC As PICDESC, RefIID As IID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long
Private Declare Function LoadImage Lib "user32" Alias "LoadImageA" (ByVal hinst As Long, ByVal lpsz As Long, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
Private Const IMAGE_ICON = 1
Public Enum GraphicTypes
BITMAP_IMAGE = 1
ICON_IMAGE = 3
CURSOR_IMAGE = 4
End Enum
Private Type IID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type
Private Type PicBmp
SIZE As Long
Type As Long
hBmp As Long
hPal As Long
Reserved As Long
End Type
Private Type PICDESC
cbSizeOfStruct As Long
picType As Long
hGdiObj As Long
hPalOrXYExt As Long
End Type
...
Public Function LoadGraphic(lngGraphicID As Long, intGraphicType As GraphicTypes) As StdPicture
Dim lngImageH As Long
Dim stdp As StdPicture
Select Case intGraphicType
Case BITMAP_IMAGE
'load the BMP Image and get BMP Handle
lngImageH = LoadImage(m_lngResourceHandle, lngGraphicID, IMAGE_BITMAP, 0&, 0&, LR_DEFAULTCOLOR)
Case ICON_IMAGE
'load the Icon Image and get Icon Handle
lngImageH = LoadImage(m_lngResourceHandle, lngGraphicID, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR)
Case CURSOR_IMAGE
'load the Cursor Image and get Cursor Handle
lngImageH = LoadImage(m_lngResourceHandle, lngGraphicID, IMAGE_CURSOR, 0, 0, LR_DEFAULTCOLOR)
End Select
'Pass the handle to the create function to create a picture of type stdpicture
CreateBitmapPicture lngImageH, intGraphicType, stdp
'return the picture
Set LoadGraphic = stdp
'free our memory
Set stdp = Nothing
End Function
Function CreateBitmapPicture(ByVal hBmp As Long, intGraphicType As GraphicTypes, stdp As StdPicture)
Dim R As Long, pic As PicBmp, IPic As StdPicture, IID_IDispatch As IID
Dim lngPicType As Long, picdes As PICDESC
Select Case intGraphicType
'assign the respective GUID's and Values
Case BITMAP_IMAGE
lngPicType = 1& 'vbPicTypeBitmap
With IID_IDispatch
.Data1 = &H20400
.Data4(0) = &HC0
.Data4(7) = &H46
End With
picdes.picType = 1& 'vbPicTypeBitmap
Case ICON_IMAGE
lngPicType = 3& 'vbPicTypeIcon
With IID_IDispatch
.Data1 = &H7BF80980
.Data2 = &HBF32
.Data3 = &H101A
End With
picdes.picType = 3& 'vbPicTypeIcon
MoveMemory IID_IDispatch.Data4(0), dblID, 8
Case CURSOR_IMAGE
lngPicType = 3& 'vbPicTypeIcon
With IID_IDispatch
.Data1 = &H7BF80980
.Data2 = &HBF32
.Data3 = &H101A
End With
MoveMemory IID_IDispatch.Data4(0), dblID, 8
picdes.picType = 3& 'vbPicTypeIcon
End Select
picdes.cbSizeOfStruct = Len(picdes)
picdes.hGdiObj = hBmp
'Create the picture
R = OleCreatePictureIndirect(picdes, IID_IDispatch, True, stdp)
End Function
I guess my question really is if there is something wrong with my code causing this, if it's a VB6 thing OR if it is more likely to have something to do with Resource Builder and how the resource is created/provided?
Thankful for any feedback and/or point in direction as I have never really bothered with this side of VB6 earlier.
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
That is some awful code, full of "don'ts," inconsistencies, incorrect comments, and worse. Looks like some copy/paste cowboy cobbled it together.
If you check the documentation though you will find:
LoadImage
cxDesired
[in] Specifies the width, in pixels, of the icon or cursor. If this parameter is zero and the fuLoad parameter is LR_DEFAULTSIZE, the function uses the SM_CXICON or SM_CXCURSOR system metric value to set the width. If this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual resource width.
cyDesired
[in] Specifies the height, in pixels, of the icon or cursor. If this parameter is zero and the fuLoad parameter is LR_DEFAULTSIZE, the function uses the SM_CYICON or SM_CYCURSOR system metric value to set the height. If this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual resource height.
So you have asked for the small icon image.
That size varies based on things like the DPI setting in force, and the displayed result depends on the DPI appcompat in effect and the control you are trying to display it in.
Say SM_CXICON is 16, but your control was told to use 24. Bam, stretching and smearing.
I see no clue that there is any IDE vs. compiled issue unless there is different DPI appcompat in effect for your 2 cases.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Thanks for replying dilettante. As said above, it's not my code but something I picked up years ago, cannot remember from where. So far I have only used it for reading strings from the resource and it has worked fine. The code as such doesn't look that horrible to me, but it doesn't mean they could be a better way of doing it.
I have ready the API docs for LoadImage and have tried with passing 16, 32 as well as 48 (the sizes available in the icon file) and only 32 worked to give the same result as before, the others give the result attached below. What information are you missing?
TIA
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
We'd need to know more about your situation.
What OS? What DPI setting? If not 100%, then how are you dealing with DPI scaling in your program? Where are you using the icons (what controls)? What size images do you need for those controls?
As I tried to point out, you are asking for the small icon size (at 100% that's normally 16x16). Even if you ask for 24x24 but your resource icon doesn't have that size then it grabs the smaller icon and tries to scale it up. That gets blurred and smudged results.
LoadIconWithScaledown() yields better results than creaky old LoadImage(), but I'm pretty sure you need a Common Controls 6 manifest to select the correct Comctl32.dll assembly.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by dilettante
We'd need to know more about your situation.
What OS? What DPI setting? If not 100%, then how are you dealing with DPI scaling in your program? Where are you using the icons (what controls)? What size images do you need for those controls?
Windows 10, 100% (think that's 96DPI), in this case the icons only purpose is to be used in form captions, so nothing fancy exactly. It's only question of 1 icon at this stage, really. I may move on later to more advanced us of icons stored in my resource dll later, but before even starting to think about that I need to have this basic thing working. Currently I have added the icon to my startup form by using the forms Icon property in the IDE's Properties window for the form, so it gets stored in the forms .frx file. Then in other other forms I set the icon by referencing the startup form
Code:
Form_Load()
Icon = frmStart.Icon
This works but it means I always have to keep this form loaded and it's not a solution I like to stay with.
Originally Posted by dilettante
As I tried to point out, you are asking for the small icon size (at 100% that's normally 16x16). Even if you ask for 24x24 but your resource icon doesn't have that size then it grabs the smaller icon and tries to scale it up. That gets blurred and smudged results.
You saw the result above when I feed the 16x16 internal version of the icon, so something is definitively wrong there. Btw, I should point out that the icon I use here is not really the one I mean to use in my program, but to exclude the posibility that my own created icon from image template isn't the cause, I have selected an "factory" icon that was shipped with my icon editor program Axialis IconWorkshop. Just to ensure that the icon isn't bad in any way. But the result is the same.
Originally Posted by dilettante
LoadIconWithScaledown() yields better results than creaky old LoadImage(), but I'm pretty sure you need a Common Controls 6 manifest to select the correct Comctl32.dll assembly.
I have a manifest including for Common Controls 6 and some other things I have picked together from here, mostly from LaVolpe I think. I will paste it below and have a look at LoadIconWithScaledown and see what I can put together.
Here is my manifest, I link it to my exe using Resource Builder 4
Code:
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="6.6.0.0"
processorArchitecture="X86"
name="Astrocalc"
type="win32"
/>
<description></description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<!-- Identify the application security requirements: Vista and above -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
<!-- Identify the application as DPI-aware: Vista and above -->
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by 7edm
in this case the icons only purpose is to be used in form captions, so nothing fancy exactly. It's only question of 1 icon at this stage, really. I may move on later to more advanced us of icons stored in my resource dll later, but before even starting to think about that I need to have this basic thing working. Currently I have added the icon to my startup form by using the forms Icon property in the IDE's Properties window for the form, so it gets stored in the forms .frx file. Then in other other forms I set the icon by referencing the startup form
Code:
Form_Load()
Icon = frmStart.Icon
This works but it means I always have to keep this form loaded and it's not a solution I like to stay with.
This is a completely different issue than you led us to believe earlier.
Originally Posted by 7edm
Btw, I should point out that the icon I use here is not really the one I mean to use in my program, but to exclude the posibility that my own created icon from image template isn't the cause, I have selected an "factory" icon that was shipped with my icon editor program Axialis IconWorkshop. Just to ensure that the icon isn't bad in any way. But the result is the same.
And this is a 3rd issue, again completely different from the other two.
In order to use high color icons with VB6 you can't use icons stored in FRX resource files. You also can't use VB's Resource Editor to place them into the RES file. To maintain fidelity you must use the command line RC.exe resource compiler (or some 3rd party tool that doesn't have the same problems as VB's Resource Editor).
I have no idea what "Resource Builder" is, but it sounds busted. If it isn't broken then you might be (1.) using it incorrectly, or (2.) using its resulting RES data incorrectly.
Here is an example that probably does everything you want and more. The only snag is that the Form icon will not appear in IDE runs because it has not yet been compiled into a PE file.
See the ReadMe.txt file.
I should have changed the Form2 Caption back to "Child form" since I am loading it modally. I got tired of fiddling with moving the modeless Form2 on top of Form1.
The code might also work with the RES data created using that weird 3rd party tool. But RC.exe comes with VB6 and it is worth learning.
Last edited by dilettante; Feb 26th, 2021 at 08:31 PM.
Reason: Fixed icon handle leaks in Seticon method
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by dilettante
We'd need to know more about your situation.
What OS? What DPI setting? If not 100%, then how are you dealing with DPI scaling in your program? Where are you using the icons (what controls)? What size images do you need for those controls?
As I tried to point out, you are asking for the small icon size (at 100% that's normally 16x16). Even if you ask for 24x24 but your resource icon doesn't have that size then it grabs the smaller icon and tries to scale it up. That gets blurred and smudged results.
LoadIconWithScaledown() yields better results than creaky old LoadImage(), but I'm pretty sure you need a Common Controls 6 manifest to select the correct Comctl32.dll assembly.
Originally Posted by dilettante
This is a completely different issue than you led us to believe earlier.
No, it's not. Actually, this is not an issue but how I currently assign the program icon to my forms. This works i.e. the icon is displayed without lack of quality, but there are other side effects and limitations that I don't like, and I am trying to change method to do this by putting the icon in my resource dll and assign it from there to the form's Icon property. I have never said anything else, but maybe due to not being native English speaker, I may explain myself a bit awkwardly. Sorry for that.
So at this stage, to make it clear, this is only about assigning an icon to the form's Icon property, and I have an issue with doing so from a resource dll as described and shown above.
Originally Posted by dilettante
And this is a 3rd issue, again completely different from the other two.
No, it's not. I think you read with all to much complication in mind. I was just "informed" you that the icon I showed here is not the same as I intend to use in my program, but that one has the same issue. I selected and tested with this icon, because it shows the problem in a clearer way to see, and that I can be sure this icon is 100% ok created by a professional, rather than the icon created by myself. In short, 2 different icon, same problem and I use the icon her that show it in clearest way.
Originally Posted by dilettante
In order to use high color icons with VB6 you can't use icons stored in FRX resource files. You also can't use VB's Resource Editor to place them into the RES file. To maintain fidelity you must use the command line RC.exe resource compiler (or some 3rd party tool that doesn't have the same problems as VB's Resource Editor).
When you assign an icon to the form's Icon property, in the IDE, using the Property Explorer, the icon is stored in the forms frx file - as far as I understand it anyway. It's then possible assign the same icon to another form by simply making a reference to the original form's icon in Form_Load() like Me.Icon = OrgFrm.Icon, well Me. isn't really needed.
It has some quirks though, and I think is something in line with "Dim MyObj As New clsMyClass". Anyway, this is not the issue at hand discussed here.
Originally Posted by dilettante
I have no idea what "Resource Builder" is, but it sounds busted. If it isn't broken then you might be (1.) using it incorrectly, or (2.) using its resulting RES data incorrectly.
Resource Builder is a Resource File Editor and compiler, it's not "busted" but I have never used it for this before. But of course, I cannot exclude it having a problem in this case, but at the moment I am working on the assumption that's not the case. It's a commercial product, so I don't think it's proper to put an url here.
Originally Posted by dilettante
Here is an example that probably does everything you want and more. The only snag is that the Form icon will not appear in IDE runs because it has not yet been compiled into a PE file.
See the ReadMe.txt file.
I should have changed the Form2 Caption back to "Child form" since I am loading it modally. I got tired of fiddling with moving the modeless Form2 on top of Form1.
The code might also work with the RES data created using that weird 3rd party tool. But RC.exe comes with VB6 and it is worth learning.
Thanks for you example and help, I will have a look at it. Just in case it's not clear to you Resource Builder is like RC.exe but with a GUI including editor etc.
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by 7edm
When you assign an icon to the form's Icon property, in the IDE, using the Property Explorer, the icon is stored in the forms frx file - as far as I understand it anyway.
Yes and no. I think the problems come in when the FRX data gets used.
VB was never updated to handle very large images or color depths above 8-bit color directly. Most of the limitations seem to be coded somewhere within the OLE libraries.
Last edited by dilettante; Feb 26th, 2021 at 09:10 PM.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by dilettante
We'd need to know more about your situation.
What OS? What DPI setting? If not 100%, then how are you dealing with DPI scaling in your program? Where are you using the icons (what controls)? What size images do you need for those controls?
As I tried to point out, you are asking for the small icon size (at 100% that's normally 16x16). Even if you ask for 24x24 but your resource icon doesn't have that size then it grabs the smaller icon and tries to scale it up. That gets blurred and smudged results.
LoadIconWithScaledown() yields better results than creaky old LoadImage(), but I'm pretty sure you need a Common Controls 6 manifest to select the correct Comctl32.dll assembly.
Originally Posted by dilettante
Yes and no. I think the problems come in when the FRX data gets used.
VB was never updated to handle very large images or color depths above 8-bit color directly. Most of the limitations seem to be coded somewhere within the OLE libraries.
I think you misunderstand, I don't have a problem with the icon stored in the frx file, I have a problem when it's stored in my resource dll, and from there assigned to the form's Icon property. This situation never involved frx afaik.
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
You can test your cLang.LoadGraphic icon directly by placing it in a AlphaBlendImage control if it retains alpha channel going through LoadImage and OleCreatePictureIndirect APIs. Both of these can drop alpha and/or reduce color depth.
Unfortunately the code you posted does not compile and a full repro of the issue will include the resource DLL with the icon. I would have tested it myself if I could and everyone partaking in this thread is struggling needlessly now.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by 7edm
I don't have a problem with the icon stored in the frx file, ...
I have a problem when it's stored in my resource dll, ...
I think so as well...
So, why not "ban" this old-fashioned way to store resources for good?
These days I use either SVGs or PNGs (in a decent enough size, usually 64x64 or 48x48),
for "Icon-like" render-outputs (on Buttons, Toolbars or in Menus, downscaled to the size currently needed).
What you need for that, is only a "high-quality-downscaler".
The Class, as it sits in the Demo-Zip from the link above, needs to be enhanced about the following
(to be able to provide Form.Icon-Props with a StdPic-wrapped version of an hIcon)
In the Declaration-Section, an API-Declare has to be added:
Code:
Private Declare Function OleCreatePictureIndirect Lib "olepro32" (PictDesc As Any, IID As Any, ByVal fPictureOwnsHandle As Long, Pic As StdPicture) As Long
And in the Code-section of the Class, this Public Method:
Code:
Public Function ToStdPicture(ByVal hIco_hCur_hBmp As Long, _
Optional ByVal imgType As PictureTypeConstants = vbPicTypeIcon) As StdPicture
Dim PictDesc(0 To 3) As Long
PictDesc(0) = 16& 'PictDesc.Size
PictDesc(1) = imgType 'PictDesc.Type
PictDesc(2) = hIco_hCur_hBmp 'PictDesc.Handle
Dim IID(0 To 3) As Long
IID(0) = &H7BF80980: IID(1) = &H101ABF32
IID(2) = &HAA00BB8B: IID(3) = &HAB0C3000
OleCreatePictureIndirect PictDesc(0), IID(0), 1, ToStdPicture
End Function
Ok, here is a ScreenShot, how a Form-Icon (similar to your own) will look like:
The Shot above was taken on a 4K-Display (15" Notebook-Screen, which I run with 250% DPI-Scaling).
And the Form-Icon you see there, was directly downscaled from a 64x64-PNG-resource -
to its correct DPI-aware size via cGDIPlusCache beforehand -> to (16 * 2.5) = 40x40
The two render-outputs which sit directly on the Form, show the quality of the downscaled 64x64-PNG
as they are currently sitting (under their ImageKeys) in the cGDIPlusCache-Class itself, rendered to the Form this way:
(the 16x16 Icon, to show how it looks downscaled in a size, one would provide the Form.Icon-Prop with, on a normal 100% (96DPI) display...)
Code:
Private Sub Form_Click()
GC.AlphaRenderTo hDC, "frmIco_40x40", 16, 2
GC.AlphaRenderTo hDC, "frmIco_16x16", 60, 2
End Sub
The Form-Icon I've placed in the Form.Icon-Prop this way (in the magenta-colored lines):
(the code below is the entire modMain.bas, as borrowed from the Cursor-Demo-Project)
Code:
Option Explicit
'below are two *.png-Consts + an old *.cur from the VB98-Common\Graphics\Cursor-Folder (Pencil.cur)
'as for creating these Const-Strings, e.g. Cross_Png_B64 was printed into the Debug-Window this way:
' Dim x!, y!, B() As Byte
' B = GC.ReadBytesFromFile("c:\temp\cross.cur")
' GC.AddIcon "Cur2Png", B, 32, 32, x, y
' B = GC.SaveImageToPngByteArray("Cur2Png")
' Debug.Print x * 32, y * 32, GC.Base64Enc(B)
Const Cross_png_B64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH4SURBVFhH7ZZBSwJREMeNCMqDSAReoqBAOgaGbqwLXqK70K1T0MmOgn2CDn3FhUUQRJAFEUQQYZvf4w142Gy13fWyA38eb2bezLz35v92S3/IkcWx4GQDzNWWqZCAhGVBRVC1I3P0mRfATsuO43zU6/Wo2Wz2ZX4luEBv7ZkKuzwnue/7EaPMHwS36K09UzkV1BqNRhQEQcQo82fBPXprz1TOBJedTicaDocRo8xfBA56a89UuOdrEo9GIy3gVeCht/Z/i9JJqcaxsjOC02x3JB6Px1rAm+AJvbXjhz/rWL8zRXFkIYFoLO6W42WHJHkk8WQy0QJ6gi56a8cPf9axnjjES1yAoZrruoZqcSDxdDo1Y5wdtFqtgcSBHTtTlGorBAnDcG+wXuJAUd4JHiviJhIcq57n9dnhb5jNZrF6hZzAt8RxBTfEs3ETiTkBAZWzA3gO1eh2Gq5Hgvl8bhLJ/Evwid7a8cOfdXudgOkBAXfHHfLIwHOoRrd3SbxYLLQAkr+jt3b88GfdXj2QiAXL5VILSJ0FOAIqZmHsO7BarbSA1N+BbUJw8xKu12stIPWXcJuwM/MtQGwBuX4LONaaJB6QvN1uQ7Vcv4bcKY1Fd0MxeJ7r/8AmReE3j0yuf0R0Mrsk2UH+CZVOSlFFqlQrpJBCCjmglEo/SUrtUvFsymoAAAAASUVORK5CYII="
Const Arrow_png_B64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAAkklEQVRYhe3W3Q6AIAgFYGS9/yvTRXMZFVqTgzXPjf0s+WTlIiIRCgxvQxyC98MYBB9P8Qg+X8IiLgBYxA0AhzAAGEQF4I9oAPgiGgF+iMW+nZJH0TKqA7og9CX0X60BKItju8BRK88xiuuV+0AffIYhEYn+Y1LJmLdjKKJrcdRzXSabHZgd+G8HPrUJDbWdD5YVCDR3uuOVR8QAAAAASUVORK5CYII="
Const Pencil_cur_RLE_B64 = "BCACEAEgACAFsAEQQAEwARADEGAFIIAFIAZABxACEA8PDwn1Dw8PDw8PDwxABuAGYAZwBjAGMIAFEAfABuAG4A8PDwr///////ng9uBw9eAw9eAQ9eAA9eAA9gBw9QBw9YAw9YAw9cAQ9cAQ9eAA9eAA9hD////y"
Public GC As New cGDIPlusCache 'one usually needs only one, global Instance of the Cache
Sub Main()
LoadResources
GC.AddImage "frmIco_16x16", App.Path & "\TextCheck_White_64x64.png", 16, 16 '<-desired scaledown-size 16
GC.AddImage "frmIco_40x40", App.Path & "\TextCheck_White_64x64.png", 40, 40 '<-desired scaledown-size 40
Set fTest.Icon = GC.ToStdPicture(GC.GetHIconFromImage("frmIco_40x40"))
'...the following is not really needed, just to prove (writing 3 new files into App.Path),
'that the decoded Const-Strings are matching their respective file-formats ...
'(check it out by loading them from there with IrfanView or your ImageViewer of choice)
GC.WriteBytesToFile App.Path & "\cross.png", GC.Base64Dec(Cross_png_B64)
GC.WriteBytesToFile App.Path & "\arrow.png", GC.Base64Dec(Arrow_png_B64)
GC.WriteBytesToFile App.Path & "\pencil.cur", GC.RLEDec(GC.Base64Dec(Pencil_cur_RLE_B64))
fTest.Show
End Sub
Sub LoadResources()
Dim B() As Byte
B = GC.Base64Dec(Cross_png_B64) 'the Cross-png String-Const was only Base64-encoded (RLE not needed, PNG is already compressed)
GC.AddImage "Cross", B 'add this Alpha-Png-resource under a given Key via the decoded ByteArray
B = GC.Base64Dec(Arrow_png_B64) 'the Arrow-png String-Const was only Base64-encoded (RLE not needed, PNG is already compressed)
GC.AddImage "Arrow", B 'add this Alpha-Png-resource under a given Key via the decoded ByteArray
B = GC.RLEDec(GC.Base64Dec(Pencil_cur_RLE_B64)) 'the Pencil-cur String-Const was RLE-encoded, prior to the final Base64-encoding
GC.AddIcon "Pencil", B, 32, 32 'add this cursor-resource under a given Key via the decoded ByteArray
End Sub
Maybe that helps - if not in "switching to a more modern approach of Resource-Handling",
then hopefully at least, to identify where the cause for the "blurry-distortion" is really located.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by 7edm
I think you misunderstand, I don't have a problem with the icon stored in the frx file, I have a problem when it's stored in my resource dll, and from there assigned to the form's Icon property. This situation never involved frx afaik.
When you add an icon to a Form at design time it is stored in the Form's FRX file. The icon of the startup Form also gets added as an icon resource, as the EXE's icon.
As far as I can tell, OLE can only "load" a multi-image icon StdPicture from an ICO-format IStream. That's what gets stored in the FRX file (and data after compiling). Things like the VB LoadPicture() function only load a single hIcon-wrapping StdPicture, i.e. one image.
It might be possible to call OleLoadPicture() passing it an IStream containing ICO format data to get a multi-image icon StdPicture. But the icon data stored as a resource is not in ICO format.
So you'd need to extract multiple resources and re-assemble these into an ICO format IStream. And of course that also assumes that OleLoadPicture() will accept that data.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by Schmidt
So, why not "ban" this old-fashioned way to store resources for good?
Lots of reasons.
To be compatible with Windows rather than carrying a lot of baggage to support some arbitrary hack.
The ICO format supports icons at multiple color depths and sizes. A small image might be completely different from larger ones, for example flatter with no shadows, etc. Monochrome is pretty obsolete, but it might also impact how those images are drawn. So it isn't just about scaling, but picking an image "close in size" and then scaling that if required.
But...
If you can carry along an external file (like a resource-only DLL) you could also use another "bag" format. A few that comes to mind include OLE Structured Storage, CAB, and ZIP. They all support "a file of files" concept though Storage and CAB are both natively supported in Windows going back quite far.
I don't see "one big PNG scaled down to any size needed" as a serious alternative. I suppose you could bag up a lot of PNGs though.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by Eduardo-
I use this technique and it works.
It's basically a crude version of what the code I posted does. One thing it fails at is scaling if your ICO doesn't contain exactly the image sizes/depths you want. It "smudges upward" which is bad form (lousy results). It also doesn't support an external resource DLL.
It also has hilarious mistakes like LoadImageAsString() when he means LoadImageAsHandle().
Last edited by dilettante; Feb 27th, 2021 at 12:32 PM.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by dilettante
It's basically a crude version of what the code I posted does. One thing it fails at is scaling if your ICO doesn't contain exactly the image sizes/depths you want. It "smudges upward" which is bad form (lousy results). It also doesn't support an external resource DLL.
OK dilettante, I didn't check your code.
One thing it fails at is scaling if your ICO doesn't contain exactly the image sizes/depths you want
Yes, it requires to have several sizes in the icon file.
I don't think that to scale icons is a good idea. There are reasons why the ico files store different versions for different uses.
Of course, in a function is better to have the option than not.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by dilettante
The problem is that SM_CXSMICON returns 24 at 150% DPI, etc.
Well, and 150% applied to 16 is: 1.5 * 16 = 24
(I've given an example for that calculation already in #13 - for 250% DPI-Zoom)
So there's no need to consult some cranky, age-old Icon-APIs - just to operate "system-conform".
Modern Apps are fully DPI-aware - and usually free-zoomable (via gestures or <Ctrl>+<Mousewheel>).
Graphics-designers and Devs the world-over have long said good-bye to image-resources in *.ico format
(same goes for "resource-dlls").
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Olaf, I don't think that your approach handles the icon sizes requirement from Windows to show the proper icon in the task bar, all the explorer views, "pinned to taskbar" icon, Etc.
We are not taking (or at least I am not) about just showing an icon in a form, but providing the icons that Windows needs for many different things.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
I tested at 175% DPI. Sees to work fine after adding a GDI Scaling node to the manifest ("System (enhanced)" scaling appcompat feature in Windows 10 1703 Creator's Update Redstone 2 March 2017, and later).
Looks fine, but of course the program isn't doing much. I was just focusing on the application, Form, and PictureBox.Picture icon drawing.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
I was hoping that there might be some "secret format" used by StdPicture/IPicture to wrap a multiimage icon from an ICO file. But I tested OleLoadPicture() with an ICO file and it merely loads a single image.
The upshot is that even at the best of times the VB6 Icon property yields incorrect results because a window is supposed to have two sizes of image associated, "normal" and small (the one we see in the caption bar, taskbar, etc.
Windows doesn't really use the "normal" icon for Alt-Tab navigation any more.
I think distortion occurs in some cases because the Icon property sets the small icon using the "normal" size icon, crudely downscaling it without even using HALFTONE mode scaling (much less the better downscaling used by LoadIconWithScaleDown() calls).
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Thanks you guys for chipping and help! I will digest the info you have contributed and make some testing, especially if I somehow in some other way can test and read the icon from my resource.dll to make sure there isn't an issue there. BTW (at Olaf), I don't think it's "out dated" in anyway to use a resource.dll, it's just a way of storing data, text or binary, in a deliverable way and usable for the program and I think it's very practical to store this outside of the exe rather than in it. The case with .ico may be different, but I really haven't had any urge/need to dig deeper into the Graphical stuff so far, but as I try to modernize my program I guess I will devote some time now to studying it.
I will be back to either ask for further help or present my final solution as I eventually tick off the resolved box. Again, thanks for all the input, much appreciated.
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Yes, in the form's icon property VB uses the 32x32 version and scales it down to 16x16 (probably by nearest neighbor) and that's the problem.
For the App icon, it need to be saved as a resource with a named ID (for example "APPICON") and must be the first icon resource. It must have all the needed sizes.
I have:
Loading the icon with the API LoadImage from the resource in the exe (named "APPICON" in my case) automatically chooses the right icon size from the resource and for the sizes that are not present it chooses the nearest one and scales it (up or down) to the size required by the parameters cx and cy.
This is the function I'm using:
Code:
Private Const SM_CXICON = 11
Private Const SM_CYICON = 12
Private Const SM_CXSMICON = 49
Private Const SM_CYSMICON = 50
Private Declare Function LoadImageAsString Lib "user32" Alias "LoadImageA" ( _
ByVal hInst As Long, _
ByVal lpsz As String, _
ByVal uType As Long, _
ByVal cxDesired As Long, _
ByVal cyDesired As Long, _
ByVal fuLoad As Long _
) As Long
Private Const LR_SHARED = &H8000&
Private Const IMAGE_ICON = 1
Private Const WM_SETICON = &H80
Private Const ICON_SMALL = 0
Private Const ICON_BIG = 1
Public Sub SetIcon(ByVal nForm As Object, Optional ByVal bSetAsAppIcon As Boolean)
Dim lhWndTop As Long
Dim lhWnd As Long
Dim cx As Long
Dim cy As Long
Dim hIconLarge As Long
Dim hIconSmall As Long
If (bSetAsAppIcon) Then
' Find VB's hidden parent window:
lhWnd = nForm.hWnd
lhWndTop = lhWnd
Do While Not (lhWnd = 0)
lhWnd = GetWindow(lhWnd, GW_OWNER)
If Not (lhWnd = 0) Then
lhWndTop = lhWnd
End If
Loop
End If
cx = GetSystemMetrics(SM_CXICON)
cy = GetSystemMetrics(SM_CYICON)
hIconLarge = LoadImageAsString( _
App.hInstance, "APPICON", _
IMAGE_ICON, _
cx, cy, _
LR_SHARED)
If (bSetAsAppIcon) Then
SendMessageLong lhWndTop, WM_SETICON, ICON_BIG, hIconLarge
End If
SendMessageLong nForm.hWnd, WM_SETICON, ICON_BIG, hIconLarge
cx = GetSystemMetrics(SM_CXSMICON)
cy = GetSystemMetrics(SM_CYSMICON)
hIconSmall = LoadImageAsString( _
App.hInstance, "APPICON", _
IMAGE_ICON, _
cx, cy, _
LR_SHARED)
If (bSetAsAppIcon) Then
SendMessageLong lhWndTop, WM_SETICON, ICON_SMALL, hIconSmall
End If
SendMessageLong nForm.hWnd, WM_SETICON, ICON_SMALL, hIconSmall
End Sub
Only at program startup from Sub Main it is called with the optional parameter bSetAsAppIcon set to True to set the App icon and then without it for each other form (since I use the same icon for all the forms).
It probably should be splitted into two procedures, one for setting the App icon and one for setting the form icon.
Tools:
To work with resources: ResourceHacker.
To work with icons: Greenfish Icon Editor.
Last edited by Eduardo-; Feb 28th, 2021 at 02:46 PM.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Thanks Eduardo, that seems to be something I can use. One question though, why do you have as argument 'ByVal nForm As Object' in Sub SetIcon when you only use hWnd anyway, why not 'ByVal nFrmhWnd As Long' and for the 2nd Optional argument, why don't you add ' = False' (or True) after Boolean as you don't use the 'IsMissing' function?
As for Tools, I use 'Resource Builder' instead of 'ResourceHacker', and for Icon Edotor I use 'IconWorkshop' from Axialis, never heard of Greenfish.
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by 7edm
Thanks Eduardo, that seems to be something I can use. One question though, why do you have as argument 'ByVal nForm As Object' in Sub SetIcon when you only use hWnd anyway, why not 'ByVal nFrmhWnd As Long'
Probably because you need to type less if you pass the form than the hWnd.
It is faster to write:
Code:
SetIcon Me
than
Code:
SetIcon Me.hWnd
Since that sub is called many times (once for form).
Do you see a problem with that?
Originally Posted by 7edm
and for the 2nd Optional argument, why don't you add ' = False' (or True) after Boolean
Because it is not needed since the Boolean default is False already, and that's what the default needs to be there.
Originally Posted by 7edm
as you don't use the 'IsMissing' function?
IsMissing can't be used with Boolean types (anyway), only with Variants you can use IsMissing.
Originally Posted by 7edm
As for Tools, I use 'Resource Builder' instead of 'ResourceHacker', and for Icon Edotor I use 'IconWorkshop' from Axialis, never heard of Greenfish.
Yes, there are lots of alternatives. I posted those as an example for the ones that do not know what programs to use.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by Eduardo-
Probably because you need to type less if you pass the form than the hWnd.
It is faster to write:
Code:
SetIcon Me
than
Code:
SetIcon Me.hWnd
Since that sub is called many times (once for form).
Do you see a problem with that?
Indeed I do First of all, what you "win" in just typing Me. you loose many times by repeatedly typing 'nForm.hWnd' instead of just 'nhWnd' although you have some help by intellisense, but that's also true for 'Me.hWnd' - but this all is not of any great importance imo.
However, you pass the form 'As Object', which means it will be late bound, which is noticeably slower, and passing the whole form is also "heavier" that just passing a Long, considering that the function may get called many times. Your call, not trying to change your programming style, instead grateful you provided what from just looking at it seems to be a solution to my problem
Originally Posted by Eduardo-
Because it is not needed since the Boolean default is False already, and that's what the default needs to be there.
IsMissing can't be used with Boolean types (anyway), only with Variants you can use IsMissing.
Yes, there are lots of alternatives. I posted those as an example for the ones that do not know what programs to use.
Yes, when you mention it, IsMissing requires a Variant, I knew that somewhere in the back of my head, but I never use neither of them and now only one of them came to show... Funny, I have never realized that the default value was set anyway, if not explicit set i the argument, but of course it makes sense. I just always use it, if nothing else for clarity and readability. Personal style, nothing is better or worse, just important it fits you.
Yes there are many tools, you choose what fits you or what you can afford - Free is never wrong, if it does the job you need to be done.
Thanx!
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Just seeking some clarification on this section.
Originally Posted by Eduardo-
Yes, in the form's icon property VB uses the 32x32 version and scales it down to 16x16 (probably by nearest neighbor) and that's the problem.
For the App icon, it need to be saved as a resource with a named ID (for example "APPICON") and must be the first icon resource. It must have all the needed sizes.
I have:
Loading the icon with the API LoadImage from the resource in the exe (named "APPICON" in my case) automatically chooses the right icon size from the resource and for the sizes that are not present it chooses the nearest one and scales it (up or down) to the size required by the parameters cx and cy.
By 'resource' here, is your scenario that you have added the icon to a .RES that you compile into the Exe or how do you go about to add the icon resource? I figure that if the icon is in a RES file compiled in or in an external resource.dll created from a .RC file shouldn't really matter?
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by 7edm
Indeed I do First of all, what you "win" in just typing Me. you loose many times by repeatedly typing 'nForm.hWnd' instead of just 'nhWnd' although you have some help by intellisense, but that's also true for 'Me.hWnd' - but this all is not of any great importance imo.
You are wrong
The idea of a function is to write something once and to use it many times.
So in fact it does not matter to type more inside a function if you gain easiness for its use.
The hWnd could have been catched into a variable for some unneeded optimization if I had wish.
To use As Object instead of As [Specific object type] can avoid problems in some circumstances, mostly when called from a client App (not sure in this particular case).
So if speed is not critical sometimes I prefer As Object for generic functions.
Originally Posted by 7edm
However, you pass the form 'As Object', which means it will be late bound, which is noticeably slower,
It is slower but it does not matter two microseconds there. It is only called at the startup of a form once and used three times inside the procedure. It does not matter at all in fact.
To optimize things that don't need to be optimized is pointless.
It is a waste of time, but if I had foresaw that someone would come with this critique, I would had saved more time doing the unneeded optimization than explaining why I did what I did. I have to recognize that at the end I lost time.
Originally Posted by 7edm
and passing the whole form is also "heavier" that just passing a Long, considering that the function may get called many times.
Yes? Sure? Who told you that?
Passing an object reference is very fast, similar a long (for the case).
The overhead is that it needs to add a reference to the object and de-reference it at the end of the scope, but it is done very fast.
Originally Posted by 7edm
Your call, not trying to change your programming style
When there is a reason I change things.
Last edited by Eduardo-; Feb 28th, 2021 at 05:29 PM.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Sorry if it offended you, but there were no criticism from me, I just asked why because I am of a curious nature and it turns out we see things a bit differently, have different coding style - fine, nop. You are a valued contributor to this community, and very appreciated at least by me.
M$ vs. VB6 = The biggest betrayal and strategic mistake of the century!?
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by Eduardo-
Loading the icon with the API LoadImage from the resource in the exe (named "APPICON" in my case) automatically chooses the right icon size from the resource and for the sizes that are not present it chooses the nearest one and scales it (up or down) to the size required by the parameters cx and cy.
Actually it picks the closest match for current screen color depth and size. If no exact match is found it chooses the next smaller size and scales up. Always, unless (I suppose, though it is not documented) there is no smaller size. In that case it probably takes the next larger size and crudely squeezes that down.
That's why the newer LoadIconWithScaleDown was added in Vista: an alternative that produces cleaner results.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by dilettante
Actually it picks the closest match for current screen color depth and size.
It depends on the arguments.
If you supply the cx and cy as I was doing in my code, it chooses the closest match to that size (regardless of the system default size).
Originally Posted by dilettante
If no exact match is found it chooses the next smaller size and scales up. Always, unless (I suppose, though it is not documented) there is no smaller size. In that case it probably takes the next larger size and crudely squeezes that down.
Well, that behavior is not documented. What I did was to experiment, and it does choose the closest size, smaller or bigger to the size you asked in the cx and cy parameters, and scales it.
I did it by painting each icon size version with a rectangle of different color, so I could see what icon size it was using.
I was surprised that an MS function was so "intelligent".
(now I have deleted the icon and resource files I used to experiment, so I can't easily retest)
Originally Posted by dilettante
That's why the newer LoadIconWithScaleDown was added in Vista: an alternative that produces cleaner results.
Re: Icon loaded from resource DLL gets blurred, but fine if loaded in IDE
Originally Posted by dilettante
Easy.
Scaling down from an image with more picture information is usually (almost always) better than scaling up from less information.
If it wasn't true the new call would never have been added to Windows Vista.
I do not agree.
In one test, and maybe the most significant one (in my case), it was requested a 20x20 version of the icon to render in the form's caption bar, because Windows was at 125% (120 DPI) and the icon needed for the caption at 100% is 16x16, but scaled at 120% it is 20x20.
It was picking the 24x24 version. (not the 16x16 one)
Specially for small icons (and maybe for any size if there are different icon versions) IMO it is better to use the closest size, not the largest.
The largest version sometimes has thin edges that are lost in the conversion, or small fine details that only produce garbage for a small sized image.
That's why they are different icon "versions". Otherwise only the 256x256 one would be needed and it should be scaled to all the other sizes.