FAQ der Newsgroup de.comp.lang.assembler (d.c.l.a.)

Wie verhindere ich das Öffnen einer Konsole in Windows?

Manche Programme öffnen eine Konsole (Eingabeaufforderungsfenster), wenn sie per Mausklick gestartet werden. Diese Konsole bleibt während der Laufzeit des Programms offen. Ein kurzes Beispiel soll diesen Effekt verdeutlichen:

Nasm & GoLink
; Assemblieren: nasm.exe -fwin32 -o <Name>.obj <Name>.nasm
; Linken:       GoLink.exe /console /entry _main <Name>.obj user32.dll
SECTION .data
    MsgText  db "Hallo Welt",0
    Caption  db "Mitteilung",0
EXTERN MessageBoxA  ; user32.dll
SECTION .text
GLOBAL _main
_main:
    push 0
    push Caption
    push MsgText
    push 0
    call MessageBoxA
    mov eax, 0
    ret

Wenn man dieses Programm assembliert, wie angegeben linkt (mit Option /console) und per Klick im Windows-Explorer startet, öffnet sich eine schwarze Konsole und darüber die Message-Box. Beides verschwindet erst mit einem Klick auf OK.

Verantwortlich für dieses Verhalten ist das Subsystem-Flag im PE-Header der EXE-Datei. Normalerweise interessieren nur zwei der verschiedenenen Subsysteme: Console (CUI - Console User Interface) und Windows (GUI - Graphical User Interface). Das Console-Subsystem öffnet eine Konsole, wenn das Programm nicht bereits eine Konsole zur Verfügung hat. Beim Windows-Subsystem muss der Programmierer selbst das Erscheinungsbild des Programms bestimmen. Dieses Subsystem ist auch das richtige Subsystem, wenn man überhaupt kein Erscheinungsbild haben möchte.

Das Subsystem-Flag wird vom Linker gesetzt. Hier die Kommandozeilenparameter einiger Linker für das Setzen des Windows-Subsystem-Flags:

GoLink.exekeine (stellt defaultmäßig GUI-Applikationen her)
link.exe (Microsoft)/SUBSYSTEM:WINDOWS
ml.exe, cl.exe (Microsoft)/link /SUBSYSTEM:WINDOWS
tlink32.exe (Borland)/aa
gcc.exe (MingW, CygWin)-mwindows oder -Wl,--subsystem,windows
ld.exe (MingW, CygWin)--subsystem,windows
alink.exe-subsys win

Das Subsystem-Flag kann auch nachträglich gesetzt werden. In jedem Visual-Studio-Paket befindet sich der COFF-Binärdatei-Editor EditBin.exe, mit dem man das Subsystem-Flag ändern kann.

Die Eigenentwicklung rbSubSys kann mit Nasm-Quellcode hier heruntergeladen werden.

Der große Nachteil besteht darin, dass ein GUI-Programm zwar von der Konsole gestartet werden kann, aber keine Ausgabe an diese Konsole senden kann. Ab Windows XP gibt es die Kernel-Funktion AttachConsole(-1), mit der man eine Ausgabe wenigstens über "start /wait ..." erzwingen kann:

Nasm & GoLink
; Assemblieren: nasm.exe -fwin32 -o <Name>.obj <Name>.nasm
; Linken:       GoLink.exe /entry _main <Name>.obj kernel32.dll user32.dll
; Starten:      Von der Konsole: start /wait <Name>.exe

SECTION .data
    String1     db "Hallo Welt von Konsole",10
    lString1    EQU $-String1
    Caption     db "Mitteilung",0
    MsgText     db "Hallo Welt vom Fenster",0
    Dummy       dd 0
    StdOut:     dd 0

EXTERN AttachConsole,GetStdHandle,WriteFile  ; kernel32.dll
EXTERN MessageBoxA                           ; user32.dll

SECTION .text
GLOBAL _main
_main:

    push -1             ; ATTACH_PARENT_PROCESS
    call AttachConsole  ; Windows-Version mind. 5.1 (XP, Server 2003)
    test eax, eax
    jz .B

    push -11            ; STD_OUTPUT_HANDLE
    call GetStdHandle
    mov [StdOut], eax

    push 0              ; lpOverlapped
    push Dummy          ; lpNumberOfBytesWritten
    push lString1       ; nNumberofBytesToWrite
    push String1        ; lpBuffer
    push dword [StdOut] ; hFile: Handle zur Standardausgabe
    call WriteFile
    jmp Ende

.B:
    push 0              ; uType=0: Default-Box
    push Caption        ; lpCaption
    push MsgText        ; lpText
    push 0              ; hWnd=0: kein Elternfenster
    call MessageBoxA

Ende:
    mov eax, 0          ; Exitcode
    ret

Eine andere Möglichkeit ist, beim Subsystem CONSOLE zu bleiben und das Konsolenfenster so schnell wie möglich zu entkoppeln (es schließt sich dann von selbst). Die Win32-Funktion hierfür heißt FreeConsole. Es bleibt aber ein kurzes Aufblitzen der Konsole.

Nasm & GoLink
; Assemblieren: nasm.exe -fwin32 -o <Name>.obj <Name>.nasm
; Linken:       GoLink.exe /console /entry _main <Name>.obj kernel32.dll user32.dll
SECTION .data
    MsgText  db "Hallo Welt",0
    Caption  db "Mitteilung",0
EXTERN FreeConsole      ; kernel32.dll
EXTERN MessageBoxA      ; user32.dll
SECTION .text
GLOBAL _main
_main:
    call FreeConsole
    push 0
    push Caption
    push MsgText
    push 0
    call MessageBoxA
    mov eax, 0
    ret

Links zum Thema GUI-Programm und Konsole:

http://support.microsoft.com/kb/105305/en-us
http://www.halcyon.com/~ast/dload/guicon.htm
http://www.codeproject.com/KB/cpp/EditBin.aspx

Ralph 'rkhb' Bauer Feb 2009