0

I believe what my code complies to LoadImage specification, but despite of explicitly specified dimensions, loaded image is largest non-PNG icon.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Picture.Icon.Handle := LoadImage(
    0,
    MakeIntResource(OIC_SHIELD),
    IMAGE_ICON,
    GetSystemMetrics(SM_CXSMICON),
    GetSystemMetrics(SM_CYSMICON),
    LR_SHARED
  );
  Win32Check(Image1.Picture.Icon.HandleAllocated);

  OutputDebugString(PChar(Format('%d×%d', [
    Image1.Picture.Icon.Width, 
    Image1.Picture.Icon.Height
  ]))); //  128×128
end;

Note: i prefer to be compliant to newer LoadImage semantics rather than to rely on the explicit module and resource id (essentially falling back to LoadIcon semantics) as specified in the answer to this question.


Quotes from LoadImage specs are exactly outlining my problem with mutually exclusive LoadImage behaviours (either fail or use previously loaded stock resource, ignoring desired dimensions) - see Adrian McCarthy's answer.


While OIC_SHIELD is Windows 6.0+ specific, the same happens with other stock icons (OIC_xxx constants) present in Windows since version 4.0.

Community
  • 1
  • 1
Premature Optimization
  • 1,917
  • 1
  • 15
  • 24
  • 1
    -1. The first link you supplied showed you a workaround for this problem. The fact you don't seem to like it doesn't change the fact that it's the solution. "I know there's a solution, but I don't wanna use it" doesn't make this a good question, and trying to use "MS might change the meaning of constants defined in a no-longer suppoorted version that tons of apps rely on" doesn't either. (The fact you downvoted @David's answer in spite of the fact that it's correct is ridiculous, too. It's not wrong, and should not have been downvoted. If you don't agree with it, just don't accept it.) – Ken White Jul 08 '11 at 01:45
  • 1
    @Ken White, presence of well-known workaround doesn't automatically make it a good solution. Read the details below. Do not attempt to falsificate my words any more. I never said a thing against **constants**. – Premature Optimization Jul 08 '11 at 02:13
  • But in the presence of documentation that explains the problem you're having directly, a well-known workaround **is** the solution. And your first comment to @David's answer was "The point of stock resources is what you identify it as single constant" - can you read the last word **you** wrote in the quote? You can't see the "constant" **you** yourself typed (particularly if you're going to accuse me of falsifying it)? – Ken White Jul 08 '11 at 02:37
  • @Ken White, you clearly didnt read entire phrase before copypasting it. – Premature Optimization Jul 08 '11 at 12:56

2 Answers2

5

Use SHGetStockIconInfo on Vista and up, and the solution from the other question for all other operating systems.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    The point of stock resources is what you identify it as single constant without desperately searching for library which contains it as resource identified by id. – Premature Optimization Jul 07 '11 at 17:52
  • 1
    I don't know what you are talking about. Do you want a solution to the problem, or are you just looking for an argument? – David Heffernan Jul 07 '11 at 17:53
  • Yes, you dont know (i told thrice already). I need solution to **specific** problem, not a rather dirty workaround (at least until specific problem proven to be unsolvable). – Premature Optimization Jul 07 '11 at 18:07
  • 1
    This is a solution. What don't you like about code that works and will work forever? – David Heffernan Jul 07 '11 at 18:08
  • Cant deny this possibility, however it will make LoadImage(OIC_* rather useless for dealing with stock resources (see above). – Premature Optimization Jul 07 '11 at 18:12
  • 1
    Your comments are very unclear. You're first comment to this answer just makes no sense to me. I suppose you mean that you would rather call a function like `SHGetStickIconInfo`. I agree with that sentiment but it's no use on XP where it doesn't exist. I suppose you could make a point and stop supporting XP on principle. Or you could use code that works and solves the problem. You don't need to search for a library, it's called user32. You don't need to hunt for an ID, they are known. The IDs used in 2000 and XP are not going to change. – David Heffernan Jul 07 '11 at 18:16
  • Oh, would you like to start an argument like "my solution is good and i dont want to hear any objections"? No, it is a reinvented wheel, and will not work forever (relies on 3.0 standard resources). What if MS decide to move it and amend everything except *your* code? Anyway, API call meaning "give me a standard resource N" implies API already knows module,name,language,etc. Otherwise, what the point of standard resources? – Premature Optimization Jul 07 '11 at 18:33
  • 2
    So you think it's possible that microsoft might release a new version of xp that changes the IDs of the standard icons? I don't believe that's likely to happen. – David Heffernan Jul 07 '11 at 18:39
  • 3
    +1 for a good answer that solves the problem described. I'd upvote twice if I could to offset the improper downvote you received from the OP as well. – Ken White Jul 08 '11 at 01:46
4

From the notes on LR_SHARED in the LoadImage documentation that you linked to:

This function finds the first image in the cache with the requested resource name, regardless of the size requested.

Unfortunately, you can't just drop the LR_SHARED because:

When loading a system icon or cursor, you must use LR_SHARED or the function will fail to load the resource.

So that explains the problem, but it's not clear what to do about it. You could use SHGetStockIconInfo. That requires Vista+, but since you're trying to get the shield icon, I assume you're already limited to Vista+.

I'm not a .NET programmer, but it looks like there's an API to get the shield icon.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175