Newsgroup: it.comp.programmare.win32
Titolo: La console in win32...

Salve a tutti,
vorrei proporre un quesito piu' per interesse teorico che pratico.
Mi piacerebbe capire a fondo cos'e', come viene gestita e a che livello
viene gestita la console nei sistemi windows (diciamo sia nei 9x che nei
vari NT anche se mi aspetto che ci siano differenze).
Dopo un po' che ci ho pensato sono giunto alla conclusione che un buon
modo per iniziare a pensarci sia questo: voglio fare un programma che
sostituisca la console. Operativamente, questo coso dovrebbe funzionare
cosi: linea di comando in una finestra NON-dos (ovvero decorata come una
qualsiasi finestra Windows in cui sia contentuto del testo e sulla quale
si possa avere totale controllo) che mi permetta di avviare programmi
e catturarne l'output.... eh, gia' voi penserete... basta una
createprocess e redirezione di stdin, stdout e stderr.... No. Io voglio
redirigere TUTTO l'output... Se il programma stampa su console, io
voglio intercettare quell'output. Avete presente il TurboDebugger?
Quello gira in una finestra di console. la schermata che si vede, non la
si intercetta tramite lo stdout.
Dopo una attenta analisi sono giunto alla conclusione che la console di
Windows sia gestita a livello driver (altrimenti come farebbe a sputare
sullo schermo la schermata del TurboDebugger che e' prodotta scrivendo
nella memoria video (in modo testo)?.
Insomma vorrei capire come dovrebbe essere fatto un programma che
gestisca completamente da solo la console.
Dubbio alternativo (piu' semplice): 
Faccio un programma Windows NON console (che inizia con WinMain per
intenderci). Se voglio, da dentro il programma posso aprire un console 
(Api AllocConsole) e posso scrivere nel suo stdin-out-err.
OK.
Ma se io apro il programma per esempio in pipe con un altro, come faccio
a recuperare lo stdin (oppure stdout) della console dalla quale e' stato
lanciato il programma?
Magari sono solo piste malate. Non insultatemi... :-)
Ciao,
Marco.
______________________________________________
If you want to contact me, there are some alternative ways
 E-Mail:  
m.laur...@cclinf.polito.it
 
m.laur...@studenti.to.it
 
 
m.laur...@tiscalinet.it
 
 
m.laur...@libero.it
 
 PowWow: 
pi...@computing.it
... and PGP key available by request.

 della console dalla quale e' stato lanciato il programma?
Cioe`, una cosa del tipo: io lancio l'applicazione Win32 GUI da riga di
comando, e voglio che sia in grado (un po' "alla unix") di mandare
l'output testuale sulla console che l'ha lanciato? Dubito che si possa
fare, ma forse mi sbaglio.
---
Bye! Lorenzo Lutti
http://www.geocities.com/cirovampiro/

 fare, ma forse mi sbaglio.
Esattamente alla unix :-)
Mi spiego: hai presente il comando "less" (o le sue varianti grafiche)?
E' una cosa che prende dallo stdin e mette ordinatamente in una finestra
scrollabile (su e giu) cio' che arriva dallo stdin.
Per fare un prog. simile sotto win sarebbe semplice: faccio un prog.
console che apre una finestra e ci butta la roba dentro.
Ora pero', lo stesso programma (esattamente come less) dovrebbe poter
accettare anche un nome di un file da listarti sullo schermo. In questo
caso e' lo stdin non viene usato e, se ricordo bene tutti  gli
esperimenti che ho fatto, l'unico modo di chiudere la finestra del
prompt e' quello di forzare la chiusura della console con l'API duale di
AllocConsole (che adesso non ricordo ma che si trova nell'help win32 sdk).
Risultato: la finestra nera si apre e poi si chiude. OK. Pero' non e'
affatto bello.
Insomma, saro' un paranoico lo ammetto, ma quello che volevo fare era un
programma che potesse decidere runtime se comportarsi da programma
console oppure no.
Ma se non si puo' fare, tant'e'... (ovviamente non mi arrendo cosi'
facilmente :-)
Grazie,
Marco.

 writes:
ML> (o le sue varianti grafiche)?
(Hanno fatto  varianti _grafiche_ di  less sotto U*x?  Personalmente lo
trovo uno spreco di tempo.)
ML> Insomma, saro' un paranoico lo ammetto, ma quello che volevo fare era un
ML> programma che potesse decidere runtime se comportarsi da programma
ML> console oppure no.
Beh, una  soluzione sarebbe di  fare un programma non-console  che usa
per l'output printf() e sorelle di stdio.h a meno che un'opzione sulla
command line (qui è meno facile che con la solita coppia argc, **argv)
non gli dica di usare una finestra.
Per  l'input da file  : Se  non ci  sono parametri  (i parametri  e le
opzioni  sono  2  cose   diverse)  allora  legge  da  standard  input,
altrimenti da file.
Probabilmente, usando GetConsoleTitle() o GetConsoleMode() si riesce a
sapere se il processo ha o no una console, e crearne una quando serve.
Oppure  si prevede  un'opzione che  forzi  la creazione  di una  nuova
console (al posto di quella eventuale del processo chiamante).
\begin{avviso}
 
Attenzione: Leggersi lo header riguardo al mio e-mail!
Warning: read header for infos about my e-mail.
\end{avviso}
+----------------------------------------------------------------+
| Gian Uberto Lauri * "So, are you working on fixing that bug    |
| 
sa...@eng.it
      *  *now* or leaving it until later ?" - YES  |
+----------------------------------------------------------------+

 console (al posto di quella eventuale del processo chiamante).
Se il programma e' NON-console qualsiasi console che venga allocata sara'
diversa da quella di lancio (che puo' non esistere se hai avviato dal
Run di windows).
Puo' essere interessante l'idea di cercare la console aperta (ammesso
che esista) e vedere se si riesce a riaprire lo stdin di una specifica
console....
Chissa'....
Grazie,
Marco.

 
http://www.geocities.com/cirovampiro/
Tentare una redirection out-process e' una bella sfida! Non l'ho mai
fatto ma temo che abbia ragione tu. Anche pensando di duplicare gli
handle dello stdin-out-err del processo di una console aperta non si ha
alcuna garanzia che sia quella che effettivamente ha sganciato il
processo. Invece creando una shell ex-novo e redirigendo lo stdin-out-err
dei processi sganciati e' forse possibile. Basta a mio avvio creare una
pipe (CreatePipe), impostare il processo della console sullo stdin-out-err
sulla nuova pipe (SetStdHandle), creare il processo figlio con l'opzione
di ereditare gli handle del padre. A questo punto dal processo figlio
si ottiene l'handle di console con GetStdHandle dal quale e' possibile
scrivere/leggere alla/dalla console via WriteFile()/ReadFile() o
redirigere il tutto via SetStdHandle. Cosa ne pensi?
Ciao.
Il Michett@
--

 di ereditare gli handle del padre.
Si`, cosi` funziona senz'altro (l'ho fatto piu` volte), ma qui il
problema e` il contrario: il nostro programma e` il "lanciato", non il
"lanciante". In generale non abbiamo controllo su come gli altri
processi lanciano il nostro.


 nell'help win32 sdk).
