Newsgroup: it.comp.lang.visual-basic
Titolo: [?] standard input - difficile?

Ciao.
Il VB gestisce lo "standard input"??
Spiego:
da una shell dos scrivete "DIR C:\*.* | MORE" ( "|" = simbolo "pipe")
il risultato della DIR finisce nello "standard input" di MORE.EXE
oppure CIRUZZO.EXE < CICCIO.EXE
quello che ciccio.exe "produce" come output, finisce nello "standard input"
di ciruzzo.exe
non è il "command" di VB... è un'altra cosa, che in C per dos sapevo gestire
(era lo "stdin")
esiste un concetto equivalente in VB?
grazie

No
cerca un po' di messaggi fa, avevo inviato un link dove c'era un esempio per
catturare output Dos e leggerlo da VB....era una pazzia, però.
Se ti interessa ho un esempio a casa su come aprire una finestra Dos e
scriverci dentro, non so però a cosa possa servire...

 esiste un concetto equivalente in VB?
Puoi ottenere un riferimento allo standard input del tuo programma in questo
modo:
Declare Function GetStdHandle Lib "kernel32" _
 (ByVal nStdHandle As Long) As Long
Public Const STD_INPUT_HANDLE = -10&
Public hStdIn As Long   ' handle dello Standard Input
hStdIn = GetStdHandle(STD_INPUT_HANDLE)
a questo punto puoi verificare se sono presenti dati da leggere con quest'altra
funzione:
Declare Function PeekNamedPipe Lib "kernel32" _
    (ByVal hNamedPipe As Long, lpBuffer As Any, _
    ByVal nBufferSize As Long, lpBytesRead As Long, _
    lpTotalBytesAvail As Long, lpBytesLeftThisMessage As Long) As Long
Function StdInputPolling() As Boolean
    'verifica se sono presenti nuovi dati nello standard input;
    'puo' essere richiamata in un ciclo, o in un timer ecc..
    Dim sBuff       As String
    Dim lBytesRead  As Long
    Dim lTotalBytes As Long
    Dim lAvailBytes As Long
    Dim rc          As Long
    sBuff = String(2048, Chr$(0))
    rc = PeekNamedPipe(hStdIn, ByVal sBuff, 2048, lBytesRead, lTotalBytes,
lAvailBytes)
    StdInputPolling= CBool(rc And lBytesRead > 0)
End Function
e infine leggerlo cosi':
Declare Function ReadFile Lib "kernel32" _
    (ByVal hFile As Long, _
    lpBuffer As Any, _
    ByVal nNumberOfBytesToRead As Long, _
    lpNumberOfBytesRead As Long, _
    lpOverlapped As Any) As Long
Function StdInputRead() As String
    Dim sBuff      As String
    Dim lBytesRead As Long
    Dim rc         As Long
    'verifichiamo prima la presenza di nuovi dati, necessario altrimenti
    'la chiamata a ReadFile rimane bloccata finche' non riceviamo qualcosa
    If StdInputPolling Then
        sBuff = String(2048, Chr$(0))
        rc = ReadFile(hStdIn, ByVal sBuff, 2048, lBytesRead, ByVal 0&)
        StdInputRead = Left$(sBuff, lBytesRead)
    End If
End Function
al termine chiudi l'handle aperto in precedenza
Declare Function CloseHandle Lib "kernel32" _
    (ByVal hObject As Long) As Long
CloseHandle hStdIn
Spero sia quello che ti serviva...
Ciao
(P.S. gia' che in questi giorni vi sto annoiando sull'argomento scacchi, questo
e' grosso modo il sistema con cui i nostri motori di gioco comunicano con
l'interfaccia grafica...)
--
Luca Dormio
luca....@tin.it

 scriverci dentro, non so perņ a cosa possa servire...
www.vb2themax.com
www.msjogren.net

fantastico.
Non l'ho ancora provato, ma.... grazie molte.
"Luca Dormio" <lucaFAV...@tinFAVA.it> wrote in message
news:9eiicf$nmd$1...@fe2.cs.interbusiness.it...


Pregiatissimo.....
Magari sai anche come reindirizzare alla finestra Dos che ha lanciato il
programma? (con una tecnica simile a quella che indichi riesco ad aprire una
finestra Dos e a scriverci dentro quello che voglio, ma non riesco a) ad
identificare la finestra Dos che ha lanciato il programma, perché la caption
normalmente usata con findwindow o simili cambia subito b) a scriverci
dentro (in questo caso, però, se riuscissi ad identificare l'handle della
finestra Dos qualche idea potrei avercela))
Grazie.

 > questo modo:
Se poi ti serve, posso postare anche come scrivere sullo Standard Output.
Bye, G.
--
Microsoft gives you Windows,
Linux give you the whole house :-)

