trunin
asked on
Closing application
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;
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
begin
temp := ShellExecute(handle, 'open', 'test.exe', nil, nil, SW_SHOWNORMAL);
end;
procedure TForm1.Button2Click(Sender
begin
SendMessage(temp, WM_CLOSE, 0, 0);
end;
waiting for Madshi :-)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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
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('not epad'),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(ProcInf o.hProcess ,tmpCard) then
begin
if TerminateProcess(ProcInfo. hProcess,t mpCard) then
FillChar(ProcInfo, SizeOf(ProcInfo),#0);
end;
end;
end.
procedure TForm1.Button2Click(Sender
var
wnd : hwnd;
begin
wnd:=FindWindow(pchar('not
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
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:\
'notepad.exe')),
SUInfo,
ProcInfo) then
ShowMessage('CreateProcess
end;
procedure TForm1.Button2Click(Sender
var
tmpCard : Cardinal;
begin
if GetExitCodeProcess(ProcInf
begin
if TerminateProcess(ProcInfo.
FillChar(ProcInfo, SizeOf(ProcInfo),#0);
end;
end;
end.
>> 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.
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.
ASKER
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)
>> 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.
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.
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.
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.
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.
Regards, Madshi.
Oh, sorry. Now I see I should have said WM_QUIT. Wouldn't that work?
F.
F.
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.
Regards, Madshi.
ASKER
Thanks to all. All work. I will give points to Madshi.
brg, Trunin
brg, Trunin