2010-05-04 24 views
4

J'essaie d'utiliser des outils de ligne de commande Windows à partir d'un programme Pascal court. Pour le rendre plus facile, j'écris une fonction appelée DoShell qui prend une chaîne de commande en argument et retourne un type d'enregistrement appelé ShellResult, avec un champ pour le code de sortie du processus et un champ pour le texte de sortie du processus.Utilisation de la ligne de commande Windows à partir de Pascal

Je rencontre des problèmes majeurs avec certaines fonctions de bibliothèque standard ne fonctionnant pas comme prévu. La fonction DOS Exec() n'exécute pas réellement la commande que je lui passe. La procédure Reset() me donne une erreur d'exécution RunError (2) à moins que je mette le mode compilateur {I-}. Dans ce cas, je n'obtiens aucune erreur d'exécution, mais les fonctions Readln() que j'utilise par la suite ne lisent rien, et les fonctions Writeln() utilisées après ce point dans l'exécution du code ne font rien non plus.

Voici le code source de mon programme jusqu'à présent. J'utilise bêta Lazare 0.9.28.2, avec Free Pascal Compiler 2,24


program project1; 

{$mode objfpc}{$H+} 

uses 
    Classes, SysUtils, StrUtils, Dos 
    { you can add units after this }; 

{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF} 

type 
    ShellResult = record 
    output : AnsiString; 
    exitcode : Integer; 
    end; 

function DoShell(command: AnsiString): ShellResult; 
    var 
     exitcode: Integer; 
     output: AnsiString; 
     exepath: AnsiString; 
     exeargs: AnsiString; 
     splitat: Integer; 
     F: Text; 
     readbuffer: AnsiString; 
    begin 
     //Initialize variables 
     exitcode := 0; 
     output  := ''; 
     exepath := ''; 
     exeargs := ''; 
     splitat := 0; 
     readbuffer := ''; 
     Result.exitcode := 0; 
     Result.output := ''; 

     //Split command for processing 
     splitat := NPos(' ', command, 1); 
     exepath := Copy(command, 1, Pred(splitat)); 
     exeargs := Copy(command, Succ(splitat), Length(command)); 

     //Run command and put output in temporary file 
     Exec(FExpand(exepath), exeargs + ' >__output'); 
     exitcode := DosExitCode(); 

     //Get output from file 
     Assign(F, '__output'); 
     Reset(F); 
     Repeat 
     Readln(F, readbuffer); 
     output := output + readbuffer; 
     readbuffer := ''; 
     Until Eof(F); 

     //Set Result 
     Result.exitcode := exitcode; 
     Result.output := output; 

    end; 

var 
    I : AnsiString; 
    R : ShellResult; 
begin 
    Writeln('Enter a command line to run.'); 
    Readln(I); 
    R := DoShell(I); 
    Writeln('Command Exit Code:'); 
    Writeln(R.exitcode); 
    Writeln('Command Output:'); 
    Writeln(R.output); 
end. 
+0

sous Windows essayer cmd/s nom_du_programme param1 param2 ... –

Répondre

1

à un coup d'œil, je vois que vous essayez de diviser la commande en fonction de l'espace. Que faire si:

  • J'essaye d'exécuter quelque chose sans paramètres, comme fpc? (réponse: exepath sera vide)
  • J'essaie d'exécuter quelque chose avec le chemin complet et avec de l'espace dedans comme C:\Program Files\Edit Plus 3\editplus.exe?

J'ai essayé Exec() et il semble fonctionner quand vous lui donnez le chemin complet de l'exécutable que vous voulez exécuter, mais la redirection de sortie ne fonctionne pas. Regardez: Command line redirection is performed by the command line interpreter. Cependant, vous pouvez exécuter le fichier .bat qui fait la redirection (créer le fichier temporaire .bat avec l'utilisateur de la commande donne + redirection, et exécuter ce lot).

+1

Voilà pourquoi sysutils.executeprocess (avec un tableau de const comme arguments) a été introduit en 2004, et dos.exec a été dépréciée depuis –

1

N'utilisez pas dos.exec, elle est limitée à une courte ligne de commande (255 caractères). Utilisez sysutils.executeprocess. Toutefois, les commentaires de Michal touchent probablement le problème principal. Lors de l'exécution via les fonctions noyau (non shell), il faut toujours fournir un chemin complet. En outre, en utilisant les fonctions du noyau, on ne peut pas utiliser les commandes du shell comme la redirection. En général, je vous suggère d'essayer d'utiliser la classe TProcess dans l'unité process. Il résume tout cela et plus, et est également utilisé par Lazarus pour appeler des outils externes.

+0

Dans les versions plus récentes , le processus d'unité a des fonctions de commande qui s'exécutent et capturent la sortie. –