Embedding binary data with Windows Resource Compiler

By Macoy Madson. Published on .

It is convenient to only have a single executable file when distributing an application for several reasons:

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 Filename

In 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.

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.rc

This 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.res

Provided 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: