Author: Christian Cristofori
Using resources to include files into your EXE is a great thing, but I prefer using
another way...
Answer:
When you compiled your code, and you want to attach 1 file to your file just use
this command line:
COPY /B PROJECT1.EXE + DATA.TXT PROJECT2.EXE
A file, called Project2.Exe will be created and it will contain first file with 2nd
file attached. That doesn't compromise EXE and it will be still working.
But: how to easly extract that file form the EXE?
First of all, you should use this function:
1
2 function GetAttachedData(MS: TMemoryStream): boolean;
3 var
4 pMySelf: pChar;
5 IdX, SectionsCount: integer;
6 EXESize, EXEOriginalSize: cardinal;
7 SR: TSearchRec;
8 FS: TMemoryStream;
9 EXEName: array[0..MAX_PATH] of char;
10 begin
11 result := false;
12 if MS = nil then
13 exit;
14 try
15 MS.clear;
16 // Gets EXE/DLL filename.
17 fillchar(EXEName, sizeof(EXEName), #0);
18 getmodulefilename(HInstance, EXEName, MAX_PATH);
19 // Gets file size.
20 EXESize := 0;
21 if findfirst(EXEName, faAnyFile, SR) = 0 then
22 begin
23 EXESize := SR.size;
24 sysutils.findclose(SR);
25 end;
26 // Gets originalsize.
27 EXEOriginalSize := 0;
28 try
29 pMySelf := pointer(HInstance);
30 if PImageDosHeader(pMySelf).E_Magic <> $00004550 then
31 exit;
32 inc(pMySelf, PImageDosHeader(pMySelf)._lfanew);
33 if pDWord(pMySelf)^ <> $00004550 then
34 exit;
35 inc(pMySelf, sizeof(dword));
36 SectionsCount := PImageFileHeader(pMySelf).NumberOfSections;
37 inc(pMySelf, sizeof(TImageFileHeader) + sizeof(TImageOptionalHeader));
38 for IdX := 1 to SectionsCount do
39 begin
40 with PImageSectionHeader(pMySelf)^ do
41 if (PointerToRawData + SizeOfRawData) > EXEOriginalSize then
42 EXEOriginalSize := PointerToRawData + SizeOfRawData;
43 inc(pMySelf, sizeof(TImageSectionHeader));
44 end;
45 except
46 on e: exception do
47 EXEOriginalSize := 0;
48 end;
49 // If there's something attached...
50 if EXESize > EXEOriginalSize then
51 begin
52 FS := TMemoryStream.create;
53 try
54 try
55 // Read it...
56 FS.loadfromfile(EXEName);
57 FS.position := EXEOriginalSize;
58 // and return it in the stream.
59 MS.copyfrom(FS, EXESize - EXEOriginalSize);
60 result := true;
61 except
62 on e: exception do
63 result := false;
64 end;
65 finally
66 FS.destroy;
67 end;
68 end;
69 except
70 on e: exception do
71 result := false;
72 end;
73 end;
74
75 //Then, you can use it like this:
76
77 procedure TForm1.Button1Click(Sender: TObject);
78 var
79 s: tmemorystream;
80 begin
81 s := tmemorystream.create;
82 try
83 if GetAttachedData(s) then
84 s.SaveToFile('output.txt');
85 finally
86 s.destroy;
87 end;
88 end;
That's all. You don't need to use constants, resources or anything else.
Note that the code will work also if the EXE file is compressed with tools like UPX
or similar.
Thanks to the site U.N.D.U.http://www.undu.com/ for some code snippets.
|