Click here to Skip to main content
12,758,605 members (34,013 online)
Click here to Skip to main content
Add your own
alternative version

Stats

137.9K views
60 bookmarked
Posted 7 Sep 2003

UpdateResource

, 7 Sep 2003
Rate this:
Please Sign up or sign in to vote.
How to manipulate raw resources (RT_RCDATA) using UpdateResource().

Introduction

Over the years, I've seen various flavors of the question "How do I include a file or data with my program that I can extract at run-time and do something with it?" For example, the asker might have had a .WAV file or a .MDB (MS Access) file that s/he wanted to include in the actual executable itself. For one reason or another, they do not want to package the two files separately. One advantage this has over a separate data/configuration file is that it'll never get lost. If the user decides they want to start fresh, they can remove everything but the application itself, and when the application is started up again, it extracts an empty database, all without the user knowing the behind-the-scenes details.

So thre are really two questions on the table here: "How to include the file?" and "Once the file is included, how to extract it and 'use' it?" Let's look at a simple example.

Including the file

In this example, I'll show the necessary code to take the entire Windows calculator (calc.exe) and add it as a resource to some test .EXE. The .EXE could just as easily be the application where these code snippets reside. The first thing we must do is open calc.exe in read-only mode, and read the entire file into a buffer.

HANDLE hFile;
DWORD dwFileSize,      
      dwBytesRead;
LPBYTE lpBuffer;

hFile = CreateFile(L"C:\\Winnt\\System32\\calc.exe", GENERIC_READ, 
                   0,
                   NULL,
                   OPEN_EXISTING,
                   FILE_ATTRIBUTE_NORMAL,
                   NULL);

if (INVALID_HANDLE_VALUE != hFile)
{
    dwFileSize = GetFileSize(hFile, NULL);

    lpBuffer = new BYTE[dwFileSize];

    if (ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL) != FALSE)
    {
        // do something with lpBuffer here
    }

    delete [] lpBuffer;        
    
    CloseHandle(hFile);
}

Updating the resource data

Now it's simply a matter of getting access to the resource data of the test file and updating it with the data pointed to by lpBuffer. The third parameter to UpdateResource() is the name we want to give the resource. I just chose an arbitrary name of 104.

HANDLE hResource;

hResource = BeginUpdateResource(L"C:\\...\\t3.exe", FALSE);
if (NULL != hResource)
{
    if (UpdateResource(hResource, 
        RT_RCDATA, 
        MAKEINTRESOURCE(104), 
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
        (LPVOID) lpBuffer, 
        dwFileSize) != FALSE)
    {
        EndUpdateResource(hResource, FALSE);
    }
}

At this point, you can actually open the test file with Visual Studio and see the addition of our data in the "Data" section. Be sure to open the file as a "resource"!

Extracting the data

So now your application has been delivered, and you need to extract the resource data.

Extracting the resource data uses functions from the same family as UpdateResource(). The required steps are to load the file containing the resource data, find the desired resource, load the resource, and then lock it.

HMODULE hLibrary;
HRSRC hResource;
HGLOBAL hResourceLoaded;
LPBYTE lpBuffer;

hLibrary = LoadLibrary(L"C:\\...\\t3.exe");
if (NULL != hLibrary)
{
    hResource = FindResource(hLibrary, MAKEINTRESOURCE(104), RT_RCDATA);
    if (NULL != hResource)
    {
        hResourceLoaded = LoadResource(hLibrary, hResource);
        if (NULL != hResourceLoaded)        
        {
            lpBuffer = (LPBYTE) LockResource(hResourceLoaded);            
            if (NULL != lpBuffer)            
            {                
                // do something with lpBuffer here            
            }
        }    
    }

    FreeLibrary(hLibrary);
}

Saving the data to a file

All that's left is to create a file with the data pointed to by lpBuffer. Nothing special needs to be done to the data. It's the entire Windows calculator!

DWORD dwFileSize,
      dwBytesWritten;
HANDLE hFile;

dwFileSize = SizeofResource(hLibrary, hResource);

hFile = CreateFile(L"C:\\Winnt\\Temp\\calc2.exe",
                   GENERIC_WRITE,
                   0,
                   NULL,
                   CREATE_ALWAYS,
                   FILE_ATTRIBUTE_NORMAL,
                   NULL);

if (INVALID_HANDLE_VALUE != hFile)
{
    WriteFile(hFile, lpBuffer, dwFileSize, &dwBytesWritten, NULL);

    CloseHandle(hFile);
}

Now you should be able to run the newly created file, calc2.exe! As I indicated at the beginning of the article, this can be done with any sort of file that you want to include along with your main application or DLL.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

