Foros del Web » Programación para mayores de 30 ;) » Programación General » Visual Basic clásico »

Ejecutar sentencia de MS-DOS

Estas en el tema de Ejecutar sentencia de MS-DOS en el foro de Visual Basic clásico en Foros del Web. El tema es asi... Quiero ejecutar cualquier comando DOS... Puede ser una linea o varias... Y al final, cuando se termine de ejecutar me avise ...
  #1 (permalink)  
Antiguo 02/05/2006, 17:25
Avatar de culd  
Fecha de Ingreso: noviembre-2003
Mensajes: 959
Antigüedad: 20 años, 5 meses
Puntos: 19
Ejecutar sentencia de MS-DOS

El tema es asi... Quiero ejecutar cualquier comando DOS... Puede ser una linea o varias...
Y al final, cuando se termine de ejecutar me avise que termino...

Lei este post: http://www.forosdelweb.com/showthrea...light=ejecutar
El tercer mensaje que dejo jrp01

Y la verdad que funciona bastante bien...

Solo que tengo varios problemas/cuestiones...

1- Si bien ejecuta la sentencia, lo hace con la ventana minimizada, como se hace para que lo que se ejecute en la ventana de ms-dos directamente aparezca sin minimizar

2- Solo se puede enviar 1 linea de comando y esperar a que termine esa linea... Como seria para enviar barias lineas y esperar todas esas lineas...

3- Lo mas importante, hay ciertas aplicaciones bajo DOS, que cuando mando esa sentencia, hay veces que se ejecuta correctamente y hay veces que "no se ejecuta" es decir, mando la sentencia y automaticamente salta el mensaje que ya termino de ejecutarse, y no se ve si se ejecuto o no...
Pero hay veces que se ejecuta normalmente, y recien avisa cuando se termina de ejecutar... Sinceramente no entiendo, por que aveces anda bien y otras no...
Por ejemplo, si en un BAT pongo la misma sentencia, y luego ejecuto el BAT desde VB, directamente sale y entra la ventana DOS...

ANTES DE QUE TIREN LA IDEA DE UN BAT Y LUEGO EJECUTAR EL BAT... Sinceramente no me sirve... Necesito que ejecute directamente.
  #2 (permalink)  
Antiguo 02/05/2006, 23:15
Avatar de aldo1982  
Fecha de Ingreso: noviembre-2004
Ubicación: Santa Fe (Argentina) Colon F.C
Mensajes: 1.362
Antigüedad: 19 años, 4 meses
Puntos: 6
De acuerdo

Seria Bueno Ke Alguien Ke Sepa Explique Bien Ya Ke Es Algo Muy Util

Salu2
__________________
LA MUERTE ESTÁ TAN SEGURA DE VENCER QUE NOS DA TODA UNA VIDA DE VENTAJA
  #3 (permalink)  
Antiguo 03/05/2006, 06:17
Avatar de culd  
Fecha de Ingreso: noviembre-2003
Mensajes: 959
Antigüedad: 20 años, 5 meses
Puntos: 19
Estuve analizando el codigo aportado por el amigo y ya tengo la solucion para mi primer pregunta...

1- Como hacer para que la ventana de MS-DOS no aparezca minimizada...

En la linea de codigo

hShell = Shell(Environ$("Comspec") & " /c " & sCmd, 2)

el 2, tiene un valor de vbMinimizedFocus, osea que minimiza la ventana y a la vez lo pone en primer plano...

Si cambiamos por 4, o ponemos directamente "vbNormalFocus" sin las comillas... La ventana aparece normalmente y queda en primer plano...

Ahora bien, hay que encontrar la solucion a mi pregunta 2 y la 3, voy a seguir analizando.

Si alguien sabe, desenbuchen
  #4 (permalink)  
Antiguo 03/05/2006, 06:43
Avatar de culd  
Fecha de Ingreso: noviembre-2003
Mensajes: 959
Antigüedad: 20 años, 5 meses
Puntos: 19
Nuevamente estuve analizando, y lei que "Eternal Idol" aconsejaba usar WaitForSingleObject en vez de GetExitCodeProcess.

Rearme el codigo pero con el GetExitCodeProcess, para que detecte cuando se termina de ejecutar y avise... y logre lo siguiente

Poner en un Modulo:

Código:
Global Const SYNCHRONIZE = &H100000
Global Const INFINITE = &HFFFFFFFF

Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
         ByVal dwProcessId As Long) As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long

Public Sub WaitForTerm(ByVal PID As Long)
    On Error GoTo Gestion_Error

    'Variables locales
    Dim phnd As Long

    phnd = OpenProcess(SYNCHRONIZE, 0, PID)
    If phnd <> 0 Then
        'si en vez de INFINETE se pone la cantidad de milisegundos
        'el programa si el programa no se llega a liberar, se libera solo cuando
        'pasen esos milisegundos
        Call WaitForSingleObject(phnd, INFINITE)
        Call CloseHandle(phnd)
        MsgBox "El Proceso ha Terminado", vbInformation + vbOKOnly, "Mensaje"
    End If