Mah
secondo te lo standard output di un programma VB lanciato da una finestra
Dos č la finestra Dos?
Se sě a me interessa moltissimo.
Grazie.

TROVATO standard output
--------------------------------
Option Explicit
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As
Long) _
    As Long
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, _
    lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, _
    lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
Private Const STD_OUTPUT_HANDLE = -11&
' write to standard output channel
'
' NOTE: this routine works only in compiled applications
Sub WriteToStdOutput(ByVal Text As String)
    Dim hStdOut As Long
    Dim ret As Long
    Dim bytesWritten As Long
    ' get the handle of standard output
    hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
    ' write to standard output
    ret = WriteFile(hStdOut, ByVal Text, Len(Text), bytesWritten, ByVal 0&)
    ' deal with errors
    If ret = 0 Then
        Err.Raise 1001, , "Unable to write to standard output"
    ElseIf bytesWritten < Len(Text) Then
        Err.Raise 1002, , "Incomplete write operation"
    End If
End Sub
------------------------------
"Paperino" <non...@lo.dico> wrote in message
news:9eir0e$2j9o$1...@stargate1.inet.it...


 wrote in message
9eipk7$ae2$1...@fe1.cs.interbusiness.it...

Onestamente non sono sicuro,
la versione completa di questo codice (che poi e' a sua volta un adattamento
dell'esempio di CGI sul Sito Comune) riesce a leggere lo stdin e a scrivere
sullo stdout, questi dati pero' sono gestiti da una seconda applicazione Win32
che ridirige i due canali del mio eseguibile; in scrittura uso WriteFile con
l'handle dello standard output, con sintassi simile a quella di ReadFile.
Direttamente con una finestra DOS sembra non funzionare (a video non stampa
nulla), nota pero' che se dalla stessa finestra DOS lancio il programma con
pippo.exe > pippo.txt
tutto quello che scrivo con WriteFile viene catturato correttamente nel file...
Non ho capito bene pero' qual'e' il "giro" che ti serve, non riesci a scrivere o
a leggere? (scusa ma nell'altro messaggio mi sembrava di aver capito un'altra
cosa...)
In ogni caso ho anche questo codice, che ribalta il concetto rispetto al
precedente: avvia un processo e ridirige le pipe di lettura e scrittura (in
pratica fa la perte della "seconda applicazione Win32" di cui parlavo prima);
tra 2 applicazioni console (ma anche applicazioni GUI normali) funziona, cosi'
come funziona se lo usi per intercettare l'output si un batch con, ad esempio,
il comando "dir"; rimangono i dubbi sulla *scrittura* nella finestra DOS...
comunque guarda se ti puo servire...
Private Declare Function CreatePipe Lib "kernel32" _
 (phReadPipe As Long, phWritePipe As Long, _
 lpPipeAttributes As SECURITY_ATTRIBUTES, _
 ByVal nSize As Long) As Long
Private Declare Function DuplicateHandle Lib "kernel32" _
 (ByVal hSourceProcessHandle As Long, ByVal hSourceHandle As Long, _
 ByVal hTargetProcessHandle As Long, lpTargetHandle As Long, _
 ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
 ByVal dwOptions As Long) As Long
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" _
 (ByVal lpApplicationName As String, ByVal lpCommandLine As String, _
 lpProcessAttributes As Long, lpThreadAttributes As Long, _
 ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
 lpEnvironment As Long, ByVal lpCurrentDirectory As String, _
 lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As
Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As
Long
Private Const DETACHED_PROCESS = &H8
Private Const CREATE_NEW_PROCESS_GROUP = &H200
Private Const DUPLICATE_SAME_ACCESS = &H2
Private Const STARTF_USESTDHANDLES = &H100
Private Type STARTUPINFO
        cb As Long
        lpReserved As Long
        lpDesktop As Long
        lpTitle As Long
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Long
        hStdInput As Long
        hStdOutput As Long
        hStdError As Long
End Type
Private Type SECURITY_ATTRIBUTES
        nLength As Long
        lpSecurityDescriptor As Long
        bInheritHandle As Long
End Type
Private Type PROCESS_INFORMATION
        hProcess As Long
        hThread As Long
        dwProcessId As Long
        dwThreadId As Long
End Type
Public Function StartEngine(strCommandLine As String) As Boolean
'avvia un processo figlio e ridirige le pipe di standard input e output
'tratto dall'esempio
'"Creating a Child Process with Redirected Input and Output"
'su MSDN.
Dim hChildStdinRd As Long
Dim hChildStdinWr As Long
Dim hChildStdoutRd As Long
Dim hChildStdoutWr As Long
Dim hChildStdinWrDup As Long
Dim hChildStdoutRdDup As Long
Dim piProcInfo As PROCESS_INFORMATION
Dim saAttr As SECURITY_ATTRIBUTES
Dim siStartInfo As STARTUPINFO
Dim retval As Long
saAttr.nLength = Len(saAttr)
saAttr.bInheritHandle = True
saAttr.lpSecurityDescriptor = 0&
CreatePipe hChildStdoutRd, hChildStdoutWr, saAttr, 0
DuplicateHandle GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), _
                hChildStdoutRdDup, 0, False, DUPLICATE_SAME_ACCESS
CloseHandle hChildStdoutRd
CreatePipe hChildStdinRd, hChildStdinWr, saAttr, 0
DuplicateHandle GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), _
                hChildStdinWrDup, 0, False, DUPLICATE_SAME_ACCESS