DavidCrow
Software Developer (Senior) Pinnacle Business Systems
United States United States

The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.

HTTP 404 - File not found
Internet Information Services

You may also be interested in...

Comments and Discussions

 
GeneralCursor Resource Pin
nenfa23-Jul-10 4:57
membernenfa23-Jul-10 4:57 
AnswerRe: Cursor Resource Pin
DavidCrow23-Jul-10 5:51
mvpDavidCrow23-Jul-10 5:51 
GeneralRe: Cursor Resource Pin
nenfa26-Jul-10 23:52
membernenfa26-Jul-10 23:52 
QuestionRe: Cursor Resource Pin
DavidCrow27-Jul-10 3:56
mvpDavidCrow27-Jul-10 3:56 
GeneralBITMAP Pin
filipe_madureira29-May-09 6:27
memberfilipe_madureira29-May-09 6:27 
GeneralRe: BITMAP Pin
DavidCrow29-May-09 11:49
mvpDavidCrow29-May-09 11:49 
GeneralRe: BITMAP Pin
filipe_madureira1-Jun-09 23:31
memberfilipe_madureira1-Jun-09 23:31 
QuestionIs it possible to execute the data? Pin
flaushi20-Mar-09 3:30
memberflaushi20-Mar-09 3:30 
AnswerRe: Is it possible to execute the data? Pin
DavidCrow20-Mar-09 3:47
mvpDavidCrow20-Mar-09 3:47 
GeneralRe: Is it possible to execute the data? Pin
marc ochsenmeier6-Jul-10 3:01
membermarc ochsenmeier6-Jul-10 3:01 
QuestionRe: Is it possible to execute the data? Pin
DavidCrow6-Jul-10 4:29
mvpDavidCrow6-Jul-10 4:29 
AnswerRe: Is it possible to execute the data? Pin
marc ochsenmeier6-Jul-10 4:39
membermarc ochsenmeier6-Jul-10 4:39 
GeneralThe article helped a lot Pin
adenissov18-Nov-08 13:30
memberadenissov18-Nov-08 13:30 
AnswerA way for updating application ICON (from .ICO file) Pin
Elad raz15-Oct-08 7:35
memberElad raz15-Oct-08 7:35 
As mentioned before the .ICO file doesn't store as a raw data. In fact .ICO file may contains one or more icons and it's logically divided into two segment: Main icon file header containing the types of the icons in the file and many standalone icon image.
The PE resources table contain also TWO type of resources: RT_GROUP_ICON and RT_ICON. The raw content of the resources are similar to the content .ICO file BUT DIFFERENT. Here is a small summery of the changes and a code to use UpdateResource for changing application's icon.

The .ICO file is composed from this header:
#pragma pack(2)
typedef struct 
{
  WORD            idReserved;   // Reserved (must be 0)
  WORD            idType;       // Resource type (1 for icons)
  WORD            idCount;      // How many images?
  ICONDIRENTRY    idEntries[1]; // The entries for each image
} ICONDIR;

// For each 1..idCount:
typedef struct
{
  BYTE   bWidth;               // Width, in pixels, of the image
  BYTE   bHeight;              // Height, in pixels, of the image
  BYTE   bColorCount;          // Number of colors in image (0 if >=8bpp)
  BYTE   bReserved;            // Reserved
  WORD   wPlanes;              // Color Planes
  WORD   wBitCount;            // Bits per pixel
  DWORD  dwBytesInRes;         // how many bytes in this resource?
  DWORD  dwImageOffeset;       // the ID
} ICONDIRENTRY;


Where dwImageOffeset is an offset to a BITMAPHEADERINFO and the icon palette's table and raw data.

The same icon is stored in the resource as a only header in RT_GROUP_ICON:

typedef struct 
{
  WORD            idReserved;   // Reserved (must be 0)
  WORD            idType;       // Resource type (1 for icons)
  WORD            idCount;      // How many images?
  GRPICONDIRENTRY   idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;

typedef struct
{
  BYTE   bWidth;               // Width, in pixels, of the image
  BYTE   bHeight;              // Height, in pixels, of the image
  BYTE   bColorCount;          // Number of colors in image (0 if >=8bpp)
  BYTE   bReserved;            // Reserved
  WORD   wPlanes;              // Color Planes
  WORD   wBitCount;            // Bits per pixel
  DWORD   dwBytesInRes;         // how many bytes in this resource?
  WORD   nID;                  // the ID
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;


The only different is that instead of using offset from the start of the resource, the icon is store as a GROUP resource containing pointers to 'nID' icon of type RT_ICON.

So here is a code sample of how translating .ICO file to a resource.
The input for this code is:
ICON_FILENAME - The .ICO filename
IDI_ICON - The icon index to modify
      HANDLE inFile = CreateFile(ICON_FILENAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
      if (inFile == INVALID_HANDLE_VALUE)
      {
        printf("Error cannot open input file: %s\n", ICON_FILENAME);
        return -1;
      }

      DWORD read;
      size = GetFileSize(inFile, NULL);
      temp = (BYTE*)GlobalAlloc(GMEM_FIXED, size);    
      ReadFile(inFile, temp, size, &read, NULL);
      CloseHandle(inFile);

      // Change the icon group
      ICONDIR* ig = (ICONDIR*)(temp);

      DWORD newSize = sizeof(GRPICONDIR) + (sizeof(GRPICONDIRENTRY)*(ig->idCount - 1));
      GRPICONDIR* newDir = (GRPICONDIR*)GlobalAlloc(GMEM_FIXED, newSize);
      newDir->idReserved = ig->idReserved;
      newDir->idType =  ig->idType;
      newDir->idCount = ig->idCount;

      DWORD rv;
      for (int i = 0; i < ig->idCount; i++)
      {
        BYTE* temp1 = temp + ig->idEntries[i].dwImageOffeset;
        DWORD size1 = ig->idEntries[i].dwBytesInRes;

        newDir->idEntries[i].bWidth = ig->idEntries[i].bWidth;
        newDir->idEntries[i].bHeight = ig->idEntries[i].bHeight;
        newDir->idEntries[i].bColorCount = ig->idEntries[i].bColorCount;
        newDir->idEntries[i].bReserved = ig->idEntries[i].bReserved;
        newDir->idEntries[i].wPlanes = ig->idEntries[i].wPlanes;
        newDir->idEntries[i].wBitCount = ig->idEntries[i].wBitCount;
        newDir->idEntries[i].dwBytesInRes = ig->idEntries[i].dwBytesInRes;
        newDir->idEntries[i].nID = i + 1;
        
        type = RT_ICON;
        name = MAKEINTRESOURCE(i + 1);
        if (0 == (rv = ReplaceResource(wOut, temp1, size1, type, name)))
        {
          printf("Icon %d replaced OK!\n", i + 1);
        } else 
        {
          printf("Replacing the icon  %d group FAILED!\n", i + 1);
        }
      }

      type = RT_GROUP_ICON;
      name = MAKEINTRESOURCE(IDI_ICON);

      if (0 == (rv = ReplaceResource(wOut, (BYTE*)newDir, newSize, type, name)))
      {
        printf("Icon group replaced OK!\n");
      } else 
      {
        printf("Replacing the icon group FAILED!\n");
      }

      GlobalFree(newDir);
      GlobalFree(temp);

Enjoy,
Elad.

Elad Raz
QuestionRe: A way for updating application ICON (from .ICO file) Pin
DavidCrow15-Oct-08 7:42
mvpDavidCrow15-Oct-08 7:42 
AnswerRe: A way for updating application ICON (from .ICO file) Pin
Elad raz15-Oct-08 7:48
memberElad raz15-Oct-08 7:48 
GeneralRe: A way for updating application ICON (from .ICO file) Pin
DavidCrow15-Oct-08 7:55
mvpDavidCrow15-Oct-08 7:55 
GeneralBe sure to apply your checks.. Pin
ChizI2-May-08 6:47
memberChizI2-May-08 6:47 
GeneralRe: Be sure to apply your checks.. Pin
DavidCrow2-May-08 6:53
mvpDavidCrow2-May-08 6:53 
QuestionIcon resources Pin
ArnorBld11-Dec-06 21:13
memberArnorBld11-Dec-06 21:13 
AnswerRe: Icon resources Pin
DavidCrow13-Dec-06 5:19
memberDavidCrow13-Dec-06 5:19 
GeneralRe: Icon resources Pin
ArnorBld14-Dec-06 8:05
memberArnorBld14-Dec-06 8:05 
GeneralJust cant get any better Pin
Rajesh R. Subramanian28-Jun-06 2:14
memberRajesh R. Subramanian28-Jun-06 2:14 
GeneralRe: Just cant get any better Pin
DavidCrow28-Jun-06 3:28
memberDavidCrow28-Jun-06 3:28 
GeneralUpdateResource RT_ICON Pin
CG2i0331-May-06 4:13
memberCG2i0331-May-06 4:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170217.1 | Last Updated 8 Sep 2003
Article Copyright 2003 by DavidCrow
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid