Discussion:
ImageList_GetImageInfo - alter the bitmap(s) ?
Add Reply
R.Wieser
2024-09-30 19:11:50 UTC
Reply
Permalink
Hello all,

Using XPsp3.

I was playing with the idea to dynamically alter the contents of an
ImageList, and found the
https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-imagelist_getimageinfo
function, which says :

"The information in this structure can be used to *directly* manipulate the
bitmaps for the image"

(bolding mine).

I've been trying to think of how that is possible - the bitmaps cannot be
selected into a memoryDC - and to google information about how that would
work, but came up empty.

Question:
Does anyone know what "directly manipulate the bitmaps" method MS is
referring to in the above ?

Remark:
I already thought of and written another way to do what I want, but would
like to know how the above works. Who knows, their (MS) method might be
simpler. :-)

Regards,
Rudy Wieser
Newyana2
2024-09-30 19:41:57 UTC
Reply
Permalink
Post by R.Wieser
Hello all,
Using XPsp3.
I was playing with the idea to dynamically alter the contents of an
ImageList, and found the
https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-imagelist_getimageinfo
"The information in this structure can be used to *directly* manipulate the
bitmaps for the image"
(bolding mine).
I've been trying to think of how that is possible - the bitmaps cannot be
selected into a memoryDC - and to google information about how that would
work, but came up empty.
Does anyone know what "directly manipulate the bitmaps" method MS is
referring to in the above ?
I already thought of and written another way to do what I want, but would
like to know how the above works. Who knows, their (MS) method might be
simpler. :-)
I've never used an ImageList, but the docs say GetImageInfo returns
an ImageInfo structure, which includes an hBitmap. With that you can
call things like GetDIBits, SetDIBits, etc.
R.Wieser
2024-10-01 07:02:57 UTC
Reply
Permalink
Newyana2,
but the docs say GetImageInfo returns an ImageInfo structure, which
includes an hBitmap.
Indeed it does. Having the bitmap(s) is where my problems started. :-\
With that you can call things like GetDIBits, SetDIBits, etc.
Yep, I found the first one too (as well as GetBitmapBits). But I realized
that it takes a *lot* of work to be able to create something generic from it
(for instance, it would need handlers for all 6 BPP modi).

Also SetDIBits needs a BITMAPINFO structure filled in with stuff I /somehow/
would need to extract/copy from the origional bitmap.

The easier way (I think) would be to use CopyBitmap, load it into a
memoryDC* and use that to make the alterations on.

* which I would need to make sure it would have the same configuration
(Image List Creation Flags) as the one the ImageList was created with. In
short: another problem.

... but that than has a "how do I get it back into the origional
bitmap/imagelist ?" problem.

I was hoping that the MS way would show me a simple, smart way to circumvent
all that clumsy work.

By the way:
for one test approach I invoked "the dark arts" and retrieved the
memoryDC(s) the ImageList uses internally. Drawing on them works as
expected, very easy. Though there are a number of gotya's to recon with. As
well as the use of "the dark arts" ofcourse. :-)

Regards,
Rudy Wieser
Newyana2
2024-10-01 14:37:57 UTC
Reply
Permalink
Post by R.Wieser
Newyana2,
but the docs say GetImageInfo returns an ImageInfo structure, which
includes an hBitmap.
Indeed it does. Having the bitmap(s) is where my problems started. :-\
With that you can call things like GetDIBits, SetDIBits, etc.
Yep, I found the first one too (as well as GetBitmapBits). But I realized
that it takes a *lot* of work to be able to create something generic from it
(for instance, it would need handlers for all 6 BPP modi).
Also SetDIBits needs a BITMAPINFO structure filled in with stuff I /somehow/
would need to extract/copy from the origional bitmap.
The easier way (I think) would be to use CopyBitmap, load it into a
memoryDC* and use that to make the alterations on.
* which I would need to make sure it would have the same configuration
(Image List Creation Flags) as the one the ImageList was created with. In
short: another problem.
... but that than has a "how do I get it back into the origional
bitmap/imagelist ?" problem.
I was hoping that the MS way would show me a simple, smart way to circumvent
all that clumsy work.
for one test approach I invoked "the dark arts" and retrieved the
memoryDC(s) the ImageList uses internally. Drawing on them works as
expected, very easy. Though there are a number of gotya's to recon with. As
well as the use of "the dark arts" ofcourse. :-)
That stuff is something I have to figure out anew every time I
work with it. I once wrote a program for my girlfriend to easily
do auto-cropping and resizing of photos in high quality. The image
ops were so complicated that I used a class to load images, convert
to DIB, then do operations on that. GDI gets very complicated.
Gdiplus is worse.