Il tuo problema si risolverebbe lanciando la console passando SW_HIDE a
CreateProcess(), e poi (nel caso che serva) rendendola visibile solo in
un secondo tempo. Pero` come dicevo nell'altro messaggio noi siamo i
"chiamati", e non abbiamo nessun controllo su come viene chiamata
CreateProcess().
A questo punto ci si riallaccia a una domanda che ho fatto io tempo fa,
e che rimane tutt'ora senza una risposta: come si puo` fare in modo che
un'applicazione console pensi essa stessa a nascondersi quando viene
lanciata? Apparentemente non e` possibile, sembra che la console venga
creata dal codice di sistema e non dal codice 'stub' contenuto nel
nostro eseguibile. Quindi al massimo puoi nasconderla appena puoi, ma il
flash antiestetico rimane. :-(


Ciao,
da poco programmo in vc6 e da cio' che ho letto nella vostra discussione
mi pare che possiate aiutarmi.
La mia applicazione principale dovrebbe caricare da un menu un
eseguibile Dos che apre una console e prende delle informazioni dallo
standard input rilasciando delle informazioni nello sandard output.
Vorrei riuscire a reindirizzare lo stdout su un file in modo da poterlo
visualizzare in seguito. Non sono sicuro di avere capito perfettamente
come fare per intercettare l'handle che mi interessa e soprattutto come
fare per reindirizzarlo su un file.
Prima riuscivo a caricare l'applicazione con ShellExecuteEx ma ottenevo
solo l'output sulla console. Se qualcuno potesse darmi qualche consiglio
e un paio di righe di codice ..... 
Grazie in anticipo.
	Stefano

 e un paio di righe di codice .....
Per reindirizzare stdin/out/err devi usare CreateProcess(), che ti
permette di specificare tali handles. Quindi ti basta creare tre pipes
con CreatePipe(), creare il processo in modo che possa ereditare gli
handles del genitore e usare quelle.
Questo codice lancia nascosta un'applicazione in console (funziona sia
con i programmi DOS che con quelli Win32) passandole nello stdin un
buffer e leggendo il risultato su stdout/err. E` fatto per le MFC, ma e`
facilmente riadattabile (basta usare stringhe normali al posto di
CString):
(pero` un'altra volta guarda anche su Deja, e` la terza volta che lo
posto!)
BOOL CWndDummy::Filtro_EseguiEsterno( CString& str, CString& prg)
{
 CString dopo;
 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 // Crea una pipe per stdin e una per stdout
 SECURITY_ATTRIBUTES sa;
 HANDLE in[2], out[2];
 ::FillMemory( &sa, sizeof(sa), 0);
 sa.nLength = sizeof(sa);
 sa.bInheritHandle = TRUE;
 if( !::CreatePipe( &out[0], &out[1], &sa, 0))
  return FALSE;
 if( !::CreatePipe( &in[0], &in[1], &sa, 0))
 {
  ::CloseHandle( out[0]);
  ::CloseHandle( out[1]);
  return FALSE;
 }
 // Lancia il filtro esterno, con gli handles modificati
 FillMemory( &si, sizeof(si), 0);
 si.cb = sizeof(si);
 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
 si.wShowWindow = SW_HIDE;
 si.hStdOutput = si.hStdError = out[1];
 si.hStdInput = in[0];
 if( !::CreateProcess( NULL, (char *)LPCTSTR(prg), NULL, NULL,
  TRUE, 0, NULL, NULL, &si, &pi))
 {
  ::CloseHandle( out[0]);
  ::CloseHandle( out[1]);
  ::CloseHandle( in[0]);
  ::CloseHandle( in[1]);
  return FALSE;
 }
 // Chiude i lati che non servono piu`
 ::CloseHandle( out[1]);
 ::CloseHandle( in[0]);
 // Spedisce nell'stdin dell'altro processo il messaggio (con
 // EOF alla fine)...
 str += "\032\r\n";
 int a=0, n=str.GetLength();
 DWORD nIO;
 while( a<n)
 {
  if( !::WriteFile( in[1], LPCTSTR(str.Mid(a)), n-a, &nIO, NULL) ||
    nIO == 0)
   break;
  a += nIO;
 }
 ::CloseHandle( in[1]);
 // ...e legge il risultato dal suo stdout
 char buf[64];
 while( ::ReadFile( out[0], buf, 64, &nIO, NULL) && nIO>0)
  dopo += CString( buf, nIO);
 ::CloseHandle( out[0]);
 str = dopo;
 return TRUE;


dici cosa esce..... ;-)
Delphi mi da' handle non valido, idem WSH in modalità console. Te credo, 
stdin non esiste, dove scrive? In compenso, usa il programma come CGI, e 
dimmi cosa esce :)

vari NT anche se mi aspetto che ci siano differenze).
leggiucchiando all'interno di file, andando un po' a naso e un po' a culo, 
smanettando ecc ecc ho scoperto che:
 - la console è un eseguibile 16 bit (winoldap.mod nella cartella 
%windir%\system), che non viene eseguito direttamente (impossibile perchè 
risulta linkato ad una dll inesistente) ma caricato da... boh? che 
evidentemente rimappa in memoria la dll mancante (suppongo dunque si tratti 
del kernel)
 - i programmi DOS quando avviati generano due thread: uno è il programma 
in sè, l'altro è una delle mille propaggini di kernel32.dll, la famosa 
goccia 32 bit nel mare 16 bit di Windows
 - la finestra della console viene identificata dagli altri processi come 
appartenente al processo kernel32.dll (com'è possibile che sia residente 
come un exe se si tratta solo di una dll? mysteri)
quindi occorrerebbe:
 - sostituire winoldap.mod con un exe 16 bit che abbia il medesimo header
 - rinominare kernel32.dll e sostituirlo con una dll che faccia da "ponte"
 - fucilare il team responsabile di Windows e chiedere all'ultimo 
superstite di consegnarci il sorgente

trovo uno spreco di tempo.)
eccome! xless (per X11) e kless (per KDE)
spreco di tempo mica tanto, dato che less nativamente mi sembra non abbia 
una funzione di ricerca. E dato che *nix non distingue tra applicazioni 
console e applicazioni GUI (dato che le applicazioni sono in realtà tutte 
console, e l'unica applicazione GUI propriamente detta è l'X-server, che 
poi è molto più vicino ad un device driver che ad un eseguibile)