Ver Mensaje Individual
  #5  
Antiguo 12-01-2006
Avatar de mg1821
mg1821 mg1821 is offline
Miembro
 
Registrado: may 2003
Ubicación: lima
Posts: 69
Reputación: 22
mg1821 Va por buen camino
aqui esta el archivo completo, prefiero colocarlo asi para que este a la vista de todos. disculpas si esto no estaba permitido (el archivo era solo de 17k )

Starting an external application with Kylix
Here are three methods of invoking external applications. By Matthias Thoma.

Method 1: LibC.System function call
function system(Command: PChar): Integer;
The Libc.System function call is the most convenient way to start an external application. It simply executes the given argument command as shell command.
system is a blocking function, which means it will not return until the child process has terminated. The result value is -1 or 127 if an error occurred. The value 127 has the special meaning that execve (used within the system function - a more detailed description follows) failed.
On some shells you can add an ampersand (the "&" char) to the argument command. This will force the system function call to return immediately:

procedure PlayWave;
begin
if Libc.system('playwav ~/test.wav') = -1 then
begin
ShowMessage('Can''t play wav file');
end;
end;
Example 1.1: Play a wav file using system

You can determine if a shell is available by using nil as argument. If the result value is not zero, system was unable to invoke a shell.

procedure ShellAvail;
begin
if Libc.system(nil) <> 0 then
begin
ShowMessage('No shell available.');
end;
end;
Example 1.2: Determine if a shell is available

Method 2: popen
This method is extremely useful when you need to get the standard output of the external application. The popen function is declared as

function popen(const Command: PChar; Modes: PChar): PIOFile; cdecl;

It invokes the shell, runs the command, and creates a pipe. This demo simply displays the contents of the current directory within a memo.

var
Output: PIOFile;
line: PChar;
txt: string;
str: string;
StrLst: TStringList;
rb: integer;
const
BufferSize: Integer = 1000;
begin
SetLength(txt,0);
Output := popen('ls -l','r');
StrLst := TStringList.Create;
GetMem(Line,BufferSize);
StrLst.Add('Hallo');
if Assigned(output) then
begin
while FEOF(Output)=0 do
begin
rb := libc.fread(line,1,BufferSize,output);
SetLength(Txt,length(txt)+rb);
MemCpy(@txt[length(txt)-(rb-1)],line,rb);
while pos(#10,txt) > 0 do
begin
str := copy(txt,1,pos(#10,txt)-1);
StrLst.Add(str);
txt := copy(txt,pos(#10,txt)+1,length(txt));
end;
end;
end;
Memo1.Lines.AddStrings(StrLst);
StrLst.Free;
libc.pclose(output);
wait(nil);
FreeMem(Line,BufferSize);
end;

Method 3: Fork and Exec
Fork and Exec is how hardcore Linux and Unix programmers would create a child process. In fact, the previous functions are internally implemented using fork and exec.
function fork: __pid_t; cdecl;
The fork function makes a copy the parent process and therefore creates a new subprocess. Within the parent process the result value of fork is the Process ID (PID) of the subprocess or an error code. In the newly created subprocess the result value is zero.
Note: The function fork and the Kylix debugger do not seem to be 100% compatible currently. If you encounter problems and you are running the application within the IDE it is recommended that you disable the debugger.

{$APPTYPE CONSOLE}
uses
Libc;
procedure Forking;
var
pid: PID_T;
begin
pid := fork;
if pid = 0 then
begin
writeln('Hello. I am your new sub-process.');
writeln('Bye.');
halt;
end;
writeln('Hello. I am the parent process. I am going to wait some time...');
__sleep(3);
end;
begin
Forking;
writeln('Close parent process.');
writeln('Bye.');
end.
Example 3.1: Fork

As you see, fork copies the parent process. The child process starts to execute after the fork call. The differences between the parent process and the child process are only:
* The child has a different process identifier.
* The child has a different parent process.
* File locks are not inherited.
* Pending signals are not inherited.

Exec

Since we have now a new child process it is necessary to replace that process image with a new one:

function execve(PathName: PChar; const argv: PPChar; const envp: PPChar): Integer;
function execv(PathName: PChar; const argv: PPChar): Integer;

The execve function loads and executes PathName. The arguments are stored in argv and the environment is stored in envp.
execv performs the same actions as execve, except that the environment is taken from the "environ" setting.

program ForkExecDemo;
{$APPTYPE CONSOLE}
uses
Libc;
procedure ForkAndExec;
var
pid: PID_T;
parg: array[1..3] of PChar;
filetoplay: string;
begin
pid := fork;
if pid = 0 then
begin
filetoplay := 'test.wav';
parg[1] := 'playwave';
parg[2] := PChar(FileToPlay);
parg[3] := nil;
if execv('/usr/bin/playwave',PPChar(@parg[1])) = -1 then
begin
writeln('Something is wrong in the sub process.');
Halt;
end;
end;
writeln('Hello. I am the parent process. I am going to wait some time...');
__sleep(3);
end;
begin
ForkAndExec;
writeln('Close parent process.');
writeln('Bye.');
end.
Example 3.2: Fork and Exec

While this works great in console applications you may get problems in X applications because fork copies all the file descriptors. In such a case you'll have to close them within the child process. Example 3.3 illustrates this:

procedure ForkAndExec;
var
pid: PID_T;
Max: Integer;
I: Integer;
begin
pid := fork;
if pid = 0 then
begin
Max := sysconf(_SC_OPEN_MAX);
for i := (STDERR_FILENO+1) toMax do
begin
fcntl(i, F_SETFD, FD_CLOEXEC);
end;
[...]
end;
[...]
end;
Example 3.3: Closing the file descriptors

Sometimes you may want to let the parent process wait until the child process has been terminated. This can be done using the function waitpid. It is declared as:

function waitpid(__pid: pid_t; __stat_loc: PInteger; __options: Integer): pid_t; cdecl;
__pid: The process to wait for.
__stat_loc: The status of the terminated app. Can be nil.
__options: Zero,a flag or an combination of the flags WNOHANG and WUNTRACED. WNOHANG doesn't let the parent wait until the child has finished while WUNTRACED delivers status information not only from terminated applications but also from stopped ones. None of the flags are of interest for our purposes.
Example 3.4 illustrates the usage of the function WaitPid. It uses fork and execvp.

function StartApp(name: string; arguments: array of string): Integer;
var
pid: PID_T;
Max: Integer;
I: Integer;
parg: PPCharArray;
argnum: Integer;
begin
Result := -1;
pid := fork;
if pid = 0 then
begin
Max := sysconf(_SC_OPEN_MAX);
for i := (STDERR_FILENO+1) to Max do
begin
fcntl(i, F_SETFD, FD_CLOEXEC);
end;
argnum := High(Arguments) + 1;
GetMem(parg,(2 + argnum) * sizeof(PChar));
parg[0] := PChar(Name);
i := 0;
while i <= high(arguments) do
begin
inc(i);
parg[i] := PChar(arguments[i-1]);
end;
parg[i+1] := nil;
execvp(PChar(name),PPChar(@parg[0]));
halt;
end;
if pid > 0 then
begin
waitpid(pid,@Result,0);
end;
end;
Example 3.4: StartApp function
__________________
mg1821
Responder Con Cita