Windows API ako zistiť či aplikácia má výstup na konzolu?

Neviem či to patrí zrovna na root, ale chodia sem ľudia s dosť širokými znalosťami tak skúsim tu.

Pomocou CreateProcessW spúšťam z môjho programu rôzne externé aplikácie. Po dokončení aplikácie sa snažím z pipe prečítať jej výstup a logovať ho do súboru. Funguje to s konzolovými aplikáciami, alebo zmiešanými aplikáciami (ktoré majú výstup na konzolu a zároveň zobrazujú aj okná). No ak prečítam výstup z aplikácie ktorá nemá vôbec žiadny textový výstup, ale je čisto len okenná tak to celé zamrzne. Žiaľ neviem ako mám rozlíšiť spúšťanú aplikáciu medzi takou ktorá má alebo nemá / výstup na konzolu a vyhnúť sa čítaniu z neexistujúcej pipe. Vygooglil som si že aplikácie ktoré majú kozolový výstup volajú AllocConsole z kernel32.dll:

Kód: [Vybrat]
[DllImport("kernel32.dll")]
private static extern bool AllocConsole();

Ale ako mám zistiť či mnou spúšťaná aplikácia volá túto funkciu?


Re:Windows API ako zistiť či aplikácia má výstup na konzolu?
« Odpověď #1 kdy: 05. 04. 2020, 00:16:46 »
Jestli to chápu správně, tak máte problém s aplikacemi, které nezapisují na standardní výstup, takže váš pokus o čtení příslušné roury "zamrzne" (čeká se na data, která nemusí nikdy přijít).

Pokud se tomuto chcete vyhnout, čtěte z rour asynchronně. Má to i výhodu v tom, že aplikace může psát na standardní výstup i standardní chybový výstup, což pro vás může být zajímavé rozlišit. Mrkněte na poslední parametr funkce ReadFile či na funkci ReadFileEx. Myslím ale, že pro asynchronní operace budete muset roury vytvářet přes CreateNamedPipe, abyste jim mohl nastavit FILE_FLAG_OVERLAPPED, protože pohodlné CreatePipe toto specifikovat nedovoluje.

Aplikace nemusí alokovat vlastní konzoli přes AllocConsole, ale může se připojit např. na konzoli svého rodiče (AttachConsole). Záleží také, jaké příznaky předáte při volání CreateProcess (pár jich ovlivňuje konzolové chování).

Pokud se vám nechce číst asynchronně, možná by se dalo vše zařídit tak, že vytvoříte vlastní rouru a předáte ji aplikaci jako standardní výstupy. Pokud bude ke každému konci roury existovat nejvýše jedno handle, vaše aplikace "odmrzne", jakmile spuštěná aplikace zavře handle ke svému konci roury (dostanete něco jako ERROR_BROKEN_PIPE). Problém samozřejmě je, že aplikace obvykle zavírají tato handle až v momeně svého ukončení.

Re:Windows API ako zistiť či aplikácia má výstup na konzolu?
« Odpověď #2 kdy: 05. 04. 2020, 20:26:34 »
Jestli to chápu správně, tak máte problém s aplikacemi, které nezapisují na standardní výstup, takže váš pokus o čtení příslušné roury "zamrzne" (čeká se na data, která nemusí nikdy přijít).

Pokud se tomuto chcete vyhnout, čtěte z rour asynchronně. Má to i výhodu v tom, že aplikace může psát na standardní výstup i standardní chybový výstup, což pro vás může být zajímavé rozlišit. Mrkněte na poslední parametr funkce ReadFile či na funkci ReadFileEx. Myslím ale, že pro asynchronní operace budete muset roury vytvářet přes CreateNamedPipe, abyste jim mohl nastavit FILE_FLAG_OVERLAPPED, protože pohodlné CreatePipe toto specifikovat nedovoluje.

Aplikace nemusí alokovat vlastní konzoli přes AllocConsole, ale může se připojit např. na konzoli svého rodiče (AttachConsole). Záleží také, jaké příznaky předáte při volání CreateProcess (pár jich ovlivňuje konzolové chování).

Pokud se vám nechce číst asynchronně, možná by se dalo vše zařídit tak, že vytvoříte vlastní rouru a předáte ji aplikaci jako standardní výstupy. Pokud bude ke každému konci roury existovat nejvýše jedno handle, vaše aplikace "odmrzne", jakmile spuštěná aplikace zavře handle ke svému konci roury (dostanete něco jako ERROR_BROKEN_PIPE). Problém samozřejmě je, že aplikace obvykle zavírají tato handle až v momeně svého ukončení.

