* fix DosExitCode for sessions of other types, consider ExecFlags for other session types

git-svn-id: trunk@19398 -
This commit is contained in:
Tomas Hajny 2011-10-06 23:57:59 +00:00
parent 9edae25cae
commit af03a73af2

View File

@ -54,6 +54,14 @@ Type
threadvar threadvar
(* For compatibility with VP/2, used for runflags in Exec procedure. *) (* For compatibility with VP/2, used for runflags in Exec procedure. *)
ExecFlags: cardinal; ExecFlags: cardinal;
(* Note that the TP/BP compatible method for retrieval of exit codes *)
(* is limited to only one (the last) execution! Including the following *)
(* two variables in the interface part allows querying the status of *)
(* of asynchronously started programs using DosWaitChild with dtNoWait *)
(* parameter, i.e. without waiting for the final program result (as *)
(* opposed to calling DosExitCode which would wait for the exit code). *)
LastExecRes: TResultCodes;
LastExecFlags: cardinal;
{$i dosh.inc} {$i dosh.inc}
@ -64,12 +72,15 @@ function GetEnvPChar (EnvVar: string): PChar;
function DosErrorModuleName: string; function DosErrorModuleName: string;
(* In case of an error in Dos.Exec returns the name of the module *) (* In case of an error in Dos.Exec returns the name of the module *)
(* causing the problem - e.g. name of a missing or corrupted DLL. *) (* causing the problem - e.g. name of a missing or corrupted DLL. *)
(* It may also contain a queue name in case of a failed attempt *)
(* to create queue for reading results of started sessions. *)
implementation implementation
{$DEFINE HAS_GETMSCOUNT} {$DEFINE HAS_GETMSCOUNT}
{$DEFINE HAS_DOSEXITCODE}
{$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *) {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
{$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *) {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
@ -79,7 +90,6 @@ implementation
threadvar threadvar
LastDosErrorModuleName: string; LastDosErrorModuleName: string;
ExecCounter: cardinal;
const FindResvdMask = $00003737; {Allowed bits in attribute const FindResvdMask = $00003737; {Allowed bits in attribute
@ -142,13 +152,40 @@ begin
end; end;
function DosExitCode: word;
var
Res: TResultCodes;
PPID: cardinal;
RC: cardinal;
begin
if (LastExecFlags = deAsyncResult) or (LastExecFlags = deAsyncResultDb) then
begin
RC := DosWaitChild (DCWA_PROCESS, dtWait, Res, PPID, LastExecRes.PID);
if RC = 0 then
(* If we succeeded, the process is finished - possible future querying
of DosExitCode shall return the result immediately as with synchronous
execution. *)
begin
LastExecFlags := deSync;
LastExecRes := Res;
end
else
LastExecRes.ExitCode := RC shl 16;
end;
if LastExecRes.ExitCode > high (word) then
DosExitCode := high (word)
else
DosExitCode := LastExecRes.ExitCode and $FFFF;
end;
procedure Exec (const Path: PathStr; const ComLine: ComStr); procedure Exec (const Path: PathStr; const ComLine: ComStr);
{Execute a program.} {Execute a program.}
var var
Args0, Args: PByteArray; Args0, Args: PByteArray;
ArgSize: word; ArgSize: word;
Res: TResultCodes;
ObjName: string; ObjName: string;
Res: TResultCodes;
RC: cardinal; RC: cardinal;
ExecAppType: cardinal; ExecAppType: cardinal;
HQ: THandle; HQ: THandle;
@ -186,7 +223,7 @@ begin
GetMem (Args0, MaxArgsSize); GetMem (Args0, MaxArgsSize);
Args := Args0; Args := Args0;
(* Work around a bug in OS/2 - argument to DosExecPgm *) (* Work around a bug in OS/2 - argument to DosExecPgm *)
(* should not cross 64K boundary. *) (* should not cross a 64K boundary. *)
if ((PtrUInt (Args) + 1024) and $FFFF) < 1024 then if ((PtrUInt (Args) + 1024) and $FFFF) < 1024 then
Inc (pointer (Args), 1024); Inc (pointer (Args), 1024);
ArgSize := 0; ArgSize := 0;
@ -211,7 +248,8 @@ begin
RC := DosExecPgm (ObjName, cardinal (ExecFlags), Args, nil, Res, Path); RC := DosExecPgm (ObjName, cardinal (ExecFlags), Args, nil, Res, Path);
if RC = 0 then if RC = 0 then
begin begin
LastDosExitCode := Res.ExitCode; LastExecFlags := ExecFlags;
LastExecRes := Res;
LastDosErrorModuleName := ''; LastDosErrorModuleName := '';
end end
else else
@ -222,9 +260,49 @@ begin
DSS := true; DSS := true;
if DSS then if DSS then
begin begin
Str (GetProcessID, SPID);
Str (ThreadID, STID);
QName := '\QUEUES\FPC_Dos_Exec_p' + SPID + 't' + STID + '.QUE'#0;
FillChar (SD, SizeOf (SD), 0); FillChar (SD, SizeOf (SD), 0);
SD.Length := SizeOf (SD); SD.Length := SizeOf (SD);
RC := 0;
case ExecFlags of
deSync:
begin
SD.Related := ssf_Related_Child; SD.Related := ssf_Related_Child;
LastExecFlags := ExecFlags;
SD.TermQ := @QName [1];
RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
end;
deAsync,
deAsyncResult:
begin
(* Current implementation of DosExitCode does not support retrieval *)
(* of result codes for other session types started asynchronously. *)
LastExecFlags := deAsync;
SD.Related := ssf_Related_Independent;
end;
deBackground:
begin
(* Current implementation of DosExitCode does not support retrieval *)
(* of result codes for other session types started asynchronously. *)
LastExecFlags := ExecFlags;
SD.Related := ssf_Related_Independent;
SD.FgBg := ssf_FgBg_Back;
end;
deAsyncResultDB:
begin
(* Current implementation of DosExitCode does not support retrieval *)
(* of result codes for other session types started asynchronously. *)
LastExecFlags := ExecFlags;
SD.Related := ssf_Related_Child;
SD.TraceOpt := ssf_TraceOpt_Trace;
end;
end;
if RC <> 0 then
ObjName := Copy (QName, 1, Pred (Length (QName)))
else
begin
if Args = nil then if Args = nil then
(* No parameters passed, Args not allocated for DosExecPgm, so allocate now. *) (* No parameters passed, Args not allocated for DosExecPgm, so allocate now. *)
begin begin
@ -237,40 +315,35 @@ begin
SD.PgmInputs := PChar (@Args^ [Length (QName) + 1]); SD.PgmInputs := PChar (@Args^ [Length (QName) + 1]);
SD.PgmName := PChar (Args); SD.PgmName := PChar (Args);
SD.InheritOpt := ssf_InhertOpt_Parent; SD.InheritOpt := ssf_InhertOpt_Parent;
Str (GetProcessID, SPID);
Str (ThreadID, STID);
Str (ExecCounter, SCtr);
Inc (ExecCounter);
QName := '\QUEUES\FPC_Dos_Exec_p' + SPID + 't' + STID + '.QUE'#0;
SD.TermQ := @QName [1];
SD.ObjectBuffer := @ObjName [1]; SD.ObjectBuffer := @ObjName [1];
SD.ObjectBuffLen := SizeOf (ObjName) - 1; SD.ObjectBuffLen := SizeOf (ObjName) - 1;
RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
if RC <> 0 then
ObjName := Copy (QName, 1, Pred (Length (QName)))
else
begin
RC := DosStartSession (SD, SID, PID); RC := DosStartSession (SD, SID, PID);
if (RC = 0) or (RC = 457) then if (RC = 0) or (RC = 457) then
begin begin
RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0); LastExecRes.PID := PID;
if RC = 0 then if ExecFlags = deSync then
begin begin
LastDosExitCode := PCI^.Return; RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
if (RC = 0) and (PCI^.SessionID = SID) then
begin
LastExecRes.ExitCode := PCI^.Return;
DosCloseQueue (HQ); DosCloseQueue (HQ);
DosFreeMem (PCI); DosFreeMem (PCI);
end end
else else
DosCloseQueue (HQ); DosCloseQueue (HQ);
end;
end end
else else if ExecFlags = deSync then
DosCloseQueue (HQ); DosCloseQueue (HQ);
end; end;
end; end;
if RC <> 0 then if RC <> 0 then
begin begin
LastDosErrorModuleName := ObjName; LastDosErrorModuleName := ObjName;
LastDosExitCode := 0; (* Needed for TP/BP compatibility *) LastExecFlags := deSync;
LastExecRes.ExitCode := 0; (* Needed for TP/BP compatibility *)
LastExecRes.TerminateReason := $FFFFFFFF;
end; end;
DosError := RC; DosError := RC;
if Args0 <> nil then if Args0 <> nil then
@ -561,8 +634,8 @@ begin
begin begin
LastDosExitCode := 0; FillChar (LastExecRes, SizeOf (LastExecRes), 0);
LastDosErrorModuleName := ''; LastDosErrorModuleName := '';
ExecFlags := 0; ExecFlags := 0;
ExecCounter := 0; LastExecFlags := deSync;
end. end.