New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Add Extract methods to Icon #8929
Comments
In the example API usage the
So presumably to get the icon of the current running application: // get app icon
using Icon icon = Icon.ExtractIcon(Environment.ProcessPath, id: 0, size: 32); |
That's for the existing
Yes, if it has one. You need to check for null and use some other icon if one isn't embedded. |
I like this plan. So we don't need any new PInvokes? Have we migrated |
Just a couple of new ones. We can't migrate System.Drawing to CsWin32 until the Win32 metadata includes the gdiplusflat header. There is an active issue for it, I haven't had time to try and get it working myself. There is also an issue with some of the shell APIs technically being platform specific. For our purposes we can use any definition, but there is no way to force pick one for AnyCPU in CsWin32. |
Love it! |
@JeremyKuhne : Did you think about an information for the possible Icon sizes? The information about the sizes are inside of a MultiIcon file in the iconheader.
There is a very old interesting article in codeproject.com for MultiIcons with sources. See MultiIcons. |
@harborsiem I did. I didn't address it here as I'd want to prototype it to make sure the proposed API is solid. I believe it would have to be hand-spun to match the semantics of the proposed APIs above. While we do have existing code for cruising the raw data for info, we'd need to handle resource id vs index specification. I'm guessing it is a fair amount of work and at the moment I don't have cycles. I'm happy to assist if someone else has some time to create another API request and do some prototyping as a part of it. |
@JeremyKuhne when is the next api review meeting? |
@elachlan Hopefully tomorrow |
namespace System.Drawing;
public partial class Icon
{
// Existing:
// public static Icon ExtractAssociatedIcon(string filePath);
public static Icon? ExtractIcon(string filePath, int id, bool smallIcon = false);
public static Icon? ExtractIcon(string filePath, int id, int size);
}
public partial class SystemIcons
{
// Existing:
// public static Icon GetStockIcon(StockIconId stockIcon, StockIconOptions options = StockIconOptions.Default);
public static Icon GetStockIcon(StockIconId stockIcon, int size);
} |
@JeremyKuhne what PInvoke did you want to use? |
According to the docs (https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-extracticonexa), we might be able to extract an array of icons? Are the docs wrong?
Edit: example usage, its possible. - http://www.jasinskionline.com/windowsapi/ref/e/extracticonex.html |
This looks like it works. I only tested with one icon though. internal static unsafe Icon[]? ExtractSmallIcons(string? lpszFile)
{
if (string.IsNullOrWhiteSpace(lpszFile))
{
return null;
}
HICON[] iconSmall;
uint readIconCount = 0;
fixed (char* lpszFileLocal = lpszFile)
{
uint numIcons = ExtractIconEx(lpszFile: lpszFileLocal, nIconIndex: -1, nIcons: 0);
iconSmall = new HICON[numIcons];
fixed (HICON* phiconSmall = iconSmall)
{
readIconCount = ExtractIconEx(lpszFile: lpszFileLocal, nIconIndex: 0, phiconLarge: null, phiconSmall: phiconSmall, nIcons: numIcons);
}
}
if (readIconCount == 0)
{
return null;
}
Icon[] iconArray = new Icon[readIconCount];
for (int i = 0; i < readIconCount; i++)
{
HICON icon = iconSmall[i];
if (!icon.IsNull)
{
iconArray[i] = (Icon)Icon.FromHandle(icon).Clone();
}
}
return iconArray;
} |
To be clear, my implementation is to get an array of icons without looping. |
@elachlan The difficulty with that API is that there is no way to specify the icon size. You will be able to iterate through with this proposal, I'll have a test that validates that. |
I was attempting to solve the issue raised by the API review. Which was the file being continuously opened and closed for each icon if you want a list of icons. |
Understood. It isn't a terrible thing that the handle gets reopened multiple times. There is IO caching in the OS and it is probably a pretty rare scenario where users code is going to be significantly impacted by the overhead of multiple calls. |
This adds Icon.Extracticon to allow extracting icons from icon files and native resources from PE files at any specified resolution. Also adds an overload to SystemIcons.GetStockIcon() to get a specified size. Fixes dotnet#8929
This adds Icon.Extracticon to allow extracting icons from icon files and native resources from PE files at any specified resolution. Also adds an overload to SystemIcons.GetStockIcon() to get a specified size. Fixes #8929
Verified it in VS insertion PR with .Net 8 Preview 4 test pass build: 8.0.0-preview.4.23253.2, the Icon.ExtractIcon method has been added. Same test result as above. |
Some missing APIs that I can think of:
@JeremyKuhne Is any work planned in this direction? |
Background and motivation
System.Drawing.Icon
has methods for creating icons from managed resources and associated native icons. It doesn't, however, allow you to get all native resource icons, or always specify the size that you require.The
Icon
constructors that take a path / stream only support.ico
files. They do allow choosing a particular size, but also try to pick a color depth based on the current display settings. Color depth matching is of limited use and these constructors are costly as they manually load the entire file, parsing it to create the "best-fit" icon. The full stream is kept in memory (this is particularly painful if you're trying to load smaller icons).System.Drawing.Icon.ExtractAssociatedIcon()
has some overlap with these new APIs. It will load the first icon from the file it's given or fall back on whatever executable the file is associated with. The API used for this doesn't allow specifying a size. (We could spin our own by callingFindExecutable
if we find a need in the future.)API Proposal
API Usage
Alternative Designs
Could potentially add additional constructors to
Icon
, but behavior differences between string overloads would probably be confusing. For example, as the entire source file is not copied, resizing viaCopy
is scaled, instead of reparsed.Risks
Nothing notable.
Notes
SHGetStockIconInfo
- I believe it tries to scale down from larger sizes.Icon
s loaded through these APIs you'll just get the current backing bitmap scaled if you change sizes with the copy constructors (as you would withHICON
constructedIcon
s andExtractAssociatedIcon
).The text was updated successfully, but these errors were encountered: