• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1254
  • Last Modified:

Terminating a child process - Win32 in Delphi

I have spawned a child process using CreateProcess and want to
terminate it politely i.e. not by using TerminateProcess which is
draconian.  I had thought of sending a WM_CLOSE message.  However, the
handle to the process (from ProcessInfo.hProcess) is not the same as
the app handle I need nor the handle of the spawned app's main form.

Does anybody know either
a) how I can get the appropriate handle
b) a better way of politely terminating the process than sending a
WM_CLOSE message.

The precise executable spawned is not known at designtime so I can't
look for the window by name.

Cheers.
0
Ency
Asked:
Ency
  • 2
  • 2
1 Solution
 
geobulCommented:
Hi,

var
  TargetHWND: HWND;
  TargetProcID: cardinal;

function EnumerateWindows(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;
var ProcessId: cardinal;
begin
  GetWindowThreadProcessId(hWnd,@ProcessId);
  if ProcessID = TargetProcID then begin
    TargetHWND := hWnd;
    result := false; // stop enumeration
  end else
    result := true; // continue enumeration
end;

// usage:
TargetHWND := 0;
TargetProcID := ...; //your value here
EnumWindows(@EnumerateWindows, 0); // enumerate all top-level windows
if TargetHWND <> 0 then begin
  SendMessage(TargetHWND, WM_CLOSE, 0, 0);
end;

Regards, Geo
0
 
EncyAuthor Commented:
Thanks for that.  However it does not seem to work.  Here's what I'm getting:

Firstly, the call back is working and is picking up (among many others) the main window of my spawned process.  
I know this because I've made API calls GetClassName and GetWindowText with the enumerated windows handles.  

The problem is that the process and thread IDs passed back by GetWindowThreadProcessId are different to the
Handle I get returned by CreateProcess in TProcessInformation.  I can only assume that a process or thread's ID is
not the same thing as its handle.

Have I misunderstood something?  If not is there some way of getting the process or thread ID from the handle
or vice versa?

For what it's worth the code that demonstrates this problem is below.
=========================================================================

var
  Target: TListView;

function EnumerateWindows(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
  ProcessId: cardinal;
  ThreadID: cardinal;
  lpString: PChar;
  ListItem: TlistItem;
begin
  lpString := StrAlloc(256);
  try
    ListItem := Target.Items.Add;
    GetClassName(hWnd,lpString,255);
    ListItem.Caption := lpString;
    GetWindowText(hWnd,lpString,255);
    ListItem.SubItems.Add( lpString );
    ThreadId := GetWindowThreadProcessId(hWnd,@ProcessId);
    ListItem.SubItems.Add( IntToSTr(ProcessId) );
    ListItem.SubItems.Add( IntToStr(ThreadId) );
    Result := True;
  finally
    StrDispose(lpString);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ListView1.Items.BeginUpdate;
  try
    Target := ListView1;
    ListView1.Items.Clear;
    EnumWindows(@EnumerateWindows,0);
  finally
    ListView1.Items.EndUpdate;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ProcessInfo: TProcessInformation;
  StartupInfo: TStartupInfo;
begin
  { Null these records }
  FillChar( StartupInfo, SizeOf(StartupInfo), 0 );
  FillChar( ProcessInfo, SizeOf(ProcessInfo), 0 );

  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow := SW_SHOWNORMAL;

  if not CreateProcess( nil, PChar('c:\test\project1.exe'), nil, nil, False, NORMAL_PRIORITY_CLASS,
    nil, PChar('c:\test'), StartupInfo, ProcessInfo ) then
    raise Exception.Create( 'CreateProcess Failed' );

  label1.Caption := IntToStr(ProcessInfo.hProcess);
  label2.Caption := IntToStr(ProcessInfo.hThread);
end;


0
 
EncyAuthor Commented:
Doh!

<sheepish>
I've just realised that TProcessInfo has members dwProcessId and dwThreadId.  I feel pretty silly now.
</sheepish>

Oh well I supose if you have to make a fool of yourself there's nothing quite like doing it on the internet.
0
 
geobulCommented:
Oh, I'm sorry. I really forgot to say where you should get the TargetProcID from. Glad you've managed it yourself.

Thanks for the grade :-)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now