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

Finding a instance after it is created with ShellExecute

I want to open a DOS Window and execute a DOS program (such as the extract command) using the ShellExceute command. Since the window is hidden, it doesn't have a Window handle. (At least FindWindow can't find it). Is there a way, I can determin that the program is still running? I get a hInstance back from ShellExecute, but I can't find a function that is able to check if it is still vaild. Thanks for help...
  • 3
  • 2
1 Solution
jonnyfiveAuthor Commented:
Edited text of question
Hi JonnyFive,

try this one:

unit runThread_;


  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, tools, ddraw,
  ExtCtrls, ComCtrls;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    { Private-Deklarationen}
    { Public-Deklarationen}

var Form1 : TForm1 = nil;


{$R *.DFM}

const unitName = 'runThread_.';

type TRunThread = class(TThread)
    processHandle : cardinal;
    processReady  : boolean;
    waitingThread : cardinal;
    procedure Execute; override;

procedure TRunThread.Execute;
  WaitForSingleObject(processHandle,INFINITE);   // This call does not return, unless copy is stopped
  processReady:=true;                            // Set "processReady" flag for main thread
  PostThreadMessage(waitingThread,WM_NULL,0,0);  // Wake up main thread
                                                 // If you call Application.HandleMessage (see below) in the
                                                 // main thread, the main thread is sleeping the most time in
                                                 // winAPI "waitMessage". So we send a "dummy" message in order
                                                 // to let the main thread return from Application.HandleMessage

procedure TForm1.Button1Click(Sender: TObject);
var si : TStartupInfo;
    pi : TProcessInformation;
  caption:='start copy...';
  ZeroMemory(@si,sizeOf(si)); si.cb:=sizeOf(si);
  si.dwFlags:=STARTF_USESHOWWINDOW; si.wShowWindow:=SW_HIDE;
  if CreateProcess(nil,'c:\command.com /c copy c:\autoexec.bat c:\test.bat >c:\output.txt',nil,nil,false,0,nil,nil,si,pi) then begin
    caption:='copy started...';
    with TRunThread.Create(true) do         // create the thread object, but do not start it now...
        processHandle:=pi.hProcess;         // tell the thread what process it has to watch
        processReady:=false;                // flag for the loop (see below)
        waitingThread:=GetCurrentThreadID;  // the current threadID for the wakeup message (see above)
        caption:='wait for copy...';
        Resume;                             // now all information is prepared; so let's start the thread
          Application.HandleMessage;        // message loop
        until Application.Terminated or processReady;  // continue with normal program when either the
                                                       // started process has stopped or our program is closed
        caption:='copy stopped...';
      finally Free end;
    CloseHandle(pi.hThread); CloseHandle(pi.hProcess); // Never forget to close handles...
  end else caption:='could not start copy...';


Regards, Madshi.
I was going to post some code, but Madshi's method is much better than mine.  I will copy his instead!  hehehe :)

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

jonnyfiveAuthor Commented:
Hi Madshi... Thanks for the fast answer... I just tried the code. The reason why I want to know if the task is still running is simple: I want to wait for the Dos command to be finished before I go on in my program. Your code seems to work also parallel to the main program. What has to be changed to do this?
Thanks, Jonny Five :-)
It works *quite* parallel. The Button1Click procedure does not return until the dos process is finished, but messages are handled nevertheless. If you would not handle messages, it would have strange results. Your main form would not be repainted and such stuff.
I think you should use "enabled:=false" in the beginning of Button1Click and "enabled:=true" at the end of Button1Click. Then the user can't do anything with your form. I think that is exactly what you need...   :-)

Hi Heath, yeah, copy it. I like it if other experts like my sources...  :-)

Regards, Madshi.
jonnyfiveAuthor Commented:
After I tested the code a bit more, I think it is a very nice solution to the problem. Thanks... :-)
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Train for your Pen Testing Engineer Certification

Enroll today in this bundle of courses to gain experience in the logistics of pen testing, Linux fundamentals, vulnerability assessments, detecting live systems, and more! This series, valued at $3,000, is free for Premium members, Team Accounts, and Qualified Experts.

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