Exit Sub
Gestion_Error:
    Call MsgBox(Err.Number & ": " & Err.Description)
End Sub


Public Sub EjecutarComandoDOS(Comando As String)
Dim PID As Long
PID = Shell(Environ$("Comspec") & " /c " & Comando, vbNormalFocus)

If PID <> 0 Then
    'Esperar a que finalice
    WaitForTerm PID
End If
End Sub
Luego para llamarlo desde cualquier parte, lo que pueden hacer es:

Código:
Call EjecutarComandoDOS("SU COMANDO DE MS-DOS"
Quiero aclarar lo siguiente...

El codigo de "jrp01", lo que hace es:
1- Ejecuta una sentencia (una sola linea) de MS-DOS y esperar a que esta termine.
Pero... Se puede seguir utilizando el programa...

Este nuevo codigo que estoy poniendo, lo que hace es:
1- Ejecuta una sentencia (una sola linea) de MS-DOS y espera a que esta termine.
La diferencia, es que este codigo, no deja que el programa se utilice, hasta que termine de ejecutarse la sentencia...
Pero, lo que se puede hacer es, poner un tiempo para que corte solo si es que no se corto.. En ves de poner INFINITE, poner la cantidad de milisegundos que se quiere esperar...

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

Nuevamente, ya estamos solucionando este tema...

Voy a seguir analizando, como enviar mas de una linea...
Y tambien por que hay veces que "se ejecuta" pero en realidad no se ejecuta, o directamente hace algo mal...
  #5 (permalink)  
Antiguo 03/05/2006, 07:19
Avatar de culd  
Fecha de Ingreso: noviembre-2003
Mensajes: 959
Antigüedad: 20 años, 5 meses
Puntos: 19
Ya detecte cuando no se ejecuta la sentencia DOS, y pasa de largo...

Hay veces en la que nos e ejecuta la sentencia, es decir... Se manda la ejecucion y directamente dice "Se termino la ejecucion". Si se cierra el programa (hecho por mi) y se vuelve a abrir, ahi ejecuta correctamente...

Puede ser que el proceso queda acumulado en esa variable, y luego cuando se quiere volver a abrir, automaricamente detecta como que ya se termino el proceso?... Por eso hay que cerrar y abrir el programa para que se limpie la variable?...

EDITO:

Fijense esto:

Shell(Environ$("Comspec") & " /c " & sCmd, 2)

Estuve mirando en otras webs, y lei que el " /c " lo que hace es cerrar la ventana de MS-DOS cuando se termina de ejecutar la sentencia...

Teoricamente si el /c y dejo solo " ", la idea es que ejecute la sentencia y no se cierre la ventana de MS-DOS. El problema es que no la ejecuta, abre la ventana de MS-DOS pero lo deja en la carpeta desde donde se ejecuta el programa...

Puede que el problema de "ejecutar" y que diga que se ejecuto, sin que se haya ejecutado, se puede solucionar sin cerrar la ventana MS-DOS, asi se obliga a ejecutar

PD Che, alguien tire algo... Estoy haciendo solo el post.

Última edición por culd; 03/05/2006 a las 07:32
  #6 (permalink)  
Antiguo 03/05/2006, 07:59
Avatar de VisualGuallabo  
Fecha de Ingreso: marzo-2005
Mensajes: 288
Antigüedad: 19 años, 1 mes
Puntos: 2
Te voy a dar una solución:
1-Crear un .bat(archivo de lotes de msdos) y ejecutarlos directamente.
Ejemplo:
Call EjecutarComandoDOS("c:\dos.Bat")
de esta forma ejecutara todas las lineas de comandos de msdos que pongas en el archivo de lotes.
__________________
"No hay lenguaje de programación potente que sea inferior a otro semejante cuando existe un buen programador que lo defiende"

Yosvanis Cruz Alias VisualGuallabo
Ycruz
  #7 (permalink)  
Antiguo 03/05/2006, 08:09
Avatar de culd  
Fecha de Ingreso: noviembre-2003
Mensajes: 959
Antigüedad: 20 años, 5 meses
Puntos: 19
Cita:
Iniciado por VisualGuallabo
Te voy a dar una solución:
1-Crear un .bat(archivo de lotes de msdos) y ejecutarlos directamente.
Ejemplo:
Call EjecutarComandoDOS("c:\dos.Bat")
de esta forma ejecutara todas las lineas de comandos de msdos que pongas en el archivo de lotes.
1- No sirve con BAT... la idea es hacerlo directamente...

2- Hay aplicaciones que si vos ejecutas al .bat desde VB, no llega a leer el bat, no se cual es el problema, pero hay problemas...

Por ejempl, hise esto para probar

Código:
Public Sub EjecutarCMDDOS(Comando As String)
Open "Archivo.bat" For Output As #1
Print #1, Comando
Close #1

Dim ret As String
ret = Shell("rundll32.exe url.dll,FileProtocolHandler " & "Archivo.bat, vbNormalFocus)
'Call BorrarArchivo("Archivo.bat")
End Sub
No anda...
La idea es:
1- Crear un archivo bat con el comando que se quiere...
2- Ejecutar el archivo bat
3- Borrar el archivo bat...

No se por que, pero hay veces que si se llama a una aplicacion con parametros, no llega a ejecutarse la aplicacion con los parametros...

Si mando el comando:
PROGRAMA.EXE PARAMETRO1 PARAMETRO2 PARAMETRON

No anda..
Pero si creo un .BAT y lo ejecuto haciendo DOBLE CLICK... Ahi si anda...
  #8 (permalink)  
Antiguo 03/05/2006, 11:14
Avatar de VisualGuallabo  
Fecha de Ingreso: marzo-2005
Mensajes: 288
Antigüedad: 19 años, 1 mes
Puntos: 2
socio ya puse un ejemplo en la faq es la respuesta 138.
ejecuta uno o mas comandos
__________________
"No hay lenguaje de programación potente que sea inferior a otro semejante cuando existe un buen programador que lo defiende"

Yosvanis Cruz Alias VisualGuallabo
Ycruz
  #9 (permalink)  
Antiguo 03/05/2006, 11:40
Avatar de culd  
Fecha de Ingreso: noviembre-2003
Mensajes: 959
Antigüedad: 20 años, 5 meses
Puntos: 19
Cita:
Iniciado por VisualGuallabo
socio ya puse un ejemplo en la faq es la respuesta 138.
ejecuta uno o mas comandos
Si, usaste lo que puse para crear el bat...

No sirve... si es con bat no sirve..
  #10 (permalink)  
Antiguo 03/05/2006, 13:44
Avatar de VisualGuallabo  
Fecha de Ingreso: marzo-2005
Mensajes: 288
Antigüedad: 19 años, 1 mes
Puntos: 2
Mira socio eso que dices que en algunas veces no se ejecuta no es cierto, cual es el problema, pues fácil es que se ejecuta tan rápido que no lo puedes ver, para que te convenzas siempre pon al final el comando de msdos pause. y veras. la cuestión es agregar los comandos al Texbox multiline=true
ya que el bat se crea con los comandos según los pones en el textbox. de los contrario te los pone todos en una sola línea. si esto no te convence me gustaría saber porque el bat no sirve
__________________
"No hay lenguaje de programación potente que sea inferior a otro semejante cuando existe un buen programador que lo defiende"

Yosvanis Cruz Alias VisualGuallabo
Ycruz
  #11 (permalink)  
Antiguo 03/05/2006, 14:36
Avatar de VisualGuallabo  
Fecha de Ingreso: marzo-2005
Mensajes: 288
Antigüedad: 19 años, 1 mes
Puntos: 2
Cita:
Iniciado por culd

No se por que, pero hay veces que si se llama a una aplicacion con parametros, no llega a ejecutarse la aplicacion con los parametros...

Si mando el comando:
PROGRAMA.EXE PARAMETRO1 PARAMETRO2 PARAMETRON

No anda..
Pero si creo un .BAT y lo ejecuto haciendo DOBLE CLICK... Ahi si anda...
si usas shell no tiene por que dar error
ejemplo:
shell "ping 193.169.0.2", vbNormalFocus


claro si creas un programa com mas de un parametro tienes que crear un caracter separador, para separar los parametros.
__________________
"No hay lenguaje de programación potente que sea inferior a otro semejante cuando existe un buen programador que lo defiende"

Yosvanis Cruz Alias VisualGuallabo
Ycruz
  #12 (permalink)  
Antiguo 04/05/2006, 05:53
Avatar de culd  
Fecha de Ingreso: noviembre-2003
Mensajes: 959
Antigüedad: 20 años, 5 meses
Puntos: 19
Cita:
Iniciado por VisualGuallabo
si usas shell no tiene por que dar error
ejemplo:
shell "ping 193.169.0.2", vbNormalFocus


claro si creas un programa com mas de un parametro tienes que crear un caracter separador, para separar los parametros.
Para el tipo de aplicacion a la que quiero llamar, si trae error...

No es por que lo haga rapido... Sino que no llega a llamar a la aplicacion, o la aplicacion no recoje bien los parametros...
  #13 (permalink)  
Antiguo 04/05/2006, 12:19
 
Fecha de Ingreso: abril-2005
Mensajes: 351
Antigüedad: 19 años
Puntos: 3
hola provaste con este modulo


Cita:
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

y luego en el form pones dos textbox y un command1(el textbox1 con la propiedad multiline = ture)

Cita:
Private Sub Command1_Click()
Text1 = ShellDos(Text2)
End Sub
__________________
www.leandroascierto.com
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:17.