T
Terry
After some playing around with icons and ImageList, I'm not quite
sure I understand what's happening. Either the resources are not really
getting cleaned up like I thought they would or what I'm using to measure
the resources isn't accurate, or there's something else going on.
I'm using Task Manager and added the column for "GDI Objects". I created a
little test Form and added some code to load an icon in various ways, and
then call Dispose() or DestroyIcon(). I performed three tests.
1. Load an icon using "ExtractIcon()" (the IconLoader.extractIcon below is
just a
static method I wrote that does the actual ExtractIcon and then creates an
"Icon" object using FromHandle() and returns the icon)
Icon icon = IconLoader.extractIcon(@"F:\Media\Icons\go.ico", 0);
icon.Dispose();
What happens is on the "extractIcon()" call I see the GDI handle count go up
by 2. The GDI handle count remains the same after the "Dispose()".
2. Load an icon using "ExtractIcon()" but use "DestroyIcon()" to clean up
the icon resource
Icon icon = IconLoader.extractIcon(@"F:\Media\Icons\go.ico", 0);
IconLoader.destroyIcon(icon.Handle);
What happens here, is on the "extractIcon()" call the GDI handle count goes
up by 2 and on the "destroyIcon()" call, it goes down by 2.
3. Load an icon from an embedded resource and call "Dispose()"
Stream s =
this.GetType().Assembly.GetManifestResourceStream("TestResourceUsage.go.ico"
);
Icon icon = new Icon( s );
icon.Dispose();
What happens here is on the "new Icon(s)" line, the GDI handle count goes up
by 2 and on the "Dispose()" call it goes down by 2.
The way I'm reading the results of these three tests is that if you load a
resource using a Win32 API call like "ExtractIcon()" then you *must* call
"DestroyIcon()" to free the resource. If it's loaded from a managed
assembly then it's ok for you to just call "Dispose()" to clean up the
resource.
I'm still confused when it comes to ImageLists. When I watch the GDI Handle
count as I'm adding an image or icon to an ImageList, I see the GDI handle
count go up by 2 (which corresponds to what Nicholas had said about the
ImageList making a copy of the resource) but no matter what I do, I'm unable
to recover the resources that are allocated by the ImageList. Even if I
clear the Images collection, call "Dispose()" on the ImageList and set it's
reference to "null" the allocated GDI handles are never recovered - even if
the image is loaded from the managed manifest. I would expect that clearing
the ImageList would also call Dispose() on each of the images contained in
the ImageList (but maybe it doesn't).
Maybe what I'm doing is not a valid test, but it makes me uncomfortable when
I get behavior that doesn't seem consistent. Are my tests invalid? My
conclusions wrong? Or is there something else going on here that I'm
unaware of?
Thanks,
Terry
sure I understand what's happening. Either the resources are not really
getting cleaned up like I thought they would or what I'm using to measure
the resources isn't accurate, or there's something else going on.
I'm using Task Manager and added the column for "GDI Objects". I created a
little test Form and added some code to load an icon in various ways, and
then call Dispose() or DestroyIcon(). I performed three tests.
1. Load an icon using "ExtractIcon()" (the IconLoader.extractIcon below is
just a
static method I wrote that does the actual ExtractIcon and then creates an
"Icon" object using FromHandle() and returns the icon)
Icon icon = IconLoader.extractIcon(@"F:\Media\Icons\go.ico", 0);
icon.Dispose();
What happens is on the "extractIcon()" call I see the GDI handle count go up
by 2. The GDI handle count remains the same after the "Dispose()".
2. Load an icon using "ExtractIcon()" but use "DestroyIcon()" to clean up
the icon resource
Icon icon = IconLoader.extractIcon(@"F:\Media\Icons\go.ico", 0);
IconLoader.destroyIcon(icon.Handle);
What happens here, is on the "extractIcon()" call the GDI handle count goes
up by 2 and on the "destroyIcon()" call, it goes down by 2.
3. Load an icon from an embedded resource and call "Dispose()"
Stream s =
this.GetType().Assembly.GetManifestResourceStream("TestResourceUsage.go.ico"
);
Icon icon = new Icon( s );
icon.Dispose();
What happens here is on the "new Icon(s)" line, the GDI handle count goes up
by 2 and on the "Dispose()" call it goes down by 2.
The way I'm reading the results of these three tests is that if you load a
resource using a Win32 API call like "ExtractIcon()" then you *must* call
"DestroyIcon()" to free the resource. If it's loaded from a managed
assembly then it's ok for you to just call "Dispose()" to clean up the
resource.
I'm still confused when it comes to ImageLists. When I watch the GDI Handle
count as I'm adding an image or icon to an ImageList, I see the GDI handle
count go up by 2 (which corresponds to what Nicholas had said about the
ImageList making a copy of the resource) but no matter what I do, I'm unable
to recover the resources that are allocated by the ImageList. Even if I
clear the Images collection, call "Dispose()" on the ImageList and set it's
reference to "null" the allocated GDI handles are never recovered - even if
the image is loaded from the managed manifest. I would expect that clearing
the ImageList would also call Dispose() on each of the images contained in
the ImageList (but maybe it doesn't).
Maybe what I'm doing is not a valid test, but it makes me uncomfortable when
I get behavior that doesn't seem consistent. Are my tests invalid? My
conclusions wrong? Or is there something else going on here that I'm
unaware of?
Thanks,
Terry