20

How can I do this one?

For some reason or selected by the user, “ask” the current application to restart it self.

DRokie
  • 705
  • 2
  • 9
  • 20

4 Answers4

37
uses ShellAPI;

...

procedure TForm1.RestartThisApp;
begin
  ShellExecute(Handle, nil, PChar(Application.ExeName), nil, nil, SW_SHOWNORMAL);
  Application.Terminate; // or, if this is the main form, simply Close;
end;
Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • 2
    this does "restart and close", not vice versa (meaning **resource sharing** happens instead of **resource release**) – user422039 May 17 '11 at 04:05
  • 2
    @simon relatively easy to get around if you use a command line param known only to the app (e.g. '-newinstance'), which will prevent multiple instance checking on start up. – Stuart May 17 '11 at 09:30
  • 1
    @Stuart, *re-start* should preserve command-line from previous instance, don't you think? – user422039 May 18 '11 at 04:24
  • @user422039 - agreed 100%, although nothing to stop you adding an additional command line param to the existing ones. :) – Stuart May 24 '11 at 09:43
  • 1
    @Stuart, yep, to bypass single instance check :) But what if previous instance was restarted too :) Also, `.code` section will be never ever unlocked since process deleted after new one created. – Premature Optimization May 27 '11 at 22:17
  • Neat solution! And you can use `GetCommandLine` to obtain the original command line parameters and pass to the new instance. – Edwin Yip Dec 11 '16 at 15:16
  • 1
    how can i make a small delay,for example 2-3 seconds before next run? my app use serial port and os need a delay on close and reopen to close all ports – peiman F. May 24 '18 at 16:00
2

I can add to @Andreas Rejbrand answer:

If the code is perfomed in .dpr file before Application.Initialize. for me it is better to call Halt(0) instead of Application.Terminate. I need it because on the first launch program does some installation and then restarts. If I call Application.Terminate main form blinks for a seconds (but it shouldn't be created at all!) and then application closes. So my code is following:

project.dpr:

if FirstRun then
begin
    DoFirstRunStuff();
    ShellExecute(Application.Handle, nil, PChar(Application.ExeName), nil, nil, SW_SHOWNORMAL);
    Halt(0);
end;
...
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
Artem Mostyaev
  • 3,874
  • 10
  • 53
  • 60
2

There is another way for closing-restarting the application:

Save a scheduled task to a short time after the application closes. This will have to be the VERY LAST thing your application does before exiting (no further data processing, saving, uploading or whatever)

eg.

  1. get the system time first
  2. set the scheduled task some time after this time (scheduled event will have to start your executable)
  3. exit your application (closing the main form or application.terminate will do it)

When your program starts again, it should check for any such scheduled task and remove them. This must be the VERY FIRST action your application should do when starting. (cleanup)

  1. check for any scheduled tasks created by your executable
  2. remove them

AFAIK, The Delphi Jedi component set has a component you can do the task scheduling stuff with.

beerwin
  • 9,813
  • 6
  • 42
  • 57
1

You could have a separate simple restart.exe program that you run from your program and pass it the name of your executable file. Then close your program. The restart program can wait for a time, or until the executable file is read-writeable which seems to mean it is not running, then it can execute it and close itself.

I expect there is a better way to do this, maybe sombody can provide a better solution, but this function seems to tell me whether an executable is currently running:

function CanReadWriteFile(const f: TFileName): boolean;
var
  i: integer;
begin
  Result := false;
  i := FileOpen(f, fmOpenReadWrite);
  if i >= 0 then begin
    Result := true;
    FileClose(i);
  end;
end;
soid
  • 541
  • 8
  • 15