2010-05-25 2 views
2

J'utilise Delphi 7 et ne peux pas prédire la version cible de Windows.Delphi 7: comment exécuter la commande shell et vérifier le résultat?

J'ai besoin de créer une base de données (probablement MySQL, mais peut-être quelque chose d'autre) et de définir certaines structures de table. Je n'ai pas besoin de renseigner des données. Malheureusement, tous les composants ADO semblent s'attendre à ce qu'une base de données existe déjà et ils vous permettront alors de la manipuler. Donc, comme il ne s'agit que de quelques commandes simples, j'ai pensé que je pourrais aussi bien utiliser ShellExectute().

D'accord? Être en désaccord?

Quelqu'un peut-il me donner un exemple de code qui va tenter de lancer "MySql --version" et me laisser vérifier le résultat? Après cela, je devrais être capable de le comprendre par moi-même. Merci.


[modifier]

Aucune infraction prévu, mais je ne sais comment google. C'est juste que je ne trouve pas de résultats utiles. C'est ma propre faute de ne pas être explicite dans cette question, alors s'il vous plaît accepter mes excuses - ce dont j'ai besoin est un exemple de code, pas seulement le nom d'un composant.

Désolé (et merci pour les réponses à ce jour (qui sont tous +1))


[modifier]

Les liens que Robert donne faire le travail (procédure RunDosInMemo() ne l'astuce) ... MAIS Vous devez vous rappeler d'inclure une extension .exe (donc, 'notepad.exe', pas seulement 'notepad', et de ge un chemin complet si votre commande n'est pas sur le chemin.)

+1

Demandez-vous des conseils sur la façon de créer une base de données à partir de zéro, ou demandez-vous comment exécuter une commande et capturer sa sortie? (Si votre réponse est * les deux *, alors vous devriez avoir posé deux questions distinctes.) –

+0

Rob, je prends l'un ou l'autre. Bottom line est que j'ai besoin de créer une base de données et quelques tables, mais pas de remplir des données. Plusieurs personnes dans des questions difficiles ont essayé d'aider mby en faisant mention de firebird ou ado, mais ces gens ne donnent pas de détails sur la façon de créer par programme la base de données avec ces outils - et je ne vois pas comment. Donc, puisque je connais la ligne de commande pour créer une base de données et une table, j'ai pensé que je pourrais exécuter une commande shell à la place. En fin de compte, je me fiche de savoir comment ça se passe, mais quelqu'un peut-il me montrer comment créer une base de données MySQL avec une seule table de Delphi? – Mawg

Répondre

7

Voici un article qui explique en détail

Capture the output from a DOS (command/console) Window

Mais bref, vous devez créer deux tuyaux pour lire et écrire la sortie. Vous devez ensuite définir StdInput et StdOutput dans le TStartUpInfo structure, puis passer cette structure à l'appel CreateProcess().

Voici another article qui indique comment attendre la fin du processus.

+0

merci pour certains bons liens (+1) – Mawg

+0

hmmm, http://delphi.about.com/cs/adptips2001/a/bltip0201_2.htm semblait très bien, mais quand je l'exécute dans Windows 7, puis CreateProcess() échoue. – Mawg

+0

Aaaaaaaaaaargh !!!! Vous ne pouvez pas donner un nom de commande, comme "notepad" !!!! Vous devez donner "Notepad.exe" !!!! – Mawg

3

Je me demande pourquoi tout le monde qui veut lancer un nouveau processus te nds pour utiliser ShellExecute à la place, qui est conçu pour ouvrir le fichier dans l'application associée?

Vous voulez un nouveau processus? Ensuite, utilisez CreateProcess. Fin de l'histoire. CreateProcess vous permet d'attendre le processus, d'obtenir son code de sortie, de lire sa sortie de la console et bien d'autres.

+2

bon conseil général (+1) - des exemples de code spécifiques? – Mawg

+2

Tout le monde utilise ShellExecute parce que c'est beaucoup plus simple: pas de paramètres de sécurité à prendre en compte, pas de structure à remplir avant de l'appeler, pas de processus et de threads à nettoyer par la suite. Les gens utiliseraient WinExec s'ils le pouvaient. –

+1

> des exemples de code spécifiques? Avez-vous essayé la recherche? Recherchez "console" dans la balise Delphi. Ici: http://stackoverflow.com/questions/1212176/delphi-6-read-console-apps-output-while-running http://stackoverflow.com/questions/2015388/how-to-send-command-to -console-application-from-gui-application http://stackoverflow.com/questions/2856772/read-unicode-output-of-console-application Et beaucoup d'autres questions ... – Alex

3

Ce que vous cherchez, probablement, est une base de données intégrée.Certaines options:

  • Firebird Embarqués
  • embarqué MySQL
  • SQLite

Avec l'une des bases de données et des composants d'accès aux données appropriées (pas sûr à propos de ADO pour FB intégré et MySQL), vous sera en mesure de:

  • attach sans DB
  • créer un DB
  • puis créer les tables
+0

désolé, et absolument aucune infraction prévue, mais j'ai déjà posé une autre question et obtenu une réponse similaire. Je dois préciser que j'ai besoin d'un exemple de code - pouvez-vous m'aider, s'il vous plaît? Désolé de ne pas le dire plus explicitement, je vais éditer la question. – Mawg

+0

Au moins, vous devez indiquer explicitement quel SGBD vous allez utiliser. Aussi, envisagez-vous seulement ADO? –

+1

Ce qui n'est pas assez explicite à propos de "Quelqu'un peut-il me donner un exemple de code qui va tenter de lancer" MySql --version "et laisser moi vérifier le résultat?" – mghie

5

Utilisation DSiExecuteAndCapture de DSiWin32:

var 
    exitCode: integer; 
    output : TStringList; 
begin 
    output := TStringList.Create; 
    try 
    if DSiExecuteAndCapture('mysql --version', output, '', exitCode) = 0 then 
     Log(Format('error %d, cannot start', [GetLastError])) 
    else begin 
     // check exitCode and output 
    end; 
    finally FreeAndNil(output); end; 
end; 
+0

Cela semble très bon, donc plus 1, mais je me suis un peu enlisé en essayant de l'installer (pas beaucoup de documentation). J'y reviendrai si les autres choses ne marchent pas, mais en général je préférerais ne pas utiliser de trucs de tierce partie. – Mawg

+0

Il n'y a rien à installer, il suffit d'ajouter DSiWin32 à la clause 'uses'. Sinon, copiez et collez DSiExecuteAndCapture dans votre code. – gabr

2

J'ai sauvé ce d'un newsgroup message il y a longtemps; Je ne sais pas qui est originallall l'a écrit, cependant.

Ce code vous permet d'exécuter une application DOS et de capturer sa sortie dans un TMemo. Vous pouvez ensuite tirer ce que vous avez besoin du mémo avec un peu d'essais et d'erreurs d'analyse des lignes.

procedure TFMainForm.RunDosInMemo(const DosApp: String; AMemo: TRichEdit); 
const 
    ReadBuffer = 2400; 
var 
    Security : TSecurityAttributes; 
    StdInPipeR, StdInPipeW : THandle; 
    StdOutPipeR, StdOutPipeW : THandle; 
    StartInfo : TStartUpInfo; 
    ProcessInfo : TProcessInformation; 
    Buffer : PByte; 
    BytesAvailable, BytesRead : DWord; 
    sDosApp: String; 
    sData: RawByteString; 
begin 
    sDosApp := DosApp; 
    UniqueString(sDosApp); 

    with Security do begin 
    nLength := SizeOf(TSecurityAttributes); 
    bInheritHandle := True; 
    lpSecurityDescriptor := nil; 
    end; 

    if CreatePipe(StdInPipeR, StdInPipeW, @Security, 0) then 
    try 

    SetHandleInformation(StdInPipeW, HANDLE_FLAG_INHERIT, 0); 
    if CreatePipe(StdOutPipeR, StdOutPipeW, @Security, 0) then 
    try 
     SetHandleInformation(StdOutPipeR, HANDLE_FLAG_INHERIT, 0); 
     GetMem(Buffer, ReadBuffer); 
     try 
     ZeroMemory(@StartInfo, SizeOf(StartInfo)); 
     StartInfo.cb := SizeOf(StartInfo); 
     StartInfo.hStdOutput := StdOutPipeW; 
     StartInfo.hStdInput := StdInPipeR; 
     StartInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; 
     StartInfo.wShowWindow := SW_HIDE; 

     if CreateProcess(nil, 
         PChar(sDosApp), 
         nil, 
         nil, 
         True, 
         NORMAL_PRIORITY_CLASS, 
         nil, 
         nil, 
         StartInfo, 
         ProcessInfo) then 
      try 
      while WaitForSingleObject(ProcessInfo.hProcess, 500) <> WAIT_TIMEOUT do 
       Application.ProcessMessages; 
      while PeekNamedPipe(StdOutPipeR, nil, 0, nil, BytesAvailable, nil) do 
      begin 
       if BytesAvailable < 1 then 
       Break; 
       if BytesAvailable > ReadBuffer then 
       BytesAvailable := ReadBuffer; 
       if not ReadFile(StdOutPipeR, 
           Buffer[0], 
           BytesAvailable, 
           BytesRead, 
           nil) then 
       Break; 
       SetString(sData, PAnsiChar(Buffer), BytesRead); 
       // assign an appropriate codepage for the output data: 
       // 0 for default Ansi, 1252 or 20157 for ASCII, 1200 for 
       // Unicode, etc... 
       SetCodePage(sData, ...); 
       // this is faster and more efficient than reading/writing the 
       // Text property directly... 
       AMemo.SelStart := AMemo.GetTextLen; 
       AMemo.SelLength := 0; 
       AMemo.SelText := sData; 
      end; 
      finally 
      CloseHandle(ProcessInfo.hThread); 
      CloseHandle(ProcessInfo.hProcess); 
      end; 
     finally 
     FreeMem(Buffer); 
     end; 
    finally 
     CloseHandle(StdOutPipeR); 
     CloseHandle(StdOutPipeW); 
    end; 
    finally 
    CloseHandle(StdInPipeR); 
    CloseHandle(StdInPipeW); 
    end; 
end; 
+0

Une technique similaire à celle du code About.com auquel Robert répond. Les deux sont sensibles au même problème général. Si le programme de réception ne lit pas à partir du tube, alors lorsque le tampon du tube se remplit, le programme d'envoi bloque lors de son prochain appel WriteFile jusqu'à ce qu'il y ait assez de place pour une autre écriture. Mais si le programme de réception attend la fin de l'expéditeur avant de lire quoi que ce soit, alors vous avez une impasse. –

+0

+1 pour publication. Merci. Cela ne m'aide pas puisque RawByteString est apparu dans D2009 et j'ai D7. – Mawg

+0

Ajoutez simplement "{$ IFNDEF UNICODE} type RawByteString = AnsiString; {$ ENDIF}" quelque part et vous avez terminé. Toutes les chaînes sont RawByteStrings dans D7. – Alex

1

j'ai écrit une unité et un ensemble de composants pour gérer la redirection de console dans delphi tout à fait il y a longtemps:

http://www.fulgan.com/delphi/dospipes15.zip

Mais au-delà, vous ne devriez pas avoir à passer par ce qui suit: utilisez le composant de connexion ADO simplement pour vous connecter au catalogue par défaut de la base de données, puis utilisez la méthode "execute" pour créer la base de données et le schéma dont vous avez besoin. La base de données SERVER doit être correctement installée et exécutée pour que cela fonctionne, mais, au moins avec MSSQL, il n'y a aucun problème avec la création de nouvelles bases de données de cette façon. Cependant, la chaîne de connexion exacte à utiliser peut varier en fonction de la base de données cible.

+0

Merci pour vos commentaires sur les deux points. – Mawg

+0

Btw, j'ai posté une question demandant l'aide de codage ADO à http://stackoverflow.com/questions/2918016/delphi-7-ado-need-basic-coding-example – Mawg

Questions connexes