Recently I've been working on functionality to change caret width
and color in a text window. The way to do it is to use a bitmap. So
I needed to be able to generate an endless variety of bitmaps
"on the fly". It took awhile to refresh my memory about hbitmaps and
DCs and such. But in VB6 there's the Picturebox control. Lightweight
and it wraps a lot of GDI ops. It turned out that I could paint the caret
in a hidden picturebox, then pass that picture's handle to the caret
function because a picture in a picturebox is a StdPicture. Maybe you
have something like that with Borland?

In terms of imaglists, I have no idea. I've never had occasion to
use one. I sometimes use Image controls and sometimes use resources,
but never an imagelist.
R.Wieser
2024-10-01 17:11:02 UTC
Reply
Permalink
Newyana2,
GDI gets very complicated. Gdiplus is worse.
I've used both, but have not tried anything complicated with it.
Recently I've been working on functionality to change caret width
and color in a text window. The way to do it is to use a bitmap.
That makes me remember something ..Oh yes, there it is. Maybe its useful to
you :

https://devblogs.microsoft.com/oldnewthing/20240916-00/?p=110272
But in VB6 there's the Picturebox control. Lightweight
and it wraps a lot of GDI ops.
...
Maybe you have something like that with Borland?
:-) Thats the nice thing of using an Assembler : No programming-language
provided wrappers around anything, you have to (understand and) write all of
them yourself.

... which is also its downside.

But with me being me I normally have little problem with that. Even though
that leads to problems as my current one.
I sometimes use Image controls and sometimes use resources,
but never an imagelist.
If you have ever used a List- or TreeView showing icons (including
sorting-direction arrows and tickboxes) than you have used an ImageList.

Regards,
Rudy Wieser
Newyana2
2024-10-02 00:12:25 UTC
Reply
Permalink
Post by R.Wieser
That makes me remember something ..Oh yes, there it is. Maybe its useful to
https://devblogs.microsoft.com/oldnewthing/20240916-00/?p=110272
Even Raymond Chen has opted for totally fucked up web design.
His page is pure white for me unless I disable CSS. He must be tryint
to force script.
Post by R.Wieser
If you have ever used a List- or TreeView showing icons (including
sorting-direction arrows and tickboxes) than you have used an ImageList.
Nope. I've never needed those and they seem like a pain.
R.Wieser
2024-10-02 07:08:40 UTC
Reply
Permalink
Newyana2,
Post by Newyana2
Even Raymond Chen has opted for totally fucked up web design.
His page is pure white for me unless I disable CSS.
Ah yes, I forgot about that. I scrubbed that page (like many others) using
GreaseMonkey. A quite handy add-on.
Post by Newyana2
He must be tryint to force script.
He ? devblogs.microsoft.com isn't his private domain you know. :-)

But yes, JS could have something to do with it - as I have disabled it too.
Post by Newyana2
Post by R.Wieser
If you have ever used a List- or TreeView showing icons (including
sorting-direction arrows and tickboxes) than you have used an ImageList.
Nope. I've never needed those and they seem like a pain.
List- and/or TreeViews, or images in them ?

I can't say I've used TreeViews much, but have used ListViews a number of
times, and some of them with ImageLists.

Images in in either a List- or TreeView is easier than you might think.
Just create an ImageList and assign it to the View, load some images/icons
into it, and tell, when adding an entry into either View, which image you
want to display. Thats all there is to it.

