windows - win32 GUI app, der skriver brugen tekst til stdout når påkaldt som 'app.exe - help'

Indlæg af Hanne Mølgaard Plasc

Problem



Hvordan opretter jeg et Windows-program, der gør følgende:



  • Det er en almindelig GUI-app, når den påberåbes uden argumenter for kommandolinjer

  • angiver det valgfrie '--help' kommandolinjeprincip får appen til at skrive brugstekst til stdout derefter opsige

  • Det skal være en enkelt eksekverbar. Ingen snyd ved at lave en konsol app exec en 2. eksekverbar.

  • Antag, at hovedprogrammet er skrevet i C/C ++

  • bonuspoint, hvis der ikke oprettes et GUI-vindue, når '--help' er angivet. (dvs. ingen flimmer fra et kortlivet vindue)



I min erfaring har den standard visuelle studio skabelon til konsol app ingen GUI kapacitet, og den normale win32 skabelon sender ikke sin stdout til den overordnede cmd shell.

Bedste reference


Microsoft designet konsol og GUI apps til at udelukke hinanden.
Denne bit af kortsynethed betyder, at der ikke er nogen perfekt løsning.
Den mest populære tilgang er at have to eksekverbare filer (f.eks. Cscript/wscript,
java/javaw, devenv.com/devenv.exe osv.) men du har angivet, at du overvejer dette 'snyd'.


Du har to muligheder - for at lave en 'konsol eksekverbar' eller en 'gui executable',
og brug derefter kode for at forsøge at give den anden adfærd.



  • GUI eksekverbar:



cmd.exe vil antage, at dit program ikke har en konsol I/O, så det vil ikke vente på, at det skal opsiges
før du fortsætter, hvilket i interaktiv tilstand (dvs. ikke en batch) betyder at vise den næste ('C:>' prompt
og læsning fra tastaturet. Så selvom du bruger AttachConsole, bliver din output blandet
med cmd s output, og situationen bliver værre, hvis du forsøger at gøre input. Dette er dybest set en ikke-starter.



  • Konsol eksekverbar:



I modsætning til tro er der intet at stoppe en konsol eksekverbar fra at vise en GUI, men der er to problemer.


Den første er, at hvis du kører det fra kommandolinjen uden argumenter (så du vil have GUI)
cmd vil stadig vente på, at den skal opsige, før den fortsætter, så den særlige
konsollen vil være ubrugelig for varigheden. Dette kan overvindes ved lanceringen
en anden proces af den samme eksekverbare (mener du dette snyd?),
passerer DETACHED\_PROCESS flag til CreateProcess () og straks forlader.
Den nye proces kan så opdage, at den ikke har nogen konsol og vise GUI'en.


Her er C-kode for at illustrere denne tilgang:


#include <stdio.h>
#include <windows.h>

int main(int argc, char *argv[])
{
    if (GetStdHandle(STD\_OUTPUT\_HANDLE) == 0) // no console, we must be the child process
    {
        MessageBox(0, "Hello GUI world!", "", 0);
    }
    else if (argc > 1) // we have command line args
    {
        printf("Hello console world!
");
    }
    else // no command line args but a console - launch child process
    {
        DWORD dwCreationFlags = CREATE\_DEFAULT\_ERROR\_MODE | DETACHED\_PROCESS;
        STARTUPINFO startinfo;
        PROCESS\_INFORMATION procinfo;
        ZeroMemory(&startinfo, sizeof(startinfo));
        startinfo.cb = sizeof(startinfo);
        if (!CreateProcess(NULL, argv[0], NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &startinfo, &procinfo))
            MessageBox(0, "CreateProcess() failed :(", "", 0);
    }
    exit(0);
}


Jeg kompilerede det med cygwin s gcc - YMMV med MSVC.


Det andet problem er, at når du kører fra Explorer, vil dit program gå i et split sekund
Vis et konsolvindue. Der er ingen programmatisk vej rundt om dette, fordi konsollen er
oprettet af Windows, når appen er lanceret, inden den begynder at køre. Det eneste du kan
gør det i din installatør, lav snarvejen til dit program med en 'show command' af
SW\_HIDE (dvs. 0). Dette påvirker kun konsollen, medmindre du med vilje respekterer wShowWindow-feltet i STARTUPINFO
i dit program, så gør det ikke.


Jeg har testet dette ved at hackt cygwin 's' mkshortcut.exe '. Hvordan du opnår
det i dit installerede program valg er op til dig.


Brugeren kan selvfølgelig køre dit program ved at finde den eksekverbare i Explorer og
dobbeltklikke på det, omgå den konsol-skjule genvej og se den korte sorte flash i et konsolvindue. Der er ikke noget du kan gøre ved det.

Andre referencer 1


Du kan bruge AllocConsole() WinApi-funktionen til at tildele en konsol til GUI-applikation. Du kan også prøve at vedhæfte en konsol til en forældersproces med AttachConsole(), det giver mening, hvis den allerede har en. Den komplette kode med omdirigering af stdout og stderr til denne konsol vil være som denne: [12] [13]


if(AttachConsole(ATTACH\_PARENT\_PROCESS) || AllocConsole()){
    freopen("CONOUT$", "w", stdout);
    freopen("CONOUT$", "w", stderr);
}


Jeg fandt denne tilgang i Pidgin-kilderne (se WinMain() i pidgin/win32/winpidgin.c) [14]

Andre referencer 2


Jeg ved, at mit svar kommer sent, men jeg tror, ​​at den foretrukne teknik til situationen her er '.com' og '.exe' -metoden.


Dette kan betragtes som 'snyd' ved din definition af to eksekverbare, men det kræver meget lille ændring på programmørens del og kan gøres en og glemmes. Også denne løsning har ikke ulemperne ved Hughs løsning, hvor du har en konsolvindue, der vises i et split sekund.


I Windows fra kommandolinjen, hvis du kører et program og ikke angiver en udvidelse, foretrækker rækkefølgen for at finde den eksekverbare, en .com over en .exe.


Derefter kan du bruge tricks til at have, at '.com' er en proxy for stdin/stdout/stderr og lancere den samme navngivne .exe-fil. Dette giver adfærden om at tillade programmet at præforme i en kommandolinjemodus, når den kaldes danne en konsol (muligvis kun når visse kommandolinjeforskere er registreret), mens du stadig kan starte som en GUI-applikation fri for en konsol.


Der er forskellige artikler, der beskriver dette som 'Hvordan laver man en applikation som både GUI og Console application?' (se referencer i link nedenfor).


Jeg var vært for et projekt kaldet dualsubsystem på google kode, der opdaterer en gammel codeguru løsning af denne teknik og giver kildekoden og arbejder eksempel binarier. [15]


Jeg håber det er nyttigt!