Ďakujem Vám za vyčerpávajúci popis ako to riešiť. Skúsim teda to asynchrónne čítane. Vidím že máte výborný prehľad vo Windows API.

Re:Windows API ako zistiť či aplikácia má výstup na konzolu?
« Odpověď #3 kdy: 05. 04. 2020, 22:17:45 »
Citace
Ďakujem Vám za vyčerpávajúci popis ako to riešiť. Skúsim teda to asynchrónne čítane. Vidím že máte výborný prehľad vo Windows API.
Ve Windows právě není tak zvykem komunikovat přes standardní vstup a výstup, zejména ne u okenních aplikací. I různé ladící výpisy se často řeší jinak, třeba přes funkci OutputDebugString, která dovoluje odelsat zprávu debuggeru.

Možná spíš zkuste napsat, jaký problém přesně řešíte, protože třeba jej půjde vyřešit použitím vhodných funkcí Windows API místo volání externích programů a parsování jejich vstupu.

Re:Windows API ako zistiť či aplikácia má výstup na konzolu?
« Odpověď #4 kdy: 07. 04. 2020, 20:24:59 »
Citace
Ďakujem Vám za vyčerpávajúci popis ako to riešiť. Skúsim teda to asynchrónne čítane. Vidím že máte výborný prehľad vo Windows API.
Ve Windows právě není tak zvykem komunikovat přes standardní vstup a výstup, zejména ne u okenních aplikací. I různé ladící výpisy se často řeší jinak, třeba přes funkci OutputDebugString, která dovoluje odelsat zprávu debuggeru.

Možná spíš zkuste napsat, jaký problém přesně řešíte, protože třeba jej půjde vyřešit použitím vhodných funkcí Windows API místo volání externích programů a parsování jejich vstupu.

Ja práveže chcem volať externé programy, tá aplikácia slúži na spúštanie externých programov. Ale keď náhodou ten externý program spadne, tak výstup chcem logovať do súboru. Viem že niečo podobné má už zabudované v sebe aj OS. Ale chcel som vlastné customizovateľné riešenie, presne na mieru mojim potrebám a chcel som sa pritom aj niečo nové naučiť.

Ja to už vlastne mám aj hotové až na túto jednu vec.


Re:Windows API ako zistiť či aplikácia má výstup na konzolu?
« Odpověď #5 kdy: 10. 04. 2020, 12:58:26 »
...

Išiel som podľa Vašich rád no nakoľko nie som vo Win32 API ažtak moc zbehlý ako vy, musel som si vygoogliť nejaké príklady. Na základe, ktorých som si potom upravil CreatePipeW s FILE_FLAG_OVERLAPPED

Tu je zdroják dal som ho na pastebin nech je to pekne naformátované:
https://pastebin.com/R6NT11pp

Funkcia končí na riadku 57 to znamená že CreateFileW() vracia hodnotu INVALID_HANDLE_VALUE a nechápem prečo idem zistiť aký bude GetLastError.

Re:Windows API ako zistiť či aplikácia má výstup na konzolu?
« Odpověď #6 kdy: 10. 04. 2020, 13:10:19 »
Ale už mi to funguje, len som predtým nepoužil správny názov pipe, treba použiť niečo takéto:

Kód: [Vybrat]
L"\\\\.\\pipe\\stdOutPipe"
Ďakujem za pomoc a nasmerovanie.

Re:Windows API ako zistiť či aplikácia má výstup na konzolu?
« Odpověď #7 kdy: 10. 04. 2020, 15:11:59 »
Nemyslim si ze to bude niekto potrebovat, ale ked uz som tu o tom zalozil forum a niekto nan nahodou narazi ked bude riesit podobny problem tak mozno mu to pride vhod v jeho vyrieseni:


Ked vytvaram pipe pomocou mojej custom CreatePipeW() a aplikacia nema vystup na kozolu tak GetLastError() vracia hodnotu ERROR_PIPE_BUSY. To znamena ze dokopy treba osetrit 3 mozne stavy:

1. Pokial sa zachyti ERROR_PIPE_BUSY pojde sa dalej bez pipe.  Toto je stav pri aplikaciach ktore nemaju konzolu.
2. A ak sa nevrati ziaden error tak sa ide dalej s pipe. Toto je stav pri aplikaciach ktore maju konzolu.
3. Ak sa vrati iny error thrownem exception s prislusnym kodom (viem ze windows api nema rado exceptiony, ale ja hej)