Link to home
Start Free TrialLog in
Avatar of urif
urif

asked on

terminate all open applications

ok, this was already asked in https://www.experts-exchange.com/questions/20083127/getting-this-code-to-work.html
but no answer there.
when you load that code delphi complains about PTaskEntry, and i can't seem to find any referece to it anywhere.

anyway, what i need is to close all open applications on the dektop (not ALL app in the system), meaning that if i have notepad, mozilla, thunderbird and word i want to close those 4 programs.

the code i found that supposedly do that is as follow:


Q:  How do I terminate all running tasks?

A:  Below is some code that will help if you want to terminate ALL tasks,
    no questions asked.

A word of caution, before you run this for the first time, make sure
that you save it and anything else that may have some pending data.


procedure TForm1.ButtonKillAllClick(Sender: TObject);
var
  pTask   : PTaskEntry;
  Task    : Bool;
  ThisTask: THANDLE;
begin
  GetMem (pTask, SizeOf (TTaskEntry));
  pTask^.dwSize := SizeOf (TTaskEntry);

  Task := TaskFirst (pTask);
  while Task do
  begin
    if pTask^.hInst = hInstance then
      ThisTask := pTask^.hTask
    else
      TerminateApp (pTask^.hTask, NO_UAE_BOX);
    Task := TaskNext (pTask);
  end;
  TerminateApp (ThisTask, NO_UAE_BOX);
end;


can anyone give me a good code example on how to close all the open applications?

thanks so much
ASKER CERTIFIED SOLUTION
Avatar of Hypoviax
Hypoviax
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of urif
urif

ASKER

Hypoviax

thanks for the code it works great, but since i opened the binary from the command line it didn't kill it (the form with the button in it)
now, question tho, if i run an application that has this code inside from the tray area and it starts when windows starts (either from the registry or from the start menu), will it kill itself when i close all apps?

thanks again, the points are yours.
Avatar of urif

ASKER

Hypoviax

ok, the code works great, a little TOO great.
it closes all the application on the desktop, but also all the tray applications that are run from the start menu, the registry and other autorun options.

any way to limit the closing of the applications to those on the desktop ONLY?
may take the name of the apps running by scanning the taskbar?

thanks again
Hi,

I've been away for the past few days. Will check it out tommorow.

Regards,

Hypoviax
Avatar of urif

ASKER

thanks
Acutally, over the next few days i will try and look. I'm just starting uni so it's a bit busy at the moment. If you can wait around i'll post as soon as possible
Avatar of urif

ASKER

sure, but again this is my question:


i need to close all open applucations "on th desktop", those that are actually showing on the taskbar.

thanks
I'm not sure if this would work but you could try to do a complete enumeration of windows and close all. This effectively will close the applications:

Code. You need a list view called listwindow:

Function EnumWindowsProc(
hwnd:HWND;//handle to parent window
lParam:LPARAM // Application defined value
):Boolean;stdcall;
var
{p,} buffer{, v}:pchar;
listitem:tlistitem;
Begin
      result:=false;
try
//reserve a string space
Getmem(buffer,1000);
            getwindowtext(hwnd,buffer,1000);
                  listitem:=form1.listwindows.Items.Add ;
                  listitem.caption:=buffer;
        if length(listitem.caption)=0 then
        begin
        listitem.Delete         ;
         end;
           result:=true;
            //free the string space
          freemem(buffer, 1000);
except
end;
end;

procedure TForm1.killspawnedapps;
var X:integer;
begin
For X:=0 to listwindow.items.count-1 do

end;
procedure TForm1.Button1Click(Sender: TObject);
begin
enumwindows(@EnumWindowsProc,0);
killspawnedapps ; //The procedure to kill all applications
end;


end.
sorry i accidently pressed enter (after pressing tab)
 
this should be the code:

Function EnumWindowsProc(
hwnd:HWND;//handle to parent window
lParam:LPARAM // Application defined value
):Boolean;stdcall;
var
{p,} buffer{, v}:pchar;
listitem:tlistitem;
Begin
     result:=false;
try
//reserve a string space
Getmem(buffer,1000);
          getwindowtext(hwnd,buffer,1000);
               listitem:=form1.listwindows.Items.Add ;
               listitem.caption:=buffer;
        if length(listitem.caption)=0 then
        begin
        listitem.Delete         ;
         end;
          result:=true;
          //free the string space
         freemem(buffer, 1000);
except
end;
end;

procedure TForm1.killspawnedapps;
var X:integer;
begin
For X:=0 to listwindows.items.count-1 do
   begin
         postmessage(findwindow(nil,pchar(listwindows.item.item[x].caption)),wm_close,0,0);
   end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
enumwindows(@EnumWindowsProc,0);
killspawnedapps ; //The procedure to kill all applications
end;


