Click here to Skip to main content
15,885,366 members
Articles / Desktop Programming / MFC
Article

Using UpdateResource to change a string resource

Rate me:
Please Sign up or sign in to vote.
4.49/5 (7 votes)
21 Sep 20043 min read 99.2K   15   14
Code for changing a string resource, that actually works!

Introduction

This routine shows how to use UpdateResource to change a single string resource in an executable file.

This all started because I was writing an internationalized screen saver that had to work on all Windows platforms, and I needed to be able to change the screen saver's name to the correct language at install time.

With Win9x, this is easy, because the .scr file name is the name shown in the Display settings (to verify, on a 9x system, search for *.scr files), so all I had to do was rename the file. With NT4/2000/XP, it was another story. On those OSs, the screen saver's name is in string resource ID=1 of the .scr file; the filename is completely different.

So, I had to somehow figure out how to change a string resource on the fly.

I knew UpdateResource was the solution, but it wasn't well documented, and I had found a number of questions in newsgroups by people who had been having lots of problems with it when trying to use it on string resources. It's one of those fun API routines that seems to never return an error code even though it doesn't work!

Well, I poked and prodded and with the help of a hex editor and a resource viewer for debugging, I figured it all out.

The keys to getting things to work were:

  • Converting the replacement string to Unicode first (that one was clearly documented).
  • Unless you are writing string ID=0, the buffer passed to UpdateResource must start with one or more leading zeroed WCHARs; each one you add increments the string resource ID by one (so in the code below, to get string ID=1, I start the buffer with a single zeroed WCHAR).
  • After the leading zero WCHARs, include a WCHAR containing the number of characters in the string, then fill out the buffer with the actual converted Unicode characters.
  • The buffer must be WCHAR-aligned, and its size must be an even number of WCHARs (to guarantee this, I use GlobalAlloc).

I am sure my code could be cleaner, and some of the assumptions above may not be exactly correct, though they work in the limited scope in which I have tried the code.

The PADDINGXX mystery solved?

I discovered that UpdateResource has an innocuous but curious side effect... if it needs to insert padding to correctly align sections, it inserts the repeating pattern PADDINGXX as needed. So, if you ever see those bytes in a file, it's probably because the file was processed by UpdateResource. If you are debugging UpdateResource, the presence of fragments of PADDINGXX bytes in the output file can also be a tip-off that you have an alignment or padding problem (but they may also be there innocuously, for example, if the preceding section needed to be padded out by a few bytes).

Caveats

  • This code has been tested only on executables that have a string resource ID=1 in a string table separate from other string tables (e.g., a screen saver).
  • This will only work on Windows NT4/2000/XP only (Win9x doesn't support UpdateResource and related APIs).

Sample Code

// szSSPath = path to .exe file
// szSSName = replacement text
BOOL SetScreenSaverName(LPCTSTR szSSPath, LPCTSTR szSSName)
{
  HANDLE h = ::BeginUpdateResource(szSSPath,FALSE);
  if(!h)
  {
    // BeginUpdateResource failed
    return FALSE;
  }
  CString sNewString = szSSName;
  int iCharCount = sNewString.GetLength() + 1;
  LPWSTR pUnicodeString = new WCHAR[iCharCount];
  if(!pUnicodeString)
  {
    // new failed
    return FALSE;
  }
  DWORD dwUnicodeCharCount = 
     MultiByteToWideChar(CP_ACP, NULL, sNewString.GetBuffer(0), 
                               -1, pUnicodeString, iCharCount);
  HGLOBAL hGlob =
     GlobalAlloc(GHND, (dwUnicodeCharCount + 4) * sizeof(WCHAR) );
  if(!hGlob)
  {
    // GlobalAlloc failed
    delete pUnicodeString;
    return FALSE;
  }
  LPWSTR pBufStart = (LPWSTR)GlobalLock(hGlob);
  if(!pBufStart)
  {
    // GlobalLock failed
    GlobalFree(hGlob);
    delete pUnicodeString;
    return FALSE;
  }
  LPWSTR pBuf = pBufStart;
  pBuf++;
  // offset to make it string ID=1. Increment by more
  // to change to a different string ID

  // next 2 bytes is string length
  *(pBuf++) = (WCHAR)dwUnicodeCharCount-1;
  for(int i=0; i<(int)dwUnicodeCharCount-1; i++)
    // remaining bytes are string in wide chars (2 bytes each)
    *(pBuf++) = pUnicodeString[i];
  delete pUnicodeString;
  if(++dwUnicodeCharCount % 1)
    // make sure we write an even number
    dwUnicodeCharCount++;
  BOOL bSuccess = TRUE;
  if(!::UpdateResource(h, RT_STRING, MAKEINTRESOURCE(1), 
      MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 
      pBufStart, dwUnicodeCharCount * sizeof(WCHAR) ) )
  {
    // UpdateResource failed
    bSuccess = FALSE;
  }

  GlobalUnlock(hGlob);
  GlobalFree(hGlob);
  ::EndUpdateResource(h, FALSE); // write changes 
  return bSuccess; 
}

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


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalhey, I found an err in your thought~ Pin
postchen16-May-11 20:40
postchen16-May-11 20:40 
GeneralCorrect code for RT_STRING [modified] Pin
FancyBytes11-Jan-10 23:56
FancyBytes11-Jan-10 23:56 
GeneralRe: Correct code for RT_STRING [modified] Pin
zwhit8-May-12 22:24
zwhit8-May-12 22:24 
GeneralRe: Correct code for RT_STRING [modified] Pin
MrDooDoo9-Oct-13 2:41
MrDooDoo9-Oct-13 2:41 
Generallanguage trouble Pin
yopia7-Sep-07 1:17
yopia7-Sep-07 1:17 
Generalnot working at all in my system Pin
mahbubabbas14-Jun-07 3:58
mahbubabbas14-Jun-07 3:58 
Generalit doesnt work Pin
ste82712-Mar-07 18:43
ste82712-Mar-07 18:43 
GeneralUpdateResource Pin
Anonymous11-Sep-05 19:18
Anonymous11-Sep-05 19:18 
GeneralHello Sir!!! , How TO... Pin
ThatsAlok20-Jan-05 1:47
ThatsAlok20-Jan-05 1:47 
GeneralMS sample and doc Pin
Brooks Harris17-Nov-04 12:55
Brooks Harris17-Nov-04 12:55 
GeneralRe: MS sample and doc Pin
constantin.a.cristian2-Nov-06 22:49
constantin.a.cristian2-Nov-06 22:49 
GeneralRe: MS sample and doc Pin
fprie00219-Mar-11 8:51
fprie00219-Mar-11 8:51 
GeneralA small correction Pin
black_cat4-Oct-04 4:05
black_cat4-Oct-04 4:05 
Generalgets my 5 Pin
.dan.g.22-Sep-04 16:50
professional.dan.g.22-Sep-04 16:50 

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.