But yes, it took me a while until I had/have everything figured out. Thats
what happens when most of what you find is "learn.microsoft.com" pages
(which mostly do not /learn/ you anything, but are "what again where the
arguments to that function?" reference pages - and often incomplete. As the
one I started this thread with) and the odd bits-and-pieces of "example"
code I can find on the Web.

Regards,
Rudy Wieser
Kerr-Mudd, John
2024-10-02 16:07:34 UTC
Reply
Permalink
On Tue, 1 Oct 2024 19:11:02 +0200
Post by R.Wieser
Newyana2,
GDI gets very complicated. Gdiplus is worse.
I've used both, but have not tried anything complicated with it.
Recently I've been working on functionality to change caret width
and color in a text window. The way to do it is to use a bitmap.
That makes me remember something ..Oh yes, there it is. Maybe its useful to
https://devblogs.microsoft.com/oldnewthing/20240916-00/?p=110272
But in VB6 there's the Picturebox control. Lightweight
and it wraps a lot of GDI ops.
...
Maybe you have something like that with Borland?
:-) Thats the nice thing of using an Assembler : No programming-language
provided wrappers around anything, you have to (understand and) write all of
them yourself.
Unless you use libraries aznd function calls extensively.
Post by R.Wieser
... which is also its downside.
But with me being me I normally have little problem with that. Even though
that leads to problems as my current one.
I sometimes use Image controls and sometimes use resources,
but never an imagelist.
If you have ever used a List- or TreeView showing icons (including
sorting-direction arrows and tickboxes) than you have used an ImageList.
Regards,
Rudy Wieser
--
Bah, and indeed Humbug.
R.Wieser
2024-10-02 16:55:41 UTC
Reply
Permalink
John,
Post by Kerr-Mudd, John
No programming-language provided wrappers around anything,
you have to (understand and) write all of them yourself.
Unless you use libraries aznd function calls extensively.
And thats indeed what I do. :-)

I *have* to, as, as mentioned, my programming language of choice, Assembly
(Borlands Tasm32), doesn't offer such wrappers.

Regards,
Rudy Wieser
Newyana2
2024-10-02 17:28:17 UTC
Reply
Permalink
Post by R.Wieser
John,
Post by Kerr-Mudd, John
No programming-language provided wrappers around anything,
you have to (understand and) write all of them yourself.
Unless you use libraries aznd function calls extensively.
And thats indeed what I do. :-)
I *have* to, as, as mentioned, my programming language of choice, Assembly
(Borlands Tasm32), doesn't offer such wrappers.
I bought the assembly bible once and started reading. I decided
life's too short for that. The beauty of VB6 is that I can drag-drop
GUI elements. No 3 pages of code to create a button. At the same
time, I can use Win32 API for most of the functionality. I probably
never would have bothered if the only choice were early C++. If I
want to write that doesn't mean I also want to perfect paper
manufacturing. I can see the appeal of building a ship in a
bottle. I'm just too practical to do all that work only to have an
object to sit on a bookshelf.
R.Wieser
2024-10-02 19:47:52 UTC
Reply
Permalink
Newyana2,
Post by Newyana2
I bought the assembly bible once and started reading. I decided
life's too short for that.
:-)

I pretty-much started with Assembly and worked my way thru a number of home
computers (TRS80, Apple 2e, commodore 64) to arrive at the X86 machines,
starting with DOS 3.3, where I started to use borlands assembler(s). Later
on I bought Borlands Tasm32

Although I've tried a few other programming languages, somehow I always
returned to Assembly.
Post by Newyana2
The beauty of VB6 is that I can drag-drop GUI elements. No 3 pages of code
to create a button.
Ah, that. Yes, I started with that too. But when I discovered Dialogs and
how I could add a button (or any other control) with just a single line in a
resource file I dropped the whole CreateWindowEx and all of that approach,
and used DialogBoxParam instead.
Post by Newyana2
I can see the appeal of building a ship in a bottle. I'm just too
practical to do all that work only to have an object to sit on a
bookshelf.
:-) My interrest is mosty towards figuring out how to get stuff working.
As a result I have a lot of "how does this work" test programs, which I
often abandon when I have a clear view of the harbour.

Regards,
Rudy Wieser
legalize+ (Richard)
2024-11-04 16:57:52 UTC
Reply
Permalink
[Please do not mail me a copy of your followup]
Post by R.Wieser
but the docs say GetImageInfo returns an ImageInfo structure, which
includes an hBitmap.
Indeed it does. Having the bitmap(s) is where my problems started. :-\
I'm confused. The ImageList is giving you the *handle* of the bitmap
that it is using. So whatever you do using that bitmap handle as the
target of some drawing operation will update the bitmap that is being
used by the ImageList.

Are you not seeing the changes in the ImageList?

Remember that if you change the ImageList that was used to draw
something on screen, you'll need to redraw whatever control is using
the ImageList to see the effect on screen, e.g. call InvalidateRect.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
R.Wieser
2024-11-04 17:28:19 UTC
Reply
Permalink
Richard,
Post by legalize+ (Richard)
Post by R.Wieser
Indeed it does. Having the bitmap(s) is where my problems started. :-\
I'm confused.
Yes, you are. :-)
Post by legalize+ (Richard)
The ImageList is giving you the *handle* of the
bitmap that it is using. So whatever you do using that bitmap
handle as the target of some drawing operation will update the
bitmap that is being used by the ImageList.
To be able to alter a HBITMAP you need to select it into a "device context"
(DC). described in the docs you can only do that into one at a time (1).

And as an imagelist has already selected the bitmap(s) into its own DC (2)
...

(1)
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectobject

"An application cannot select a single bitmap into more than one DC at a
time."
Post by legalize+ (Richard)
Are you not seeing the changes in the ImageList?
See above. As long as I can't select the HBITMAP into a DC I can't draw on
it.
Post by legalize+ (Richard)
you'll need to redraw whatever control is using the ImageList
to see the effect on screen, e.g. call InvalidateRect.
Yes, I know. Still, thanks for mentioning it.

(2) For one test I dug into the "hImageList" structure and found its DCs.
By using those I was able to both alter the bitmap(s) and draw it (in the
"paint" event) onto the dialog.

But as using stuff from within unspecified, "MS internal" structures is a
bit of a no-no (and it also caused its own problems) ...

Regards,
Rudy Wieser
legalize+ (Richard)
2024-11-04 17:47:10 UTC
Reply
Permalink
[Please do not mail me a copy of your followup]
Post by R.Wieser
Post by legalize+ (Richard)
The ImageList is giving you the *handle* of the
bitmap that it is using. So whatever you do using that bitmap
handle as the target of some drawing operation will update the
bitmap that is being used by the ImageList.
To be able to alter a HBITMAP you need to select it into a "device context"
(DC). described in the docs you can only do that into one at a time (1).
And as an imagelist has already selected the bitmap(s) into its own DC (2)
...
I see that on ComCtl32.dll version 6 or later, they have a way for you
to QueryInterface for an IImageList interface which has a Replace
method that you can use to replace the bitmap. So they do expose a
way to do it in later versions of the common controls library.
<https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-himagelist_queryinterface>

Can you use that?

If not, have you tried calling ShowWindow to hide the control and then
try to select the bitmap into a DC? Perhaps if the window is hidden,
it deselects the bitmap from its internal DC.

Also, maybe I missed it in the thread where you stated it, but I
assume you're using the image list in association with another
control. Have you tried just creating a new image list with the
updated bitmap and replacing the image list on the target control?
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
R.Wieser
2024-11-04 18:56:58 UTC
Reply
Permalink
Richard,
Post by legalize+ (Richard)
I see that on ComCtl32.dll version 6 or later, they have a way
for you to QueryInterface for an IImageList interface which has
a Replace method that you can use to replace the bitmap.
The "IImageList::Replace" method you mean (or the function
"ImageList_Replace") ? Yes, you can replace the image *of a single item*
with that. Which is rather useless when you have a big bitmap (from
"ImageList_GetImageInfo"), with all items on it.

