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

PostMessage to process

Hi, Im trying to figure out how I can stop a process started with the following code:

function WinExecAndWait32(FileName:String; Visibility : integer):integer;
var
 zAppName:array[0..512] of char;
 zCurDir:array[0..255] of char;
 WorkDir:String;
 StartupInfo:TStartupInfo;
 ProcessInfo:TProcessInformation;
begin
 StrPCopy(zAppName,FileName);
 GetDir(0,WorkDir);
 StrPCopy(zCurDir,WorkDir);
 FillChar(StartupInfo,Sizeof(StartupInfo),#0);
 StartupInfo.cb := Sizeof(StartupInfo);

 StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
 StartupInfo.wShowWindow := Visibility;
 if not CreateProcess(nil,
   zAppName,                      { pointer to command line string }
   nil,                           { pointer to process security attributes }
   nil,                           { pointer to thread security attributes }
   false,                         { handle inheritance flag }
   CREATE_NEW_CONSOLE or          { creation flags }
   NORMAL_PRIORITY_CLASS,
   nil,                           { pointer to new environment block }
   nil,                           { pointer to current directory name }
   StartupInfo,                   { pointer to STARTUPINFO }
   ProcessInfo) then Result := -1 { pointer to PROCESS_INF }

 else begin
---->   PostThreadMessage(ProcessInfo.hThread, WM_QUIT, 0, 0); { I tried this, but no go }
   WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
   MainForm.Win32ExecHandle := -1;
   Result := SUCCESS;
 end;
end;


I want another thread to be able to stop the process. I assume posting a WM_QUIT message would be the nicest way to do it (I'd prefer not to use TerminateProcess). But the question is, which handle should I post to? As you can see above I post a quit message right before I wait for the process to end. But it never ends. Im testing this by executing notepad, which shows up but never stops unless I close it manually.
0
pede
Asked:
pede
  • 2
  • 2
1 Solution
 
Russell LibbySoftware Engineer, Advisory Commented:

The PostThreadMessage expects a thread id, not a thread handle, which is what you are passing. Try using the dwThreadId from the ProcessInfo. Also capture the return value of PostThreadMessage so you can determine if you should call GetLastError (to find out what went wrong)

Russell

0
 
PandoraCommented:
listening...
0
 
pedeAuthor Commented:
I forgot to mention it, but I already tried with dwThreadId, which didnt work either. I got invalid thread identifier in both cases.

But! I just discovered something interesting:

This fails:

   if not PostThreadMessage(ProcessInfo.dwThreadId, WM_QUIT, 0, 0) then begin
    MessageBox(0, pchar(SysErrorMessage(GetLastError)), 'LastError', MB_ICONERROR);
   end;
   WaitforSingleObject(ProcessInfo.hProcess,INFINITE);


This works:

   Sleep(2000);
   if not PostThreadMessage(ProcessInfo.dwThreadId, WM_QUIT, 0, 0) then begin
    MessageBox(0, pchar(SysErrorMessage(GetLastError)), 'LastError', MB_ICONERROR);
   end;
   WaitforSingleObject(ProcessInfo.hProcess,INFINITE);

Looks like the main thread isnt initialized when CreateProcess returns (please correct me if Im mistaken). The reason I try to quit at once is just that I thought it was the easiest way to test if it worked or not. I just want the ability to abort it, so unless I try to abort a split second after CreateProcess it will be fine. This could happen though, even if very unlikely. Is there a function that can wait until the main thread is created for sure?

Regards,
Pede
0
 
Russell LibbySoftware Engineer, Advisory Commented:

Pede,
Yes, you could use WaitForInputIdle:

The WaitForInputIdle function waits until the given process is waiting for user input with no input pending, or until the time-out interval has elapsed.

The WaitForInputIdle function only works with GUI applications. If a console application calls the function, it returns immediately, with no wait.

DWORD WaitForInputIdle(

    HANDLE hProcess,     // handle to process
    DWORD dwMilliseconds      // time-out interval in milliseconds  
    );    
 

Parameters

hProcess

Identifies the process.

dwMilliseconds

Specifies the time-out interval, in milliseconds. If dwMilliseconds is INFINITE, the function does not return until the process is idle.

Remarks

The WaitForInputIdle function enables a thread to suspend its execution until a specified process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronizing a parent process and a newly created child process. When a parent process creates a child process, the CreateProcess function returns without waiting for the child process to finish its initialization. Before trying to communicate with the child process, the parent process can use WaitForInputIdle to determine when the child's initialization has been completed. For example, the parent process should use WaitForInputIdle before trying to find a window associated with the child process. Remarks

-------------

Hope this does what you want it to,
Russell

0
 
pedeAuthor Commented:
Looks good, thanks
0

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

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