Easy EXE attached data (Views: 721)
Problem/Question/Abstract: 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: function GetAttachedData(MS: TMemoryStream): boolean; var pMySelf: pChar; IdX, SectionsCount: integer; EXESize, EXEOriginalSize: cardinal; SR: TSearchRec; FS: TMemoryStream; EXEName: array[0..MAX_PATH] of char; begin result := false; if MS = nil then exit; try MS.clear; // Gets EXE/DLL filename. fillchar(EXEName, sizeof(EXEName), #0); getmodulefilename(HInstance, EXEName, MAX_PATH); // Gets file size. EXESize := 0; if findfirst(EXEName, faAnyFile, SR) = 0 then begin EXESize := SR.size; sysutils.findclose(SR); end; // Gets originalsize. EXEOriginalSize := 0; try pMySelf := pointer(HInstance); if PImageDosHeader(pMySelf).E_Magic <> $00004550 then exit; inc(pMySelf, PImageDosHeader(pMySelf)._lfanew); if pDWord(pMySelf)^ <> $00004550 then exit; inc(pMySelf, sizeof(dword)); SectionsCount := PImageFileHeader(pMySelf).NumberOfSections; inc(pMySelf, sizeof(TImageFileHeader) + sizeof(TImageOptionalHeader)); for IdX := 1 to SectionsCount do begin with PImageSectionHeader(pMySelf)^ do if (PointerToRawData + SizeOfRawData) > EXEOriginalSize then EXEOriginalSize := PointerToRawData + SizeOfRawData; inc(pMySelf, sizeof(TImageSectionHeader)); end; except on e: exception do EXEOriginalSize := 0; end; // If there's something attached... if EXESize > EXEOriginalSize then begin FS := TMemoryStream.create; try try // Read it... FS.loadfromfile(EXEName); FS.position := EXEOriginalSize; // and return it in the stream. MS.copyfrom(FS, EXESize - EXEOriginalSize); result := true; except on e: exception do result := false; end; finally FS.destroy; end; end; except on e: exception do result := false; end; end; Then, you can use it like this: procedure TForm1.Button1Click(Sender: TObject); var s: tmemorystream; begin s := tmemorystream.create; try if GetAttachedData(s) then s.SaveToFile('output.txt'); finally s.destroy; end; 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. for some code snippets. |