Mega Code Archive

 
Categories / Delphi / Examples
 

How to store everything in your exe file

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, '<Name of your Ressource>', '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.