Text in DOS mit einem Mal auf dem Bildschirm ausgeben



  • Evtl. hilft das Programm aus dem Fundus.

    /********************************************************************/
    /* Programm  :                VIDMODE                               */
    /* ---------------------------------------------------------------- */
    /* Zweck     :  Setzt den Videomodus neu                            */
    /* ---------------------------------------------------------------- */
    /* Autor     :                                                      */
    /* erstellt  :  1990                                                */
    /* ---------------------------------------------------------------- */
    /* Compile   :  QC2 Compiler                                        */
    /* Link      :                                                      */
    /* ---------------------------------------------------------------- */
    /* Aufruf    :  VIDMOD modus | -mxx | ? [-c[x]] [-lxxx] [-zxx,y]    */
    /* modus     :  MONO           setzt Modus 7 (MDA)                  */
    /*              CO80 / CO40    setzt Modus 3 / 1                    */
    /*              BW80 / BW40    setzt Modus 2 / 0                    */
    /*                                                                  */
    /*   -m      :  Expliziete Angabe des Modus                         */
    /*              xx = Modus als Dezimal oder Hexzahl                 */
    /*   -c      :  Bildschirm x = 0 : nicht löschen                    */
    /*                             1 : 1mal nicht löschen               */
    /*                             2 : löschen                          */
    /*                                                                  */
    /*   -l      :  Zeilenzahl setzen xxx = 200   (CGA)                 */
    /*                                    = 350   (EGA)                 */
    /*                                    = 400   (VGA)                 */
    /*                                                                  */
    /*   -z      :  Zeichensatz 8*xx und Tabelle y aktivieren           */
    /*                            xx = 16                               */
    /*                                 14                               */
    /*                                  8                               */
    /*                             y =  0 oder 1                        */
    /*                                                                  */
    /*   ?       : Hilfetext ausgeben                                   */
    /*                                                                  */
    /* ---------------------------------------------------------------- */
    /* Sonstiges : Funktioniert nur mit VGA-Karte                       */
    /********************************************************************/
    
    #include <stdio.h>
    
    /* Bildschirmmodi */
    #define  BW40           0
    #define  CO40           1
    #define  BW80           2
    #define  CO80           3
    #define  MONO           7
    #define  CO13243     0x54
    #define  CO13225     0x55
    #define  MO13243     0x56
    #define  MO13225     0x57
    
    struct mods { char *modtxt;
    	      int   modnr;
    	    }
    
    static struct mods modes[] = {
    		  "BW40",BW40,
    		  "CO40",CO40,
    		  "BW80",BW80,
    		  "CO80",CO80,
    		  "MONO",MONO,
    		  "CO13243",CO13243,
    		  "CO13225",CO13225,
    		  "MO13243",MO13243,
    		  "MO13225",MO13225,
    		  NULL,0
    		 };
    
    /* Bildschirmzeilen */
    #define  SL200  0
    #define  SL350  1
    #define  SL400  2
    
    /* Zeichensätze */
    #define  CS8   0x12
    #define  CS14  0x11
    #define  CS16  0x14
    
    /* err Codes */
    #define  NOSWITCH       -11
    #define  INVALIDCOMMAND -12
    #define  LINES          -13
    #define  ZEICHEN        -14
    #define  OK              0
    
    int  modus_n = -1,
         modus_b,
         modus_a,
         lines_n = -1,
         lines_a,
         lines_aa,
         zeich_n = -1,
         zeich_a,
         table   =  0,
         loesch_a,
         loesch_n = -1,
         err = OK,
         rows,coll,
         crsr_x,crsr_y,seite,
         videoinfo,videoinfo1,videoinfo2,videoinfo3;
    char buff[80];
    
    void initvideo(char vidmode)
    { _asm {
    	       mov al,vidmode
    	       mov ah,00h              ; Videomodus setzten
    	       int 10h
           }
    }
    
    void  setscanlines(char lines)
    { _asm {
    		mov bl,30h              ; Bildschirmzeilen setzten
    		mov al,lines
    		mov ah,12h
    		int 10h
           }
    }
    
    void  setcharakterset(char set,char table)
    { _asm {
    		mov al,set
    		mov bl,table
    		mov ah,11h              ; Bildschirmzeilen setzten
    		int 10h
           }
    }
    
    void set_BIOSvar_10h(char flag)
    { _asm {
    		mov ax,0040h
    		mov es,ax
    
    		mov cl,4
    		mov bl,2
    		add bl,flag
    		shl bl,cl
    		mov ah,es:10h
    		mov al,ah
    		and ah,0cfh
    		or ah,bl
    		mov es:10h,ah
           }
    }
    
    int peekb(int segm,int offs)
    { _asm {
    		mov ax,segm
    		mov es,ax
    		mov di,offs
    		mov al,es:[di]
    		mov ah,0
           }
    }
    
    int peekw(int segm,int offs)
    { _asm {
    		mov ax,segm
    		mov es,ax
    		mov di,offs
    		mov ax,es:[di]
           }
    }
    
    void pokeb(int segm,int offs,int bwert)
    { _asm {
    		mov ax,segm
    		mov es,ax
    		mov di,offs
    		mov ax,bwert
    		mov es:[di],al
           }
    }
    
    void setcrsr(int x,int y,int p)
    { _asm {
    		mov dx,x
    		mov bx,y
    		mov dh,bl
    		mov ah,02
    		mov bx,seite
    		mov bh,bl
    		int 10h
           }
    }
    
    int setmodus()
    { int i;
      for(i=0;modes[i].modtxt!=NULL;i++)
    	if(!(strcmp(modes[i].modtxt,buff)))
    	{ modus_n = modes[i].modnr; return(OK);}
      return(INVALIDCOMMAND);
    }
    
    void get_old_mode()
    { int  i,j;
      char c;
    
      i = peekb(0x40,0x10);
      i &= 0x30;
      i >>= 4;
      switch(i)
      { case 0 : modus_b = -1;break;
        case 1 : modus_b =  1;break;
        case 2 : modus_b =  3;break;
        case 3 : modus_b =  7;break;
        default: modus_b = -2;break;
      }
    
      modus_a = peekb(0x40,0x49);/* & 0x7f; */
    
      coll = peekw(0x40,0x4a);
    
      rows = peekb(0x40,0x84) + 1;
    
      zeich_a = peekw(0x40,0x85);
    
      lines_a = rows * zeich_a;
      lines_aa = lines_a;
      if (lines_a <= 480) lines_aa = 480;
      if (lines_a <= 400) lines_aa = 400;
      if (lines_a <= 350) lines_aa = 350;
      if (lines_a <= 200) lines_aa = 200;
    
      videoinfo  = peekb(0x40,0x87);
      videoinfo1 = peekb(0x40,0x88);
      videoinfo2 = peekb(0x40,0x89);
      videoinfo3 = peekb(0x40,0x8a);
    
      seite = peekb(0x40,0x62);
      crsr_x = peekb(0x40,0x50+2*seite);
      crsr_y = peekb(0x40,0x51+2*seite);
    
    }
    
    int testit()
    { int  i,j;
      char c;
    
      printf("Videomode beim Einschalten : ");
      switch(modus_b)
      { case 0 : printf("Keine Video-Karte\n");break;
        case 1 : printf("40x25 CGA\n");break;
        case 3 : printf("80x25 CGA\n");break;
        case 7 : printf("80x25 MDA\n");break;
        default: printf("%i  (Fehler)\n",modus_b);break;
      }
    
      printf("Aktueller Videomode        : ");
      for(i=0;modes[i].modtxt!=NULL;i++)
        if(modes[i].modnr == modus_a) {printf("%s",modes[i].modtxt); break;}
      printf(" (%i)\n",modus_a);
    
      printf("Spalten: %i ",coll);
      printf("Zeilen: %i ",rows);
      printf("Zeichenhöhe: %i\n",zeich_a);
    
      printf("Scanlines: %i ",lines_a);
      printf("von: %i\n",lines_aa);
    
      if(( videoinfo & 0x80) == 0x80) printf("Bildschirm nicht löschen\n");
      printf("Videoadapter ist ");
      if(( videoinfo & 0x08) == 0) printf("MCGA, EGA oder VGA\n");
    			  else printf("MDA oder CGA\n");
      if(( videoinfo & 0x02) == 2) printf("mit Monochrom-Monitor\n");
    /*if(( videoinfo & 0x01) == 0) printf("als CGA-Emulation\n");*/
      i = videoinfo & 0x60;
      i >>= 5;
      i = (i+1)*64;
      printf("Videospeicher : %d KByte\n",i);
    
      if(( videoinfo2 & 0x04) == 4) printf("VGA Monochrom-Monitor angeschlossen\n");
    			   else printf("VGA Farb-Monitor angeschlossen\n");
    
      printf("Videoinfo   : $%-2x   ",videoinfo);
      printf("Videoinfo1  : $%-2x \n",videoinfo1);
      printf("Videoinfo2  : $%-2x   ",videoinfo2);
      printf("Videoinfo3  : $%-2x \n",videoinfo3);
    
      printf("zeile: %i  spalte: %i  seite: %i",crsr_y,crsr_x,seite);
    }
    
    int schalter()
    { char c;
      char *b;
    
      c = buff[1];
      switch (c)
      { case 'L' : sscanf(buff+2,"%i",&lines_n);
    	       break;
        case 'M' : sscanf(buff+2,"%i",&modus_n);
    	       break;
        case 'C' : sscanf(buff+2,"%i",&loesch_n);
    	       break;
        case 'Z' : sscanf(buff+2,"%i",&zeich_n);
    
    	       b = strchr(buff,44);
    	       if (b)
    		   sscanf(b+1,"%i",&table);
    	       break;
        default  : return(NOSWITCH);break;
      }
      return(OK);
    }
    
    int help()
    { puts("Help:");
      puts(" modus ");
      puts(" -cx    : Bildschirm nicht löschen");
      puts("          x = 0: nie, 1: Einmal nicht, 2: immer  löschen");
      puts(" -lxxx  : Bildschirmlinien");
      puts(" -zxx,y : Zeichensatz");
      puts(" -mxx   : Modus als Zahl");
      return(0);}
    
    int main(argc,argv)
    int argc;
    char *argv[];
    { int  i;
      char *bb, c ;
    
      get_old_mode();
      if (argc < 2) testit();
      else
      { for(i=1; i<argc; i++)
        { strcpy(buff,argv[i]);
          strupr(buff);
          c = buff[0];
          switch (c)
          { case '?' : err = help();return(0);     break;
    	case '-' :
    	case '/' : err = schalter(); break;
    	default  : err = setmodus(); break;
          }
        }
    
          if (lines_n>0)
    	switch (lines_n)
    	{  case 200 : setscanlines((char)SL200); break;
    	   case 350 : setscanlines((char)SL350); break;
    	   case 400 : setscanlines((char)SL400); break;
    	   default  : err = LINES;
    	}
    
          if (modus_n < 0)  modus_n = modus_a;
          if (modus_n == MONO || modus_n == MO13225 || modus_n == MO13243)
    						    set_BIOSvar_10h('\1');
    					      else  set_BIOSvar_10h('\0');
          if (loesch_n == 0 || loesch_n == 1) modus_n |= 0x80;
          initvideo(modus_n);
          if (loesch_n == 1)
          { i = peekb(0x40,0x87);
    	i = i & 0x7f;
    	pokeb(0x40,0x87,i);
          }
    
          if (loesch_n == 0 || loesch_n == 1)
          {
    	crsr_x = (crsr_x >= coll) ? coll : crsr_x;
    	crsr_y = (crsr_y >= rows) ? rows : crsr_y;
    	setcrsr(crsr_x,crsr_y,seite);
          }
    
          if (zeich_n>0 && table < 2)
    	switch (zeich_n)
    	{  case  8 : setcharakterset((char)CS8,(char)table); break;
    	   case 14 : setcharakterset((char)CS14,(char)table); break;
    	   case 16 : setcharakterset((char)CS16,(char)table); break;
    	   default : err = ZEICHEN;
    	}
    
      }
      return(err);
    }
    

    Keine Lästerein über den Stil, das ist über 20 Jahre her 😉



  • Laut PC-Intern bekommt man den aktuellen Videomodus mit

    _asm { 
            mov ah, 0fh   ;Videomode auslesen
            int 10h 
           } 
    
    Ergebnis:
      al: Videomode
      ah: Anzahl der Zeichen pro Zeile
      bh: aktuelle Bildschirmseite
    

    Harper schrieb:

    Textmodus mit 80 x 25 Zeichen (8 x 16 Pixel pro Zeichen) [oder] 80 x 50 Zeichen
    (8 x 8 Pixel pro Zeichen) wird vom Programm als Mode 3 interpretiert.

    Mode 3 sagt erstmal nur das es ein Textmode ist.
    Was auf den Sceen passt, ist abhängig vom eingestellten
    ROM-Zeichensatz.

    _asm { 
            mov ax, 1111h   ;8x14-ROM-Zeichensatz auswählen
            mov bl, 0h 
            int 10h 
           }
    

    oder

    _asm { 
            mov ax, 1112h   ;8x8-ROM-Zeichensatz auswählen
            mov bl, 0h 
            int 10h 
           }
    


  • Danke. Das mit dem Videomodus hat jetzt auch geklappt.

    Ich hab nun versucht, die Codepage einzustellen. Auf http://poli.cs.vsb.cz/misc/rbint/text/2112.html steht es folgendermaßen:

    INT 21 - DOS 3.3+ - GET GLOBAL CODE PAGE TABLE
    	AX = 6601h
    Return: CF set on error
    	    AX = error code (see #01680 at AH=59h/BX=0000h)
    	CF clear if successful
    	    BX = active code page (see #01757)
    	    DX = system code page (see #01757)
    SeeAlso: AX=6602h
    
    ----------
    
    INT 21 - DOS 3.3+ - SET GLOBAL CODE PAGE TABLE
    	AX = 6602h
    	BX = active code page (see #01757)
    	DX = system code page (active page at boot time)
    Return: CF set on error
    	    AX = error code (see #01680 at AH=59h/BX=0000h)
    	CF clear if successful
    	    AX = EB41h (Novell NWDOS v7.0 when NLSFUNC not installed and
    		  request was for previously-active code page)
    SeeAlso: AX=6601h,INT 2F/AX=14FFh
    

    Mein Code sieht so aus:

    #include <stdio.h>
    #include <dos.h>
    
    void get()
    {
    	union REGS in, out;
    
    	in.x.ax = 0x6601;
    	int86(0x21, &in, &out);
    
    	printf("Active code page: %i\n", out.x.bx);
    	printf("System code page: %i\n", out.x.dx);
    }
    
    void set()
    {
    	union REGS in, out;
    
    	in.x.ax = 0x6602;
    	in.x.bx = 850;
    	in.x.dx = 850;
    	int86(0x21, &in, &out);
    
    	printf("Code pages were set.\n");
    }
    
    int main()
    {
    	int i;
    	for (i = 128; i < 256; i++)
    		printf("%c", i);
    
    	printf("\n\n");
    
    	get();
    	set();
    	get();
    
    	return 0;
    }
    

    Das Ermitteln der Codepages geht. System-Codepage ist 437, active ist 850. Doch wenn ich dann beide auf 850 setze und sie mir danach noch mal ermitteln lasse, stehen sie immer noch auf 437 und 850. Das Setzen hat also nicht geklappt. Was mache ich falsch?



  • Wie dort steht, ist die "system code page" die code page, die beim Booten aktiv ist. Vermutlich die im BIOS eingestellte code page. Die kannst du iaR. nicht ueber diese Funktion umstellen. ZB. die Doku von DR-DOS fuehrt diese Moeglichkeit daher konsequenterweise gar nicht erst auf.



  • Ja, das macht Sinn. Aber auch wenn ich Zeile 21 auskommentiere (und in Zeile 20 dann 437 hinschreibe, weil 850 ja schon gesetzt ist), bleibt die Active Code Page so wie sie war.



  • Sehe da sonst gerade keinen groben Fehler...
    Checke die Fehlercodes (CF und AX) und stelle sicher, dass die ganzen Geschichten mit country.sys und das mode select Zeugs in deinem DOS korrekt eingerichtet sind, bzw. die Funktion ueberhaupt unterstuetzt wird.



  • Was soll eigentlich CF sein? Ich lese das ständig, aber REGS besitzt keine Variable CF. Was muss ich da genau abprüfen?

    Nobuo T schrieb:

    und stelle sicher, dass die ganzen Geschichten mit country.sys und das mode select Zeugs in deinem DOS korrekt eingerichtet sind, bzw. die Funktion ueberhaupt unterstuetzt wird.

    Na ja, ich arbeite nicht unbedingt unter einem richtigen DOS, sondern benutze meistens die Konsole in Windows XP, die das Programm ja durchaus abspielen kann. Ich denke nicht, dass ich da im Vorfeld irgendwie großartig was einstellen kann. Ansonsten habe ich auch noch DOSBox.
    Gibt es für das, was du hier erwähnst, eine Möglichkeit, es im Programm selbst zu realisieren? Ich möchte ungern ein Programm schreiben, bei dem ich dem Benutzer erst erklären muss, was er vorher einstellen soll. Das soll das Programm am Anfang selbst machen und am besten am Ende wieder zurückstellen.



  • Harper schrieb:

    Was soll eigentlich CF sein? Ich lese das ständig, aber REGS besitzt keine Variable CF. Was muss ich da genau abprüfen?

    CF ist das Carry-Flag aus dem Status-Register.



  • Es sollte in den REGS die Variable "cflag" geben, wenn ich mich nicht irre. Sonst sollte REGS.x.flags & 1 funktionieren.
    Habe zu dieser Gelegenheit mal seit Langem wieder schnell ein kleines ASM-Programm zum Testen der Code Pages hingehackt (http://btm.homeip.net/cppde/codept.com wen's interessiert 300+x Byte, Haelfte Text -> fuer Quelltext einen Disassembler bemuehen). Ergebnis: Die DOS-VM von Windows XP kennt wohl Funktion 6602 nicht (gibt Fehler 01).
    Falls du also mit Code Pages spielen willst, versuch's mit der DOS Box oder einem echten DOS.



  • An Windows XP scheint's nicht zu liegen. Ich hab noch mal folgenden Code geschrieben:

    #include <stdio.h>
    #include <dos.h>
    
    void int86func(int intno, union REGS *in, union REGS *out)
    {
    	int retval = int86(intno, in, out);
    
    	printf("int86 returned:   %i\n", retval);
    	printf("REGS.x.cflags:    %i\n", out->x.cflag);
    	printf("REGS.x.flags & 1: %i\n", out->x.flags & 1);
    }
    
    void get()
    {
        union REGS in, out;
    
        printf("GET\n");
    
        in.x.ax = 0x6601;
        int86func(0x21, &in, &out);
    
        printf("Active code page: %i\n", out.x.bx);
        printf("System code page: %i\n\n", out.x.dx);
    }
    
    void set(unsigned int page)
    {
        union REGS in, out;
    
        printf("SET active code page to %i\n", page);
    
        in.x.ax = 0x6602;
        in.x.bx = page;
        int86func(0x21, &in, &out);
    
        printf("\n");
    
        get();
    }
    
    int main()
    {
        int i;
    
        for (i = 128; i < 256; i++)
    	printf("%c", i);
    
        printf("\n\n");
    
        get();
        set(850);
        set(437);
    
        return 0;
    }
    

    Und egal ob ich das ganze in Windows XP ausführe oder in DOSBox, Windows 98, dem DOS-Modus von Windows 98 oder FreeDOS (alles außer XP läuft bei mir in Virtual PC), das get liefert bei cflag zwar 0, aber das set liefert immer den Fehlercode 1. Da muss also noch irgend etwas falsch sein bzw. fehlen. Auch mit deinem Programm hat es in noch keiner Konfiguration geklappt, die Codepage tatsächlich zu setzen.



  • ... vielleicht hilft dir das hier auch noch weiter... http://www.drdos.net/documentation/sysprog/chap4.htm



  • Meinst du irgendetwas spezielles in dem Dokument?



  • Den Abschnitt ueber Funktion 66?



  • Das einzig Neue bzw. Hilfreiche war dort der Satz:

    NLSFUNC must be loaded to change the global code page.

    Wenn ich das mache, geht's nämlich. Aber insgesamt ist das doch auch blöd: Soll ich jetzt in meinem Programm etwa system("nlsfunc"); schreiben? Zumal es diese Datei zum Beispiel in DOSBox gar nicht gibt. Die hätten mal lieber hinschreiben sollen, was man quellcodetechnisch machen muss, um das Ändern der Codepage zu ermöglichen.



  • Quelltext ist wohl nicht das grosse Problem:

    http://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/dos/nlsfunc/nlsfn04s.zip

    http://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/dos/nlsfunc/

    , sondern eher die Aussage:

    Verwenden Sie den Befehl NLSFUNC nicht, wenn Sie Windows gestartet haben. Er könnte Ihren Computer daran hindern, richtig zu funktionieren.
    

    http://www.i8086.de/dos-befehle/nlsfunc.html

    .



  • Tja, da meine Programme möglichst auch unter Windows korrekt funktionieren sollen, muss ich erneut fragen: Was kann man da machen? Ist es denn wirklich nicht möglich, mal eben schnell die Codepage umzustellen und am Ende wieder zurück zu stellen?

    Alles andere lässt sich doch auch einstellen: Bildschirmmodus, Auflösung und sogar die Frage, ob Zeichen blinken können sollen oder ob man lieber 16 statt 8 Hintergrundfarben haben kann. Alles kann man mit einem Mal ändern. Warum ist das bei der Codepage so schwierig?

    Ist das letztendlich nicht einfach nur eine Bitmap, die dort ausgetauscht wird? Und gibt es denn wirklich keine Programme, wo das mal tatsächlich gemacht wird, so dass man dort nachgucken kann? Ist es wirklich so, dass man nur Stückchen und Brocken in irgendwelchen Dokus findet, wie man diesen Befehl theoretisch aufrufen könnte, wenn man das und das und das eingestellt hat, statt mal ein Beispiel zu zeigen, was ein Programm machen muss, um die Codepage zu setzen und am Ende wieder zurück zu setzen?



  • Keiner eine Idee?


Anmelden zum Antworten