But you've skipped the most important part of the problem: How do I edit
that big bitmap ?

MS tells me that its possible : "The information in this structure can be
used to directly manipulate the bitmaps for the image" ?

(
https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-imagelist_getimageinfo )

But how ?

Regards,
Rudy Wieser
legalize+ (Richard)
2024-11-04 21:56:35 UTC
Reply
Permalink
[Please do not mail me a copy of your followup]
Post by R.Wieser
Richard,
Post by legalize+ (Richard)
I see that on ComCtl32.dll version 6 or later, they have a way
for you to QueryInterface for an IImageList interface which has
a Replace method that you can use to replace the bitmap.
The "IImageList::Replace" method you mean (or the function
"ImageList_Replace") ?
I didn't notice the function until you mentioned it, but they seem to
be the same.

Have you tried the function? It seems to do what you want.

Without decompiling, we don't know what the implementation does, but
if I were to implement it, I would take the given bitmap and use that
as a source for a copy operation into the internal bitmap used by the
image list. Otherwise you impose the requirement on the caller that
the supplied bitmap must outlive the image list, which is not only a
poor design but isn't documented in the Replace or Add functions for
image lists. In fact, the Add function documentation explicitly
mentions that the supplied bitmap is copied into an "internal data
structure".
Post by R.Wieser
Yes, you can replace the image *of a single item*
with that. Which is rather useless when you have a big bitmap (from
"ImageList_GetImageInfo"), with all items on it.
Again, without decompiling, we can't infer what happens behind the
scenes. At best, we should only be going by what is documented
behavior, and it seems that ImageList_Replace is the function provided
to do what you want.

Again, have you tried that and does it give the desired visual
results?

If yes, what exactly is the problem?
Post by R.Wieser
But you've skipped the most important part of the problem: How do I edit
that big bitmap ?
I don't think you can edit it directly; you are intended to use the
ImageList functions to replace images as a whole. The bitmap handle
in the IMAGEINFO struct could be use as the source for a bitmap copy,
but as you (and the documentation points out) the bitmap is selected
into a DC and there's no way to obtain that internal DC. I'm away
from my copy of Rector & Newcomer, so I don't have anything besides
the MS docs to go on.

It's entirely possible that this "manipulate the bitmap directly"
language is a holdover from Win16 and isn't relevant to Win32.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
R.Wieser
2024-11-05 09:46:24 UTC
Reply
Permalink
Richard,
Post by legalize+ (Richard)
Post by R.Wieser
The "IImageList::Replace" method you mean (or the function
"ImageList_Replace") ?
I didn't notice the function until you mentioned it, but they seem
to be the same.
Have you tried the function? It seems to do what you want.
[quote=me]
Yes, you can replace the image *of a single item* with that. Which is
rather useless when you have a big bitmap (from "ImageList_GetImageInfo"),
with all items on it.
[/quote]
Post by legalize+ (Richard)
Without decompiling, we don't know what the implementation does,
Yes, we do. That is what the "learn.microsoft.com" website is for.
Post by legalize+ (Richard)
but if I were to implement it, I would take the given bitmap and use
that as a source for a copy operation into the internal bitmap used
by the image list.
There are exacly *two* functions which accept images for multiple items, and
those do not seem to accept a grid of them (such as ImageList_GetImageInfo
returns), looking at the explanation "The number of images is inferred from
the width of the bitmap" to the "hbmImage" argument.
Post by legalize+ (Richard)
In fact, the Add function documentation explicitly mentions that
the supplied bitmap is copied into an "internal data structure".
Besides the above problem, how does that "add" function REPLACE the
origional bitmap ?
Post by legalize+ (Richard)
Again, without decompiling, we can't infer what happens behind the
scenes.
Again, yes we can. Its called "reading the documentation". Unless you want
to claim that the MS documentation is untrustworthy and should be ignored.
:-)
Post by legalize+ (Richard)
At best, we should only be going by what is documented behavior,
and it seems that ImageList_Replace is the function provided
to do what you want.
The "iIndex" parameter and its "An index of the image to replace"
explanation to that function tells me otherwise.
Post by legalize+ (Richard)
Again, have you tried that and does it give the desired visual
results?
If yes, what exactly is the problem?
You want me to test something that is at odds with the explanation to those*
functions ? Why ? Just to see if you can catch MS on having made a mistake
?

