Resource scripts are *.rc text files. Compiled resources are stored in *.res files and linked to executables. Delphi provides *.dcr files to hold *.res data which is available only at design time.
Delphi provides several commands to read bitmap resources. For example
Warning: All resource editors I've found contain fatal design errors. Be careful. If you follow my notes, resources will work for you.
Instead of using their pre-defined resource keys, Delphi programs save Forms (Dialogs), Menus, and Accelerators in *.dfm files which are stored in RCData.
As of 2014, I was no longer satisfied with the available options to create ico files.
There are several free options on the web, but they have various drawbacks.
Therefore, I have added a section on using
Resources -
Application Icons
| Cursors
| Bitmaps
|
Resource Hacker
Once you install it, just right click any *.exe, *.dll, *.ocx. or *.cpl file and select Resource Hacker. (Some files with these extensions may be in a different format and can not be read.) (The right click capability was in version 3.2.4, but omitted in version 3.4. If you want, you can manually add this capability to the registry. See the section on *.bpl files below.) Use this program to explore your system - you will learn a lot. For instance, try
c:\windows\system\comdlg32.dllYou should recognize most of the dialog boxes. The help provides step by step instructions on how to add your icons to one of these. (Please be careful, you could hose your system.)
Notice that it will open an *.res file, but not an *.dcr file. However, if you simply rename the *.dcr file to *.res, then it will open it.
*.bpl Files
This registry hack will make viewing their resources easier - with it, you can just right click an *.bpl file and select Open using Resource Hacker. Simply add and configure HKCR\.bpl and HKCR\bplfile (these already exist if Depends is installed).
If necessary, add
HKCR\.bpl @=bplfileUnder HKCR\bplfile, add
HKCR\bplfile\shell\ResourceHacker @=Open using Resource &Hacker HKCR\bplfile\shell\ResourceHacker\command @="C:\Downloads\Resource Hacker\reshacker.exe" "%1"For versions 3.2.4, use the following path
@="C:\Program Files\Resource Hacker\reshacker.exe" "%1"Notes:
As of 2014, the version I have (3.4) no longer "installs" itself. Therefore, I have an alternate registry file that includes exe and dll files .. and a different path. (Be careful.)
As of 2014, the current version is 3.6.0.
Image Editor
Personally, I use it to create the images used on the component tool bar (bitmaps).
Notes:
Design Error
Basically, Image Editor contains a major design error - if you create 2 (or more) icons and then delete all but one, all the "deleted" icons are still in the *.res file. Resource Hacker can see them, but Image Editor simply hides them from you. So far, this is not a big deal. Unfortunately, if your application contains more than one *.res file, and one of those files contains a "deleted" icon, then the problem described above occurs - when the resource files were linked, the "deleted" icon was added to one of the existing icons.
Resource Explorer
C:\Program Files\BORLAND\Delphi5\Demos\Resxplor\resxplor.dprIt shows only one section for icons and one section for cursors. (Resource Hacker shows 2 sections for each.) The form definition is in hex, Resource Hacker shows it as text.
Borland C++
This program has several important design errors - see discussions below. Basically, when you delete a cursor or icon resource, it lies to you and then you get very weird problems with your application. The only solution is to create a new *.res file.
Warning: | Do Not use this program |
Similar to using Borland C++ to edit *.res files. To add additional images per cursor
For icons, it supports 16x16, 32x32, and 64x64 - the Delphi 5 Image Editor does not support 64x64. Use Images / New image... to add additional icons.
Resource Script Language help is installed with the workshop. Unfortunately, it is not quite complete.
Resource Workshop is on the Delphi 5 CD.
D:\Workshop\Disk1\SETUP.EXE |
Warning: | Do Not use this program - I created 2 ico files using this. The program was able to see the directory entries - but no other Windows XP program could see them. I assume that the program directly manipulated the directory file assuming that it was FAT. In fact, it was an NT partition!!! As a result, this program created 2 invisible files that can never be removed. |
Visual C++
I tried using one of these in Delphi 5 (with all the C stuff removed) and got a "Unsupported 16-bit resource" error. If you also create a matching *.res file, the following syntax does not produce errors. However, it also does not include the cursor and icon resources in the *.rc file in the *.exe file.
{$R cursor_test.res cursor_test.rc} // the names must match
On the other hand, each cursor and icon is saved in a separate file (*.cur and *.ico respectively).
Gimp
This is pretty straight forward
Note that each layer must be the same size as the icon it holds. If you just resize the image, this won't work.
Some applications will want a 48x48 icon.
For more details, see my help on using gimp to create icons.
Application Icons
{$R *.res}The project's icon (the icon shown in Windows Explorer and in the project's title bar) is saved as MAINICON, a 32x32
Under the covers (as revealed using Resource Hacker), MAINICON is actually just a pointer to a numbered icon (normally to icon number one). If a component, or another resource file, contains a partially deleted icon (such as an icon "deleted" using Image Editor), then you have a problem - when the resources are linked, the "deleted" icons may be combined with the one MAINICON points to. If that happens, then you no longer have control over which icon is displayed for your application. In my case, my application's icon was actually the one I "deleted".
Note: Delphi caches ProjectName.res. Modifications made to this file are not included in the ProjectName.exe file until you close (File / Close All) and reopen the project. I discovered this by modifying the application icon - MAINICON - in ProjectName.res and then checking ProjectName.exe with Resource Hacker. The unmodified default icon was present, not the modified icon that Resource Hacker showed in ProjectName.res. After closing and reopening the project, the new icon appeared.
If you set the application's icon via Project / Options... / Application / Load Icon, then the new icon is immediately available.
Icons are used
FIcon := TIcon.Create; FIcon.Handle := LoadIcon(MainInstance, 'MAINICON');
Component icons (displayed in the tool palette) are 25x25 bitmaps with the same name as the class.
Note: In the resource file, use Bitmap, not Icon, to create these.
Since these are identified by name, you have a good chance of avoiding conflicts.
Cursors
According to the Delphi 5 help (see TScreen.Cursors), this is how to use a cursor located in a resource file.
Screen.Cursors[2] := LoadCursor(HInstance, 'Cursor2'); cursor := 2;(The resource name is not case sensitive.)
The Delphi components use numbers instead of strings (see Delphi5\Lib\controls.res).
Screen.Cursors[2] := LoadCursor(HInstance, MAKEINTRESOURCE(1234)); cursor := 2;Notice that in Image Editor, "1234" is a string, but in the command above, it is an integer (it also appears to be an integer in the *.res file). (Of course, you must make sure to select a number between 0 and 32K that no one else has ever used ... and that no one else WILL ever use. Yeah, right!)
Strangely, this code also works
Screen.Cursors[2] := LoadCursor(HInstance, PChar(1234)); cursor := 2;(Casting an integer as a null terminated string is definitely weird. The Resource Workshop Reference provided with
For additional information, see
Unique Identifiers
IDC_CompanyIDComponent_Cursorname IDC_mcTSpin_Drag(IDC_ is a standard meaning a Resource of type Cursor. It is not required.)
The Screen.Cursors array presents another problem - its "index" must be a number. (The Screen.Cursors "array" is actually a linked list and the "indices" are node ID's. If you try to read a non-existent node, Screen.Cursors returns the handle for node zero.) The Delphi predefined cursors won't be a problem since they are all negative integers. However, other components may have already defined a cursor or two. This code will find the next unused positive index.
procedure LoadScreenCursor(var CursorID: Integer; CursorName: String); var Form1: TForm1; IDC_T1 : integer = 0; // global or class variables IDC_Cursor1 : integer = 0; // 0 means empty IDC_ProjectRes: integer = 0; implementation procedure TForm1.Load_UIButtonClick(Sender: TObject); begin LoadScreenCursor(IDC_Cursor1, 'IDC_Cursor1'); LoadScreenCursor(IDC_T1, 'IDC_T1'); LoadScreenCursor(IDC_ProjectRes, 'IDC_ProjectRes'); end; procedure LoadScreenCursor(var CursorID: Integer; CursorName: String); var A: array[0..79] of Char; // Used for StrPCopy i, xx, yy : integer ; begin if CursorID = 0 then begin // If the ID is not assigned, find an empty index yy := Screen.Cursors[0] ; // This speeds up the loop for i:=1 to 6000 do begin // 6000 is just a big number, 10 should be enough xx := Screen.Cursors[i]; // This makes trouble shooting easier if xx = yy then begin // if Screen.Cursors[0] = Screen.Cursors[i] CursorID := i; // This is an unused value break; end; end ; end; // if CursorID = 0 if CursorID = 0 then exit; // This is just a safety, it should never exit Screen.Cursors[CursorID] := LoadCursor(HInstance, StrPCopy(A, CursorName)); end; procedure TForm1.IDC_Cursor1_Var_UIButtonClick(Sender: TObject); begin Cursor := IDC_Cursor1; // This sets the cursor end;
Editor Quirks
Image Editor Must re-name cursors or you can't see them in Delphi. Resource Hacker has no problem if they are not re-named. Shows only one Cursor section even though there are actually two.
Allows only one color depth and only one size.
Borland C++ Select Edit as Text to set the name of the cursor. Cursors already named with numbers using Image Editor will no longer work in Delphi.
Resource Error
Using Image Editor to delete one of the cursors only removes the pointer to the cursor. According to Resource Hacker, the cursor is still in the *.res and *.exe files. (The Cursor Group was removed, but Cursor was still present.)
Apparently, when several resource files are included in the same *.exe, the cursor numbers are re-assigned so that there are no conflicts. However, if a cursor is not associated with a group, then it gets associated with an existing cursor and there are problems.
Bitmaps
Form Descriptions
Strings
However, if you want to include your string constants in the executable's resources, use resourcestring instead of const.
resourcestring str1 = 'Cannot create file %s'; // for explanations of format specifiers, str2 = 'Cannot open file %s'; // see 'Format strings' in the online Help
Grammar Note
I realize that some people will not agree with this.
References
Microsoft's Resource Compiler page - slow and wordy, but at least there is some data
Author: Robert Clemenzi