[WinAPI] Jak rozpoznać typ stdout (screen, file, null, pipe)

0

Tak sobie obserwuję niektóre polecenia w konsoli windows i widzę rzecz w zasadzie oczywistą. Jeśli polecenie wywala x stron tekstu, to często robi przerwę co 25/50 lini:

c:\> if /?
długi
długi tekst
...
Aby kontynuować, naciśnij dowolny klawisz . . . 
reszta długiego
długiego tekstu
...
Aby kontynuować, naciśnij dowolny klawisz . . . 
itd

A jeśli wynik polecenia przekierujemy do pliku, to rzecz jasna, nikt o klawisz nie prosi:

c:\> if /? > out.txt

i mamy w pliku natychmiast wszystkie 100,200, x-set lini.

Jak to rozpoznać, że w programie dając na cout piszemy do pliku?
A może nawet jak rozpoznać, że przekierowano nas do null - w takim wypadku może mój program na przykład powstrzyma się od pisania, bo i tak to leci w powietrze...

Czasem niektóre komunikaty nie dają się przekierować - są pisane na ekran bez względu na przekierowania. Jak za pomocą rozsądnych metod (mile widziane WinAPI) pisać bezpośrednio do konsoli, a nie na stdout?

I na koniec rzecz, która mi się marzy. Załóżmy, że mam programik jakiś. Jeśli wywołany zostanie z konsoli poleceniem, to wypisze tekst na konsolę. Jeśli zostanie uruchomiony podwójnym klikiem, to zamiast pisać na konsolę, wyświetli np MessageBox. Inaczej: czy da się napisać jeden "program.exe", który zachowuje się jak konsolowy albo GUI zależnie od kontekstu wywołania? Czy to w sumie nie sprowadzałoby się do tego, żeby sprawdzić, co programik uruchomiło: proces "cmd.exe" czy "explorer.exe"? Czy windows programowi podaje proces "rodzica" na tyle fajnie, żeby się dało dobrać do pliku .exe rodzica i sprawdzić we właściwościach obrazu czy jest skompilowany jako Win32 GUI, czy jako Win32 Console?

0

A jeśli wynik polecenia przekierujemy do pliku, to rzecz jasna, nikt o klawisz nie prosi

to nie kwestia stdout'a, chociaz tak moze to wygladac :) tutaj spraw tkwi w tym, ze STDIN jest ZAMKNIETY. proba czytania znaku z stdin'a zwraca stan eof no i ... juz wiadomo ze stdin nie jest otwarty w trybie interaktywnym - nie jest skojarzony z terminalem

Jak to rozpoznać, że w programie dając na cout piszemy do pliku?

imho, nie da sie jednoznacznie i pewnie. ewentualnie moznaby pobrac deskryptor pliku i probowac jakichs informacji o nim zebrac

Czasem niektóre komunikaty nie dają się przekierować

te komunikaty sa wywalane na stderr (cerr) nie na stdout (cout). w windozowej konsoli, blah > bleh powoduje przekierowanie stdout'a, a stderr pozostaje skojarzony z terminalem

czy da się napisać jeden "program.exe", który zachowuje się jak konsolowy albo GUI zależnie od kontekstu wywołania

hym.. a tutaj zagwostka. wydaje mi sie ze nie. jesli program kompilowany na podsystem WIN32/CONSOLE odpalisz dwuklikiem to otworzy sie okno konsoli no i .. bedzie terminal, strumienie beda w 100% poprawne, tak samo jakbys odpalal w linii polecen.

pewna pomoca moglobybyc ogladanie argv[0] oraz pwd. zazwyczaj, w konsoli, jak sie program odpala z palca, to argv[0] wskazuje na pwd. z kolei jak dwuklikniesz, to pwd ustawia sie na homedir (c/docs&sett/user/) a argv[0] zawieralby pewnie wtedy np. c/programf/mojprog/mojprog.exe... ale ale to takie malo dajace, bo przeciez w skrocie do programu mozna inny workingdir ustawic, albo tez pod konsola odpalac np. ze sciezka absolutna..

oooooooo, mam: trzeba w jakis sposob dorwac kto jest Twoim parentem. jesli ParentProcess == cmd.exe || command.com/exe to znaczy ze odpalony byl z palca, a jesli explorer.exe -- prosto z 'pulpitu'.. no sa jeszcze totalcommandery itp.. wiec na explorer.exe nie mozna polegac. na cmd/command - mozna. bedzie tylko problem jesli chcialbys swoj program odpalac przez np. jakiegos .bat -- bo wtedy bat otworzy cmd a dopiero cmd odpali program.. ale poza tym przypadkiem - powinno byc ok

edit: buahaha.. przyczytalem pytanie, nie doczytalem do konca i wpadlem na to samo wyjscie..
co do subsystem rodzica - generalnie, jak poznasz parenta, to jestes w stanie dowiedziec sie od systemu na jakiej sciezce lezy jego plik.exe, wiec jestes w stanie sobie go otworzyc w binarysharedread i patrzec do srodka ile wlezie. ale --- to jest takie na okolo mocno.. wydaje mi sie ze rozpoznawanie po nazwie cmd-nie-cmd powinno wystarczyc do prostych 'ukladow'.. tak jak mowilem, problem pojawialby sie tylko w przypadku gdy twoj prog bylby wywolywany przez jeszcze-cos-innego niz bezposrendio przez usera

a tak w ogole, to do takich tych tam to zwykle stosuje sie po prostu... przelaczniki. jakies /s(ilent) czy /n(oninteractive) czy /c(onsole) i po prostu programowi sie mowi jak sie ma odpalic

0

a może się komuś przyda. Trochę czasu minęło od kiedy pytałem, później od kiedy znalazłem, a jeszcze dłużej, żebym sobie przypomniał o poście na forum przypadkowo ;)

przekierowania. ekran i klawiatura SĄ NIEZALEŻNE. Można dać program<input.txt, można program>output.txt. Pierwszy ma dostęp do ekranu, drugi do klawiatury. Jak rozróżnić przekierowania:

DWORD mode;
if( GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode) )
    // piszemy na ekran

if( GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode) )
    // dostaliśmy prawdziwą klawiaturę

i jeśli na ekran nie piszemy, to możemy zdecydować sami, że nie będziemy interaktywni... z drugiej strony interaktywni możemy być. Funkcje modułu msvcrt:

/* Wymusza pracę z klawiaturą/ekranem, bez względu na przekierowania: */
getch() // klawisz z klawiatury
cscanf(fmt, ...) // tekst z klawiatury
cprintf(fmt, ...) // wyjście na ekran

/* Normalna praca ze stdin/stdout */
scanf
printf

Z tym rodzajem uruchomienia. Można po parencie, można oprzeć się na specyficznej zależności: konsolowy program uruchomiony klikiem dostaje zdarzenia myszy:

DWORD mode;
DWORD result = GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
if( result & ENABLE_MOUSE_INPUT) 
   // mamy myszę, więc ktoś klikł
   // w przeciwnym wypadku jesteśmy uruchomieniu z linii poleceń, "start|uruchom", albo innego skryptu

1 użytkowników online, w tym zalogowanych: 0, gości: 1