VB 5/6-Tipp 0518: DOS-Programm starten mit Ausgabe in einer Datei
von Klaus Langbein
Beschreibung
Es ist immer wieder mal nötig einen DOS-Befehl abzusetzen und das Ergebnis auszulesen. Hierfür gibt es mehrere Lösungen, wobei manchmal die einfachste Möglichkeit das Beste ist. Hier wird die Ausgabe eine Batchdatei in eine Datei umgelenkt und anschließend ausgelesen. Das DOS-Fenster wird unsichtbar gestartet und nach Abarbeiten der Befehle mit Terminateprocess geschlossen.
Zum Schluss wird die Ausgabe noch nach ANSI übersetzt, damit auch die Umlaute richtig dargestellt werden. Wer will, kann das übergehen.
Update von Peter Körner (koerner-familie@t-online.de): Diverse kleine Fehler wurden behoben. Außerdem kann nun auch in die Standarteingabe (STDIN) geschrieben werden.
Schwierigkeitsgrad: | Verwendete API-Aufrufe: CloseHandle, GetShortPathNameA (GetShortPathName), GetTempPathA (GetTempPath), OemToCharA (OemToChar), OpenProcess, TerminateProcess, WaitForSingleObject | Download: |
'Dieser Quellcode stammt von http://www.activevb.de 'und kann frei verwendet werden. Für eventuelle Schäden 'wird nicht gehaftet. 'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum. 'Ansonsten viel Spaß und Erfolg mit diesem Source! '------------- Anfang Projektdatei Project1.vbp ------------- '--------- Anfang Formular "Form1" alias Form1.frm --------- ' Steuerelement: Textfeld "txtCommand" ' Steuerelement: Textfeld "txtOutput" ' Steuerelement: Schaltfläche "cmdGo" ' ' Autor K. Langbein (Klaus@ActiveVB.de) ' Beschreibung ' Es ist immer wieder mal nötig einen DOS-Befehl abzusetzen und das ' Ergebnis auszulesen. Hierfür gibt es einige Lösungen, aber ' manchmal ist eine einfache Möglichkeit das beste. ' Hier wird die Ausgabe eine Batchdatei in eine Datei umgelenkt ' und anschließend ausgelesen. Das DOSfenster wird unsichtbar gestartet ' und nach Abarbeiten der Befehle mit Terminateprocess geschlossen. ' Zum Schluss wird die Ausgabe noch nach ANSII übersetzt, damit auch ' die Umlaute richtig dargestellt werden. Wer will, kann das übergehen. Option Explicit Private Sub cmdGo_Click() txtOutput = ShellDos(txtCommand) End Sub Private Sub txtCommand_KeyDown(KeyCode As Integer, Shift As Integer) If KeyCode = 13 Then Call cmdGo_Click End If End Sub '---------- Ende Formular "Form1" alias Form1.frm ---------- '--- Anfang Modul "modExecDosCommand" alias modExecDosCommand.bas --- Option Explicit 'Er wurde Teilweise von mir (Peter Körner) verändert. ' ' Autor K. Langbein (Klaus@ActiveVB.de), Peter Körner (koerner-familie@t-online.de) ' Beschreibung ' Es ist immer wieder mal nötig einen DOS-Befehl abzusetzen und das ' Ergebnis auszulesen. Hierfür gibt es einige Lösungen, aber ' manchmal ist eine einfache Möglichkeit das beste. ' Hier wird die Ausgabe eine Batchdatei in eine Datei umgelenkt ' und anschließend ausgelesen. Das DOS-Fenster wird unsichtbar gestartet ' und nach Abarbeiten der Befehle mit Terminateprocess geschlossen. ' Zum Schluss wird die Ausgabe noch nach ANSII übersetzt, damit auch ' die Umlaute richtig dargestellt werden. Wer will, kann das übergehen. Private Declare Function GetShortPathName Lib _ "kernel32" Alias "GetShortPathNameA" (ByVal _ lpszLongPath As String, ByVal lpszShortPath As String, _ ByVal cchBuffer As Long) As Long Private Declare Function CloseHandle Lib "kernel32" (ByVal _ hObject As Long) As Long Private Declare Function OpenProcess Lib "kernel32" (ByVal _ dwDesiredAccess As Long, ByVal bInheritHandle As Long, _ ByVal dwProcessId As Long) As Long Private Declare Function TerminateProcess Lib "kernel32" (ByVal _ hProcess As Long, ByVal uExitCode As Long) As Long Private Declare Function WaitForSingleObject Lib "kernel32" _ (ByVal hHandle As Long, ByVal dwMilliseconds As Long) _ As Long Private Declare Function OemToChar Lib "user32" Alias "OemToCharA" _ (ByVal lpszSrc As String, ByVal lpszDst As String) As Long Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _ (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long Private Const PROCESS_TERMINATE = &H1 Private Const BUFFER_LENGTH = 512 Private Const INFINITE = -1& Private Const SYNCHRONIZE = &H100000 Public Function ShellDos(ByVal Cmd As String, Optional ByVal WorkingDir As String = ".", _ Optional ByVal STDIN As String = "") As String Dim errflag As Long ' verwenden wir um der Fehlerbehandlungs- ' routine zu sagen, wo wir gerade sind Dim Batfile$ ' Unser Batchfile Dim DataFile$ ' Unser STDIN-DataFile Dim ReplyFile$ ' Unsere Ausgabedatei Dim t As Single ' Allgemeine Zeitabfrage Dim l As Long ' Dateilänge Dim Task As Long ' TaskID Dim Result As Long ' Für Rückgabewerte aus API-Funktionen Dim fno As Long ' Dateinummer Dim TaskID As Long ' Task-ID des DOS-Fensters Dim ProcID As Long ' Prozess-ID des DOS-Fensters Dim TmpDir As String ' Temporärer Ordner Dim tmp As String ' Temporärer String TmpDir = String(BUFFER_LENGTH, 0) l = GetTempPath(BUFFER_LENGTH, TmpDir) TmpDir = Left(TmpDir, l) ReplyFile = TmpDir & "DOSReply.txt" DataFile = TmpDir & "DOSSTDIN.txt" ' Die Datei muss existieren, damit ' GetShortPathName Funktioniert. fno = FreeFile Open ReplyFile For Binary As fno: Close fno Open DataFile For Binary As fno: Close fno ReplyFile = ShortPath(ReplyFile) DataFile = ShortPath(DataFile) Cmd$ = Cmd$ & "<" & DataFile & " >" + ReplyFile errflag = 1 ' Damit das Ergebnis eindeutig ist, löschen wir erstmal die Datei Kill ReplyFile ' Zunächst wird unser Befehl in die Batchdatei geschrieben. Batfile$ = TmpDir & "Batch.bat" Open Batfile$ For Output As #fno Print #fno, RootFromPath(WorkingDir) Print #fno, "cd " & WorkingDir Print #fno, Cmd$ Close #fno DoEvents ' DOS wird mit der Batchdatei aufgerufen tmp = String(BUFFER_LENGTH, 0) l = GetShortPathName(Batfile$, tmp, BUFFER_LENGTH) Batfile$ = Left(tmp, l) TaskID = Shell(Batfile$, vbHide) DoEvents errflag = 2 ProcID = OpenProcess(SYNCHRONIZE, False, TaskID) Call WaitForSingleObject(ProcID, INFINITE) terminate: ' Hier wird DOS beendet Result = TerminateProcess(ProcID, 1&) Result = CloseHandle(Task) errflag = 3 l = FileLen(ReplyFile) tmp = String(l, 0) Open ReplyFile For Binary As fno Get fno, , tmp Close fno ' ANSI -> ASCII Call OemToChar(tmp, tmp) ShellDos = tmp Kill Batfile Kill ReplyFile Kill DataFile errflag = 4 Exit Function err1: Select Case Err Case 53 Select Case errflag Case 1 Resume Next Case 3 ShellDos = "<ERROR>" Exit Function Case Else Goto err_else End Select Case Else err_else: MsgBox Error$ End Select End Function Private Function RootFromPath(ByVal Path As String) As String RootFromPath = Mid(Path, 1, InStr(Path, ":")) End Function Private Function ShortPath(ByVal Path As String) As String Dim tmp As String ' Temporärer String Dim l As Long ' Länge des Strings tmp = String(256, 0) l = GetShortPathName(Path, tmp, Len(tmp)) ShortPath = Left(tmp, l) End Function '--- Ende Modul "modExecDosCommand" alias modExecDosCommand.bas --- '-------------- Ende Projektdatei Project1.vbp --------------
Tipp-Kompatibilität:
Windows/VB-Version | Win32s | Win95 | Win98 | WinME | WinNT4 | Win2000 | WinXP |
VB4 | |||||||
VB5 | |||||||
VB6 |
Ihre Meinung
Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.
Archivierte Nutzerkommentare
Klicken Sie diesen Text an, wenn Sie die 6 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.
Kommentar von am 05.01.2010 um 16:38
schönes beispiel, blickt aber keine sau durch
Kommentar von susowa am 03.05.2006 um 08:24
Wenn man die Zeile:
TaskID = Shell(Batfile$, vbHide)
durch folgende ersetzt:
TaskID = Shell(Environ$("COMSPEC") & " /C " & Batfile$, vbHide)
funktioniert der Tip reibungslos auch unter W98.
Getestet mit VB6 und W98SE, dort hing der Aufruf, da sich das DOS-Fenster defaultmäßig nicht wieder automatisch schließt.
Kommentar von CW am 17.12.2005 um 11:53
Mit befehl "ping -t localhost" hängt! :(
Kommentar von Patrick am 16.05.2005 um 11:21
@Protogenes: Hab es mal rasch ausprobiert, funktioniert.
Kommentar von Jonathan am 12.08.2004 um 15:10
Bei mir bleibt bei diesem tipp nur das gesammte programm hängen, wenn der befehl ausgeführt wird.
Kommentar von Protogenes am 12.01.2004 um 13:19
in DOS lässt sich die Ausgabe in eine Datei auch regeln, wenn man an den Befehl " >> [Datei]" anhängt
[Datei] ist die Zieldatei.
Ich habe es im DOS 6.22 schon so gemacht, geht bis ins 2k, in XP wahrscheinlich auch, konnte ich noch nicht testen.