Newsgroup: it.comp.lang.visual-basic
Titolo: stdIn & stdOut

Ritorno (vivo, vegeto e vincitore!) dall'esame di maturità con un quesito
spinosissimo: applicazioni console in VB.
Aprire la console non è stato un problema.
Cambiare il colore del testo non è stato un problema.
Ottenere gli handle per stdIn e stdOut non è stato un problema.
RIUSCIRE A SCRIVERE UNA BANALE STRINGA DI TESTO NELLA CONSOLE MI STA FACENDO
USCIRE IL CERVELLO DALLE ORECCHIE!
hem hem... ok, non è una tragedia, ma mi urta molto.
Ecco il codice incriminato (ometto le declare):
Sub main()
Dim sbuf As String, lbuf As Long, hCon As Long, hConIn As Long, hConOut As Long
Dim hStdIn As Long, hStdOut As Long, inBuf As String
Dim charsRead As Long, charsWritten As Long
'Qui cerco di ottenere gli handle I/O della periferica CON, per sapere se
'la console è già aperta o se devo allocarne una
hConIn = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ, _
ByVal 0&, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
hConOut = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, _
ByVal 0&, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
If hConOut = -1 or hConIn = -1 Then
'La console non è ancora stata aperta o quella già aperta non se la passa
'mica tanto bene. Ci penso io
    hCon = AllocConsole()
'Si spera che stavolta gli handle siano validi (io mi fido)
    hConIn = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ, _
    ByVal 0&, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
    hConOut = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, _
    ByVal 0&, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
End If
'Cambio il titolo della console
SetConsoleTitle "Hello world!!!"
'Cambio l'input della console in modo da terminare ad ogni pressione del
'tasto INVIO (veramente vorrei semplicemente che la lettura dell'input
'terminasse ad OGNI tasto premuto, ma tant'è, non c'è verso di farlo
'funzionare altrimenti)
SetConsoleMode hConIn, ENABLE_ECHO_INPUT Or ENABLE_LINE_INPUT
'"Io sono un'applicazione console molto educata e scrivo nello Standard
'Output, non come certi programmi che scrivono direttamente sulla console,
'che poi non si possono usare pipe e redirezionamento"
hStdIn = GetStdHandle(STD_INPUT_HANDLE)
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
'Cambio il testo della console in rosso evidenziato.
'Il caret, stranamente, rimane grigio, ma in fondo non mi importa
SetConsoleTextAttribute hStdOut, FOREGROUND_INTENSITY Or FOREGROUND_RED
'Testo che mi piacerebbe scrivere nello Standard Output
sbuf = "Hello world!!!" + Chr(7) 'Chr(7) è il carattere BELL, cioè il beep
'Per terminare, mi basta che l'utente prema un tasto qualsiasi! GIURO!
inBuf = Space(1)
'TADAAAN! eccoci qui.
'Qualcuno mi spieghi perchè questa robaccia non funziona!!!
'Vengono scritti Len(sbuf) caratteri, ok, e charsWritten effettivamente
'contiene questo valore... ma, selezioniamo la console sulla taskbar...
'vediamo una manciata di caratteri assolutamente casuali scritti belli in
'rosso, effettivamente della stessa lunghezza della stringa che sto cercando
'di scriverci io... ma NON c'è quello che vorrei scrivere io, proprio no!
'Ah, ho cambiato le Declare sia di WriteFile che di ReadFile, in modo che
'l'ultimo parametro sia As Any, anzichè As OVERLAPPED. Questo per poter
'passare impunemente un Null (in VB, ByVal 0&) a dette funzioni. La
'documentazione ufficiale dice che si può, e l'ho già sperimentato con
'successo in altre occasioni
WriteFile hStdOut, sbuf, Len(sbuf), charsWritten, ByVal 0&
'Mi metto in ascolto sullo stdIn
Do
'ReadFile aspetta che lo stdIn contenga almeno 1 carattere (almeno dovrebbe,
'in realtà ritorna solo dopo un avanzamento di riga, anzi, spesso, quando
'ritorna in questo modo, OLEAUT (???) va in crash [viene chiamata anche se
'è stata rimossa dai Riferimenti del progetto???]: "Automazione OLE ha
'cercato di accedere ad un'area di memoria inesistente". Bah.
ReadFile hStdIn, inBuf, 1, charsRead, ByVal 0&
'Se dio vuole siamo arrivati fin qui (a volte VB se ne esce con "Out of
'memory", ma un Resume Next e zitto e mosca).
'Se ReadFile ha letto almeno un carattere (uno gliene ho chiesto, almeno
'quello, non mi sembra una richiesta eccessiva), usciamo dal loop e ci
'avviamo verso il viale del tramonto, sennò esclamiamo "mannaggia!" e ci
'rimettiamo in ascolto. Niente DoEvents, come potete vedere: in fondo
'un'applicazione console serve proprio a rilassarsi e per un po' dimenticarsi
'che là fuori è tutto un guizzare di Window Message, mentre qui siamo
'accoglientemente ospitati dal Kernel, che mantiene un thread tutto per noi
'che si occupi di lavori servili come il ridisegno della finestra della console
'e simili bazzecole. Tutto questo per evitare inutili sprechi di risorse
'(l'applicazione pretenderebbe di diventare un UUEncoder/Decoder, lo sarà
'quando avrò sistemato questo problemino e quando saprò come funziona UUE,
'quindi probabilmente mai)
If charsRead Then Exit Do
Loop
'Basta accussì, achiudiamo la console e andiamo a nanna
FreeConsole
End
End Sub

 Ritorno (vivo, vegeto e vincitore!) dall'esame di maturitą
[...]
Congratulazioni!
--
Ciao.
Maurizio