0

When I run this code, the calc.exe starts, but I cannot assign the process handle to a job. The process starts, but the handle is not valid?

Where did I go wrong?

The result of GetLastError() is always 6.

I followed this tutorial: Inno Setup Exec() function Wait for a limited time

const
  INFINITE=                   $FFFFFFFF;
  SEE_MASK_NOASYNC=           $00000100;
  SEE_MASK_NOCLOSEPROCESS=    $00000040;

type
  TShellExecuteInfo = record
    cbSize: DWORD;
    fMask: Cardinal;
    HWND: HWND;
    lpVerb: string;
    lpFile: string;
    lpParameters: string;
    lpDirectory: string;
    nShow: Integer;
    hInstApp: THandle;    
    lpIDList: DWORD;
    lpClass: string;
    hkeyClass: THandle;
    dwHotKey: DWORD;
    hMonitor: THandle;
    hProcess: THandle;
end;

function ShellExecuteAndWait(
  Filename : String;
  Params : String;
  WorkingDir : String;
  ShowCmd : Integer
) : Integer;
var 
  JobObject : Thandle;
  ExecInfo : TShellExecuteInfo;

  ExitCode : DWORD;
begin

  ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
  ExecInfo.hwnd := 0;
  ExecInfo.lpVerb := 'open';
  ExecInfo.lpFile := Filename;
  ExecInfo.lpParameters := Params;
  ExecInfo.lpDirectory := WorkingDir;
  ExecInfo.nShow := ShowCmd;
  ExecInfo.cbSize := SizeOf(ExecInfo);

  JobObject := CreateJobObject( '' , 'WaitJob');
  ShellExecuteEx(ExecInfo);

  if  not AssignProcessToJobObject( JobObject , ExecInfo.hProcess ) then
  begin
    MsgBox( 'Error during the assign. ' + 'Error code: ' +  IntToStr( GetLastError() ), mbConfirmation, MB_OK); //Returns: 6 - Invalid handler
  end;

  WaitForSingleObject( JobObject , INFINITE );
  GetExitCodeProcess( ExecInfo.hProcess , ExitCode );

  Result := ExitCode;
end;

EDIT: More function prototypes.

function WaitForSingleObject(
  hHandle : THandle;
  dwMilliseconds : DWORD
  ) : DWORD;
external 'WaitForSingleObject@kernel32.dll stdcall';

function ShellExecuteEx(
  lpExecInfo: TShellExecuteInfo
  ): BOOL; 
external 'ShellExecuteEx{#AW}@Shell32.dll stdcall';

function AssignProcessToJobObject(
  hJob : Thandle;
  hProcess : Thandle
  ): BOOL;
external 'AssignProcessToJobObject@kernel32.dll stdcall';

function CreateJobObject(
  lpSecurityAttributes,
  lpName: string
  ): THandle;
external 'CreateJobObject{#AW}@kernel32.dll stdcall';
Community
  • 1
  • 1
Gazben
  • 316
  • 3
  • 11
  • Are you sure it is the `ExecInfo.hProcess` that is invalid ? Have you checked if it's not the `JobObject` that is invalid ? Could you include in your post also job function prototypes ? Btw. you should check the returned values of those function calls. – TLama Aug 26 '14 at 14:45
  • 1
    Improve your error handling. CreateJobObject() can fail, an empty string for the 1st argument is rather unlikely, ShellExecuteEx() can fail. – Hans Passant Aug 26 '14 at 14:45
  • I checked the CreateJobObject() and it returned 0. – Gazben Aug 26 '14 at 14:51
  • 1
    That means the function failed. Are you using ANSI or Unicode Inno Setup ? – TLama Aug 26 '14 at 14:57
  • 1
    If CreateJobObject returned 0, it failed, and you should use GetLastError to determine why that is the case. You should **always** read the [documentation](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682409%28v=vs.85%29.aspx) – Ken White Aug 26 '14 at 15:08
  • Yes, I didn't read it carefully. Now I have to figure out how can I create a proper JobObject. – Gazben Aug 26 '14 at 15:24
  • First, you need to find out why `CreateJobObject()` failed. `GetLastError()` tells you that. Error 6 is `ERROR_INVALID_HANDLE`. Why are you even creating a job object for a single process, anyway? Especially since you are leaking it, which would cause subsequent calls to `CreateJobObject()` to report `ERROR_ALREADY_EXISTS` from `GetLastError()`. You should eliminate the job object altogether and just wait on `ExecInfo.hProcess` directly instead. – Remy Lebeau Aug 26 '14 at 22:16
  • Also note that using job objects with an installation can be problematic. In particular the uninstaller is always run within a job itself, which means that all child processes started by the uninstaller live within the same job. It is not possible to switch a process from one job to another after it has started. While there is a flag that allows a process to be started "outside" the parent job when it is first created, this requires `CreateProcess` rather than `ShellExecute`, and also that the *original* job (which you have no control over) be created permitting breakaway (not the default). – Miral Aug 28 '14 at 22:21

0 Answers0