end.
I don't really know how to do what you specifically asked, i only hope that the code above works the way you wanted
Avatar of urif

ASKER

well, we are pretty much in the same problem, the difference is that the code you post in the beginning closes all apps (and i mean ALL) without asking, the code you posted now does the same, it closes ALL app, services, etc but asking, so there;s the annoying "save" and "not responding" dialogs that the programs show.

isn't there a way to close ONLY those applications on the desktop? no the sevices, no those running on the tray area, sort of line a minimize all but close them instead of minimize them.
Avatar of urif

ASKER

by the way i tried the approach of enumarating all the windows and then closing those that are on the desktop, but i can;t find a way to know for certain which app is running on the desktop. that's why i came here for an answer.,

also, since MOST applications that me and the people around me start are not started from the explorer, no onw uses explorer here, only the command line, and oher shells.

do you know if the enumaration has a field that tells you where the application resides?

or maybe, is there any api to talk to the taskbar? maybe we can get info from the taskbar as to what applications are running there
Avatar of urif

ASKER

another way is to maybe try the link i 1st posted and try to figure where this (PTaskEntry) is declared
Avatar of urif

ASKER

how about this:

To enumerate the system's top-level windows, use the EnumWindows API
function.
EnumWindows will tell you about many more windows than you actually
want. TO check if a program has a corresponding button on the taskbar. , you need to look
at the window's extended style. Retreive that with GetWindowLong. Use
bitwise arithmetic to check for the right combination of
ws_ex_ToolWindow and ws_ex_AppWindow styles


now, i am trying this, so far no luck, then again. i am a c programmer. maybe you can try it
Avatar of urif

ASKER

ok, here's the code to get all apps running on the desktop, now how to close them:

function GetText(Wnd: HWND): string;
var
  textlength: Integer;
  Text: PChar;
begin
  textlength := SendMessage(Wnd, WM_GETTEXTLENGTH, 0, 0);
  if textlength = 0 then Result := ''
  else
  begin
    GetMem(Text, textlength + 1);
    SendMessage(Wnd, WM_GETTEXT, textlength + 1, Integer(Text));
    Result := Text;
    FreeMem(Text);
  end;
end;

function EnumWindowsProc(Wnd: HWND; lParam: lParam): BOOL; stdcall;
begin
  Result := True;
  if (IsWindowVisible(Wnd) or IsIconic(wnd)) and
    ((GetWindowLong(Wnd, GWL_HWNDPARENT) = 0) or
    (GetWindowLong(Wnd, GWL_HWNDPARENT) = GetDesktopWindow)) and
    (GetWindowLong(Wnd, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0) then
    Form1.Listbox1.Items.Add('Handle: ' + IntToStr(Wnd) + ',Text:  ' + GetText(Wnd));
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  Param: Longint;
begin
  EnumWindows(@EnumWindowsProc, Param);
end;
Avatar of urif

ASKER

ok, if you add this

postmessage(findwindow(nil,pchar(GetText(Wnd))),wm_close,0,0);

instead of

Form1.Listbox1.Items.Add('Handle: ' + IntToStr(Wnd) + ',Text:  ' + GetText(Wnd));

on EnumWindowsProc() it'l close the windows.
now, if you do it from the command line it won't work... weirds.

please try it
ok, i'll try it out today (i'm operating on a different time zone)

Regards,

Hypoviax
What i am thinking is to try to extract the PID or the actual application exename from the windows and then terminate using my earlier code
OK try this:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    ListBox2: TListBox;
    ListBox3: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function GetText(Wnd: HWND): string;
var
  textlength: Integer;
  Text: PChar;
begin
  textlength := SendMessage(Wnd, WM_GETTEXTLENGTH, 0, 0);
  if textlength = 0 then Result := ''
  else
  begin
    GetMem(Text, textlength + 1);
    SendMessage(Wnd, WM_GETTEXT, textlength + 1, Integer(Text));
    Result := Text;
    FreeMem(Text);
  end;
end;

