It is convenient to only have a single executable file when distributing an application for several reasons:
- It's no longer required to put the executable in a
.zipetc. archive with the necessary loose files/directories - The user cannot break your application by moving the executable but not copying the necessary relative data
- The user can run your application from any directory without breaking relative data paths, because there is no relative data referenced
On Linux, this can be accomplished by putting your data in an object file, then linking that directly. This tutorial (archive.org backup) is an excellent reference for doing that.
On Windows, the official way to do this is by using the Resource Compiler.
There didn't seem to be any simple tutorials on how to do this, so I'm going to fix that!
The complete source can be found here.
Creating the resource file
This file determines the name, type, and location of your resources. Many tutorials say it's scary and hard and you shouldn't edit them by hand, but that is ridiculous.
Let's say we're trying to package message.txt:
This is my message.We're going to create a resource file, MyResources.rc:
MyData CUSTOMDATA "MyData.txt"The format is simple:
Name Type FilenameIn this case, we want complete control over the data we're loading in. We use a User-Defined resource type to make sure Windows doesn't try to do anything special with our data.
- In this case, I chose
MyDatafor the name. - I used
CUSTOMDATAfor the type. This is completely arbitrary; as long as it doesn't match one of the built-in types, it's user-defined. - Of course,
"MyData.txt"is the filename of the data.
Compiling the resource
We then use RC, the Resource Compiler, to create a file we can statically link into the final executable.
In a Developer command prompt, or by finding RC.exe manually, run:
rc MyResources.rcThis creates a file MyResources.res. We can include this in our link command to package the data into the executable.
Loading resources
Let's write a C file, main.c, to load the resource:
#include <stdio.h>
#include <windows.h>
int main()
{
// This will break if we're loading from a DLL
HMODULE hModule = NULL;
HRSRC resourceInfo = FindResourceA(hModule, "MyData", "CUSTOMDATA");
if (!resourceInfo)
{
fprintf(stderr, "Could not find resource\n");
return 1;
}
HGLOBAL resource = LoadResource(hModule, resourceInfo);
if (!resource)
{
fprintf(stderr, "Could not load resource\n");
return 1;
}
DWORD resourceSize = SizeofResource(hModule, resourceInfo);
const char* message = (const char*)resource;
fprintf(stderr, "The data from the resource is: \n");
fwrite(message, resourceSize, 1, stderr);
return 0;
}You can see we first find the resource, then load it, then get the size.
We cast the HGLOBAL to whatever pointer type we want the data to be.
Note that we print the string with fwrite() because that way we can specify the size. This is for the case where the resource data is not zero-terminated.
Linking to the resource
Finally, we compile and link the .c and .res files together:
cl main.c MyApp.resProvided there are no errors, we run it:
> main.exe
The data from the resource is:
This is my message.You can copy paste the main.exe whereever you want, and you won't have any loading issues, because the data is all inside the executable.
Applications
This tutorial used a trivial file as an example, but this technique can be used to do much more interesting things:
- Package your data into a
.zipfile, then when the application loads, extract the contents into%APPDATA% - Package icons, fonts, software licenses/EULAs, documentation, or images
- Bundle default configuration files, then dump them to the user's configuration directory when requested
- Distribute the source code of the application within the executable so it can become self-modifying (I'll write more on this later)