Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Store exe in application and extract to specified folder? 2

Status
Not open for further replies.

doctorjellybean

Programmer
May 5, 2003
145
I would like to store an external application (small) inside my compiled program, and when it is needed, extract it to a specified folder, execute it from there and then delete itself when completed.

Executing and deleting it is the easy part, it is storing it within the compiled application which looks like black magic to me. From what I've Googled, it has to be created as a resource file and compiled?

It seems like everybody got their own way of doing things. Maybe someone can explain a painless way of doing it [smile] ?

Thanks.
 
yes, you need to store the executable in the resource file


follow the instructions for the MP3 file (marked as RCDATA)
try this for your EXE file, it should work.

/Daddy



-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Thanks Daddy.

It extracts the file to a stream, instead of a file on the hard disk. I'll Google some to find the method of achieving that.
 
Code:
procedure TForm1.Button2Click(Sender: TObject) ;
var
 rStream: TResourceStream;
 fStream: TFileStream;
 fname: string;
begin
 {this part extracts the mp3 from exe}
 fname := ExtractFileDir(Paramstr(0))+'Intro.mp3';
 rStream := TResourceStream.Create(hInstance, 'Intro', RT_RCDATA) ;
 try
  fStream := TFileStream.Create(fname, fmCreate) ;
  try
   fStream.CopyFrom(rStream, 0) ;
  finally
   fStream.Free;
  end;
 finally
  rStream.Free;
 end;
 {this part plays the mp3}
 MediaPlayer1.Close;
 MediaPlayer1.FileName:=fname;
 MediaPlayer1.Open;
end;

they create the mp3 file via TFilestream, then they load the file into a TMediaplayer.

for your problem the code is identical, only the mediaplayer part needs to be changed.

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Am I correct that the format of the contents in RC file is (assuming test.exe is the file I want to include):

Test EXE "D:\Temp\test.exe"
 
no that would be

Test RCDATA "D:\Temp\test.exe"

the key is that you can use the RCDATA resource type for any file type.

this would be the code to extract and run the exe (untested)

Code:
CODE
procedure TForm1.Button2Click(Sender: TObject) ;
var
 rStream: TResourceStream;
 fStream: TFileStream;
 fname: string;
begin
 {this part extracts test.exe from application}
 fname := ExtractFileDir(Paramstr(0))+'test.exe';
 rStream := TResourceStream.Create(hInstance, 'Test', RT_RCDATA) ;
 try
  fStream := TFileStream.Create(fname, fmCreate) ;
  try
   fStream.CopyFrom(rStream, 0) ;
  finally
   fStream.Free;
  end;
 finally
  rStream.Free;
 end;
 ShellExecute(Handle,'open', pchar(fname),nil, nil, SW_SHOWNORMAL) ;
end;

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
That is a non-standard resource type, but if your resource compiler takes it... AFAIK the Delphi Resource Compiler does not support it.

Just use
Code:
test_exe RCDATA "data\test.exe"
Always use relative paths unless you can't avoid it.
The underscore in the name is because the Delphi resource compiler doesn't like periods in the resource name -- otherwise I would have named it the same as the file.

Compile it with
Code:
D:\foo\> brcc32 my_resource_file.rc
(or drcc32, one of the two).

And link it into your program with
Code:
{$resource  my_resource_file.res  my_resource_file.rc}

To extract it, you'll have to do as whosrdaddy suggested to write it to file, then execute it using CreateProcess.

Hope this helps.
 
This would be something I would have to play with, but couldn't you treat an EXE like a DLL in memory, and load the execution starting point (assuming you can start from that)?

But my main point is this: Are you sure this won't ring the alarm bells on any virus scanners? This sounds awfully lot like behavior that could be construed as malware to me...(you might do better in the long run to simply distribute the exe with the app)

----------
Measurement is not management.
 
No, it shouldn't. This is common behavior for UPX and other single-file deployment applications. The extracted EXE won't have any more permissions than the original process.

Of course, if it actually is a virus, then yeah, your AV will hate it. :-D
 
Don't get me started on DLL's, that is one thing I know absolutely nothing about.

Re virus flagging, I have a real time virus scanner. Hopefully this will advise me of any "illegal" operations.
 
Just to put in my two cents worth, I have an install/uninstall process where I use a VERY small executable (98 bytes) that is actually a ".com" file: Wait.com was once quite common as a batch command to display (echo) some text, then continue processing after giving the user time to read the message. Syntax was WAIT /N where "n" is number of seconds to delay. This is actual code to create the command file to disk:
Code:
procedure TUpgrade.CreateWaitCom;
var
  f: file of byte;
  i: integer;