* you're flip-flopping, without saying, between the "add" and the "replace"
function.

But, have it your way. Testing both ... No, neither works as you expected.
Post by legalize+ (Richard)
Post by R.Wieser
But you've skipped the most important part of the problem: How do I
edit that big bitmap ?
I don't think you can edit it directly;
Even though MS says otherwise ? On what grounds ?
Post by legalize+ (Richard)
you are intended to use the ImageList functions to replace images as a
whole.
Nope. There is not a single function which does that.
Post by legalize+ (Richard)
The bitmap handle in the IMAGEINFO struct could be use as the source
for a bitmap copy,
Ofcourse you can. You just don't get the result you think you should be
getting. :-p
Post by legalize+ (Richard)
but as you (and the documentation points out) the bitmap is selected
into a DC and there's no way to obtain that internal DC.
:-) Guess again. Its even easy to get those DC's. But, as mentioned
earlier, poking into undocumented structures is a bit of a no-no.
Post by legalize+ (Richard)
I'm away from my copy of Rector & Newcomer, so I don't have anything
besides the MS docs to go on.
As mentioned and shown, the latter is what I'm using too. And as such I'm
wondering about how you got to your "can be used to replace the full image"
conclusion.
Post by legalize+ (Richard)
It's entirely possible that this "manipulate the bitmap directly"
language is a holdover from Win16 and isn't relevant to Win32.
You mean that that "information" has survived for almost a quarter of
century and multiple "remove everything about old Windows versions" cleanups
? Well, I guess that is possible. Everything is.

Regards,
Rudy Wieser
R.Wieser
2024-11-07 09:39:51 UTC
Reply
Permalink
Richard,
Post by legalize+ (Richard)
you are intended to use the ImageList functions to replace images
as a whole.
Nope.
I should perhaps extended on that "nope".

Nope, thats *your* goal.

*Mine* was to be able to alter the appearance of certain items in the
ImageList (and keep the rest as-is). Like drawing stuff onto them and/or
combine multiple items into a single one.

... Which I figured out how to do before starting this thread.

My question was solely aimed at trying to find a simpler solution, one that
the MS documentation suggested was available.


But *you* wanted to see if those "replace" and "add" functions didn't
secretly do much more than what they where documented to do, and I decided
to humor you.

First try:

Trying to "replace" or "add" using the bitmaps returned by "GetImageInfo"
always fails - due to the same reason you can't draw on those bitmaps: they
are already loaded into a DC. As a result the "replace" visually didn't
seem to do anything, and "add" just appended some blackness.

I could have stopped there-and-than, as it didn't do what *I* wanted.


Second try:

But I said I would humor you, and that means to me I follow *your* lead, not
mine. So I replaced the bitmaps by two I loaded from file, and tried
again - just to see if that would work better.

It did. Visually the "replace" function now showed a change, and the "add"
function added something beyond blackness - but both failed to load all of
the offered bitmaps contents.

And that was the result I posted.


Bottom line:

You've replaced my request for information with some quite different - and
by it skipping over the "how do I edit the imagelists own bitmaps ?" problem
to begin with, while you didn't even bother to explain why you thought you
knew better than MS own documentation.

Also, you decided that some undocumented behaviour (of the "replace" and
"add" functions) would be fully acceptable to me, while I already posted
that I could infact edit those internal bitmaps *if* I would not mind
relying on some undocumented stuff - which I indicated I didn't want to do.

Regards,
Rudy Wieser

Loading...