CloseHandle hChildStdinWr
siStartInfo.lpReserved = 0&
siStartInfo.lpDesktop = 0&
siStartInfo.lpTitle = 0&
siStartInfo.dwFlags = STARTF_USESTDHANDLES
siStartInfo.cbReserved2 = 0&
siStartInfo.lpReserved2 = 0&
siStartInfo.hStdInput = hChildStdinRd
siStartInfo.hStdOutput = hChildStdoutWr
siStartInfo.hStdError = hChildStdoutWr
If Path <> "" Then
    retval = CreateProcess(vbNullString, strCommandLine, ByVal 0&, ByVal 0&, _
             True, DETACHED_PROCESS + CREATE_NEW_PROCESS_GROUP, ByVal 0&, _
             vbNullString, siStartInfo, piProcInfo)
Else
    retval = 0
End If
CloseHandle hChildStdinRd
CloseHandle hChildStdoutWr
'a questo punto hChildStdoutRdDup e hChildStdinWrDup sono gli handle rediretti
'dell'applicazione avviata; possiamo inviare stringhe usando WriteFile e
hChildStdinWrDup
'oppure leggere le stringhe inviata dal processo figlio con ReadFile e
hChildStdoutRdDup
End Function
Ciao
--
Luca Dormio
luca....@tin.it

Quello che io sto cercando da mesi di fare è:
Se avvio il mio programma da una finestra Dos restituisco l'output nella
finestra Dos...
Per capirci: apri finestra Dos e scrivi "dir", premi invio...ecco, se io
volessi fare una cosa di questo tipo come faccio?
Sono riuscito a scrivere (usando api per simulare pressione e rilascio dei
tasti) nella finestra Dos, ma il problema è che appena invio chr(13) mi
scrive "Comando o nome di file errato"....
Sono riuscito ad aprire una finestra Dos da VB e a scriverci quello che
voglio senza far comparire il messaggio (aprendo la Dos Console senza
passare da 
command.com
)
Insomma, sono riuscito a fare cose simili ma nulla su quello che mi serve.
L'esempio pratico è: ho un programma di contabilità che era fatto
originariamente in pascal; questo programma permetteva di esser eseguito da
riga di comando per semplici operazioni: es. programma.exe /add:12000
inseriva una spesa di 12000 e scriveva a video "inserita uscita di lire
12000", a capo il saldo attuale.....
Ovviamente in un linguaggio tipo Pascal questo era non solo ovvio ma l'unico
modo di lavorare....per VB sembra invece che non ci sia soluzione...
Tra l'altro ho notato che se eseguo da Dos un programma 32bit la console non
si comporta come i programmi 16bit ma ritorna immediatamente; di conseguenza
ho anche il problema di sapere SE è stato lanciato dalla finestra Dos (che
però potrei ovviare con un parametro passato al programma)
Spero di essermi spiegato, se sai come aiutarmi te ne sarò infinitamente
grato.

 Spero di essermi spiegato, se sai come aiutarmi te ne sarò infinitamente
grato.
esagerato... basta molto meno... ehm, com'è tua sorella?

 volessi fare una cosa di questo tipo come faccio?
[...]

 esagerato... basta molto meno... ehm, com'è tua sorella?
Ahimé non ho sorelle, ed eviterei mamma e fidanzata per motivi di sicurezza
personale...qualche amica forse...:-)
Grazie comunque, se ti viene in mente qualcos'altro...


Prima di eseguire il CloseHandle sopra ho aggiunto
Dim text
 text = "prova"
 Dim ret As Long, byteswritten As Long
 ret = WriteFile(hChildStdoutWr, ByVal text, Len(text), byteswritten, ByVal
0&)
 Il risultato è bizzarro: eseguendolo direttamente da vb segnala errore
