Solved

Closing application

Posted on 2001-08-16
12
267 Views
Last Modified: 2010-04-06
Hello,
How can I start some application and then close it? I tried something like this, but it doesn't work. The problem is with closing application.

var temp:Cardinal;

procedure TForm1.Button1Click(Sender: TObject);
begin
  temp := ShellExecute(handle, 'open', 'test.exe', nil, nil, SW_SHOWNORMAL);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  SendMessage(temp, WM_CLOSE, 0, 0);
end;

0
Comment
Question by:trunin
  • 5
  • 2
  • 2
  • +3
12 Comments
 
LVL 9

Expert Comment

by:ITugay
ID: 6391721
waiting for Madshi :-)
0
 
LVL 20

Accepted Solution

by:
Madshi earned 50 total points
ID: 6391821
(-:

ShellExecute doesn't return a window handle, nor does it return a process handle. You can't use anything you get from ShellExecute to close that application.

You should either use ShellExecuteEx with the NOCLOSEPROCESS flag, then you'll get a process handle. With that handle you can call TerminateProcess (not clean, though).

Another solution would be to start the process with CreateProcess. This API tells you both the process handle and the processID. Having the processID you can enumerate the windows the belong to the newly started process and then use "PostMessage(processMainWindow, WM_CLOSE, 0, 0)" to close it cleanly.

Regards, Madshi.
0
 
LVL 3

Expert Comment

by:Stefaan
ID: 6391961
Hi,

The problem is that Temp does not hold the handle to the application you just started.  It will only contain the result of the ShellExecute funciton.  You will need to fetch the handle of the application which you have just started.

I think I have done it somewhere and I will look up the code, when I found it I will get back to you.

Best regards,


Stefaan
0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
LVL 22

Expert Comment

by:Mohammed Nasman
ID: 6391980
you can get the handle of that window by findwinow, then close it, but Madshi suggest me to don't use it, and he has  a very good experience in that

procedure TForm1.Button2Click(Sender: TObject);
var
 wnd : hwnd;
begin
 wnd:=FindWindow(pchar('notepad'),nil);
 PostMessage(Wnd, WM_CLOSE, 0, 0);
end;

and here's some code for his suggestion about CreateProcess

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    ProcInfo : TProcessInformation;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  SUInfo : TStartupInfo;
begin
  if ProcInfo.hProcess <> 0 then
    Exit;

  FillChar(SUInfo   , SizeOf(SUInfo)   , #0);
  FillChar(ProcInfo , SizeOf(ProcInfo) , #0);

  SUInfo.cb          := SizeOf(SUInfo);
  SUInfo.dwFlags     := STARTF_USESHOWWINDOW;
  SUInfo.wShowWindow := SW_SHOW;
  if not CreateProcess(nil,
                       pChar('c:\windows\'+
                             'notepad.exe'),
                       nil,
                       nil,
                       FALSE,
                       CREATE_NEW_CONSOLE or
                       NORMAL_PRIORITY_CLASS,
                       nil,
                       pChar(ExtractFilePath('c:\windows\'+
                                             'notepad.exe')),
                       SUInfo,
                       ProcInfo) then
    ShowMessage('CreateProcess FAILED!!!');
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  tmpCard : Cardinal;
begin
  if GetExitCodeProcess(ProcInfo.hProcess,tmpCard) then
  begin
    if TerminateProcess(ProcInfo.hProcess,tmpCard) then
      FillChar(ProcInfo, SizeOf(ProcInfo),#0);
  end;
end;

end.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6392009
>> you can get the handle of that window by findwinow, then close it, but Madshi suggest me to don't use it

That depends. If you know exactly the class name of the main window of the application which you want to stop, using FindWindow is fine. But often you do not know. In such cases FindWindow doesn't work, of course.

Regards, Madshi.
0
 
LVL 1

Author Comment

by:trunin
ID: 6392128
Yes I know that I can't use FindWindow. I start application now with CreateProcess and close it with TerminateProcess. Can I close it using PostMessage(...,WM_close, 0 ,0)
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6392210
>> Can I close it using PostMessage(...,WM_close, 0 ,0)

You can, but first you have to find the main window of the newly started process, because PostMessage wants to have a *window*, not a process ID or handle.

Getting the main window is a bit work: You need to call EnumWindows. In the callback function, which you give in to EnumWindows, you'll get all windows of all process. For each window you need to call GetWindowThreadProcessID to get the processID to which the window belongs. You can then compare this ID to the processID you got from CreateProcess. If it is the same, you've found a window of the newly started process. Now you can call PostMessage to that window.

Regards, Madshi.
0
 
LVL 4

Expert Comment

by:fva
ID: 6392233
What if he starts the process with CreateProcess, gets the new main thread from that and then posts the WM_CLOSE to that thread. I guess the thread should do its magic and dispatch the WM_CLOSE to the appropriate main window, closing the app.
Or, maybe I'm wrong: The thread will dispatch the WM_CLOSE to its focused window, which might not be the main one.
Which would be correct?

F.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6392274
The thread doesn't dispatch the message at all, because the TMsg.hwnd parameter is zero. If you call DispatchMessage with such a TMsg, simply nothing will happen. The main message loop (or in other words: whoever is calling Get/PeekMessage) is responsible for handling such thread messages. If the message loop does not, the message has no effect.

Regards, Madshi.
0
 
LVL 4

Expert Comment

by:fva
ID: 6392344
Oh, sorry. Now I see I should have said WM_QUIT. Wouldn't that work?

F.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6392661
Yep, WM_QUIT even MUST be sent to a thread, WM_QUIT doesn't work when sent to a window (at least in most cases). However, some applications react allergically on PostThreadMessage(WM_QUIT). Some application's close fine, some do not. Generally WM_CLOSE is safer, much less crashes. TerminateProcess is also safer then WM_QUIT, in that it produces less crashes. But then again WM_QUIT is a cleaner stop - if the application accepts it correctly...

Regards, Madshi.
0
 
LVL 1

Author Comment

by:trunin
ID: 6393434
Thanks to all. All work. I will give points to Madshi.
brg, Trunin
0

Featured Post

NAS Cloud Backup Strategies

This article explains backup scenarios when using network storage. We review the so-called “3-2-1 strategy” and summarize the methods you can use to send NAS data to the cloud

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
code issue 8 130
Delphi inherited method 6 68
update joined tables 2 46
scroll down TListBox component in Delphi 1 11
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question