Can't use a PNG from Resources file (VS2017)

Do you have a question about makefiles, a compiler or IDE you are using and need to know how to set it up for wxWidgets or why it doesn't compile but other IDE's do ? Post your questions here.
Post Reply
wonkey_monkey
Earned a small fee
Earned a small fee
Posts: 15
Joined: Sun May 26, 2019 8:10 pm

Can't use a PNG from Resources file (VS2017)

Post by wonkey_monkey » Sun May 26, 2019 8:26 pm

Hi,

I've done a lot of Googling and seen a few people having this same problem, but I've been unable to find a solution that works.

The problem is that I can't use a PNG file from my resource.rc file. I followed the instructions here:

https://wiki.wxwidgets.org/Embedding_PN ... ource_file

but it just won't work.

Code: Select all

wxImage::AddHandler(new wxPNGHandler);

	wxBitmap exit(wxT("exit.png"), wxBITMAP_TYPE_PNG); // this works; it loads the external PNG file and I can then use it on my toolbar
	wxBITMAP_PNG(IDB_PNG2); // this doesn't work (I know the bitmap doesn't get assigned anywhere, but it should still work, right?)
I get this error:

Image

even though IDB_PNG2 is most definitely in my resource.rc and resource.h files:

Code: Select all

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Resource.rc
//
#define IDB_PNG2                        105

Code: Select all

/////////////////////////////////////////////////////////////////////////////
//
// PNG
//

IDB_PNG2                RCDATA                     "hand.png"
I added the file originally by using VS's Import, which added it as a PNG resource, then I closed VS and edited the .rc file manually to change it to an RCDATA.

The only thing I've found so far which does work is:

Code: Select all

wxBITMAP_PNG(#105)
but that's inconvenient, to say the least. Even wxBITMAP_PNG(#IDB_PNG2) doesn't work, even thought IDB_PNG2 is #defined as 105.

What can I do to figure out the problem?

PS My program, such as it is, is based on the HelloWorld example

User avatar
doublemax
Moderator
Moderator
Posts: 13992
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Can't use a PNG from Resources file (VS2017)

Post by doublemax » Sun May 26, 2019 10:04 pm

Remove this line:

Code: Select all

#define IDB_PNG2                        105
Use the source, Luke!

wonkey_monkey
Earned a small fee
Earned a small fee
Posts: 15
Joined: Sun May 26, 2019 8:10 pm

Re: Can't use a PNG from Resources file (VS2017)

Post by wonkey_monkey » Sun May 26, 2019 11:16 pm

Hmm, okay, that works (I thought just removing #include "resource.h" would work, but it seems those definitions are getting included regardless), and I think I sort of see why...

...but doesn't that now have to potential to screw up any other resources I try to create? And what if I want to be able to refer to that resource by name elsewhere?

Is this just "how it has to be", or is a bit of a bug/oversight in wxWidgets?

User avatar
doublemax
Moderator
Moderator
Posts: 13992
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Can't use a PNG from Resources file (VS2017)

Post by doublemax » Mon May 27, 2019 6:02 am

Is this just "how it has to be", or is a bit of a bug/oversight in wxWidgets?
Honestly, i never thought about that - it has always been that way ;)

I think the problem arises if you use the Visual Studio resource editor to add a file. I just add the line manually in the .rc file.

However, this is a user forum. If you want to discuss this with the core developers, please ask on the wx-users group / mailing list: https://groups.google.com/forum/#!forum/wx-users
Use the source, Luke!

wonkey_monkey
Earned a small fee
Earned a small fee
Posts: 15
Joined: Sun May 26, 2019 8:10 pm

Re: Can't use a PNG from Resources file (VS2017)

Post by wonkey_monkey » Mon May 27, 2019 5:03 pm

I've gone with this as a Visual Studio compatible alternative:

Code: Select all

	hResource = FindResource(nullptr, MAKEINTRESOURCE(IDB_PNG1), L"PNG");
	size_t _size = SizeofResource(nullptr, hResource);
	hMemory = LoadResource(nullptr, hResource);
	LPVOID ptr = LockResource(hMemory);
	wxBitmap my_bitmap = wxBitmap::NewFromPNGData(ptr, _size);

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2025
Joined: Sun Jan 03, 2010 5:45 pm

Re: Can't use a PNG from Resources file (VS2017)

Post by PB » Mon May 27, 2019 7:33 pm

I am probably too late but are we clear that the issue is the resource ordinal value versus its name, originating from the hackish way (exploiting the resource ID range and memory addressing limitations) of distinguishing the two as it was created long time ago by Microsoft? The hash in wxBITMAP_PNG definition (used as stringizing operator there) may cause some more confusion as it can be used as the first character of the resource name to make it the ordinal value, see my code below.

wxBITMAP_PNG, just as wxBitmap ctor, expects the resource name (see image sample) and not the ordinal value.

If your application is MSW only and you know you will be always using their ordinals (i.e., numbers and not names) and you wish to use the macro, then the solution should be simple, something like this

Code: Select all

#ifdef __WINDOWS__
    #undef wxBITMAP_PNG
    #define wxBITMAP_PNG(resourceOrdinal) wxBitmap(wxString::Format("#%hu", static_cast<uint16_t>(resourceOrdinal)), wxBITMAP_TYPE_PNG_RESOURCE) 
#endif // #ifdef __WINDOWS__
Unfortunately, such code is somewhat brittle and with macro paramaters not having type checking does not protect nicely from silly mistakes such as passing the resource name instead of ordinal. It would be better to have a simple function such as

Code: Select all

wxBitmap PNGFromResource(uint16_t ordinal)
{
    return wxBitmap(wxString::Format("#%hu", ordinal), wxBITMAP_TYPE_PNG_RESOURCE);
}

wonkey_monkey
Earned a small fee
Earned a small fee
Posts: 15
Joined: Sun May 26, 2019 8:10 pm

Re: Can't use a PNG from Resources file (VS2017)

Post by wonkey_monkey » Tue May 28, 2019 10:47 pm

I'm definitely not clear on what causes the issue! Somewhere, I'm guessing, the name is being unexpectedly converted to the ordinal because of the macro #defined in resource.h - remove or rename the macro and the issue disappears. But it's all macros within macros within macros so who knows what's going on...

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2025
Joined: Sun Jan 03, 2010 5:45 pm

Re: Can't use a PNG from Resources file (VS2017)

Post by PB » Wed May 29, 2019 5:40 am

wonkey_monkey wrote:
Tue May 28, 2019 10:47 pm
I'm definitely not clear on what causes the issue! Somewhere, I'm guessing, the name is being unexpectedly converted to the ordinal because of the macro #defined in resource.h - remove or rename the macro and the issue disappears.
The way I understand it, an MS Windows resource can be identified (e.g., in ::FindResource()) either by its name which is a string (LPCTSTR) or its ordinal which is an integer value.

There is a "hack" using MAKEINTRESOURCE() which allows treating a passed string (pointer to character array) as an integer. It relies on the fact that MS Windows in the user space cannot address memory in the range between 0 and 64 kB. So if the address of a "name" is in that range then it is treated as an ordinal.

If you have

Code: Select all

#define IDB_PNG2 105
then the resource is accessed by an ordinal (integer with a value 105). If you omit the declaration above then the resource is accessed by a name (string with value "IDB_PNG2").

As you can see in the wxBitmap documentation, wxBitmap constructors and Create() methods take only a wxString, so the the trick with ordinal which uses a string literal address cannot be used. It can be worked around using a wxString with the hash sign as the first character of its value, see my previous post.

Most importantly, I believe that the issue can be easily worked around with wxWidgets, see the code in my previous post.

Post Reply