Jump to content




Recent Status Updates

  • Photo
      30 Sep
    rhossis

    laptop hard disk seated beneath motherboard but with no access panel. 7 hours to replace :(

    Show comments (3)
  • Photo
      19 Sep
    Chall

    I love it when you go to write a help thread, then while writing, you reach an enlightenment, and figure it out yourself.

    Show comments (3)
View All Updates

Developed by Kemal Taskin
Photo
- - - - -

Embed Array of Bytes Through Windows Resource (Using "Custom" Resource Data Type, RCDATA)

windows resource custom resource rcdata tresourcestream delphi resource stream array

  • Please log in to reply
No replies to this topic

#1 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1,320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 24 October 2012 - 07:56 PM

Recently I stumbled into a question asking how to embed array of bytes into an application using resource. I found this question is interesting because that way you can alter the array content without actually hacking the body of executable. We don't need to hack because Windows provides a way to safely modify content of a resource.

This tutorial will show you how to embed an array of bytes to an executable using resource.

Windows Resource

This time I will not dig deeper about Windows Resource. Please read this Wikipedia page to learn more about it. Simply said resouces are a collection of read-only (to the executable) data.

Please take the read-only part with a grain of salt, because there are ways to modify resources. But not easily done inside the executable that contains or uses the resource(s).


Embedding Array of Bytes Through Resource

Obviously we do this by creating a resource and then embed the resource into our Delphi application. The steps are:

  • Write the array to a resource script
  • Compile the resource script
  • Include the compiled resource file into Delphi source code

Let's learn by doing. Let's say that we have array of bytes that in Delphi code defined like this.

const
  MyArray: array[1..4] of byte = (10, 20, 30, 40);

And we want to embed this array not in plain simple Delphi code, but through resource.


1. Write the Array to Resource Script

In resource script, a resource is defined basically using 3 fields.

  • The resource's name or id
  • The resource's type
  • Content of the resource

In our case, let's use MyArray for the resource name, and RCDATA as the type, and of course 10, 20, 30, 40 for the content. But how do we write this down?

A visit to MSDN page that explains RCDATA resource type reveals interesting information and also a very helpful example. However now we hit our first problem. Because there is no direct way to store one byte value with resource command. The easier options are.

  • Cast the array of bytes content into ansi string. Remember that each member/char in ansi string is actually a byte.
  • Combine each two bytes into one word, then use one way specify integer values in the resource script.

The first option looks the easiest. And we actually can define the "numeric" value of a character in a string using escape character of "\" followed by the numeric value in octal format. Let's choose this option.

Using the first option, our array resource entry would be:

MyArray RCDATA
{
    "\12\24\36\50"
}

Let's save the resource script as "test.rc" in our project directory. Note that the .rc extension is not actually required. Just a convention, a "clue".


2. Compile the Resource Script

Now we need to compile the resource script to get the resource in binary form. Delphi installation usually already has a resource compiler named brcc32.exe. It usually already in the system path, making it available to be called from anywhere in command prompt. Calling "brcc32.exe" bare would yield more information like shown below.

Borland Resource Compiler  Version 5.40
Copyright (c) 1990, 1999 Inprise Corporation.  All rights reserved.

Syntax: brcc32 [options ...] filename
  options marked with a '*' are on by default

  @<filename>        Take instructions from command file
  -r                    (ignored for compatibility)
  -16                   Build 16-bit Windows compatible .res file
  -32                 * Build 32-bit Windows compatible .res file
  -fofilename           Set output filename
  -v                    Verbose
  -ipath                Set include path
  -dname[=string]       Define #define
  -x                    Ignore INCLUDE environment variable
  -m                    Enable multi-byte character support
  -cdddd                set default code page to nnnn
  -lxxxx                set default language to xxxx
  -31   Provided for downward compatibility (build 16-bit .res file)
  -w32  Provided for downward compatibility (build 16-bit .res file)
  -? or -h              Display this message

To compile our test.rc:

  • Open command prompt console
  • Open the folder where you stored test.rc
  • Run brcc32.exe with parameters like this:
    R:\Tutorials\WorkingWithRCDATA\Demo>brcc32 -32 -fo test.res test.rc
    

    The parameters tell brcc32 to compile test.rc into test.res in 32 bit windows format.

After executing brcc32, you will get new file named test.res in the same folder as test.rc. This is the compiled binary resource. Time to embed it to our Delphi application.


Include the Compiled Resource into Delphi Source Code

Embedding the .res is easy in Delphi. In our case, you just have add either one the following lines somewhere in any file used by your Delpi project.

{$R test.res}

or

{$RESOURCE test.res}

And that's it! Each time you compile the project, the resource will automatically be embedded to the executable. Next section will show how to read the array.


Reading the Embedded Array

Now that we have successfully embed (or at least we thought so ;P ) the array through resource, we need a way to read it. Fortunately for us, VCL already has a class for reading resource content into stream. It's [URL=http://docwiki.embarcadero.com/Libraries/XE2/en/System.Classes.TResourceStream]TResourceStream[/I]. With it, we can treat a resource like we treat any other TStream instance.

Let's say we want to read MyArray and show the content as string inside a TMemo which named Memo1. The following codes will suffice.

{$R test.res}
procedure TForm1.BitBtn1Click(Sender: TObject);
var
  R: TStream;
  S: string;
  B: Byte;
begin
  S := '';
  R := TResourceStream.Create(HInstance, ComboBox1.Text, RT_RCDATA);
  try
    R.Position := 0;
    while R.Read(B, SizeOf(<img src='http://img.codecall.net/public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' />)=SizeOf(<img src='http://img.codecall.net/public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' /> do
      S := S + IntToStr(<img src='http://img.codecall.net/public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' /> + ' ';
  finally
    R.Free;
  end;

  Memo1.Text := S;
end;

Upon running the project, you might get something like shown below.

Run001.png

See that the values are exactly what we have embedded? So that is the proof that our method is working properly. Please check the attached test.rc (inside the zip file) to see implementation of the other option.

Attached File  Demo_ArrayInResourceRCDATA.zip   211.8KB   136 downloads
  • 0





Also tagged with one or more of these keywords: windows resource, custom resource, rcdata, tresourcestream, delphi resource, stream, array