madRes Unit 

Content / madBasic /...
www.madshi.net

The Windows NT family has some nice APIs named "BeginUpdateResource", "UpdateResource" and "EndUpdateResource". With these APIs you can change the resources of a dll/exe file on the fly. Unfortunately the APIs are not supported by the Windows 9x family. If you need to change resources there, you're normally lost. Well, the Microsoft Unicode Layer for 9x promises to add support for those APIs, but in the current state it has serious bugs. It crashes most of the time when being used on Delphi programs/dlls.

The NT APIs aren't as reliable as you might think, either. If you use the resource update APIs on a Delphi binary, which has TD32 debug infos in it, the binary is totally invalid afterwards. Windows doesn't even recognize it as a valid PE file anymore. Another disadvantage of the NT resource update APIs is that the size of the resource section is often not adjusted, if you remove resources. So your binary is bigger than it has to be.

To address all those problems, I've decided to build my own resource update functions. First of all I exactly duplicated the NT APIs. Of course I didn't duplicate the bugs. My functions work well with TD32 debug infos. Also the resource section is always only as big as it needs to be.

Additionally to cloning the NT APIs I added some new functions. All of this works on both the NT and the 9x family, of course. You can get an overview of the available functions in the madRes Reference.

First of all let's have a quick look at my API clones. I duplicated the wide version of the APIs, only. All functions of this unit only work if you open an update handle with "BeginUpdateResourceW" first. Then you can do some changes with the function "UpdateResourceW". Finally you can save the changes with the "EndUpdateResourceW" function. For more detailed documentation just look at the official Microsoft documentation. What is written there is in the same way true for my functions:

// open a dll/exe file for playing with the resources
function BeginUpdateResourceW (fileName       : PWideChar;
                               delExistingRes : bool     ) : dword; stdcall;

// add, change or delete a resource
function UpdateResourceW (update   : dword;
                          type_    : PWideChar;
                          name     : PWideChar;
                          language : word;
                          data     : pointer;
                          size     : dword    ) : bool; stdcall;

// close the resource handle again, either save or discard the changes
function EndUpdateResourceW (update  : dword;
                             discard : bool ) : bool; stdcall;

// Example:
procedure KillBitmapResource(exeFullPath, bmpResName: PWideChar);
var update : dword;
begin
  update := BeginUpdateResourceW(exeFullPath, false);
  if update <> 0 then
    try
      UpdateResourceW(update, PWideChar(RT_BITMAP), bmpResName, 0, nil, 0);
    finally
      EndUpdateResourceW(update, false);
    end;
end;

The first function which I've added to the default API set is "GetResourceW". With this function you can ask the content of a specific resource. Or you can just ask whether it exists, ignoring the data:

function GetResourceW (update   : dword;
                       type_    : PWideChar;
                       name     : PWideChar;
                       language : word;
                       var data : pointer;
                       var size : dword    ) : bool; stdcall;

// Example:
function DoesIconGroupResourceExist(update: dword; iconGroupResName: PWideChar) : boolean;
var data : pointer;
    size : dword;
begin
  result := GetResourceW(update, PWideChar(RT_GROUP_ICON), iconGroupResName, data, size);
end;

The most evident thing in the resources are perhaps the icons. Of course you can do everything you need with just the functions above. However, icons are quite complicated. So I've added some types and functions specifically for easy icon dealing.

type
  // structure of the RT_GROUP_ICON resource data
  TPIconGroup = ^TIconGroup;
  TIconGroup = packed record
    reserved  : word;
    type_     : word;  // 1 = icon
    itemCount : word;
    items     : array [0..maxInt shr 4 - 1] of packed record
                  width     : byte;  // in pixels
                  height    : byte;
                  colors    : byte;  // 0 for 256+ colors
                  reserved  : byte;
                  planes    : word;
                  bitCount  : word;
                  imageSize : dword;
                  id        : word;  // id of linked RT_ICON resource
                end;
  end;

  // structure of an ".ico" file header
  TPIcoHeader = ^TIcoHeader;
  TIcoHeader = packed record
    reserved  : word;
    type_     : word;  // 1 = icon
    itemCount : word;
    items     : array [0..maxInt shr 4 - 1] of packed record
                  width     : byte;   // in pixels
                  height    : byte;
                  colors    : byte;   // 0 for 256+ colors
                  reserved  : byte;
                  planes    : word;
                  bitCount  : word;
                  imageSize : dword;
                  offset    : dword;  // data offset in ico file
                end;
  end;

// get the specified icon group resource header
function GetIconGroupResourceW (update        : dword;
                                name          : PWideChar;
                                language      : word;
                                var iconGroup : TPIconGroup) : bool; stdcall;

// save the specified icon group resource to an ico file
function SaveIconGroupResourceW (update   : dword;
                                 name     : PWideChar;
                                 language : word;
                                 icoFile  : PWideChar) : bool; stdcall;

// load the specified ico file into the resources
// if the icon group with the specified already exists, it gets fully replaced
function LoadIconGroupResourceW (update   : dword;
                                 name     : PWideChar;
                                 language : word;
                                 icoFile  : PWideChar) : bool; stdcall;

// delete the whole icon group including all referenced icons
function DeleteIconGroupResourceW (update   : dword;
                                   name     : PWideChar;
                                   language : word     ) : bool; stdcall;

Finally we have two bitmap resource specific functions:

// save the specified bitmap resource to a bmp file
function SaveBitmapResourceW (update   : dword;
                              name     : PWideChar;
                              language : word;
                              bmpFile  : PWideChar) : bool; stdcall;

// load the specified bmp file into the resources
function LoadBitmapResourceW (update   : dword;
                              name     : PWideChar;
                              language : word;
                              bmpFile  : PWideChar) : bool; stdcall;