IC4.0/WndBufMode



  • Hi,

    Ich beschaeftige mich gerade mit der Win32-Konsole und habe mir dazu mal die Improved Console angeschaut.
    Dazu erstmal folgende Fragen: Weshalb wird mit dem Buffered mode auch das ENABLE_WRAP_AT_EOL_OUTPUT flag abgeschaltet? Hat das einen bestimmten Sinn?
    Und: In der msdn heisst es, dass wenn dieses flag nicht gesetzt wird, alle Zeichen, die ueber das Zeilenende hinausgehen, das letzte Zeichen der Zeile ueberschreiben (eher unschoen). Win9x soll dieses flag nun angeblich gar nicht unterstuetzen - heisst das dann, dass beim Schreiben ueber das Zeilenende immer og. Verhalten auftritt? Gibt es dazu irgendwelche eher schmerzfreien workarrounds, um am Zeilenende umzubrechen?



  • Weshalb wird mit dem Buffered mode auch das ENABLE_WRAP_AT_EOL_OUTPUT flag abgeschaltet?

    Wird es nicht. Abgeschaltet wird es mit "disableWndBufMode".

    Der non buffered mode hat keinen Zeilenumbruch im Sinn, er wurde gemacht um Bildschirmmasken oder kleine Spiele zu gestalten.

    Wenn du ENABLE_WRAP_AT_EOL_OUTPUT nicht abschaltest scrollt die Konsole dann automatisch nach oben wenn du das letzte Zeichen (z.B. Position 80/25) beschreibst. Ein schöner Rahmen verschiebt also alles um eine Zeile nach oben.

    Wenn du keine Bildschirmmaske erstellen willst sondern schön scrollenden Text (business as usual) verwende doch bitte nicht den non buffered mode.

    MfG SideWinder



  • Ja, gut, hab mich offenbar missverstaendlich ausgedrueckt.
    Die Funktion der IC ist mir so weit ansonsten auch klar - mir geht es vor allem darum, ob und wie ein Zeilenumbruch am Zeilenende unter win9x, das laut MSDN das ENABLE_WRAP_AT_EOL_OUTPUT flag nicht unterstuetzt, besonders trickreich realisiert werden kann.



  • In der Hinsicht muss ich passen, die IC unterstützt Win9x offiziell gar nicht mehr und ich habe auch schon lange kein Programm mehr für Win9x entwickelt oder mich damit beschäftigt.

    MfG SideWinder



  • Hm, axo. K, dann wird wohl die effektivste Loesung fuer mich sein, das Rad mal wieder neu zu erfinden, meinen eigenen virtuellen screen zu basteln und mittels WriteConsoleOutput zu kopieren... 🙄



  • *push* 😃
    Habe inzwischen meine selbstgebastelte Ausgabefunktion fertig.
    Das laeuft jetzt so, dass bei der Initialisirung (wie bei der IC ohne Buffered Mode) die Konsole auf eine feste Groesse gesetzt wird und die standard handler fuer Ein-/Ausgabe werden geholt. Dann kopiere ich damit den ScreenBuffer mit ReadConsoleOutputA in ein Array und schreibe alle Ausgaben auch erstmal in selbiges. Am Ende meiner Ausgabefunktion wird WriteConsoleOutputA aufgerufen, um den Puffer mit seinen Aenderungen anzuzeigen.
    Klappt so weit auch, aber was mich nicht unerheblich stoert ist, dass die Aenderung nicht sofort umgesetzt wird.

    KA, wovon das genau abhaengt, aber so weit ich das ueberblicke, erscheint der geaenderte ScreenBuffer im Moment erst auf der Konsole, wenn das Programm beendet wird.
    Im OllyDbg ist von der Ausgabe daher zB. nichts zu sehen und auch während mein getch (mit ReadConsoleInputA gebastelt) auf eine Taste wartet, bekommt man neue Textausgaben nicht zu sehen.

    Ich habe schon versucht FlushFileBuffers mit dem StdOut-Handle aufzurufen, das bringt aber genau gar nichts.

    Hat jemand Ideen, wie ich meinen ScreenBuffer sofort auf den Bildschirm zaubern kann?



  • Weiss das hier echt keiner? Naja, kann ich auch niemandem verdenken. Die Frickeleien in dieser API sind ja echt haarstraeubend. <_<

    Sieht so aus, als waere in WinXP die ueberaus einleuchtend dokumentierte Funktion ntdll.KiFastSystemCall, eax = C8 dafuer gut, den Puffer auf den Schirm zu zaubern - das tut sie zumindest in WriteConsole.

    In Win9x funktioniert mein Code mit WriteConsoleOut uebrigens korrekt und wie erwartet.

    *grrr* Kotzt an. 😡



  • Ich kann mich nicht erinnern, dass ich so ein Problem hatte. Zeig mal den Code zur Ausgabe, vielleicht kann ich dann helfen.

    MfG SideWinder



  • Waere ja wirklich erfreulich, wenn dir dazu noch was einfaellt - ich bin damit echt langsam am verzweifeln. 😞

    Ok, also einmal den Code zur Ausgabe... Ist allerdings assembler...
    Naja, habe es in den Kommentaren in etwa in C-Code umgesetzt, fuer alle Faelle...

    UpdateTextCursor:        ; wird beim Verlassen der Ausgabefunktion aufgerufen
    
    	push	eax
    	push	edi
    	push	esi      ; einige Werte sichern - egal
    
    ; lpWriteRegion.top=lpWriteRegion.left=0;
    	mov	dword [lpWriteRegion], 0
    
    ; lpWriteRegion.right=79;
    ; lpWriteRegion.bottom=24;
    	mov	dword [lpWriteRegion + 4], 24 << 16 | 79
    
    ; Display0_ScreenBasePtr ist ein Zeiger auf ein 2Dim-Array aus diesen
    ; 4Byte Screen-Info-Dingern, das vorher entsprechend befuellt wird. Da man wie
    ; gesagt die Ausgabe manchmal lesen kann, scheint das Befuellen vor Aufruf
    ; dieses Codes korrekt zu funktionieren...
    
    ; WriteConsoleOutputA(hConsoleOutput, Display0_ScreenBasePtr, 25<<16|80, 0, &lpWriteRegion);
    	push	lpWriteRegion;
    	push	0
    	push	25<<16|80
    	push	dword [Display0_ScreenBasePtr]
    	push	dword [hConsoleOutput]
    	call	WriteConsoleOutputA
    
    ; // FlushFileBuffers(hConsoleOutput);
    ;	push	dword [hConsoleOutput]
    ;	call	FlushFileBuffers
    
    ; SetConsoleCursorPosition(hConsoleOutput, ((LastScreenPos>>1)/80)<<16|(LastScreenPos>>1)%80);
    ; Funktioniert in WinXP uebrigens genau so wenig wie CounsoleOutput
    	movzx	eax, word [LastScreenPos]
    	mov	ebx, 50h
    	shr	eax, 1
    	xor	edx, edx
    	div	ebx
    	shl	eax, 16
    	or	eax, edx
    	push	eax
    	push	dword [hConsoleOutput]
    	call	SetConsoleCursorPosition
    
    	pop	esi
    	pop	edi
    	pop	eax   ; Werte wieder zuruecksichern - auch egal
    
    ; return;
    ret
    


  • Was mir sofort auffällt: Das Sichern des Cursors kannst du dir sparen, da WriteConsoleOutput() den Cursor nicht versetzt *g*

    Gibts in deinen ASM-Programmen keine bessere Versionen? Ich benutze immer die wchar_t-Funktionen...

    Aber das hilft dir beides nicht weiter, ansonsten sieht mir alles Koscha aus, wenn der Funktionsaufruf klappt sollte das eigentlich sofort am Bildschirm zu sehen sein 😞

    MfG SideWinder



  • SideWinder schrieb:

    Was mir sofort auffällt: Das Sichern des Cursors kannst du dir sparen, da WriteConsoleOutput() den Cursor nicht versetzt *g*

    Jup, eben drum. Da mein code praktisch eine cout-Implementierung darstellt, setze ich so den Cursor hinter das zuletzt ausgegebene Zeichen. 🙂

    SideWinder schrieb:

    Gibts in deinen ASM-Programmen keine bessere Versionen? Ich benutze immer die wchar_t-Funktionen...

    Was heisst hier "bessere Versionen"? Wegen dem unicode? Wo waere denn da die Verbesserung oder der Vorteil, wenn ich eh nur ASCII-Zeichen verwende?
    Naja, aber aus Spass an der Freud koennte ich es eigentlich auch mal mit der UniCode-Version versuchen. Muesste eigentlich genauso funktionieren.

    SideWinder schrieb:

    Aber das hilft dir beides nicht weiter, ansonsten sieht mir alles Koscha aus, wenn der Funktionsaufruf klappt sollte das eigentlich sofort am Bildschirm zu sehen sein 😞

    Hm, jetzt wo du es sagst: Ich habe das ganze nochmal mit dem Olly durchleuchtet und das WriteConsoleOutA gibt ein ERROR_NOACCESS (000003E6) zurueck, genau wie das SetCursor oder FlushBuffers 😕
    Kann doch aber eigentlich nicht sein, dass man auf den mit GetStdHandle(STD_OUTPUT_HANDLE) geholten ScreenBuffer keinen Zugriff mit diesen Funktionen hat..??



  • Dann übergibst du die Parameter wohl falsch bzw. dein CHAR_INFO-Array ist zu klein/falsch dimensioniert.

    MfG SideWinder



  • Auch nach mehrmaligem Durchgehen kann ich nicht recht nachvollziehen, wo der Fehler liegen koennte.

    Ich gehe stark davon aus, dass die Parameterreihenfolge korrekt ist, das Array sollte auch gross genug sein - schliesslich lese ich vorher schon mit
    lpWriteRegion.left=lpWriteRegion.top=0;
    lpWriteRegion.right=79; lpWriteRegion=24;
    ReadConsoleOutputA(hConsoleOutput, Display0_ScreenBasePtr, 25<<16|80, 0, &lpWriteRegion);
    den ScreenBuffer ein, und das klappt auch unter XP problemlos... 😕

    Wird LastErr eigentlich bei jedem API-Aufruf neu gesetzt? Soll heissen: Wird das nach einem fehlerhaften Aufruf beim Naechsten auch wieder auf ERROR_SUCCESS zurueckgesetzt?

    Weil, dass WriteConsoleOutputA wegen irgendwelcher Macken in den Parametern einen Fehler schmeisst, koennte ich ja vielleicht noch nachvollziehen, aber weshalb schlaegt dann SetConsoleCursorPosition(hConsoleOutput, COORD(0,4)); fehl?



  • Nobuo T schrieb:

    Wird LastErr eigentlich bei jedem API-Aufruf neu gesetzt?

    Nicht jede API-Funktion macht das. Um sicherzugehen, musst Du vor jedem Aufruf via SetLastError () den LastErr selbst zurücksetzen.

    VOID SetLastError (
        DWORD dwErrCode 	// per-thread error code  
     );
    


  • Ooooojeeee... Den kleinen Racker zu finden hat mich diesmal aber echt so einige Haare gekostet. 😮
    Das Problem war offenbar, dass der Stack beim Aufruf der fehlschlagenden Funktionen nicht dword-aligned war. Da muss man erstmal drauf kommen... 🙄

    Danke auf jeden Fall an alle, die sich hier bemueht haben. 🙂



  • Das kann dir mit einer ordentlichen Programmiersprache nicht passieren 😉

    MfG SideWinder



  • Jaja. :p Wo bleibt denn da der Spass? 😉


Anmelden zum Antworten