(chiamata dll non valida), ma potrebbe esser corretto; compilandolo ed
eseguendolo da Dos Console mi appare uno stranissimo msgbox con scritto "0"
e 2 tasti: "Ok" e "?".....vuol dire che non ha trovato lo standard output e
ha quindi rediretto il tutto sull'output "standard" di windows?
(verificata var hChildStdoutWr, l'handle esiste (diverso da zero))
Grazie, se ti viene in mente qualche altro consiglio...

 Mi restituisce -1 (compilo il programma ed eseguo da Dos Console).
Forse dico una ca##ata, ma dovrebbe funzionare solo da eseguibile
compilato, non da IDE.
E poi, io non mischierei le funzionalità Windows e Dos. Prova a fare un
programmino per prova formless, con partenza da una Sub Main, che
prende il testo in StdIn e lo scrive sullo StdOut, e vedi se funzia così.
_____________________________________________
OK, prima di mandare il post ho fatto delle prove. Allora: il -1 è corretto,
o almeno lo fa anche a me e il prg funzia. Quello che non fa è scrivere
sulla finestra Dos :-(( In compenso se reindirizzi il prg su un file funzia... BOH !
Ad esempio, compilando Test.exe e dando al prompt di Dos:
test > prova.txt
...nel file prova.txt c'è esattamente quello che io ho detto di scrivere sullo
StdOut. A questo punto, mi viene in mente che lo stdout non sia quello che
ci vuole per scrivere su una finestra Dos...
Uno "SporcoTrucco®" se hai veramente fretta e non ti importa di fare una
schifezza tecnica, potrebbe essere: invece di lanciare test.exe, lanciare un
file batch, o magari qualcosa del tipo test|more. Ho provato e funziona...
Invece test>con non funzia.
RIBOH !
Bye, G.


Anche io ho il dubbio che non sia questa la strada, funziona effettivamente
ma non reindirizza nulla, ahimé.
Ho provato anche a tenere una finestra Dos aperta, farmi restituire l'handle
e ho provato con WriteFile...nessun errore a video ma uguale, non scrive
nulla.........
Mah, le cose una volta più semplici sembrano ora infattibili....
Grazie comunque (avevo pensato anch'io alla tecnica "sporca" di quel tipo:
scrivo un batch al momento e sulla Console (questo riesco a farlo!) "digito"
dal programma il nome del batch da eseguire seguito da invio; magari come
prima riga metto un cls....fa però un po' schifo...)

 wrote in message
news:9ejl2j$cjv$1...@lacerta.tiscalinet.it...


Fine settimana provo: anche se non è esattamente quello che cerco sarebbe un
ottimo passo avanti...
Grazie

 ha quindi rediretto il tutto sull'output "standard" di windows?
[SNIP]
Ho riletto anche gli altri messaggi e temo ci sia stata un po' di confusione;
questa procedura serve per fare la parte del "padre"; cioe' sei tu che avvii un
processo figlio, con CreateProcess, e leggi/scrivi dati attraverso i suoi canali
di i/o rediretti... se invece fai il contrario, cioe' dalla finestra DOS lanci
questo programma, allora non serve a nulla (infatti ho fatto un'altro errore; la
riga 'If strCommandLine <> "" Then' andrebbe all'inizio di tutta la procedura:
se non abbiamo nessun processo da avviare, non facciamo niente)
Tanto per capirci, prova a sostituire la tua aggiunta con questo:
Dim text As String
Dim ret As Long, byteswritten As Long, lBytesRead As Long
text = "dir /W" & vbCrLf
ret = WriteFile(hChildStdinWrDup, ByVal text, Len(text), byteswritten, ByVal 0&)
text = String(2048, Chr$(0))
ret = ReadFile(hChildStdoutRdDup, ByVal text, 2048, lBytesRead, ByVal 0&)
Debug.Print Left$(text, lBytesRead)
text = "exit" & vbCrLf
ret = WriteFile(hChildStdinWrDup, ByVal text, Len(text), byteswritten, ByVal 0&)
CloseHandle hChildStdinWrDup
CloseHandle hChildStdoutRdDup
e a chiamare la funzione con
StartEngine "c:\windows\
command.com
"
vedrai che viene effettivamente aperta una istanza di command (nascosta),
eseguito il comando dir inviato sullo standard input, catturato l'output e
inviato il comando di chiusura (ricorda di salvare tutto quando lo provi; manca
un po' di codice di chiusura processo e pulizia, se lo lanci molte volte windows
potrebbe offendersi...).
Ma a te serve il contrario, e qui si ritornerebbe al primissimo esempio che ho
postato, o meglio ancora ha quello che ha mandato Ricc, dove pero' hai gia'
visto che, se vuoi scrivere a video, ti ritorna "unable to write to standard
output" mentre se ridirigi su file funziona.
Francamente non saprei cos'altro suggerirti, purtroppo come ho gia detto queste
routine erano nate per far comunicare tra loro applicazioni console win32 e non
applicazione->finestra D0S; come ulteriore tentativo puoi provare a dare un
occhiata qui:
http://www.vb-world.net/api/console/index.html
e' un'articolo che spiega come creare programmi console con VB (quindi non solo
manipolare standard i/o), vedi se ne cavi qualcosa...


Grazie infinite, mi leggo l'articolo