#Saving the icon into an executable at compile time

1 messages · Page 1 of 1 (latest)

languid swallow
#

Hello! I am trying to create a GUI program using the windows api and no external libraries.

I've created a .ico file for the icon I want to use and I want to be able to pack it in with the executable so I don't have to ship the icon separately, if that makes sense.

I created a simple resource file resource.rc that looks like this:


IDI_MYICON ICON "icon.ico"```

And a header file `resource.h` that looks like this:
```#define IDI_MYICON 101``` (yes that's all for both)

Then I used `windres .\resource.rc` to precompile it into a file called `resource.h.gch`.

Supposedly I should just be able to use `LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON));` to load the icon and it should work, but it isn't loading the icon at all and uses the default executable icon when loaded. Where am I going wrong?

(apologies if this doesn't make sense I'm happy to clarify, lol)
winter pierBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

river spindle
languid swallow
river spindle
thorny gulch
#

so far when i've needed to do something like this i've just use some of cmake's built-in functionality for creating/reading/writing files. here's an example that will take all of the .ttf font files from a directory, convert their contents to raw hex, then populate a fonts.cpp and fonts.hpp file so these don't need to be read from disk when loading them. they just end up getting compiled directly into the binary and can be loaded from the variables created a script that does something along the same lines as this cmake snippet does...

# output file paths / files...
set(binary_resource_dir "${CMAKE_CURRENT_BINARY_DIR}/resources")
file(MAKE_DIRECTORY "${binary_resource_dir}")

set(fonts_cpp "${binary_resource_dir}/fonts.cpp")
set(fonts_hpp "${binary_resource_dir}/fonts.hpp")

# input files that you want to 
# bake into the binary being built...
file(GLOB font_resources CONFIGURE_DEPENDS
  "${CMAKE_CURRENT_SOURCE_DIR}/data/fonts/*.ttf"
)

# Concatenate resource files
# into a comma separated string
string(REGEX REPLACE "([^\\]|^);" "\\1,"
  font_resources_string "${font_resources}"
)
string(REGEX REPLACE "[\\](.)" "\\1" 
  font_resources_string "${font_resources_string}"
)
string(REPLACE "," ";" 
  fonts_list ${font_resources_string}
)

# for each binary file:
# 1. Get filename
# 2. Replace filename spaces & extension separator for C compatibility
# 3. Convert to lower case
# 4. Read hex data from file
# 5. Convert hex data for C compatibility
# 6. Append data to c file
# 7. Append extern definitions to h file
file(WRITE ${fonts_hpp}
  "#include <stdint.h>\n\n"
)
file(WRITE ${fonts_cpp}
  "#include <stdint.h>\n\n"
  "#include \"resources/fonts.hpp\"\n\n"
)

message("\n\n===== ${PROJECT_NAME} fonts =====")
message("\nPacking font hex dumps into ${fonts_cpp}:")

foreach(bin ${fonts_list})
  string(REGEX MATCH "([^/]+)$" filename ${bin})
  message("> resources/${filename}")

  string(REGEX REPLACE "\\.| |-" "_" filename ${filename})
  string(TOLOWER ${filename} filename)
  file(READ ${bin} filedata HEX)
  string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," filedata "${filedata}")

  file(APPEND ${fonts_cpp} "const uint8_t ${filename}[] = {${filedata}0x00};\n")
  file(APPEND ${fonts_cpp} "const uint32_t ${filename}_size = sizeof(${filename}) - 1;\n\n")
  file(APPEND ${fonts_hpp} "extern const uint8_t ${filename}[];\n")
  file(APPEND ${fonts_hpp} "extern const uint32_t ${filename}_size;\n\n")
endforeach()
#

that script essentially ends up creating these two source files when the cmake project is configured:

#

then in the C++ code that needs to use this data can just #include "resources/fonts.hpp", then use the arrays as if they were just any normal variable:

auto font_data = std::basic_string_view{
    roboto_regular_ttf,
    roboto_regular_ttf_size,
};
#

if you aren't using cmake for your builds, this is a library that approaches this type of thing in the same way, i just don't have any personal experience working with it myself so i'm not sure how well it works compared to just letting cmake call a script like the one above: https://github.com/graphitemaster/incbin

GitHub

Include binary files in C/C++. Contribute to graphitemaster/incbin development by creating an account on GitHub.

languid swallow
#

I really need to learn Cmake at some point ^^;

thorny gulch
#

i'm sure there are different approaches you can take for this type of thing, i just tend to use this approach since it's pretty quick and easy to do. the only real requirement is that the data is stored somewhere and you know how to deserialize it in the code that needs to use it. you could always look into that library in my last message as a different option as well if nothing else seems to be working.

you could always even just dump the hex data manually and toss it in a source file if it's just for tiny bits of static data like icons.

something i do for icons is just store the utf-8 codepoints in code, then render them as text using something like stb_truetype

languid swallow
#

Yeah I only really need to store the icon data because most of everything else is going to be rendered using raw math for this specific project, lol

#

I'll see if that approach works

languid swallow
#

this didn't work

river spindle
# languid swallow I have the massive byte array, but how do I actually tell the windows api to loa...

You can use LookupIconIdFromDirectory to get an offset at which the actual icon data starts ```c
int offset = LookupIconIdFromDirectory(icon_array, TRUE);

and then use that in `CreateIconFromResource`: ```c
HICON ic = CreateIconFromResource(icon_array + offset, 4551 - offset, TRUE, 0x00030000);

(taken from https://stackoverflow.com/questions/41379285/load-hicon-from-the-buffer-ico-file)
I hope that helps. You may also want to check for failure after both function calls.

languid swallow
#

!solved