const
  ComBytes: array[1..98] of byte = ($BE,$80,$00,$BB,$01,$00,$AC,$88,$C1,$B5,
                                    $00,$80,$F9,$00,$74,$1D,$2B,$DB,$AC,$3C,
                                    $20,$74,$14,$3C,$0D,$74,$12,$2C,$30,$88,
                                    $C5,$B8,$0A,$00,$F7,$E3,$02,$C5,$80,$D4,
                                    $00,$8B,$D8,$E2,$E5,$B8,$12,$00,$F7,$E3,
                                    $8B,$D8,$B4,$00,$CD,$1A,$03,$D3,$83,$D1,
                                    $00,$8B,$F1,$89,$D7,$B4,$01,$CD,$16,$74,
                                    $0D,$B4,$00,$CD,$16,$3C,$03,$75,$11,$CD,
                                    $23,$E9,$0C,$00,$B4,$00,$CD,$1A,$39,$F1,
                                    $72,$E5,$3B,$D7,$72,$E1,$CD,$20);
begin
  assignfile(f, AppPath + 'WAIT.COM');
  rewrite(f);
  for i:= 1 to 98 do
    blockwrite(f, combytes[i], 1);
  closefile(f);
end;
The array itself was created by copy/paste from a hex viewer.

Roo
Delphi Rules!
 
Very interesting Roo [smile]

Now to make this a little bit more interesting.

The stored exe will be extracted, executed and then deleted. Is there a way to check it has completed the tasks before deleting it?
 
You won't be permitted to delete it until it terminates.

/me searches for something
Er, well, I thought I had my little uExecProcess.pas unit online, but I can't find it right now. If you want I'll post, but basically all it does is use CreateProcess with common arguments. When you use it you'll get back the child process's handle (or PID, for you unix folk), and you can use that to check to see whether the application has terminated as well.

@Roo
I don't know if you are aware, but the old DOS subsystem is no longer guaranteed to be a part of your windows installation (Vista 32 has it, but 64 doesn't).

Hope this helps.
 
This is a bit off topic but I found it interesting how few .com files are left in the OS. My (XP) C:\WINDOWS\system32\ folder only contains 14. My 1st pascal compiler created .com files only with a max binary size of 64KB. Who remembers overlays? We had to jump through several hoops to create a .exe

Note: Not to be confused with the .com top-level domain.

Roo
Delphi Rules!
 
Oy! (Memories! *sniff*) I hated dinking with overlays. (Fortunately I started between TP3 and TP4, and took to the latter right away...)

I'm not so sure all those programs actually are COM programs anymore. Windows doesn't actually pay any attention to the extension when determining what kind of executable the file represents.

For example, the venerable COMMAND.COM is actually an EXE! :-O

Also not to be confused with Component Object Model. ;-)

Heh heh heh... ya old fart. :p
 
Talking of COM and EXE.

Quite a few years ago if one had Symantec Anti-Virus installed, and got infected, causing the AV to stop running, the solution was simple. Go in Windows Explorer, rename the extension from EXE to COM, execute it, and voila, the AV worked again and could clean the machine :)
 
What started out to be a quick and dirty project, has turned into an advanced application, thanks to you guys [medal]

The stored exe, which is executed when extracted, is a batch file which has been converted to an exe. Once the exe is executed, it is deleted although the process (cmd.exe) is still ongoing.

What I now need is a popup message, showmessage if you like, when the process (cmd.exe) has completed and terminated. It could be a lengthy process, and at present there is no easy way of telling when it has finished.

Therefore, it would be once more much appreciated if someone can explain a method of establishing the end of the process. I know Roo has mentioned ExecAndWait, it is way over my head [sad]
 
Any normal wait function is blocking, meaning your program will pause until it receives the desired signal (such as the process terminating).

If that is not acceptable, you'll have to jump into the deep end and look up "Synchronization" at MSDN. It is a big subject.

The simplest process (what Roo mentioned) is basically to use CreateProcess to execute your new process and get the new process's process handle.

Then all you have to do is use WaitForSingleObject, as:
Code:
WaitForSingleObject( child_process_handle, INFINITE );
or use one of the alertable wait functions like WaitForSingleObjectEx for more options... (be sure to look up "synchronization").

Hope this helps.
 
Since you bring up synchronization, I got bit by a lag problem brought on by that program just by using CreateProcess and WaitForSingleObject as has been described here. Adding SYNCHRONIZE to the creation flags solved it.
Better to use it than to not and run into a similar problem.

Code:
 if CreateProcess(nil, PChar(DosApp), @Security, @Security, true, NORMAL_PRIORITY_CLASS+SYNCHRONIZE, nil, nil, start, ProcessInfo) then

----------
Measurement is not management.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top