By supporting resource files, Delphi gives you a great way to store static file contents like animated cursors, AVI videos, pictures or other nice typa things inside your .EXE files. In the following example, the .AVI video file myavi.avi will be stored inside the .EXE file:
Define a constant to be used to refer to the AVI:
CONST
ID_AVI_FILE = 123; { assign whatever number you want.}
Create a resource file MyRes.RC. In the file, have the following line (you can repeat steps 1 & 2 to add multiple AVI's):
IDS_AVI_FILE AVI myavi.avi
Compile the RC file to a RES with the command:
BRC32 -r MyRes.RC
Include the resulting MyRes.RES file in your project:
{$R MyRes.RES}
Now we're going to add code to access the contained AVI video: put a TAnimate component on the form, and assign it a name (in this example, the AVI is named "AviClip"). Then, in the FormCreate() event, add the following to start playing the clip:
WITH AviClip DO BEGIN
ResID := IDS_AVI_FILE; { Load AVI }
ResHandle := hInstance; { this line must be placed after assigning ResID }
Active := TRUE; { start playing immediately }
END;
Well.. that's all !
After popular demand, here comes a similar procedure to load a JPEG file from a resource:
procedure LoadJPEGfromEXE;
var
MyJPG : TJPEGImage; // JPEG object
ResStream : TResourceStream; // Resource Stream object
begin
try
MyJPG := TJPEGImage.Create;
ResStream := TResourceStream.CreateFromID(HInstance, 1, RT_RCDATA);
MyJPG.LoadFromStream(ResStream); // What!? Yes, that easy!
Canvas.Draw(12,12,MyJPG); // draw it to see if it really worked!
finally
MyJPG.Free;
ResStream.Free;
end;
end;
See the second parameter of the CreateFromID procedure of the TResourceStream component? It's simply the resource index. You can include more than one jpeg in your executable just by adding a line for each jpeg (with a different index) in the resource script (.RC) file.
And finally, a totally different procedure to play a WAVE file stored as resource:
var
FindHandle, ResHandle: THandle;
ResPtr: Pointer;
begin
FindHandle:=FindResource(HInstance, '', 'WAVE');
if FindHandle<>0 then begin
ResHandle:=LoadResource(HInstance, FindHandle);
if ResHandle<>0 then begin
ResPtr:=LockResource(ResHandle);
if ResPtr<>Nil then
SndPlaySound(PChar(ResPtr), snd_ASync or snd_Memory);
UnlockResource(ResHandle);
end;
FreeResource(FindHandle);
end;
end;
Another use for this technique can be to use this technique for program loaders like Setup programs, self-patching or self-checking utilities.
Just add the second program to the first one as a RCDATA resource. When the first program is started, it automagically extracts the second program to a temp file and starts it. Here's the code for the magic:
-----SECOND.RC file listing
SECONDAPPEXE RCDATA "c:\Apps\Second\Second.EXE"
------ EOF
In a DOS Window:
C:\>BRCC32 FIRST.RC
In first.dpr add the following line:
{$R SECOND.RES}
Then, whenever you want to save Second.Exe to file, do the following:
VAR
SecRes : TResourceStream;
pTemp : pchar;
TempPath : string;
BEGIN
SecRes := TResourceStream.Create(hInstance,'SECONDAPPEXE',RT_RCDATA);
pTemp := StrAlloc(MAX_PATH);
GetTempPath(MAX_PATH, pTemp);
TempPath := String(pTemp);
StrDispose(pTemp);
SecRes.SaveToFile(TempPath+'Second.EXE');
SecRes.Free;
WinExec(PChar(TempPath+'Second.EXE'), SW_SHOW);
END;
Optionally, you can use CreateProcess instead of WinExec. You can also use the API call GetTempFileName to make sure Second.EXE receives a unique filename in the directory returned by GetTempPath. Also, in the code above, I am presuming that the path returned by GetTempPath ends with a backslash ( \ ) character. You should also check for that.