-1

I'm trying to build a C# PInvoke for LoadImage, but I can't figure out how to pass the name parameter. I'm trying to test it by loading a system icon (in the example below the for use with WNDCLASSEX / RegisterClassEx, in place of LoadIcon).

I've tried three signatures:

This post suggested just putting new IntPtr around the value would work:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr LoadImage(IntPtr hInst, IntPtr name, uint type, int cx, int cy, uint fuLoad);

User32.LoadImage(Kernal32.GetModuleHandle("user32.dll"), new IntPtr(32513), 1, 16, 16, 0);

As per pinvoke.net, tried passing the value as a string:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr LoadImage(IntPtr hInst, string name, uint type, int cx, int cy, uint fuLoad);

User32.LoadImage(Kernal32.GetModuleHandle("user32.dll"), "32513", 1, 16, 16, 0);
User32.LoadImage(Kernal32.GetModuleHandle("user32.dll"), "#32513", 1, 16, 16, 0);

This article suggested simply using a ushort would do the trick.

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr LoadImage(IntPtr hInst, ushort name, uint type, int cx, int cy, uint fuLoad);

User32.LoadImage(Kernal32.GetModuleHandle("user32.dll"), 32513, 1, 16, 16, 0);

In all cases, the LoadImage function fails (according to GetLastWin32Error) with System error code:

ERROR_RESOURCE_TYPE_NOT_FOUND 1813 (0x715): The specified resource type cannot be found in the image file.

This suggests the value for name cannot be located in user32.dll. In C++ you'd use MAKEINTRESOURCE to get a pointer for the name value. Looking at this and this, it suggests I need my IntPtr to substitute its final bytes with a ushort representing the integer value needed. If that is the most likely issue (and simply passing a ushort doesn't work), how can I do that?

Haighstrom
  • 577
  • 5
  • 16
  • Maybe look at https://www.pinvoke.net/default.aspx/user32.loadimage for inspiration? – AKX May 31 '21 at 12:45
  • 1
    first & second versions are ok (you can use both depending if you need a resource id or name). The error just means there's nothing with this type, open user32.dll and you can check that – Simon Mourier May 31 '21 at 12:51
  • Updated to point out I got the string version I tried from pinvoke.net. – Haighstrom May 31 '21 at 12:51
  • @SimonMourier https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadicona as per here the value 32513 should be a valid icon. If it's not in User32.dll where is it? – Haighstrom May 31 '21 at 12:53
  • 1
    This is LoadIcon, not LoadImage. – Simon Mourier May 31 '21 at 12:54
  • @SimonMourier which says it has been deprecated by LoadImage. So the DLL/value combination is still valid, no? – Haighstrom May 31 '21 at 12:54
  • Erhhhh... nope. LoadIcon is for an .exe but for what you want, you must pass NULL. `[DllImport("user32", SetLastError = true)] static extern IntPtr LoadIcon(IntPtr hInstanceIntPtr lpIconName);` – Simon Mourier May 31 '21 at 12:56
  • So, how does one load a system icon using LoadImage, then? https://stackoverflow.com/questions/4285890/how-to-load-a-small-system-icon This suggests to do what I'm trying? – Haighstrom May 31 '21 at 12:56
  • In David's anwer, 103 does exit in user32.dll. 32513 is a special well-known thing. Use your first version with 103, and it should work. – Simon Mourier May 31 '21 at 13:00
  • OK 103 does indeed work. How do I find out what values the resources in user32.dll have? Is that documented somewhere? – Haighstrom May 31 '21 at 13:02
  • @SimonMourier OK I worked it out, you can see a folders called Bitmap/Cursor/Icon which shows values if you load it into Visual Studio. Thanks for your help. If you want to post this discussion as an answer I can mark it as solved. I'd quite like to know why the values used within the LoadIcon function aren't the same as these... – Haighstrom May 31 '21 at 13:06
  • Answer yourself :-) – Simon Mourier May 31 '21 at 13:08

1 Answers1

-1

It transpires that LoadIcon takes its own, custom values (e.g. 32512 for a default application icon), but user32.dll stores its icons and cursors with other reference values (100 in this case). So the issue was the values I was passing, not the way I was passing them.

This version works just fine:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr LoadImage(IntPtr hInst, ushort name, uint type, int cx, int cy, uint fuLoad);

User32.LoadImage(Kernal32.GetModuleHandle("user32.dll"), 100, 1, 16, 16, 0);

Haighstrom
  • 577
  • 5
  • 16
  • 1
    If you use the builtin Icon IDs from the headers you want to pass NULL as first argument, not the user32.dll module. This is in the documentation and you probably want to prefer that over extracting resources directly via resource ID, since some resources are redirected. – Zarat May 31 '21 at 13:21
  • @Zarat The documentation says that passing null is only to use a standalone resource, or an OEM image. I couldn't find any reference materials to explain what an OEM image is. – Haighstrom May 31 '21 at 13:54
  • Look at the documentation of LoadIcon and LoadCursor. Loading an icon via LoadImage works but you aren't going to find the documentation for loading icon constants there, because thats not how you'd load them normally. – Zarat May 31 '21 at 14:36