function EnumWindowsProc(Wnd: HWND; lParam: lParam): BOOL; stdcall;
Var pID,hProcess:DWord;
begin
  Result := True;
  if (IsWindowVisible(Wnd) or IsIconic(wnd)) and
    ((GetWindowLong(Wnd, GWL_HWNDPARENT) = 0) or
    (GetWindowLong(Wnd, GWL_HWNDPARENT) = GetDesktopWindow)) and
    (GetWindowLong(Wnd, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0) then
    begin
       Form1.Listbox1.Items.Add(IntToStr(Wnd)); //only for display
        form1.ListBox3.Items.add(GetText(Wnd)); //only for display
        GetWindowThreadProcessId(Wnd,@pID);   //find the PID from the Wnd
        form1.ListBox2.Items.add(inttostr(pID)); //yonly for display
        hProcess:=OpenProcess(PROCESS_TERMINATE,TRUE,pID);  //kill the program
       TerminateProcess(hProcess,1);//kill the program
    end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  Param: Longint;
  X:Integer;
  sz:pchar  ;
begin
  EnumWindows(@EnumWindowsProc, Param);
end;


end.

Regards,

Hypoviax
Please note when i ran it i commented the kill program part. If that doesn't work it is easy to fix
Avatar of urif

ASKER

still doesn't work from the command line. it just kills the cmd.exe and that's it.
it's important that it works from the command line.,

working as a GUI application, well, that part i have, i posted it here, but...
Ok, try this:

function GetText(Wnd: HWND): string;
var
  textlength: Integer;
  Text: PChar;
begin
  textlength := SendMessage(Wnd, WM_GETTEXTLENGTH, 0, 0);
  if textlength = 0 then Result := ''
  else
  begin
    GetMem(Text, textlength + 1);
    SendMessage(Wnd, WM_GETTEXT, textlength + 1, Integer(Text));
    Result := Text;
    FreeMem(Text);
  end;
end;

function EnumWindowsProc(Wnd: HWND; lParam: lParam): BOOL; stdcall;
Var pID,hProcess:DWord;
begin
  Result := True;
  if (IsWindowVisible(Wnd) or IsIconic(wnd)) and
    ((GetWindowLong(Wnd, GWL_HWNDPARENT) = 0) or
    (GetWindowLong(Wnd, GWL_HWNDPARENT) = GetDesktopWindow)) and
    (GetWindowLong(Wnd, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0) then
    begin
       Form1.Listbox1.Items.Add(IntToStr(Wnd)); //only for display
        form1.ListBox3.Items.add(GetText(Wnd)); //only for display
        GetWindowThreadProcessId(Wnd,@pID);   //find the PID from the Wnd
        form1.ListBox2.Items.add(inttostr(pID)); //yonly for display
        hProcess:=OpenProcess(PROCESS_TERMINATE,TRUE,pID);  //kill the program
       TerminateProcess(hProcess,1);//kill the program
    end;
end;

function KillTask(ExeFileName: string): integer; //used to kill a process
const
PROCESS_TERMINATE=$0001;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
result := 0;
FSnapshotHandle := CreateToolhelp32Snapshot
(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle,
FProcessEntry32);
while integer(ContinueLoop) <> 0 do
begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeFileName))
or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeFileName))) then
Result := Integer(TerminateProcess(OpenProcess(
PROCESS_TERMINATE, BOOL(0),
FProcessEntry32.th32ProcessID), 0));
ContinueLoop := Process32Next(FSnapshotHandle,
FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;

function FindPID(ExeFileName: string): integer; //used to find the pid of an app
const
PROCESS_TERMINATE=$0001;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
result := 0;
FSnapshotHandle := CreateToolhelp32Snapshot
(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle,
FProcessEntry32);
while integer(ContinueLoop) <> 0 do
begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile))=UpperCase(ExeFileName))
or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeFileName))) then
  begin
    Result :=FProcessEntry32.th32ProcessID
  end;
ContinueLoop := Process32Next(FSnapshotHandle,
FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;

procedure tform1.killspawnedapps ; //kill all applications
const
 PROCESS_TERMINATE=$0001;
 var
 ContinueLoop: BOOLEAN;
 FSnapshotHandle: THandle;
 FProcessEntry32: TProcessEntry32;
           begin
                FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
                        FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
                ContinueLoop := Process32First(FSnapshotHandle,FProcessEntry32);

 while integer(ContinueLoop) <> 0 do
 begin                                                        
    if FProcessEntry32.th32ParentProcessID=FindPID('cmd.exe') then //if opened by cmd.exe then terminate it
          begin
                killtask(FProcessEntry32.szExeFile);
         end;
  ContinueLoop := Process32Next(FSnapshotHandle,FProcessEntry32);
end;
 CloseHandle(FSnapshotHandle);
end;

procedure TForm1.Button1Click(Sender: TObject); //kill the apps
var
  Param: Longint;
  X:Integer;
  sz:pchar  ;
begin
  EnumWindows(@EnumWindowsProc, Param); //kill normal desktop apps
  killspawnedapps ; //kill cmd apps
end;

Regards,

Hypoviax
Avatar of urif

ASKER

thanks for the help.
but again, since i have different ways to start an application, not only explorer, or cmd but also a custom wirtten shell and the total commander and etc, etc. i can't just one function per program since i don't know what will be in the future.
so it has to be a generic, like the code i wrote above.
your alst code works great, but it did not kill those applications spawned by the custom shell.
that's why i focused on the fact that since an app has a button on the taskbar it can be killed. no matter what application spawned it.