diff options
| author | peter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2007-10-28 21:26:51 +0000 |
|---|---|---|
| committer | peter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2007-10-28 21:26:51 +0000 |
| commit | 9a1c84e2531f3f115297d745fa9f03b322e5e881 (patch) | |
| tree | b6e0165c05e881ee4bc595ed417dd9a315e0d15c /packages/fcl-process/src | |
| parent | 77722a04c495e3d5b8200c8641f56d364009f1f1 (diff) | |
| download | fpc-9a1c84e2531f3f115297d745fa9f03b322e5e881.tar.gz | |
* created fcl-async and fcl-process packages
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@8979 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fcl-process/src')
28 files changed, 3839 insertions, 0 deletions
diff --git a/packages/fcl-process/src/amiga/pipes.inc b/packages/fcl-process/src/amiga/pipes.inc new file mode 100644 index 0000000000..dc35fb365c --- /dev/null +++ b/packages/fcl-process/src/amiga/pipes.inc @@ -0,0 +1,30 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + AmigaOS specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +// Unsupported for the moment... + +Function CreatePipeHandles (Var Inhandle,OutHandle : Longint) : Boolean; + +begin + Result := False; +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + Result := 0; +end; + diff --git a/packages/fcl-process/src/amiga/process.inc b/packages/fcl-process/src/amiga/process.inc new file mode 100644 index 0000000000..74f9c2fe50 --- /dev/null +++ b/packages/fcl-process/src/amiga/process.inc @@ -0,0 +1,42 @@ +{ + Dummy process.inc +} + +procedure TProcess.CloseProcessHandles; +begin +end; + +Function TProcess.PeekExitStatus : Boolean; +begin +end; + +Procedure TProcess.Execute; +begin +end; + +Function TProcess.WaitOnExit : Boolean; +begin + Result:=False; +end; + +Function TProcess.Suspend : Longint; +begin + Result:=0; +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; +begin + Result:=False; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); +begin +end; + + diff --git a/packages/fcl-process/src/beos/pipes.inc b/packages/fcl-process/src/beos/pipes.inc new file mode 100644 index 0000000000..9e0a292569 --- /dev/null +++ b/packages/fcl-process/src/beos/pipes.inc @@ -0,0 +1,30 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + DOS/go32v2 specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +// No pipes under beos, sorry... + +Function CreatePipeHandles (Var Inhandle,OutHandle : Longint) : Boolean; + +begin + Result := False; +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + Result := 0; +end; + diff --git a/packages/fcl-process/src/dbugintf.pp b/packages/fcl-process/src/dbugintf.pp new file mode 100644 index 0000000000..b86f74d96a --- /dev/null +++ b/packages/fcl-process/src/dbugintf.pp @@ -0,0 +1,285 @@ +{ + This file is part of the Free Component library. + Copyright (c) 2005 by Michael Van Canneyt, member of + the Free Pascal development team + + Debugserver client interface, based on SimpleIPC + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +{$mode objfpc} +{$h+} +unit dbugintf; + +interface + +Type + TDebugLevel = (dlInformation,dlWarning,dlError); + +procedure SendBoolean(const Identifier: string; const Value: Boolean); +procedure SendDateTime(const Identifier: string; const Value: TDateTime); +procedure SendInteger(const Identifier: string; const Value: Integer; HexNotation: Boolean = False); +procedure SendPointer(const Identifier: string; const Value: Pointer); +procedure SendDebugEx(const Msg: string; MType: TDebugLevel); +procedure SendDebug(const Msg: string); +procedure SendMethodEnter(const MethodName: string); +procedure SendMethodExit(const MethodName: string); +procedure SendSeparator; +procedure SendDebugFmt(const Msg: string; const Args: array of const); +procedure SendDebugFmtEx(const Msg: string; const Args: array of const; MType: TDebugLevel); + +procedure SetDebuggingEnabled(const AValue : boolean); +function GetDebuggingEnabled : Boolean; + +{ low-level routines } + +Function StartDebugServer : integer; +Function InitDebugClient : Boolean; + +Const + SendError : String = ''; + +ResourceString + SProcessID = 'Process %s'; + SEntering = '> Entering '; + SExiting = '< Exiting '; + SSeparator = '>-=-=-=-=-=-=-=-=-=-=-=-=-=-=-<'; + +implementation + +Uses + SysUtils, classes,dbugmsg, process, simpleipc; + +Const + DmtInformation = lctInformation; + DmtWarning = lctWarning; + DmtError = lctError; + ErrorLevel : Array[TDebugLevel] of integer + = (dmtInformation,dmtWarning,dmtError); + IndentChars = 2; + +var + DebugClient : TSimpleIPCClient = nil; + MsgBuffer : TMemoryStream = Nil; + ServerID : Integer; + DebugDisabled : Boolean; + Indent : Integer = 0; + +Procedure WriteMessage(Const Msg : TDebugMessage); + +begin + MsgBuffer.Seek(0,soFrombeginning); + WriteDebugMessageToStream(MsgBuffer,Msg); + DebugClient.SendMessage(mtUnknown,MsgBuffer); +end; + + +procedure SendDebugMessage(Var Msg : TDebugMessage); + +begin + if DebugDisabled then exit; + try + If (DebugClient=Nil) then + InitDebugClient; + if (Indent>0) then + Msg.Msg:=StringOfChar(' ',Indent)+Msg.Msg; + WriteMessage(Msg); + except + On E : Exception do + SendError:=E.Message; + end; +end; + +procedure SendBoolean(const Identifier: string; const Value: Boolean); + +Const + Booleans : Array[Boolean] of string = ('False','True'); + +begin + SendDebugFmt('%s = %s',[Identifier,Booleans[value]]); +end; + +procedure SendDateTime(const Identifier: string; const Value: TDateTime); + +begin + SendDebugFmt('%s = %s',[Identifier,DateTimeToStr(Value)]); +end; + +procedure SendInteger(const Identifier: string; const Value: Integer; HexNotation: Boolean = False); + +Const + Msgs : Array[Boolean] of string = ('%s = %d','%s = %x'); + +begin + SendDebugFmt(Msgs[HexNotation],[Identifier,Value]); +end; + +procedure SendPointer(const Identifier: string; const Value: Pointer); + +begin + SendDebugFmt('%s = %p',[Identifier,Value]); +end; + +procedure SendDebugEx(const Msg: string; MType: TDebugLevel); + +Var + Mesg : TDebugMessage; + +begin + Mesg.MsgTimeStamp:=Now; + Mesg.MsgType:=ErrorLevel[MTYpe]; + Mesg.Msg:=Msg; + SendDebugMessage(Mesg); +end; + +procedure SendDebug(const Msg: string); + +Var + Mesg : TDebugMessage; +begin + Mesg.MsgTimeStamp:=Now; + Mesg.MsgType:=dmtInformation; + Mesg.Msg:=Msg; + SendDebugMessage(Mesg); +end; + +procedure SendMethodEnter(const MethodName: string); + +begin + SendDebug(SEntering+MethodName); + inc(Indent,IndentChars); +end; + +procedure SendMethodExit(const MethodName: string); + +begin + Dec(Indent,IndentChars); + If (Indent<0) then + Indent:=0; + SendDebug(SExiting+MethodName); +end; + +procedure SendSeparator; + +begin + SendDebug(SSeparator); +end; + +procedure SendDebugFmt(const Msg: string; const Args: array of const); + +Var + Mesg : TDebugMessage; + +begin + Mesg.MsgTimeStamp:=Now; + Mesg.MsgType:=dmtInformation; + Mesg.Msg:=Format(Msg,Args); + SendDebugMessage(Mesg); +end; + +procedure SendDebugFmtEx(const Msg: string; const Args: array of const; MType: TDebugLevel); + +Var + Mesg : TDebugMessage; + +begin + Mesg.MsgTimeStamp:=Now; + Mesg.MsgType:=ErrorLevel[mType]; + Mesg.Msg:=Format(Msg,Args); + SendDebugMessage(Mesg); +end; + +procedure SetDebuggingEnabled(const AValue: boolean); +begin + DebugDisabled := not AValue; +end; + +function GetDebuggingEnabled: Boolean; +begin + Result := not DebugDisabled; +end; + +function StartDebugServer : Integer; + +begin + With TProcess.Create(Nil) do + begin + Try + CommandLine:='debugserver'; + Execute; + Result:=ProcessID; + Except + Result := 0; + end; + Free; + end; +end; + +procedure FreeDebugClient; + +Var + msg : TDebugMessage; + +begin + try + If (DebugClient<>Nil) and + (DebugClient.ServerRunning) then + begin + Msg.MsgType:=lctStop; + Msg.MsgTimeStamp:=Now; + Msg.Msg:=Format(SProcessID,[ApplicationName]); + WriteMessage(Msg); + end; + FreeAndNil(MsgBuffer); + FreeAndNil(DebugClient); + except + end; +end; + +Function InitDebugClient : Boolean; + +Var + msg : TDebugMessage; + I : Integer; + +begin + Result := False; + DebugClient:=TSimpleIPCClient.Create(Nil); + DebugClient.ServerID:=DebugServerID; + If not DebugClient.ServerRunning then + begin + ServerID:=StartDebugServer; + if ServerID = 0 then + begin + DebugDisabled := True; + Exit; + end + else + DebugDisabled := False; + I:=0; + While (I<10) and not DebugClient.ServerRunning do + begin + Inc(I); + Sleep(100); + end; + end; + DebugClient.Connect; + MsgBuffer:=TMemoryStream.Create; + Msg.MsgType:=lctIdentify; + Msg.MsgTimeStamp:=Now; + Msg.Msg:=Format(SProcessID,[ApplicationName]); + WriteMessage(Msg); + Result := True; +end; + +Initialization + DebugDisabled := False; +Finalization + FreeDebugClient; +end. diff --git a/packages/fcl-process/src/dbugmsg.pp b/packages/fcl-process/src/dbugmsg.pp new file mode 100644 index 0000000000..2cb575824a --- /dev/null +++ b/packages/fcl-process/src/dbugmsg.pp @@ -0,0 +1,102 @@ +{ + This file is part of the Free Component library. + Copyright (c) 2005 by Michael Van Canneyt, member of + the Free Pascal development team + + Debugserver Client/Server common code. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +{$mode objfpc} +{$h+} +unit dbugmsg; + +interface + +uses Classes; + +Const + DebugServerID : String = 'fpcdebugserver'; + + lctStop = -1; + lctInformation = 0; + lctWarning = 1; + lctError = 2; + lctIdentify = 3; + +Type + TDebugMessage = Record + MsgType : Integer; + MsgTimeStamp : TDateTime; + Msg : String; + end; + +Procedure ReadDebugMessageFromStream(AStream : TStream; Var Msg : TDebugMessage); +Procedure WriteDebugMessageToStream(AStream : TStream; Const Msg : TDebugMessage); +Function DebugMessageName(msgType : Integer) : String; + + +implementation + +resourcestring + SStop = 'Stop'; + SInformation = 'Information'; + SWarning = 'Warning'; + SError = 'Error'; + SIdentify = 'Identify'; + SUnknown = 'Unknown'; + +procedure ReadDebugMessageFromStream(AStream : TStream; Var Msg : TDebugMessage); + +Var + MsgSize : Integer; + +begin + With AStream do + begin + ReadBuffer(Msg.MsgType,SizeOf(Integer)); + ReadBuffer(Msg.MsgTimeStamp,SizeOf(TDateTime)); + ReadBuffer(MsgSize,SizeOf(Integer)); + SetLength(Msg.Msg,MsgSize); + If (MsgSize<>0) then + ReadBuffer(Msg.msg[1],MsgSize); + end; +end; + +procedure WriteDebugMessageToStream(AStream : TStream; Const Msg : TDebugMessage); + +Var + MsgSize : Integer; + +begin + With AStream do + begin + WriteBuffer(Msg.MsgType,SizeOf(Integer)); + WriteBuffer(Msg.MsgTimeStamp,SizeOf(TDateTime)); + MsgSize:=Length(Msg.Msg); + WriteBuffer(MsgSize,SizeOf(Integer)); + WriteBuffer(Msg.msg[1],MsgSize); + end; +end; + +Function DebugMessageName(msgType : Integer) : String; + +begin + Case MsgType of + lctStop : Result:=SStop; + lctInformation : Result:=SInformation; + lctWarning : Result:=SWarning; + lctError : Result:=SError; + lctIdentify : Result:=SIdentify; + else + Result:=SUnknown; + end; +end; + +end. diff --git a/packages/fcl-process/src/go32v2/pipes.inc b/packages/fcl-process/src/go32v2/pipes.inc new file mode 100644 index 0000000000..2734d39a03 --- /dev/null +++ b/packages/fcl-process/src/go32v2/pipes.inc @@ -0,0 +1,30 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + DOS/go32v2 specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +// No pipes under dos, sorry... + +Function CreatePipeHandles (Var Inhandle,OutHandle : THandle) : Boolean; + +begin + Result := False; +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + Result := 0; +end; + diff --git a/packages/fcl-process/src/go32v2/process.inc b/packages/fcl-process/src/go32v2/process.inc new file mode 100644 index 0000000000..74f9c2fe50 --- /dev/null +++ b/packages/fcl-process/src/go32v2/process.inc @@ -0,0 +1,42 @@ +{ + Dummy process.inc +} + +procedure TProcess.CloseProcessHandles; +begin +end; + +Function TProcess.PeekExitStatus : Boolean; +begin +end; + +Procedure TProcess.Execute; +begin +end; + +Function TProcess.WaitOnExit : Boolean; +begin + Result:=False; +end; + +Function TProcess.Suspend : Longint; +begin + Result:=0; +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; +begin + Result:=False; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); +begin +end; + + diff --git a/packages/fcl-process/src/morphos/pipes.inc b/packages/fcl-process/src/morphos/pipes.inc new file mode 100644 index 0000000000..dc35fb365c --- /dev/null +++ b/packages/fcl-process/src/morphos/pipes.inc @@ -0,0 +1,30 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + AmigaOS specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +// Unsupported for the moment... + +Function CreatePipeHandles (Var Inhandle,OutHandle : Longint) : Boolean; + +begin + Result := False; +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + Result := 0; +end; + diff --git a/packages/fcl-process/src/morphos/process.inc b/packages/fcl-process/src/morphos/process.inc new file mode 100644 index 0000000000..74f9c2fe50 --- /dev/null +++ b/packages/fcl-process/src/morphos/process.inc @@ -0,0 +1,42 @@ +{ + Dummy process.inc +} + +procedure TProcess.CloseProcessHandles; +begin +end; + +Function TProcess.PeekExitStatus : Boolean; +begin +end; + +Procedure TProcess.Execute; +begin +end; + +Function TProcess.WaitOnExit : Boolean; +begin + Result:=False; +end; + +Function TProcess.Suspend : Longint; +begin + Result:=0; +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; +begin + Result:=False; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); +begin +end; + + diff --git a/packages/fcl-process/src/netware/pipes.inc b/packages/fcl-process/src/netware/pipes.inc new file mode 100644 index 0000000000..4a031d52a5 --- /dev/null +++ b/packages/fcl-process/src/netware/pipes.inc @@ -0,0 +1,30 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + Netware specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +// Unsupported for the moment... + +Function CreatePipeHandles (Var Inhandle,OutHandle : THandle) : Boolean; + +begin + Result := false; {dont know how to do that with netware clib} +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + Result := 0; +end; + diff --git a/packages/fcl-process/src/netware/process.inc b/packages/fcl-process/src/netware/process.inc new file mode 100644 index 0000000000..74f9c2fe50 --- /dev/null +++ b/packages/fcl-process/src/netware/process.inc @@ -0,0 +1,42 @@ +{ + Dummy process.inc +} + +procedure TProcess.CloseProcessHandles; +begin +end; + +Function TProcess.PeekExitStatus : Boolean; +begin +end; + +Procedure TProcess.Execute; +begin +end; + +Function TProcess.WaitOnExit : Boolean; +begin + Result:=False; +end; + +Function TProcess.Suspend : Longint; +begin + Result:=0; +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; +begin + Result:=False; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); +begin +end; + + diff --git a/packages/fcl-process/src/netwlibc/pipes.inc b/packages/fcl-process/src/netwlibc/pipes.inc new file mode 100644 index 0000000000..fd8b9b6115 --- /dev/null +++ b/packages/fcl-process/src/netwlibc/pipes.inc @@ -0,0 +1,30 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2004 by Michael Van Canneyt + + Netware specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +// Unsupported for the moment... + +Function CreatePipeHandles (Var Inhandle,OutHandle : THandle) : Boolean; + +begin + Result := false; {todo} +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + Result := 0; +end; + diff --git a/packages/fcl-process/src/netwlibc/process.inc b/packages/fcl-process/src/netwlibc/process.inc new file mode 100644 index 0000000000..74f9c2fe50 --- /dev/null +++ b/packages/fcl-process/src/netwlibc/process.inc @@ -0,0 +1,42 @@ +{ + Dummy process.inc +} + +procedure TProcess.CloseProcessHandles; +begin +end; + +Function TProcess.PeekExitStatus : Boolean; +begin +end; + +Procedure TProcess.Execute; +begin +end; + +Function TProcess.WaitOnExit : Boolean; +begin + Result:=False; +end; + +Function TProcess.Suspend : Longint; +begin + Result:=0; +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; +begin + Result:=False; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); +begin +end; + + diff --git a/packages/fcl-process/src/os2/pipes.inc b/packages/fcl-process/src/os2/pipes.inc new file mode 100644 index 0000000000..f47ba06588 --- /dev/null +++ b/packages/fcl-process/src/os2/pipes.inc @@ -0,0 +1,34 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + OS/2 specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +uses + DosCalls; + +const + PipeBufSize = 1024; + +Function CreatePipeHandles (Var Inhandle,OutHandle : Longint) : Boolean; + +begin + CreatePipeHandles := DosCreatePipe (InHandle, OutHandle, PipeBufSize) = 0; +end; + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + // TODO: find out if this is possible in OS/2 + Result := 0; +end; + diff --git a/packages/fcl-process/src/os2/process.inc b/packages/fcl-process/src/os2/process.inc new file mode 100644 index 0000000000..74f9c2fe50 --- /dev/null +++ b/packages/fcl-process/src/os2/process.inc @@ -0,0 +1,42 @@ +{ + Dummy process.inc +} + +procedure TProcess.CloseProcessHandles; +begin +end; + +Function TProcess.PeekExitStatus : Boolean; +begin +end; + +Procedure TProcess.Execute; +begin +end; + +Function TProcess.WaitOnExit : Boolean; +begin + Result:=False; +end; + +Function TProcess.Suspend : Longint; +begin + Result:=0; +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; +begin + Result:=False; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); +begin +end; + + diff --git a/packages/fcl-process/src/pipes.pp b/packages/fcl-process/src/pipes.pp new file mode 100644 index 0000000000..f3604c562a --- /dev/null +++ b/packages/fcl-process/src/pipes.pp @@ -0,0 +1,127 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + Implementation of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{$mode objfpc} + +Unit Pipes; + +Interface + +Uses sysutils,Classes; + +Type + EPipeError = Class(EStreamError); + ENoReadPipe = Class(EPipeError); + ENoWritePipe = Class (EPipeError); + EPipeSeek = Class (EPipeError); + EPipeCreation = Class (EPipeError); + + { TInputPipeStream } + + TInputPipeStream = Class(THandleStream) + Private + FPos : Int64; + function GetNumBytesAvailable: DWord; + public + Function Write (Const Buffer; Count : Longint) :Longint; Override; + Function Seek (Offset : Longint;Origin : Word) : longint;override; + Function Read (Var Buffer; Count : Longint) : longint; Override; + property NumBytesAvailable: DWord read GetNumBytesAvailable; + end; + + TOutputPipeStream = Class(THandleStream) + Public + Function Seek (Offset : Longint;Origin : Word) : longint;override; + Function Read (Var Buffer; Count : Longint) : longint; Override; + end; + +Function CreatePipeHandles (Var Inhandle,OutHandle : THandle) : Boolean; +Procedure CreatePipeStreams (Var InPipe : TInputPipeStream; + Var OutPipe : TOutputPipeStream); + +Const EPipeMsg = 'Failed to create pipe.'; + ENoReadMSg = 'Cannot read from OuputPipeStream.'; + ENoWriteMsg = 'Cannot write to InputPipeStream.'; + ENoSeekMsg = 'Cannot seek on pipes'; + + +Implementation + +{$i pipes.inc} + +Procedure CreatePipeStreams (Var InPipe : TInputPipeStream; + Var OutPipe : TOutputPipeStream); + +Var InHandle,OutHandle : THandle; + +begin + if CreatePipeHandles (InHandle, OutHandle) then + begin + InPipe:=TInputPipeStream.Create (InHandle); + OutPipe:=TOutputPipeStream.Create (OutHandle); + end + Else + Raise EPipeCreation.Create (EPipeMsg) +end; + +Function TInputPipeStream.Write (Const Buffer; Count : Longint) : longint; + +begin + Raise ENoWritePipe.Create (ENoWriteMsg); +end; + +Function TInputPipeStream.Read (Var Buffer; Count : Longint) : longint; + +begin + Result:=Inherited Read(Buffer,Count); + Inc(FPos,Result); +end; + +Function TInputPipeStream.Seek (Offset : Longint;Origin : Word) : longint; + +Const BufSize = 100; + +Var Buf : array[1..BufSize] of Byte; + +begin + If (Origin=soFromCurrent) and (Offset=0) then + result:=FPos; + { Try to fake seek by reading and discarding } + if Not((Origin=soFromCurrent) and (Offset>=0) or + ((Origin=soFrombeginning) and (OffSet>=FPos))) then + Raise EPipeSeek.Create(ENoSeekMSg); + if Origin=soFromBeginning then + Dec(Offset,FPos); + While ((Offset Div BufSize)>0) + and (Read(Buf,SizeOf(Buf))=BufSize) do + Dec(Offset,BufSize); + If (Offset>0) then + Read(Buf,BufSize); + Result:=FPos; +end; + +Function TOutputPipeStream.Read(Var Buffer; Count : Longint) : longint; + +begin + Raise ENoReadPipe.Create (ENoReadMsg); +end; + +Function TOutputPipeStream.Seek (Offset : Longint;Origin : Word) : longint; + +begin + Raise EPipeSeek.Create (ENoSeekMsg); +end; + +end. diff --git a/packages/fcl-process/src/process.pp b/packages/fcl-process/src/process.pp new file mode 100644 index 0000000000..6c732c9c85 --- /dev/null +++ b/packages/fcl-process/src/process.pp @@ -0,0 +1,325 @@ +{ + This file is part of the Free Component Library (FCL) + Copyright (c) 1999-2000 by the Free Pascal development team + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +{$mode objfpc} +{$h+} +unit process; + +interface + +Uses Classes, + pipes, + SysUtils; + +Type + TProcessOption = (poRunSuspended,poWaitOnExit, + poUsePipes,poStderrToOutPut, + poNoConsole,poNewConsole, + poDefaultErrorMode,poNewProcessGroup, + poDebugProcess,poDebugOnlyThisProcess); + + TShowWindowOptions = (swoNone,swoHIDE,swoMaximize,swoMinimize,swoRestore,swoShow, + swoShowDefault,swoShowMaximized,swoShowMinimized, + swoshowMinNOActive,swoShowNA,swoShowNoActivate,swoShowNormal); + + TStartupOption = (suoUseShowWindow,suoUseSize,suoUsePosition, + suoUseCountChars,suoUseFillAttribute); + + TProcessPriority = (ppHigh,ppIdle,ppNormal,ppRealTime); + + TProcessOptions = set of TProcessOption; + TStartupOptions = set of TStartupOption; + + +Type + TProcess = Class (TComponent) + Private + FProcessOptions : TProcessOptions; + FStartupOptions : TStartupOptions; + FProcessID : Integer; + FThreadID : Integer; + FProcessHandle : Thandle; + FThreadHandle : Thandle; + FFillAttribute : Cardinal; + FApplicationName : string; + FConsoleTitle : String; + FCommandLine : String; + FCurrentDirectory : String; + FDesktop : String; + FEnvironment : Tstrings; + FShowWindow : TShowWindowOptions; + FInherithandles : Boolean; + FProcessPriority : TProcessPriority; + dwXCountchars, + dwXSize, + dwYsize, + dwx, + dwYcountChars, + dwy : Cardinal; + Procedure FreeStreams; + Function GetExitStatus : Integer; + Function GetRunning : Boolean; + Function GetWindowRect : TRect; + Procedure SetWindowRect (Value : TRect); + Procedure SetShowWindow (Value : TShowWindowOptions); + Procedure SetWindowColumns (Value : Cardinal); + Procedure SetWindowHeight (Value : Cardinal); + Procedure SetWindowLeft (Value : Cardinal); + Procedure SetWindowRows (Value : Cardinal); + Procedure SetWindowTop (Value : Cardinal); + Procedure SetWindowWidth (Value : Cardinal); + procedure SetApplicationName(const Value: String); + procedure SetProcessOptions(const Value: TProcessOptions); + procedure SetActive(const Value: Boolean); + procedure SetEnvironment(const Value: TStrings); + function PeekExitStatus: Boolean; + Protected + FRunning : Boolean; + FExitCode : Cardinal; + FInputStream : TOutputPipeStream; + FOutputStream : TInputPipeStream; + FStderrStream : TInputPipeStream; + procedure CloseProcessHandles; virtual; + Procedure CreateStreams(InHandle,OutHandle,ErrHandle : Longint);virtual; + procedure FreeStream(var AStream: THandleStream); + Public + Constructor Create (AOwner : TComponent);override; + Destructor Destroy; override; + Procedure Execute; virtual; + procedure CloseInput; virtual; + procedure CloseOutput; virtual; + procedure CloseStderr; virtual; + Function Resume : Integer; virtual; + Function Suspend : Integer; virtual; + Function Terminate (AExitCode : Integer): Boolean; virtual; + Function WaitOnExit : Boolean; + Property WindowRect : Trect Read GetWindowRect Write SetWindowRect; + Property Handle : THandle Read FProcessHandle; + Property ProcessHandle : THandle Read FProcessHandle; + Property ThreadHandle : THandle Read FThreadHandle; + Property ProcessID : Integer Read FProcessID; + Property ThreadID : Integer Read FThreadID; + Property Input : TOutputPipeStream Read FInputStream; + Property Output : TInputPipeStream Read FOutputStream; + Property Stderr : TinputPipeStream Read FStderrStream; + Property ExitStatus : Integer Read GetExitStatus; + Property InheritHandles : Boolean Read FInheritHandles Write FInheritHandles; + Published + Property Active : Boolean Read GetRunning Write SetActive; + Property ApplicationName : String Read FApplicationName Write SetApplicationName; + Property CommandLine : String Read FCommandLine Write FCommandLine; + Property ConsoleTitle : String Read FConsoleTitle Write FConsoleTitle; + Property CurrentDirectory : String Read FCurrentDirectory Write FCurrentDirectory; + Property Desktop : String Read FDesktop Write FDesktop; + Property Environment : TStrings Read FEnvironment Write SetEnvironment; + Property Options : TProcessOptions Read FProcessOptions Write SetProcessOptions; + Property Priority : TProcessPriority Read FProcessPriority Write FProcessPriority; + Property StartupOptions : TStartupOptions Read FStartupOptions Write FStartupOptions; + Property Running : Boolean Read GetRunning; + Property ShowWindow : TShowWindowOptions Read FShowWindow Write SetShowWindow; + Property WindowColumns : Cardinal Read dwXCountChars Write SetWindowColumns; + Property WindowHeight : Cardinal Read dwYSize Write SetWindowHeight; + Property WindowLeft : Cardinal Read dwX Write SetWindowLeft; + Property WindowRows : Cardinal Read dwYCountChars Write SetWindowRows; + Property WindowTop : Cardinal Read dwY Write SetWindowTop ; + Property WindowWidth : Cardinal Read dwXSize Write SetWindowWidth; + Property FillAttribute : Cardinal read FFillAttribute Write FFillAttribute; + end; + + EProcess = Class(Exception); + +implementation + +{$i process.inc} + +Constructor TProcess.Create (AOwner : TComponent); +begin + Inherited; + FProcessPriority:=ppNormal; + FShowWindow:=swoNone; + FInheritHandles:=True; + FEnvironment:=TStringList.Create; +end; + +Destructor TProcess.Destroy; + +begin + FEnvironment.Free; + FreeStreams; + CloseProcessHandles; + Inherited Destroy; +end; + +Procedure TProcess.FreeStreams; +begin + If FStderrStream<>FOutputStream then + FreeStream(FStderrStream); + FreeStream(FOutputStream); + FreeStream(FInputStream); +end; + + +Function TProcess.GetExitStatus : Integer; + +begin + If FRunning then + PeekExitStatus; + Result:=FExitCode; +end; + + +Function TProcess.GetRunning : Boolean; + +begin + IF FRunning then + FRunning:=Not PeekExitStatus; + Result:=FRunning; +end; + + +Procedure TProcess.CreateStreams(InHandle,OutHandle,ErrHandle : Longint); + +begin + FreeStreams; + FInputStream:=TOutputPipeStream.Create (InHandle); + FOutputStream:=TInputPipeStream.Create (OutHandle); + if Not (poStderrToOutput in FProcessOptions) then + FStderrStream:=TInputPipeStream.Create(ErrHandle); +end; + +procedure TProcess.FreeStream(var AStream: THandleStream); +begin + if AStream = nil then exit; + FileClose(AStream.Handle); + FreeAndNil(AStream); +end; + +procedure TProcess.CloseInput; +begin + FreeStream(FInputStream); +end; + +procedure TProcess.CloseOutput; +begin + FreeStream(FOutputStream); +end; + +procedure TProcess.CloseStderr; +begin + FreeStream(FStderrStream); +end; + +Procedure TProcess.SetWindowColumns (Value : Cardinal); + +begin + if Value<>0 then + Include(FStartupOptions,suoUseCountChars); + dwXCountChars:=Value; +end; + + +Procedure TProcess.SetWindowHeight (Value : Cardinal); + +begin + if Value<>0 then + include(FStartupOptions,suoUsePosition); + dwYSize:=Value; +end; + +Procedure TProcess.SetWindowLeft (Value : Cardinal); + +begin + if Value<>0 then + Include(FStartupOptions,suoUseSize); + dwx:=Value; +end; + +Procedure TProcess.SetWindowTop (Value : Cardinal); + +begin + if Value<>0 then + Include(FStartupOptions,suoUsePosition); + dwy:=Value; +end; + +Procedure TProcess.SetWindowWidth (Value : Cardinal); +begin + If (Value<>0) then + Include(FStartupOptions,suoUseSize); + dwXSize:=Value; +end; + +Function TProcess.GetWindowRect : TRect; +begin + With Result do + begin + Left:=dwx; + Right:=dwx+dwxSize; + Top:=dwy; + Bottom:=dwy+dwysize; + end; +end; + +Procedure TProcess.SetWindowRect (Value : Trect); +begin + Include(FStartupOptions,suoUseSize); + Include(FStartupOptions,suoUsePosition); + With Value do + begin + dwx:=Left; + dwxSize:=Right-Left; + dwy:=Top; + dwySize:=Bottom-top; + end; +end; + + +Procedure TProcess.SetWindowRows (Value : Cardinal); + +begin + if Value<>0 then + Include(FStartupOptions,suoUseCountChars); + dwYCountChars:=Value; +end; + +procedure TProcess.SetApplicationName(const Value: String); +begin + FApplicationName := Value; + If (csDesigning in ComponentState) and + (FCommandLine='') then + FCommandLine:=Value; +end; + +procedure TProcess.SetProcessOptions(const Value: TProcessOptions); +begin + FProcessOptions := Value; + If poNewConsole in FProcessOptions then + Exclude(FProcessOptions,poNoConsole); + if poRunSuspended in FProcessOptions then + Exclude(FProcessOptions,poWaitOnExit); +end; + +procedure TProcess.SetActive(const Value: Boolean); +begin + if (Value<>GetRunning) then + If Value then + Execute + else + Terminate(0); +end; + +procedure TProcess.SetEnvironment(const Value: TStrings); +begin + FEnvironment.Assign(Value); +end; + +end. diff --git a/packages/fcl-process/src/process.txt b/packages/fcl-process/src/process.txt new file mode 100644 index 0000000000..1d9aeb36c5 --- /dev/null +++ b/packages/fcl-process/src/process.txt @@ -0,0 +1,281 @@ +This file describes the TProcess object. + +The TProcess object provides an easy way to start and manipulate +the running of other programs (processes) by your application. +On top of that, it allows you to redirect the program's input, output +and standard error to streams that are readable/writeable by your +program. + +It is a descendent class of TObject, but this is easily changeable to +TComponent, should you desire to do so. None of the properties will +conflict with the existing properties of TComponent. + +Furthermore it is written in such a way that it is easily extensible, +although most of the properties that a Process has, are accessible and +can be controlled with this object. + +In what follows, is a description of the object's methods and properties. + +The following two types control the creation of the TProcess Object. +See The constructor description for a description on what they do. + +TProcessOptions = (poExecuteOnCreate,poRunSuspended,poUsePipes, + poNoConsole,poStderrToOutPut,poWaitOnExit); +TCreateOptions = Set of TPRocessOptions; + + + +Constructor Create (Const ACommandline : String; + Options : TCreateOptions); + +This creates an TPRocess object. + +ACommandline is the commandline to execute, including any options +you wish to pass to the program. If you don't specify an explicit path +Windows will look for your program in the Windows directory and in the +path. + +Options control the behaviour of the object. It can be a set of the +following constants: + +poExecuteOnCreate + If you include this option, the constructor will immediatly + call the Execute method, using default settings for all parameters. + This has the effect that the program is run at once. + +poRunSuspended + If you include this option, the Execute method will start the + program in a suspended state, and the program will start running + only after you have called the Resume method. + +poUsePipes + If you include this option, the Execute method will redirect the + standard input,output and error descriptors to 3 pipes, which you + can read from or write to. + (see Input,OutPut and Error properties) + It makes little sense to use ths for GUI applications (i.e. non- + console applications) + +poNoConsole + If you include this option, the application will not display a + console, untill it explicitly needs one or requests one using the + AllocConsole method. This is very convenient in combination with the + poUsePipes option, allowing you to run an application without getting + the Console window, and being able to read it's output at once. + +poStderrToOutPut + If This option is included, then the error desciptor is redirected to + the standard output director, i.e. all output goes to the standard + output. + +poWaitOnExit + If you specify this option, then the Execute method will wait for the + executed program to finish, before returning. + This option will be ignored if you also specified ExecuteOnCreate and + CreateSuspended. + + +Destructor Destroy; virtual; + + Destroys the TProcess Object. Be careful NOT to close a TProcess + object when you use pipes, and the application is still running. + you may kill it. + +Procedure Execute; virtual; + This actually runs the application. It will return immediatly, unless + you specified the poWaitOnExit option when creating the object. + +Function Resume : Integer; virtual; + Resume lowers the suspend count of the application. + it returns the new suspend count of the application. As long as the + suspend count is larger than 0, the application will not run. + If the suspend count reaches 0, the application will continue + running. + +Function Suspend : Integer; virtual; + Increases the suspend count of the application, and returns the + new suspend count of the application. + +Function Terminate (AExitCode : Integer): Boolean; virtual; + Terminate terminates the main thread of the application, giving it + exitcode 'AExitCode' + It returns True on succes, False on failure. + +Function WaitOnExit : Boolean; + This function returns true if the wait for the process exit was succesful, + false if some error occurded. It returns immediatly if the application is + not running, and waits for the application to finish if it was still running. + +Property ApplicationName : String; + Sets the name of the application. + +Property CommandLine : String; + Read-Only + contains the commandline of the application, as set by the create + method of TProcess. + +Property ConsoleTitle : String; + For console applications only : + Sets the title that appears in the title bar of the Console window. + +Property CreateOptions : TCreateOptions; + Read-Only + Contains the options as set by the Create method of TProcess. + +Property CreationFlags : Cardinal; + This contains the creation flags that are passed to the CreateProcess + call. These flags are modified by the Execute call to reflect any + settings tat you may have made. + +Property CurrentDirectory : String; + When set, the process wil start in the directory that you have set + for it. + +Property DeskTop : String; + NT only: + Contains the name of the desktop or window station that the process + will be run on. See STARTUPINFO in the win32 programmers manual. + +Property Environment : Pointer; + A pointer to a null-terminated list of environment variable pointers. + Each pair is of the form 'Name=Value'. + If this is nil, the environment of your application is used. + +Property ExitStatus : Integer; + Read-Only + This returns the exit status of the application, or STILL_ACTIVE + (defined in Windows.pas) if the application is still running. + +Property FillAttribute : Integer; + For console processes only. + Sets the fill color for the console window. + +Property Handle : THandle; + Read-Only; + Returns the handle of the process, which can be used to pass on to + calls that require a handle of a process. + Onl valid if the process is running. + + +Property Input : TOutPutPipeStream; + Read-Only + Returns the Input handle of the process. + Anything you write to this stream, will appear on the applications + input file descriptor. + Only valid if you used poUsePipes when you created the TProcess + object. + +Property InheritHandles : LongBool; + If you set this to true, each inheritable handle of your application + is inherited by the new application. + +Property OutPut : TInputPipeStream; + Read-Only + Returns the Output handle of the process. Anything the process writes + to its standard output can be read from this stream. + Only valid if you used poUsePipes when you created the TProcess + object. + +Property ProcessAttributes : TSecurityAttributes; + +Property ProcessInformation : TProcessInformation; + Read-Only + Gives access to the ProcessInformation returned by Windows + upon executing the program. This contains + hProcess : Process Handle (See Handle property) + hThread : Process' main thread handle (See ThreadHandle property) + dwProcessId : Process ID. (as seen in the task manager) + dwThreadId : Process' main thread ID + +Property Running : Boolean; + Read-Only + Retruns True if the application is still running, False otherwise. + If the application is suspended or not doesn't affect the result. + +Property ShowWindow : Word; + You can set the applications ShowWindow attribute here. + +Property StartupInfo : TStartupInfo; + Read-Only + Gives access to the TStartupInfo that will be passed to the + application in the CreateProcess Call. You can manipulate its various + members through the properties of the TProcess object. + +Property StdErr : TinputPipeStream; + Read-Only + Returns the Output handle of the process. Anything the process writes + to its error output can be read from this stream. + Only valid if you used poUsePipes when you created the TProcess + object. + If you specified poStderrToOutput then this is the same as the + 'Output' stream. + +Property ThreadAttributes : TSecurityAttributes; + Contains the security attributes that will be passed to the process' + main thread. By default, no security attributes are passed. + +Property ThreadHandle : THandle; + Read-Only + Returns the Handle of the process' main thread. + +Property WindowColumns : Integer; + For console applications: + This will set the number of screen columns that the console window + will have. + If you don't set this property nor the WindowRows property, Windows will + choose default values. + You can only set this PRIOR to calling the execute method, after + the application was executed, or while it is running, the setting + will be ignored until you run it again. + +Property WindowHeight : Integer; + Set the height of the application's main window. + If you don't specify this, nor WindowWidth, Windows will choose + the height and Width of the applications window. + You can only set this PRIOR to calling the execute method, after + the application was executed, or while it is running, the setting + will be ignored until you run it again. + +Property WindowLeft : Integer; + Set the applications main window position, in pixels from the left + side of the screen. + If you don't specify this, nor WindowTop, Windows will choose + the Left and Top of the applications window. + You can only set this PRIOR to calling the execute method, after + the application was executed, or while it is running, the setting + will be ignored until you run it again. + +Property WindowRows : Integer; + For console applications: + This will set the number of screen rows (lines) that the console window + will have. + If you don't set this property nor the WindowColumns property, Windows will + choose default values. + You can only set this PRIOR to calling the execute method, after + the application was executed, or while it is running, the setting + will be ignored until you run it again. + +Property WindowTop : Integer; + Set the applications main window position, in pixels from the Top + side of the screen. + If you don't specify this, nor WindowLeft, Windows will choose + the Left and Top of the applications window. + You can only set this PRIOR to calling the execute method, after + the application was executed, or while it is running, the setting + will be ignored until you run it again. + +Property WindowWidth : Integer; + Set the Width of the application's main window. + If you don't specify this, nor WindowWidth, Windows will choose + the height and Width of the applications window. + You can only set this PRIOR to calling the execute method, after + the application was executed, or while it is running, the setting + will be ignored until you run it again. + +Property WindowRect : Trect; + This sets the bounding rectangle of the application's main window. + It allows to set the WindowTop, WindowLeft, WindowHeight, WindowWidth + properties in 1 call. + + + diff --git a/packages/fcl-process/src/simpleipc.pp b/packages/fcl-process/src/simpleipc.pp new file mode 100644 index 0000000000..c595e2090b --- /dev/null +++ b/packages/fcl-process/src/simpleipc.pp @@ -0,0 +1,457 @@ +{ + This file is part of the Free Component library. + Copyright (c) 2005 by Michael Van Canneyt, member of + the Free Pascal development team + + Unit implementing one-way IPC between 2 processes + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit simpleipc; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils; + +Const + MsgVersion = 1; + + //Message types + mtUnknown = 0; + mtString = 1; + +Type + + TMessageType = LongInt; + TMsgHeader = Packed record + Version : Byte; + MsgType : TMessageType; + MsgLen : Integer; + end; + + TSimpleIPCServer = class; + TSimpleIPCClient = class; + + { TIPCServerComm } + + TIPCServerComm = Class(TObject) + Private + FOwner : TSimpleIPCServer; + Protected + Function GetInstanceID : String; virtual; abstract; + Public + Constructor Create(AOwner : TSimpleIPCServer); virtual; + Property Owner : TSimpleIPCServer read FOwner; + Procedure StartServer; virtual; Abstract; + Procedure StopServer;virtual; Abstract; + Function PeekMessage(TimeOut : Integer) : Boolean;virtual; Abstract; + Procedure ReadMessage ;virtual; Abstract; + Property InstanceID : String read GetInstanceID; + end; + TIPCServerCommClass = Class of TIPCServerComm; + + { TSimpleIPC } + TSimpleIPC = Class(TComponent) + Private + procedure SetActive(const AValue: Boolean); + procedure SetServerID(const AValue: String); + Protected + FBusy: Boolean; + FActive : Boolean; + FServerID : String; + Procedure DoError(Msg : String; Args : Array of const); + Procedure CheckInactive; + Procedure CheckActive; + Procedure Activate; virtual; abstract; + Procedure Deactivate; virtual; abstract; + Property Busy : Boolean Read FBusy; + Published + Property Active : Boolean Read FActive Write SetActive; + Property ServerID : String Read FServerID Write SetServerID; + end; + + { TSimpleIPCServer } + + TSimpleIPCServer = Class(TSimpleIPC) + private + FGlobal: Boolean; + FOnMessage: TNotifyEvent; + FMsgType: TMessageType; + FMsgData : TStream; + function GetInstanceID: String; + function GetStringMessage: String; + procedure SetGlobal(const AValue: Boolean); + Protected + FIPCComm: TIPCServerComm; + Function CommClass : TIPCServerCommClass; virtual; + Procedure Activate; override; + Procedure Deactivate; override; + Procedure ReadMessage; + Public + Constructor Create(AOwner : TComponent); override; + Destructor Destroy; override; + Procedure StartServer; + Procedure StopServer; + Function PeekMessage(TimeOut : Integer; DoReadMessage : Boolean): Boolean; + Property StringMessage : String Read GetStringMessage; + Procedure GetMessageData(Stream : TStream); + Property MsgType: TMessageType Read FMsgType; + Property MsgData : TStream Read FMsgData; + Property InstanceID : String Read GetInstanceID; + Published + Property Global : Boolean Read FGlobal Write SetGlobal; + Property OnMessage : TNotifyEvent Read FOnMessage Write FOnMessage; + end; + + + { TIPCClientComm} + TIPCClientComm = Class(TObject) + private + FOwner: TSimpleIPCClient; + Public + Constructor Create(AOwner : TSimpleIPCClient); virtual; + Property Owner : TSimpleIPCClient read FOwner; + Procedure Connect; virtual; abstract; + Procedure Disconnect; virtual; abstract; + Function ServerRunning : Boolean; virtual; abstract; + Procedure SendMessage(MsgType : TMessageType; Stream : TStream);virtual;Abstract; + end; + TIPCClientCommClass = Class of TIPCClientComm; + + { TSimpleIPCClient } + TSimpleIPCClient = Class(TSimpleIPC) + Private + FServerInstance: String; + procedure SetServerInstance(const AValue: String); + Protected + FIPCComm : TIPCClientComm; + Procedure Activate; override; + Procedure Deactivate; override; + Function CommClass : TIPCClientCommClass; virtual; + Public + Constructor Create(AOwner : TComponent); override; + Destructor Destroy; override; + Procedure Connect; + Procedure Disconnect; + Function ServerRunning : Boolean; + Procedure SendMessage(MsgType : TMessageType; Stream: TStream); + Procedure SendStringMessage(const Msg : String); + Procedure SendStringMessage(MsgType : TMessageType; const Msg : String); + Procedure SendStringMessageFmt(const Msg : String; Args : Array of const); + Procedure SendStringMessageFmt(MsgType : TMessageType; const Msg : String; Args : Array of const); + Property ServerInstance : String Read FServerInstance Write SetServerInstance; + end; + + + EIPCError = Class(Exception); + +Var + DefaultIPCServerClass : TIPCServerCommClass = Nil; + DefaultIPCClientClass : TIPCClientCommClass = Nil; + +resourcestring + SErrServerNotActive = 'Server with ID %s is not active.'; + SErrActive = 'This operation is illegal when the server is active.'; + SErrInActive = 'This operation is illegal when the server is inactive.'; + + +implementation + +{ --------------------------------------------------------------------- + Include platform specific implementation. + Should implement the CommClass method of both server and client component, + as well as the communication class itself. + + This comes first, to allow the uses clause to be set. + --------------------------------------------------------------------- } + +{$i simpleipc.inc} + +{ --------------------------------------------------------------------- + TIPCServerComm + ---------------------------------------------------------------------} + +constructor TIPCServerComm.Create(AOwner: TSimpleIPCServer); +begin + FOwner:=AOWner; +end; + +{ --------------------------------------------------------------------- + TIPCClientComm + ---------------------------------------------------------------------} + +constructor TIPCClientComm.Create(AOwner: TSimpleIPCClient); +begin + FOwner:=AOwner; +end; + +{ --------------------------------------------------------------------- + TSimpleIPC + ---------------------------------------------------------------------} + +procedure TSimpleIPC.DoError(Msg: String; Args: array of const); +begin + Raise EIPCError.Create(Name+': '+Format(Msg,Args)); +end; + +procedure TSimpleIPC.CheckInactive; +begin + If Active then + DoError(SErrActive,[]); +end; + +procedure TSimpleIPC.CheckActive; +begin + If Not Active then + DoError(SErrInActive,[]); +end; + +procedure TSimpleIPC.SetActive(const AValue: Boolean); +begin + if (FActive<>AValue) then + begin + If AValue then + Activate + else + Deactivate; + end; +end; + +procedure TSimpleIPC.SetServerID(const AValue: String); +begin + if (FServerID<>AValue) then + begin + CheckInactive; + FServerID:=AValue + end; +end; + +{ --------------------------------------------------------------------- + TSimpleIPCServer + ---------------------------------------------------------------------} + +constructor TSimpleIPCServer.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FGlobal:=False; + FActive:=False; + FBusy:=False; + FMsgData:=TStringStream.Create(''); +end; + +destructor TSimpleIPCServer.Destroy; +begin + Active:=False; + FreeAndNil(FMsgData); + inherited Destroy; +end; + +procedure TSimpleIPCServer.SetGlobal(const AValue: Boolean); +begin + if (FGlobal<>AValue) then + begin + CheckInactive; + FGlobal:=AValue; + end; +end; + +function TSimpleIPCServer.GetInstanceID: String; +begin + Result:=FIPCComm.InstanceID; +end; + + +function TSimpleIPCServer.GetStringMessage: String; +begin + Result:=TStringStream(FMsgData).DataString; +end; + + +procedure TSimpleIPCServer.StartServer; +begin + if Not Assigned(FIPCComm) then + begin + If (FServerID='') then + FServerID:=ApplicationName; + FIPCComm:=CommClass.Create(Self); + FIPCComm.StartServer; + end; + FActive:=True; +end; + +procedure TSimpleIPCServer.StopServer; +begin + If Assigned(FIPCComm) then + begin + FIPCComm.StopServer; + FreeAndNil(FIPCComm); + end; + FActive:=False; +end; + +function TSimpleIPCServer.PeekMessage(TimeOut: Integer; DoReadMessage: Boolean + ): Boolean; +begin + CheckActive; + FBusy:=True; + Try + Result:=FIPCComm.PeekMessage(Timeout); + Finally + FBusy:=False; + end; + If Result then + If DoReadMessage then + Readmessage; +end; + +procedure TSimpleIPCServer.ReadMessage; +begin + CheckActive; + FBusy:=True; + Try + FIPCComm.ReadMessage; + If Assigned(FOnMessage) then + FOnMessage(Self); + Finally + FBusy:=False; + end; +end; + +procedure TSimpleIPCServer.GetMessageData(Stream: TStream); +begin + Stream.CopyFrom(FMsgData,0); +end; + +procedure TSimpleIPCServer.Activate; +begin + StartServer; +end; + +procedure TSimpleIPCServer.Deactivate; +begin + StopServer; +end; + +{ --------------------------------------------------------------------- + TSimpleIPCClient + ---------------------------------------------------------------------} + +procedure TSimpleIPCClient.SetServerInstance(const AValue: String); +begin + CheckInactive; + FServerInstance:=AVAlue; +end; + +procedure TSimpleIPCClient.Activate; +begin + Connect; +end; + +procedure TSimpleIPCClient.Deactivate; +begin + DisConnect; +end; +constructor TSimpleIPCClient.Create(AOwner: TComponent); +begin + inherited Create(AOwner); +end; + +destructor TSimpleIPCClient.destroy; +begin + Active:=False; + Inherited; +end; + +procedure TSimpleIPCClient.Connect; +begin + If Not assigned(FIPCComm) then + begin + FIPCComm:=CommClass.Create(Self); + Try + FIPCComm.Connect; + Except + FreeAndNil(FIPCComm); + Raise; + end; + FActive:=True; + end; +end; + +procedure TSimpleIPCClient.Disconnect; +begin + If Assigned(FIPCComm) then + Try + FIPCComm.DisConnect; + Finally + FActive:=False; + FreeAndNil(FIPCComm); + end; +end; + +function TSimpleIPCClient.ServerRunning: Boolean; + +begin + If Assigned(FIPCComm) then + Result:=FIPCComm.ServerRunning + else + With CommClass.Create(Self) do + Try + Result:=ServerRunning; + finally + Free; + end; +end; + +procedure TSimpleIPCClient.SendMessage(MsgType : TMessageType; Stream: TStream); + +begin + CheckActive; + FBusy:=True; + Try + FIPCComm.SendMessage(MsgType,Stream); + Finally + FBusy:=False; + end; +end; + +procedure TSimpleIPCClient.SendStringMessage(const Msg: String); +begin + SendStringMessage(mtString,Msg); +end; + +procedure TSimpleIPCClient.SendStringMessage(MsgType: TMessageType; const Msg: String + ); +Var + S : TStringStream; +begin + S:=TStringStream.Create(Msg); + try + SendMessage(MsgType,S); + finally + S.free; + end; +end; + +procedure TSimpleIPCClient.SendStringMessageFmt(const Msg: String; + Args: array of const); +begin + SendStringMessageFmt(mtString,Msg,Args); +end; + +procedure TSimpleIPCClient.SendStringMessageFmt(MsgType: TMessageType; + const Msg: String; Args: array of const); +begin + SendStringMessage(MsgType, Format(Msg,Args)); +end; + +end. + diff --git a/packages/fcl-process/src/unix/pipes.inc b/packages/fcl-process/src/unix/pipes.inc new file mode 100644 index 0000000000..e26bfbce0c --- /dev/null +++ b/packages/fcl-process/src/unix/pipes.inc @@ -0,0 +1,32 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt + + Linux specific part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +Uses + BaseUnix, Unix, TermIO; + +Function CreatePipeHandles (Var Inhandle,OutHandle : Longint) : Boolean; + +begin + Result := (AssignPipe (Inhandle,OutHandle)<>-1); +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + if fpioctl(Handle, FIONREAD, @Result)<0 then + Result := 0; +end; + diff --git a/packages/fcl-process/src/unix/process.inc b/packages/fcl-process/src/unix/process.inc new file mode 100644 index 0000000000..f88623c959 --- /dev/null +++ b/packages/fcl-process/src/unix/process.inc @@ -0,0 +1,399 @@ +{ + Unix Process .inc. +} + +uses + Unix, + Baseunix; + +resourcestring + SErrNoSuchProgram = 'Executable not found: "%s"'; + +Const + PriorityConstants : Array [TProcessPriority] of Integer = + (20,20,0,-20); + +Const + GeometryOption : String = '-geometry'; + TitleOption : String ='-title'; + + + +procedure TProcess.CloseProcessHandles; + +begin + // Do nothing. Win32 call. +end; + +Function TProcess.PeekExitStatus : Boolean; + +begin + Result:=fpWaitPid(Handle,pcint(@FExitCode),WNOHANG)=Handle; + If Result then + FExitCode:=wexitstatus(FExitCode) + else + FexitCode:=0; +end; + +Type + TPCharArray = Array[Word] of pchar; + PPCharArray = ^TPcharArray; + +Function StringsToPCharList(List : TStrings) : PPChar; + +Var + I : Integer; + S : String; + +begin + I:=(List.Count)+1; + GetMem(Result,I*sizeOf(PChar)); + PPCharArray(Result)^[List.Count]:=Nil; + For I:=0 to List.Count-1 do + begin + S:=List[i]; + Result[i]:=StrNew(PChar(S)); + end; +end; + +Procedure FreePCharList(List : PPChar); + +Var + I : integer; + +begin + I:=0; + While List[i]<>Nil do + begin + StrDispose(List[i]); + Inc(I); + end; + FreeMem(List); +end; + + +Procedure CommandToList(S : String; List : TStrings); + + Function GetNextWord : String; + + Const + WhiteSpace = [' ',#8,#10]; + Literals = ['"','''']; + + Var + Wstart,wend : Integer; + InLiteral : Boolean; + LastLiteral : char; + + begin + WStart:=1; + While (WStart<=Length(S)) and (S[WStart] in WhiteSpace) do + Inc(WStart); + WEnd:=WStart; + InLiteral:=False; + LastLiteral:=#0; + While (Wend<=Length(S)) and (Not (S[Wend] in WhiteSpace) or InLiteral) do + begin + if S[Wend] in Literals then + If InLiteral then + InLiteral:=Not (S[Wend]=LastLiteral) + else + begin + InLiteral:=True; + LastLiteral:=S[Wend]; + end; + inc(wend); + end; + + Result:=Copy(S,WStart,WEnd-WStart); + + if (Length(Result) > 0) + and (Result[1] = Result[Length(Result)]) // if 1st char = last char and.. + and (Result[1] in Literals) then // it's one of the literals, then + Result:=Copy(Result, 2, Length(Result) - 2); //delete the 2 (but not others in it) + + While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do + inc(Wend); + Delete(S,1,WEnd-1); + + end; + +Var + W : String; + +begin + While Length(S)>0 do + begin + W:=GetNextWord; + If (W<>'') then + List.Add(W); + end; +end; + + +Function MakeCommand(P : TProcess) : PPchar; + +Const + SNoCommandLine = 'Cannot execute empty command-line'; + +Var + Cmd : String; + S : TStringList; + G : String; + +begin + if (P.ApplicationName='') then + begin + If (P.CommandLine='') then + Raise EProcess.Create(SNoCommandline); + Cmd:=P.CommandLine; + end + else + begin + If (P.CommandLine='') then + Cmd:=P.ApplicationName + else + Cmd:=P.CommandLine; + end; + S:=TStringList.Create; + try + CommandToList(Cmd,S); + if poNewConsole in P.Options then + begin + S.Insert(0,'-e'); + If (P.ApplicationName<>'') then + begin + S.Insert(0,P.ApplicationName); + S.Insert(0,'-title'); + end; + if suoUseCountChars in P.StartupOptions then + begin + S.Insert(0,Format('%dx%d',[P.dwXCountChars,P.dwYCountChars])); + S.Insert(0,'-geometry'); + end; + S.Insert(0,'xterm'); + end; + if (P.ApplicationName<>'') then + begin + S.Add(TitleOption); + S.Add(P.ApplicationName); + end; + G:=''; + if (suoUseSize in P.StartupOptions) then + g:=format('%dx%d',[P.dwXSize,P.dwYsize]); + if (suoUsePosition in P.StartupOptions) then + g:=g+Format('+%d+%d',[P.dwX,P.dwY]); + if G<>'' then + begin + S.Add(GeometryOption); + S.Add(g); + end; + Result:=StringsToPcharList(S); + Finally + S.free; + end; +end; + +Function GetLastError : Integer; + +begin + Result:=-1; +end; + +Type + TPipeEnd = (peRead,peWrite); + TPipePair = Array[TPipeEnd] of cint; + +Procedure CreatePipes(Var HI,HO,HE : TPipePair; CE : Boolean); + + Procedure CreatePair(Var P : TPipePair); + + begin + If not CreatePipeHandles(P[peRead],P[peWrite]) then + Raise EProcess.Create('Failed to create pipes'); + end; + + Procedure ClosePair(Var P : TPipePair); + + begin + if (P[peRead]<>-1) then + FileClose(P[peRead]); + if (P[peWrite]<>-1) then + FileClose(P[peWrite]); + end; + +begin + HO[peRead]:=-1;HO[peWrite]:=-1; + HI[peRead]:=-1;HI[peWrite]:=-1; + HE[peRead]:=-1;HE[peWrite]:=-1; + Try + CreatePair(HO); + CreatePair(HI); + If CE then + CreatePair(HE); + except + ClosePair(HO); + ClosePair(HI); + If CE then + ClosePair(HE); + Raise; + end; +end; + +Procedure TProcess.Execute; + +Var + HI,HO,HE : TPipePair; + PID : Longint; + FEnv : PPChar; + Argv : PPChar; + fd : Integer; + PName : String; + +begin + If (poUsePipes in FProcessOptions) then + CreatePipes(HI,HO,HE,Not (poStdErrToOutPut in FProcessOptions)); + Try + if FEnvironment.Count<>0 then + FEnv:=StringsToPcharList(FEnvironment) + else + FEnv:=Nil; + Try + Argv:=MakeCommand(Self); + Try + If (Argv<>Nil) and (ArgV[0]<>Nil) then + PName:=StrPas(Argv[0]) + else + begin + // This should never happen, actually. + PName:=ApplicationName; + If (PName='') then + PName:=CommandLine; + end; + + if not FileExists(PName) then begin + PName := FileSearch(Pname,fpgetenv('PATH')); + + if Length(PName) = 0 then + raise EProcess.CreateFmt(SErrNoSuchProgram,[PName]); + end; + + Pid:=fpfork; + if Pid<0 then + Raise EProcess.Create('Failed to Fork process'); + if (PID>0) then + begin + // Parent process. Copy process information. + FProcessHandle:=PID; + FThreadHandle:=PID; + FProcessId:=PID; + //FThreadId:=PID; + end + else + begin + { We're in the child } + if (FCurrentDirectory<>'') then + ChDir(FCurrentDirectory); + if PoUsePipes in Options then + begin + fpclose(HI[peWrite]); + fpdup2(HI[peRead],0); + fpclose(HO[peRead]); + fpdup2(HO[peWrite],1); + if (poStdErrToOutPut in Options) then + fpdup2(HO[peWrite],2) + else + begin + fpclose(HE[peRead]); + fpdup2(HE[peWrite],2); + end + end + else if poNoConsole in Options then + begin + fd:=FileOpen('/dev/null',fmOpenReadWrite); + fpdup2(fd,0); + fpdup2(fd,1); + fpdup2(fd,2); + end; + if (poRunSuspended in Options) then + sigraise(SIGSTOP); + if FEnv<>Nil then + fpexecve(PName,Argv,Fenv) + else + fpexecv(PName,argv); + Halt(127); + end + Finally + FreePcharList(Argv); + end; + Finally + If (FEnv<>Nil) then + FreePCharList(FEnv); + end; + Finally + if POUsePipes in FProcessOptions then + begin + FileClose(HO[peWrite]); + FileClose(HI[peRead]); + if Not (poStdErrToOutPut in FProcessOptions) then + FileClose(HE[peWrite]); + CreateStreams(HI[peWrite],HO[peRead],HE[peRead]); + end; + end; + FRunning:=True; + if not (csDesigning in ComponentState) and // This would hang the IDE ! + (poWaitOnExit in FProcessOptions) and + not (poRunSuspended in FProcessOptions) then + WaitOnExit; +end; + +Function TProcess.WaitOnExit : Boolean; + +Var + R : Dword; + +begin + R:=fpWaitPid(Handle,pcint(@FExitCode),0); + Result:=(R=Handle); + If Result then + FExitCode:=WExitStatus(FExitCode); + FRunning:=False; +end; + +Function TProcess.Suspend : Longint; + +begin + If fpkill(Handle,SIGSTOP)<>0 then + Result:=-1 + else + Result:=1; +end; + +Function TProcess.Resume : LongInt; + +begin + If fpKill(Handle,SIGCONT)<>0 then + Result:=-1 + else + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; + +begin + Result:=False; + Result:=fpkill(Handle,SIGTERM)=0; + If Result then + begin + If Running then + Result:=fpkill(Handle,SIGKILL)=0; + end; + GetExitStatus; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); + +begin + FShowWindow:=Value; +end; + diff --git a/packages/fcl-process/src/unix/simpleipc.inc b/packages/fcl-process/src/unix/simpleipc.inc new file mode 100644 index 0000000000..143ab2471c --- /dev/null +++ b/packages/fcl-process/src/unix/simpleipc.inc @@ -0,0 +1,194 @@ +{ + This file is part of the Free Component library. + Copyright (c) 2005 by Michael Van Canneyt, member of + the Free Pascal development team + + Unix implementation of one-way IPC between 2 processes + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +uses baseunix; + +ResourceString + SErrFailedToCreatePipe = 'Failed to create named pipe: %s'; + SErrFailedToRemovePipe = 'Failed to remove named pipe: %s'; + +{ --------------------------------------------------------------------- + TPipeClientComm + ---------------------------------------------------------------------} + +Type + TPipeClientComm = Class(TIPCClientComm) + Private + FFileName: String; + FStream: TFileStream; + Public + Constructor Create(AOWner : TSimpleIPCClient); override; + Procedure Connect; override; + Procedure Disconnect; override; + Procedure SendMessage(MsgType : TMessageType; AStream : TStream); override; + Function ServerRunning : Boolean; override; + Property FileName : String Read FFileName; + Property Stream : TFileStream Read FStream; + end; + + +constructor TPipeClientComm.Create(AOWner: TSimpleIPCClient); + +Var + D : String; + +begin + inherited Create(AOWner); + FFileName:=Owner.ServerID; + If (Owner.ServerInstance<>'') then + FFileName:=FFileName+'-'+Owner.ServerInstance; + D:='/tmp/'; // Change to something better later + FFileName:=D+FFileName; +end; + + +procedure TPipeClientComm.Connect; +begin + If Not ServerRunning then + Owner.DoError(SErrServerNotActive,[Owner.ServerID]); + FStream:=TFileStream.Create(FFileName,fmOpenReadWrite); +end; + +procedure TPipeClientComm.Disconnect; +begin + FreeAndNil(FStream); +end; + +procedure TPipeClientComm.SendMessage(MsgType : TMessagetype; AStream: TStream); + +Var + Hdr : TMsgHeader; + P,L,Count : Integer; + +begin + Hdr.Version:=MsgVersion; + Hdr.msgType:=MsgType; + Hdr.MsgLen:=AStream.Size; + FStream.WriteBuffer(hdr,SizeOf(hdr)); + FStream.CopyFrom(AStream,0); +end; + +function TPipeClientComm.ServerRunning: Boolean; +begin + Result:=FileExists(FFileName); +end; + + +{ --------------------------------------------------------------------- + TPipeServerComm + ---------------------------------------------------------------------} + +Type + TPipeServerComm = Class(TIPCServerComm) + Private + FFileName: String; + FStream: TFileStream; + Public + Constructor Create(AOWner : TSimpleIPCServer); override; + Procedure StartServer; override; + Procedure StopServer; override; + Function PeekMessage(TimeOut : Integer) : Boolean; override; + Procedure ReadMessage ; override; + Function GetInstanceID : String;override; + Property FileName : String Read FFileName; + Property Stream : TFileStream Read FStream; + end; + +constructor TPipeServerComm.Create(AOWner: TSimpleIPCServer); + +Var + D : String; + +begin + inherited Create(AOWner); + FFileName:=Owner.ServerID; + If Not Owner.Global then + FFileName:=FFileName+'-'+IntToStr(fpGetPID); + D:='/tmp/'; // Change to something better later + FFileName:=D+FFileName; +end; + + +procedure TPipeServerComm.StartServer; +begin + If not FileExists(FFileName) then + If (fpmkFifo(FFileName,438)<>0) then + Owner.DoError(SErrFailedToCreatePipe,[FFileName]); + FStream:=TFileStream.Create(FFileName,fmOpenReadWrite); +end; + +procedure TPipeServerComm.StopServer; +begin + FreeAndNil(FStream); + if Not DeleteFile(FFileName) then + Owner.DoError(SErrFailedtoRemovePipe,[FFileName]); +end; + +function TPipeServerComm.PeekMessage(TimeOut: Integer): Boolean; + +Var + FDS : TFDSet; + +begin + fpfd_zero(FDS); + fpfd_set(FStream.Handle,FDS); + Result:=fpSelect(FStream.Handle+1,@FDS,Nil,Nil,TimeOut)>0; +end; + +procedure TPipeServerComm.ReadMessage; + +Var + L,P,Count : Integer; + Hdr : TMsgHeader; + +begin + FStream.ReadBuffer(Hdr,SizeOf(Hdr)); + Owner.FMsgType:=Hdr.MsgType; + Count:=Hdr.MsgLen; + if count > 0 then + begin + Owner.FMsgData.Seek(0,soFrombeginning); + Owner.FMsgData.CopyFrom(FStream,Count); + end + else + Owner.FMsgData.Size := 0; +end; + +function TPipeServerComm.GetInstanceID: String; +begin + Result:=IntToStr(fpGetPID); +end; + +{ --------------------------------------------------------------------- + Set TSimpleIPCClient / TSimpleIPCServer defaults. + ---------------------------------------------------------------------} + +Function TSimpleIPCServer.CommClass : TIPCServerCommClass; + +begin + if (DefaultIPCServerClass<>Nil) then + Result:=DefaultIPCServerClass + else + Result:=TPipeServerComm; +end; + +function TSimpleIPCClient.CommClass: TIPCClientCommClass; +begin + if (DefaultIPCClientClass<>Nil) then + Result:=DefaultIPCClientClass + else + Result:=TPipeClientComm; +end; diff --git a/packages/fcl-process/src/win/pipes.inc b/packages/fcl-process/src/win/pipes.inc new file mode 100644 index 0000000000..3f39493d0e --- /dev/null +++ b/packages/fcl-process/src/win/pipes.inc @@ -0,0 +1,43 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1998 by Michael Van Canneyt + + Win part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +uses windows; + +Const piInheritablePipe : TSecurityAttributes = ( + nlength:SizeOF(TSecurityAttributes); + lpSecurityDescriptor:Nil; + Binherithandle:True); + piNonInheritablePipe : TSecurityAttributes = ( + nlength:SizeOF(TSecurityAttributes); + lpSecurityDescriptor:Nil; + Binherithandle:False); + + + PipeBufSize = 1024; + + +Function CreatePipeHandles (Var Inhandle,OutHandle : THandle) : Boolean; + +begin + Result := CreatePipe (@Inhandle,@OutHandle,@piInheritablePipe,PipeBufSize); +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; +begin + if not PeekNamedPipe(Handle, nil, 0, nil, @Result, nil) then + Result := 0; +end; + diff --git a/packages/fcl-process/src/win/process.inc b/packages/fcl-process/src/win/process.inc new file mode 100644 index 0000000000..0661175958 --- /dev/null +++ b/packages/fcl-process/src/win/process.inc @@ -0,0 +1,257 @@ +{ + Win32 Process .inc. +} + +uses Windows; + +Const + PriorityConstants : Array [TProcessPriority] of Cardinal = + (HIGH_PRIORITY_CLASS,IDLE_PRIORITY_CLASS, + NORMAL_PRIORITY_CLASS,REALTIME_PRIORITY_CLASS); + +procedure TProcess.CloseProcessHandles; +begin + if (FProcessHandle<>0) then + CloseHandle(FProcessHandle); + if (FThreadHandle<>0) then + CloseHandle(FThreadHandle); +end; + +Function TProcess.PeekExitStatus : Boolean; + +begin + GetExitCodeProcess(ProcessHandle,FExitCode); + Result:=(FExitCode<>Still_Active); +end; + +Function GetStartupFlags (P : TProcess): Cardinal; + +begin + With P do + begin + Result:=0; + if poUsePipes in FProcessOptions then + Result:=Result or Startf_UseStdHandles; + if suoUseShowWindow in FStartupOptions then + Result:=Result or startf_USESHOWWINDOW; + if suoUSESIZE in FStartupOptions then + Result:=Result or startf_usesize; + if suoUsePosition in FStartupOptions then + Result:=Result or startf_USEPOSITION; + if suoUSECOUNTCHARS in FStartupoptions then + Result:=Result or startf_usecountchars; + if suoUsefIllAttribute in FStartupOptions then + Result:=Result or startf_USEFILLATTRIBUTE; + end; +end; + +Function GetCreationFlags(P : TProcess) : Cardinal; + +begin + With P do + begin + Result:=0; + if poNoConsole in FProcessOptions then + Result:=Result or Detached_Process; + if poNewConsole in FProcessOptions then + Result:=Result or Create_new_console; + if poNewProcessGroup in FProcessOptions then + Result:=Result or CREATE_NEW_PROCESS_GROUP; + If poRunSuspended in FProcessOptions Then + Result:=Result or Create_Suspended; + if poDebugProcess in FProcessOptions Then + Result:=Result or DEBUG_PROCESS; + if poDebugOnlyThisProcess in FProcessOptions Then + Result:=Result or DEBUG_ONLY_THIS_PROCESS; + if poDefaultErrorMode in FProcessOptions Then + Result:=Result or CREATE_DEFAULT_ERROR_MODE; + result:=result or PriorityConstants[FProcessPriority]; + end; +end; + +Function StringsToPChars(List : TStrings): pointer; + +var + EnvBlock: string; + I: Integer; + +begin + EnvBlock := ''; + For I:=0 to List.Count-1 do + EnvBlock := EnvBlock + List[i] + #0; + EnvBlock := EnvBlock + #0; + GetMem(Result, Length(EnvBlock)); + CopyMemory(Result, @EnvBlock[1], Length(EnvBlock)); +end; + +Procedure InitProcessAttributes(P : TProcess; Var PA : TSecurityAttributes); + +begin + FillChar(PA,SizeOf(PA),0); + PA.nLength := SizeOf(PA); +end; + +Procedure InitThreadAttributes(P : TProcess; Var TA : TSecurityAttributes); + +begin + FillChar(TA,SizeOf(TA),0); + TA.nLength := SizeOf(TA); +end; + +Procedure InitStartupInfo(P : TProcess; Var SI : STARTUPINFO); + +Const + SWC : Array [TShowWindowOptions] of Cardinal = + (0,SW_HIDE,SW_Maximize,SW_Minimize,SW_Restore,SW_Show, + SW_ShowDefault,SW_ShowMaximized,SW_ShowMinimized, + SW_showMinNOActive,SW_ShowNA,SW_ShowNoActivate,SW_ShowNormal); + +begin + FillChar(SI,SizeOf(SI),0); + With SI do + begin + dwFlags:=GetStartupFlags(P); + if P.FShowWindow<>swoNone then + dwFlags:=dwFlags or Startf_UseShowWindow + else + dwFlags:=dwFlags and not Startf_UseShowWindow; + wShowWindow:=SWC[P.FShowWindow]; + if (poUsePipes in P.Options) then + begin + dwFlags:=dwFlags or Startf_UseStdHandles; + end; + if P.FillAttribute<>0 then + begin + dwFlags:=dwFlags or Startf_UseFillAttribute; + dwFillAttribute:=P.FillAttribute; + end; + dwXCountChars:=P.WindowColumns; + dwYCountChars:=P.WindowRows; + dwYsize:=P.WindowHeight; + dwXsize:=P.WindowWidth; + dwy:=P.WindowTop; + dwX:=P.WindowLeft; + end; +end; + +Procedure CreatePipes(Var HI,HO,HE : Thandle; Var SI : TStartupInfo; CE : Boolean); + +begin + CreatePipeHandles(SI.hStdInput,HI); + CreatePipeHandles(HO,Si.hStdOutput); + if CE then + CreatePipeHandles(HE,SI.hStdError) + else + begin + SI.hStdError:=SI.hStdOutput; + HE:=HO; + end; +end; + + +Procedure TProcess.Execute; + + +Var + PName,PDir,PCommandLine : PChar; + FEnv: pointer; + FCreationFlags : Cardinal; + FProcessAttributes : TSecurityAttributes; + FThreadAttributes : TSecurityAttributes; + FProcessInformation : TProcessInformation; + FStartupInfo : STARTUPINFO; + HI,HO,HE : THandle; + +begin + FInheritHandles:=True; + PName:=Nil; + PCommandLine:=Nil; + PDir:=Nil; + If FApplicationName<>'' then + PName:=Pchar(FApplicationName); + If FCommandLine<>'' then + PCommandLine:=Pchar(FCommandLine); + If FCurrentDirectory<>'' then + PDir:=Pchar(FCurrentDirectory); + if FEnvironment.Count<>0 then + FEnv:=StringsToPChars(FEnvironment) + else + FEnv:=Nil; + Try + FCreationFlags:=GetCreationFlags(Self); + InitProcessAttributes(Self,FProcessAttributes); + InitThreadAttributes(Self,FThreadAttributes); + InitStartupInfo(Self,FStartUpInfo); + If poUsePipes in FProcessOptions then + CreatePipes(HI,HO,HE,FStartupInfo,Not(poStdErrToOutPut in FProcessOptions)); + Try + If Not CreateProcess (PName,PCommandLine,@FProcessAttributes,@FThreadAttributes, + FInheritHandles,FCreationFlags,FEnv,PDir,FStartupInfo, + fProcessInformation) then + Raise EProcess.CreateFmt('Failed to execute %s : %d',[FCommandLine,GetLastError]); + FProcessHandle:=FProcessInformation.hProcess; + FThreadHandle:=FProcessInformation.hThread; + FProcessID:=FProcessINformation.dwProcessID; + Finally + if POUsePipes in FProcessOptions then + begin + FileClose(FStartupInfo.hStdInput); + FileClose(FStartupInfo.hStdOutput); + if Not (poStdErrToOutPut in FProcessOptions) then + FileClose(FStartupInfo.hStdError); + CreateStreams(HI,HO,HE); + end; + end; + FRunning:=True; + Finally + If FEnv<>Nil then + FreeMem(FEnv); + end; + if not (csDesigning in ComponentState) and // This would hang the IDE ! + (poWaitOnExit in FProcessOptions) and + not (poRunSuspended in FProcessOptions) then + WaitOnExit; +end; + +Function TProcess.WaitOnExit : Boolean; + +Var + R : DWord; + +begin + R:=WaitForSingleObject (FProcessHandle,Infinite); + Result:=(R<>Wait_Failed); + If Result then + GetExitStatus; + FRunning:=False; +end; + +Function TProcess.Suspend : Longint; + +begin + Result:=SuspendThread(ThreadHandle); +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=ResumeThread(ThreadHandle); +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; + +begin + Result:=False; + If ExitStatus=Still_active then + Result:=TerminateProcess(Handle,AexitCode); +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); + + +begin + FShowWindow:=Value; +end; + + + diff --git a/packages/fcl-process/src/win/simpleipc.inc b/packages/fcl-process/src/win/simpleipc.inc new file mode 100644 index 0000000000..1bd2758119 --- /dev/null +++ b/packages/fcl-process/src/win/simpleipc.inc @@ -0,0 +1,293 @@ +{ + This file is part of the Free Component library. + Copyright (c) 2005 by Michael Van Canneyt, member of + the Free Pascal development team + + Windows implementation of one-way IPC between 2 processes + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +uses Windows,messages; + +Const + MsgWndClassName : pchar = 'FPCMsgWindowCls'; + +Resourcestring + SErrFailedToRegisterWindowClass = 'Failed to register message window class'; + SErrFailedToCreateWindow = 'Failed to create message window %s'; + +var + MsgWindowClass: TWndClass = ( + style: 0; + lpfnWndProc: Nil; + cbClsExtra: 0; + cbWndExtra: 0; + hInstance: 0; + hIcon: 0; + hCursor: 0; + hbrBackground: 0; + lpszMenuName: nil; + lpszClassName: Nil); + +{ --------------------------------------------------------------------- + TWinMsgServerComm + ---------------------------------------------------------------------} + +Type + TWinMsgServerComm = Class(TIPCServerComm) + Private + FHWND : HWND; + FWindowName : String; + FDataPushed : Boolean; + FUnction AllocateHWnd(Const aWindowName : String) : HWND; + Public + Constructor Create(AOWner : TSimpleIPCServer); override; + procedure ReadMsgData(var Msg: TMsg); + Procedure StartServer; override; + Procedure StopServer; override; + Function PeekMessage(TimeOut : Integer) : Boolean; override; + Procedure ReadMessage ; override; + Function GetInstanceID : String;override; + Property WindowName : String Read FWindowName; + end; + + +function MsgWndProc(HWindow: HWnd; Message, WParam, LParam: Longint): Longint;stdcall; + +Var + I : TWinMsgServerComm; + Msg : TMsg; + +begin + Result:=0; + If (Message=WM_COPYDATA) then + begin + I:=TWinMsgServerComm(GetWindowLongPtr(HWindow,GWL_USERDATA)); + If (I<>NIl) then + begin + Msg.Message:=Message; + Msg.WParam:=WParam; + Msg.LParam:=LParam; + I.ReadMsgData(Msg); + I.FDataPushed:=True; + If Assigned(I.Owner.OnMessage) then + I.Owner.ReadMessage; + Result:=1; + end + end + else + Result:=DefWindowProc(HWindow,Message,WParam,LParam); +end; + + +function TWinMsgServerComm.AllocateHWnd(const aWindowName: String): HWND; + +var + cls: TWndClass; + isreg : Boolean; + +begin + Pointer(MsgWindowClass.lpfnWndProc):=@MsgWndProc; + MsgWindowClass.hInstance := HInstance; + MsgWindowClass.lpszClassName:=MsgWndClassName; + isreg:=GetClassInfo(HInstance,MsgWndClassName,cls); + if not isreg then + if (Windows.RegisterClass(MsgWindowClass)=0) then + Owner.DoError(SErrFailedToRegisterWindowClass,[]); + Result:=CreateWindowEx(WS_EX_TOOLWINDOW, MsgWndClassName, + PChar(aWindowName), WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil); + if (Result=0) then + Owner.DoError(SErrFailedToCreateWindow,[aWindowName]); + SetWindowLongPtr(Result,GWL_USERDATA,PtrInt(Self)); +end; + +constructor TWinMsgServerComm.Create(AOWner: TSimpleIPCServer); +begin + inherited Create(AOWner); + FWindowName:=Owner.ServerID; + If not Owner.Global then + FWindowName:=FWindowName+'_'+InstanceID; +end; + +procedure TWinMsgServerComm.StartServer; + +begin + FHWND:=AllocateHWND(FWindowName); +end; + +procedure TWinMsgServerComm.StopServer; +begin + DestroyWindow(FHWND); + FHWND:=0; +end; + +function TWinMsgServerComm.PeekMessage(TimeOut: Integer): Boolean; + +Var + Msg : Tmsg; + B : Boolean; + R : DWORD; + +begin + Result:=FDataPushed; + If Result then + Exit; + B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE); + If not B then + // No message yet. Wait for a message to arrive available within specified time. + begin + if (TimeOut=0) then + TimeOut:=Integer(INFINITE); + R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); + B:=(R<>WAIT_TIMEOUT); + end; + If B then + Repeat + B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE); + if B then + begin + Result:=(Msg.Message=WM_COPYDATA); + // Remove non WM_COPY messages from Queue + if not Result then + GetMessage(Msg,FHWND,0,0); + end; + Until Result or (not B); +end; + +procedure TWinMsgServerComm.ReadMsgData(var Msg: TMsg); + +Var + CDS : PCopyDataStruct; + +begin + CDS:=PCopyDataStruct(Msg.Lparam); + Owner.FMsgType:=CDS^.dwData; + Owner.FMsgData.Seek(0,soFrombeginning); + Owner.FMsgData.WriteBuffer(CDS^.lpData^,CDS^.cbData); +end; + +procedure TWinMsgServerComm.ReadMessage; + +Var + Msg : TMsg; + +begin + If FDataPushed then + FDataPushed:=False + else + If Windows.PeekMessage(Msg, FHWND, 0, 0, PM_REMOVE) then + if (Msg.Message=WM_COPYDATA) then + ReadMsgData(Msg); +end; + +function TWinMsgServerComm.GetInstanceID: String; +begin + Result:=IntToStr(HInstance); +end; + +{ --------------------------------------------------------------------- + TWinMsgClientComm + ---------------------------------------------------------------------} + +Type + TWinMsgClientComm = Class(TIPCClientComm) + Private + FWindowName: String; + FHWND : HWnd; + Public + Constructor Create(AOWner : TSimpleIPCClient); override; + Procedure Connect; override; + Procedure Disconnect; override; + Procedure SendMessage(MsgType : TMessageType; Stream : TStream); override; + Function ServerRunning : Boolean; override; + Property WindowName : String Read FWindowName; + end; + + +constructor TWinMsgClientComm.Create(AOWner: TSimpleIPCClient); +begin + inherited Create(AOWner); + FWindowName:=Owner.ServerID; + If (Owner.ServerInstance<>'') then + FWindowName:=FWindowName+'_'+Owner.ServerInstance; +end; + +procedure TWinMsgClientComm.Connect; +begin + FHWND:=FindWindow(MsgWndClassName,PChar(FWindowName)); + If (FHWND=0) then + Owner.DoError(SErrServerNotActive,[Owner.ServerID]); +end; + +procedure TWinMsgClientComm.Disconnect; +begin + FHWND:=0; +end; + +procedure TWinMsgClientComm.SendMessage(MsgType: TMessageType; Stream: TStream + ); +Var + CDS : TCopyDataStruct; + Data,FMemstr : TMemorySTream; + +begin + If Stream is TMemoryStream then + begin + Data:=TMemoryStream(Stream); + FMemStr:=Nil + end + else + begin + FMemStr:=TMemoryStream.Create; + Data:=FMemstr; + end; + Try + If Assigned(FMemStr) then + begin + FMemStr.CopyFrom(Stream,0); + FMemStr.Seek(0,soFromBeginning); + end; + CDS.dwData:=MsgType; + CDS.lpData:=Data.Memory; + CDS.cbData:=Data.Size; + Windows.SendMessage(FHWnd,WM_COPYDATA,0,Integer(@CDS)); + Finally + FreeAndNil(FMemStr); + end; +end; + +function TWinMsgClientComm.ServerRunning: Boolean; +begin + Result:=FindWindow(MsgWndClassName,PChar(FWindowName))<>0; +end; + +{ --------------------------------------------------------------------- + Set TSimpleIPCClient / TSimpleIPCServer defaults. + ---------------------------------------------------------------------} + + +Function TSimpleIPCServer.CommClass : TIPCServerCommClass; + +begin + if (DefaultIPCServerClass<>Nil) then + Result:=DefaultIPCServerClass + else + Result:=TWinMsgServerComm; +end; + +Function TSimpleIPCClient.CommClass : TIPCClientCommClass; + +begin + if (DefaultIPCClientClass<>Nil) then + Result:=DefaultIPCClientClass + else + Result:=TWinMsgClientComm; +end; + diff --git a/packages/fcl-process/src/wince/pipes.inc b/packages/fcl-process/src/wince/pipes.inc new file mode 100644 index 0000000000..af26fb8b63 --- /dev/null +++ b/packages/fcl-process/src/wince/pipes.inc @@ -0,0 +1,30 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1998 by Michael Van Canneyt + + Win32 part of pipe stream. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +// Unsupported for the moment... + +Function CreatePipeHandles (Var Inhandle,OutHandle : THandle) : Boolean; +begin + Result := False; +end; + + +Function TInputPipeStream.GetNumBytesAvailable: DWord; + +begin + // Windows CE doesn´t have the API function PeekNamedPipe + Result := 0; +end; + diff --git a/packages/fcl-process/src/wince/process.inc b/packages/fcl-process/src/wince/process.inc new file mode 100644 index 0000000000..a3f358dcc2 --- /dev/null +++ b/packages/fcl-process/src/wince/process.inc @@ -0,0 +1,257 @@ +{ + Wince Process .inc. +} + +uses Windows; + +Const + PriorityConstants : Array [TProcessPriority] of Cardinal = + (HIGH_PRIORITY_CLASS,IDLE_PRIORITY_CLASS, + NORMAL_PRIORITY_CLASS,REALTIME_PRIORITY_CLASS); + +procedure TProcess.CloseProcessHandles; +begin + if (FProcessHandle<>0) then + CloseHandle(FProcessHandle); + if (FThreadHandle<>0) then + CloseHandle(FThreadHandle); +end; + +Function TProcess.PeekExitStatus : Boolean; + +begin + GetExitCodeProcess(ProcessHandle,FExitCode); + Result:=(FExitCode<>Still_Active); +end; + +Function GetStartupFlags (P : TProcess): Cardinal; + +begin + With P do + begin + Result:=0; + if poUsePipes in FProcessOptions then + Result:=Result or Startf_UseStdHandles; + if suoUseShowWindow in FStartupOptions then + Result:=Result or startf_USESHOWWINDOW; + if suoUSESIZE in FStartupOptions then + Result:=Result or startf_usesize; + if suoUsePosition in FStartupOptions then + Result:=Result or startf_USEPOSITION; + if suoUSECOUNTCHARS in FStartupoptions then + Result:=Result or startf_usecountchars; + if suoUsefIllAttribute in FStartupOptions then + Result:=Result or startf_USEFILLATTRIBUTE; + end; +end; + +Function GetCreationFlags(P : TProcess) : Cardinal; + +begin + With P do + begin + Result:=0; + if poNoConsole in FProcessOptions then + Result:=Result or Detached_Process; + if poNewConsole in FProcessOptions then + Result:=Result or Create_new_console; + if poNewProcessGroup in FProcessOptions then + Result:=Result or CREATE_NEW_PROCESS_GROUP; + If poRunSuspended in FProcessOptions Then + Result:=Result or Create_Suspended; + if poDebugProcess in FProcessOptions Then + Result:=Result or DEBUG_PROCESS; + if poDebugOnlyThisProcess in FProcessOptions Then + Result:=Result or DEBUG_ONLY_THIS_PROCESS; + if poDefaultErrorMode in FProcessOptions Then + Result:=Result or CREATE_DEFAULT_ERROR_MODE; + result:=result or PriorityConstants[FProcessPriority]; + end; +end; + +Function StringsToPWidechars(List : TStrings): pointer; + +var + EnvBlock: Widestring; + I: Integer; + +begin + EnvBlock := ''; + For I:=0 to List.Count-1 do + EnvBlock := EnvBlock + List[i] + #0; + EnvBlock := EnvBlock + #0; + GetMem(Result, Length(EnvBlock)); + CopyMemory(Result, @EnvBlock[1], Length(EnvBlock)); +end; + +Procedure InitProcessAttributes(P : TProcess; Var PA : TSecurityAttributes); + +begin + FillChar(PA,SizeOf(PA),0); + PA.nLength := SizeOf(PA); +end; + +Procedure InitThreadAttributes(P : TProcess; Var TA : TSecurityAttributes); + +begin + FillChar(TA,SizeOf(TA),0); + TA.nLength := SizeOf(TA); +end; + +Procedure InitStartupInfo(P : TProcess; Var SI : STARTUPINFO); + +Const + SWC : Array [TShowWindowOptions] of Cardinal = + (0,SW_HIDE,SW_Maximize,SW_Minimize,SW_Restore,SW_Show, + SW_ShowDefault,SW_ShowMaximized,SW_ShowMinimized, + SW_showMinNOActive,SW_ShowNA,SW_ShowNoActivate,SW_ShowNormal); + +begin + FillChar(SI,SizeOf(SI),0); + With SI do + begin + dwFlags:=GetStartupFlags(P); + if P.FShowWindow<>swoNone then + dwFlags:=dwFlags or Startf_UseShowWindow + else + dwFlags:=dwFlags and not Startf_UseShowWindow; + wShowWindow:=SWC[P.FShowWindow]; + if (poUsePipes in P.Options) then + begin + dwFlags:=dwFlags or Startf_UseStdHandles; + end; + if P.FillAttribute<>0 then + begin + dwFlags:=dwFlags or Startf_UseFillAttribute; + dwFillAttribute:=P.FillAttribute; + end; + dwXCountChars:=P.WindowColumns; + dwYCountChars:=P.WindowRows; + dwYsize:=P.WindowHeight; + dwXsize:=P.WindowWidth; + dwy:=P.WindowTop; + dwX:=P.WindowLeft; + end; +end; + +Procedure CreatePipes(Var HI,HO,HE : Thandle; Var SI : TStartupInfo; CE : Boolean); + +begin + CreatePipeHandles(SI.hStdInput,HI); + CreatePipeHandles(HO,Si.hStdOutput); + if CE then + CreatePipeHandles(HE,SI.hStdError) + else + begin + SI.hStdError:=SI.hStdOutput; + HE:=HO; + end; +end; + + +Procedure TProcess.Execute; + + +Var + PName,PDir,PCommandLine : PWidechar; + FEnv: pointer; + FCreationFlags : Cardinal; + FProcessAttributes : TSecurityAttributes; + FThreadAttributes : TSecurityAttributes; + FProcessInformation : TProcessInformation; + FStartupInfo : STARTUPINFO; + HI,HO,HE : THandle; + +begin + FInheritHandles:=True; + PName:=Nil; + PCommandLine:=Nil; + PDir:=Nil; + If FApplicationName<>'' then + PName:=PWidechar(FApplicationName); + If FCommandLine<>'' then + PCommandLine:=PWidechar(FCommandLine); + If FCurrentDirectory<>'' then + PDir:=PWidechar(FCurrentDirectory); + if FEnvironment.Count<>0 then + FEnv:=StringsToPWideChars(FEnvironment) + else + FEnv:=Nil; + Try + FCreationFlags:=GetCreationFlags(Self); + InitProcessAttributes(Self,FProcessAttributes); + InitThreadAttributes(Self,FThreadAttributes); + InitStartupInfo(Self,FStartUpInfo); + If poUsePipes in FProcessOptions then + CreatePipes(HI,HO,HE,FStartupInfo,Not(poStdErrToOutPut in FProcessOptions)); + Try + If Not CreateProcess (PName,PCommandLine,@FProcessAttributes,@FThreadAttributes, + FInheritHandles,FCreationFlags,FEnv,PDir,@FStartupInfo, + fProcessInformation) then + Raise EProcess.CreateFmt('Failed to execute %s : %d',[FCommandLine,GetLastError]); + FProcessHandle:=FProcessInformation.hProcess; + FThreadHandle:=FProcessInformation.hThread; + FProcessID:=FProcessINformation.dwProcessID; + Finally + if POUsePipes in FProcessOptions then + begin + FileClose(FStartupInfo.hStdInput); + FileClose(FStartupInfo.hStdOutput); + if Not (poStdErrToOutPut in FProcessOptions) then + FileClose(FStartupInfo.hStdError); + CreateStreams(HI,HO,HE); + end; + end; + FRunning:=True; + Finally + If FEnv<>Nil then + FreeMem(FEnv); + end; + if not (csDesigning in ComponentState) and // This would hang the IDE ! + (poWaitOnExit in FProcessOptions) and + not (poRunSuspended in FProcessOptions) then + WaitOnExit; +end; + +Function TProcess.WaitOnExit : Boolean; + +Var + R : DWord; + +begin + R:=WaitForSingleObject (FProcessHandle,Infinite); + Result:=(R<>Wait_Failed); + If Result then + GetExitStatus; + FRunning:=False; +end; + +Function TProcess.Suspend : Longint; + +begin + Result:=SuspendThread(ThreadHandle); +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=ResumeThread(ThreadHandle); +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; + +begin + Result:=False; + If ExitStatus=Still_active then + Result:=TerminateProcess(Handle,AexitCode); +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); + + +begin + FShowWindow:=Value; +end; + + + diff --git a/packages/fcl-process/src/wince/simpleipc.inc b/packages/fcl-process/src/wince/simpleipc.inc new file mode 100644 index 0000000000..a323f876ac --- /dev/null +++ b/packages/fcl-process/src/wince/simpleipc.inc @@ -0,0 +1,291 @@ +{ + This file is part of the Free Component library. + Copyright (c) 2005 by Michael Van Canneyt, member of + the Free Pascal development team + + Windows implementation of one-way IPC between 2 processes + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +uses Windows,messages; + +Const + MsgWndClassName : pwidechar = 'FPCMsgWindowCls'; + +Resourcestring + SErrFailedToRegisterWindowClass = 'Failed to register message window class'; + SErrFailedToCreateWindow = 'Failed to create message window %s'; + +var + MsgWindowClass: TWndClass = ( + style: 0; + lpfnWndProc: Nil; + cbClsExtra: 0; + cbWndExtra: 0; + hInstance: 0; + hIcon: 0; + hCursor: 0; + hbrBackground: 0; + lpszMenuName: nil; + lpszClassName: Nil); + +{ --------------------------------------------------------------------- + TWinMsgServerComm + ---------------------------------------------------------------------} + +Type + TWinMsgServerComm = Class(TIPCServerComm) + Private + FHWND : HWND; + FWindowName : Widestring; + FDataPushed : Boolean; + Function AllocateHWnd(const cwsWindowName : widestring) : HWND; + Public + Constructor Create(AOwner : TSimpleIPCServer); override; + procedure ReadMsgData(var Msg: TMsg); + Procedure StartServer; override; + Procedure StopServer; override; + Function PeekMessage(TimeOut : Integer) : Boolean; override; + Procedure ReadMessage ; override; + Function GetInstanceID : String;override; + Property WindowName : WideString Read FWindowName; + end; + + +function MsgWndProc(HWindow: HWnd; Message, WParam, LParam: Longint): Longint;stdcall; + +Var + I : TWinMsgServerComm; + Msg : TMsg; + +begin + Result:=0; + If (Message=WM_COPYDATA) then + begin + I:=TWinMsgServerComm(GetWindowLong(HWindow,GWL_USERDATA)); + If (I<>NIl) then + begin + Msg.Message:=Message; + Msg.WParam:=WParam; + Msg.LParam:=LParam; + I.ReadMsgData(Msg); + I.FDataPushed:=True; + If Assigned(I.Owner.OnMessage) then + I.Owner.ReadMessage; + Result:=1; + end + end + else + Result:=DefWindowProc(HWindow,Message,WParam,LParam); +end; + + +function TWinMsgServerComm.AllocateHWnd(const cwsWindowName: Widestring): HWND; + +var + cls: LPWNDCLASS; + isreg : Boolean; + +begin + Pointer(MsgWindowClass.lpfnWndProc):=@MsgWndProc; + MsgWindowClass.hInstance := HInstance; + MsgWindowClass.lpszClassName:=MsgWndClassName; + isreg:=GetClassInfo(HInstance,MsgWndClassName,cls); + if not isreg then + if (Windows.RegisterClass(MsgWindowClass)=0) then + Owner.DoError(SErrFailedToRegisterWindowClass,[]); + Result:=CreateWindowEx(WS_EX_TOOLWINDOW, MsgWndClassName, + PWidechar(cwsWindowName), WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil); + if (Result=0) then + Owner.DoError(SErrFailedToCreateWindow,[cwsWindowName]); + SetWindowLong(Result,GWL_USERDATA,Longint(Self)); +end; + +constructor TWinMsgServerComm.Create(AOWner: TSimpleIPCServer); +begin + inherited Create(AOWner); + FWindowName:=Owner.ServerID; + If not Owner.Global then + FWindowName:=FWindowName+'_'+InstanceID; +end; + +procedure TWinMsgServerComm.StartServer; + +begin + FHWND:=AllocateHWND(FWindowName); +end; + +procedure TWinMsgServerComm.StopServer; +begin + DestroyWindow(FHWND); + FHWND:=0; +end; + +function TWinMsgServerComm.PeekMessage(TimeOut: Integer): Boolean; + +Var + Msg : Tmsg; + B : Boolean; + R : DWORD; + +begin + Result:=FDataPushed; + If Result then + Exit; + B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE); + If not B then + // No message yet. Wait for a message to arrive available within specified time. + begin + if (TimeOut=0) then + TimeOut:=Integer(INFINITE); + R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); + B:=(R<>WAIT_TIMEOUT); + end; + If B then + Repeat + B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE); + if B then + begin + Result:=(Msg.Message=WM_COPYDATA); + // Remove non WM_COPY messages from Queue + if not Result then + GetMessage(@Msg,FHWND,0,0); + end; + Until Result or (not B); +end; + +procedure TWinMsgServerComm.ReadMsgData(var Msg: TMsg); + +Var + CDS : PCopyDataStruct; + +begin + CDS:=PCopyDataStruct(Msg.Lparam); + Owner.FMsgData.Seek(0,soFrombeginning); + Owner.FMsgData.WriteBuffer(CDS^.lpData^,CDS^.cbData); +end; + +procedure TWinMsgServerComm.ReadMessage; + +Var + Msg : TMsg; + +begin + If FDataPushed then + FDataPushed:=False + else + If Windows.PeekMessage(Msg, FHWND, 0, 0, PM_REMOVE) then + if (Msg.Message=WM_COPYDATA) then + ReadMsgData(Msg); +end; + +function TWinMsgServerComm.GetInstanceID: String; +begin + Result:=IntToStr(HInstance); +end; + +{ --------------------------------------------------------------------- + TWinMsgClientComm + ---------------------------------------------------------------------} + +Type + TWinMsgClientComm = Class(TIPCClientComm) + Private + FWindowName: String; + FHWND : HWnd; + Public + Constructor Create(AOWner : TSimpleIPCClient); override; + Procedure Connect; override; + Procedure Disconnect; override; + Procedure SendMessage(MsgType : TMessageType; Stream : TStream); override; + Function ServerRunning : Boolean; override; + Property WindowName : String Read FWindowName; + end; + + +constructor TWinMsgClientComm.Create(AOWner: TSimpleIPCClient); +begin + inherited Create(AOWner); + FWindowName:=Owner.ServerID; + If (Owner.ServerInstance<>'') then + FWindowName:=FWindowName+'_'+Owner.ServerInstance; +end; + +procedure TWinMsgClientComm.Connect; +begin + FHWND:=FindWindow(MsgWndClassName,Pwidechar(FWindowName)); + If (FHWND=0) then + Owner.DoError(SErrServerNotActive,[Owner.ServerID]); +end; + +procedure TWinMsgClientComm.Disconnect; +begin + FHWND:=0; +end; + +procedure TWinMsgClientComm.SendMessage(MsgType: TMessageType; Stream: TStream + ); +Var + CDS : TCopyDataStruct; + Data,FMemstr : TMemorySTream; + +begin + If Stream is TMemoryStream then + begin + Data:=TMemoryStream(Stream); + FMemStr:=Nil + end + else + begin + FMemStr:=TMemoryStream.Create; + Data:=FMemstr; + end; + Try + If Assigned(FMemStr) then + begin + FMemStr.CopyFrom(Stream,0); + FMemStr.Seek(0,soFromBeginning); + end; + CDS.lpData:=Data.Memory; + CDS.cbData:=Data.Size; + Windows.SendMessage(FHWnd,WM_COPYDATA,0,Integer(@CDS)); + Finally + FreeAndNil(FMemStr); + end; +end; + +function TWinMsgClientComm.ServerRunning: Boolean; +begin + Result:=FindWindow(MsgWndClassName,PWidechar(FWindowName))<>0; +end; + +{ --------------------------------------------------------------------- + Set TSimpleIPCClient / TSimpleIPCServer defaults. + ---------------------------------------------------------------------} + + +Function TSimpleIPCServer.CommClass : TIPCServerCommClass; + +begin + if (DefaultIPCServerClass<>Nil) then + Result:=DefaultIPCServerClass + else + Result:=TWinMsgServerComm; +end; + +Function TSimpleIPCClient.CommClass : TIPCClientCommClass; + +begin + if (DefaultIPCClientClass<>Nil) then + Result:=DefaultIPCClientClass + else + Result:=TWinMsgClientComm; +end; + |
