
{$A+}   { Align data }
{$B-}   { Boolean evaluation }
{$E+}   { 80x87 emulator }
{$F-}   { Force FAR calls }
{$G+}   { 80286 code }
{$I-}   { I/O checking }
{$K-}   { Smart Callbacks }
{$N-}   { 80x87 code }
{$O-}   { Overlays allowed }
{$P-}   { Open parameters }
{$T-}   { Typed pointers }
{$V-}   { String VAR checking }
{$W-}   { Windows stack frame for real mode }
{$X+}   { Extended syntax }

{$IFDEF DEBUG}
    {$D+}   { Debug information }
    {$L+}   { Local symbols }
    {$Q+}   { Overflow checking }
    {$R+}   { Range checking }
    {$S+}   { Stack checking }
    {$Y+}   { Symbol reference information }
{$ELSE}
    {$D-}   { Debug information }
    {$L-}   { Local symbols }
    {$Q-}   { Overflow checking }
    {$R-}   { Range checking }
    {$S-}   { Stack checking }
    {$Y-}   { Symbol reference information }
{$ENDIF}

{$C Moveable Demandload Discardable} { Code Segment attributes }

{$M 4096,4096}

PROGRAM VMode_13h;

(*
  This short example switches Windows first in a 80x25 character text mode
  and later in a 320x200 graphics mode using two undocumented functions.
  Note that it requires a VGA compatible graphics adapter.
  This program runs well under Windows 3.1, but I haven't tested it with
  Windows 3.0.

  As usual, if you're using it, you do it on your own risk.

  Olaf Hess, CIS: 100 031, 35 36.
*)

USES WinTypes, WinProcs;

TYPE
    TOneChar = RECORD
        chChar : Char;
        byAttr : Byte;
    END;

    abyTextmode = ARRAY [0..1999] OF TOneChar;

VAR
    SegA000, SegB800 : Word;
    pToTextMode : ^abyTextMode;

(* ---- *)
{ Undocumented functions. See "Undocumented Windows" by Schulman, Maxey and
  Pietrek for more info. }

PROCEDURE Death (hDesktopDC: hDC); FAR;
    EXTERNAL 'GDI' index 121;
PROCEDURE Resurrection (hDesktopDC: hDC; w1, w2, w3, w4, w5, w6: Word); FAR;
    EXTERNAL 'GDI' index 122;

PROCEDURE __A000H; FAR;
    EXTERNAL 'KERNEL' index 174;
PROCEDURE __B800H; FAR;
    EXTERNAL 'KERNEL' index 182;

(* ---- *)

PROCEDURE PutPixel (wXPos, wYPos: Word; byColor: Byte);
{ Set a pixel. The upper left corner is (00,00) }
BEGIN
    Mem [SegA000:Word (320 * wYPos + wXPos)] := byColor;
END; { PutPixel }

(* ---- *)

PROCEDURE WriteChar (wXPos, wYPos: Word; chChar: Char; byAttr: Byte);
{ Write a character to screen. The upper left corner is (01, 01) }
BEGIN
    IF (wXPos > 0) THEN Dec (wXPos);
    IF (wYPos > 0) THEN Dec (wYPos);
    pToTextMode^[(wYPos * 80) + wXPos].chChar := chChar;
    pToTextMode^[(wYPos * 80) + wXPos].byAttr := byAttr;
END; { WriteChar }

(* ---- *)

VAR
    wX, wY, i : Word;
    hDesktopDC : hDC;
    dwWait : LongInt;

BEGIN
    { Get selector for segment $A000 }
    SegA000 := Ofs (__A000H);

    { Get selector for segment $B800 }
    SegB800 := Ofs (__B800H);

    { Pointer points to beginning of segment $B800 }
    pToTextMode := Ptr (SegB800, 0);

    { Get DC for desktop window }
    hDesktopDC := GetDC (GetDesktopWindow);

    { Switch to 80x25 text mode }
    Death (hDesktopDC);

    i := 0;

    { Write some characters on the screen }
    FOR wY := 1 TO 25 DO
        FOR wX := 1 TO 80 DO
            BEGIN
                WriteChar (wX, wY, Char ((i MOD 26) + 65), Byte (i MOD 256));
                Inc (i);
            END; { for }

    { Wait a while }
    FOR dwWait := 0 TO 2000000 DO
        INLINE ($90/$90/$90); { NOP, NOP, NOP }

    { Set video mode $13 (320x200 in 256 colors) }
    ASM
        mov ax, $0013;
        Int $10
    END; { asm }

    { Paint palette }
    FOR wY := 0 TO 200 DO
        FOR wX := 0 TO 300 DO
            PutPixel (wX, wY, Byte (wX));

    { Wait a while }
    FOR dwWait := 0 TO 2000000 DO
        INLINE ($90/$90/$90); { NOP, NOP, NOP }

    { Restore Windows' video mode }
    Resurrection (hDesktopDC, 0, 0, 0, 0, 0, 0);

    { Release desktop DC }
    ReleaseDC (GetDesktopWindow, hDesktopDC);

    { Force Windows to repaint all visible windows }
    InvalidateRect (0, NIL, TRUE);
    UpdateWindow (0);
END. { VMode_13h }

