First post, by songoffall
- Rank
- Member
Back in 90s, when I was a kid with a 486, some of my early programming experiences came from making DIY tools to customize my MSDOS experience. The code wasn't the nicest, but it got the job done.
Now that my MS-DOS programming skills are a bit rusty, and I'm in the process of restoring a DOS PC, I knew beforehand I was going to run either MS DOS command prompt, Norton Commander or Windows 3.11, and I'd rather have a way to choose one on boot.
Pretty sure there are proper loaders out there, but I'm in this for the adventure, and some of you might find the techniques used useful. It's in Borland C, and uses Borland-specific libraries, like conio.h, and I used Borland C++ 4.5 - I think I used an older version back in the day, because this one doesn't seem to have a DOS editor.
I'm not using Borland's GUI tools, because for something as simple as this, that's too much hassle. This is very much work in progress done in a couple of hours, so pretty sure it will change later, like using a cfg file to generate the menu to be customizable, etc.
First, here's the full code, it's public domain.
//Simple MS DOS Startup Manager
//Allows you to choose between three options:
//MS DOS Prompt, Norton Commander and Windows
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <process.h>
#include <dos.h>
#include <string.h>
typedef int Boolean; //Support for booleans in Borland C++
const Boolean TRUE = 1;
const Boolean FALSE = 0;
int SCREENMODE;
//Screen modes:
//1 - BW40 - Black and white, 40 columns
//2 - C40 - Color, 40 columns
//3 - BW80 - Black and white, 80 columns
//4 - C80 - Color, 80 columns
//5 - MONO - Monochrome, 80 columns
//Only C80 is fully implemented and tested at this point in time
//Color pallette and the number of screen columns, the number of lines is assumed to be 25
int ScreenBG;
int ScreenFiller;
int WindowBG;
int WindowShadow;
int WindowBorder;
int WindowText;
int ButtonBG;
int ButtonText;
int Columns;
//Global cursor location
int CursorX;
int CursorY;
//Cursor routine written by Gary Chambers
static void cursor (int state);
void screeninit (void); //Initializes the screen
void screenreset (void); //Resets the screen for use in DOS
void drawwindow (void); //Draws the window
void drawbuttons (int selection); //Draws and updates the selection buttons
int main(int argc, char* argv[])
{
int selection=0;
char input=0;
Boolean proceed=TRUE;
SCREENMODE=4; //Default screen mode: 80x25 color
if (!strcmp (argv[1], "help")){
printf ("MS-DOS Loading Screen 1.0 by Bayandur Poghosyan.\n\n");
printf ("Usage: dolor [SCREENMODE]\n");
printf ("Supported screen modes:\n");
printf ("BW40 - Black and white, 40 columns\n");
printf ("C40 - Color, 40 columns\n");
printf ("BW80 - Black and white, 80 columns\n");
printf ("C80 - Color, 80 columns *DEFAULT SETTING*\n");
printf ("MONO - Monochrome, 80 columns");
printf ("\n");
printf ("Example: dolor BW80 - Launches the program in black and white, 80 columns mode.");
proceed=FALSE;
} else if (!strcmp(argv[1], "BW40")){
SCREENMODE=1;
} else if (!strcmp(argv[1], "C40")){
SCREENMODE=2;
} else if (!strcmp(argv[1], "BW80")){
SCREENMODE=3;
} else if (!strcmp(argv[1], "C80")){
SCREENMODE=4;
} else if (!strcmp(argv[1], "MONO")){
SCREENMODE=5;
}
if (proceed){
screeninit();
drawwindow();
while (input!=13){
drawbuttons (selection);
switch (getch()){
case 13:
input=13;
break;
case 'H':
if (selection>0){
selection--;
} else if (selection==0){
selection=2;
}
break;
case 'P':
if (selection<2){
selection++;
} else {
selection=0;
}
break;
}
}
screenreset ();
switch (selection){
case 1: system("nc");
case 2: system("win");
}
}
return 0;
}
//Hide or unhide cursor
static void cursor (int state)
{
union REGS regs;
static int oldstart=0, oldstop=0, hidden=0;
if (state && hidden){ //Restores cursor
regs.h.ah=0x01; //BIOS set cursor
regs.h.ch=oldstart; //Retrieve starting scan line
regs.h.cl=oldstop; //Retrieve ending scan line
int86(0x10, ®s, ®s); //Call BIOS
hidden=0; //Not hidden
} else if (!hidden){ //Removes cursor
regs.h.ah=0x03; //BIOS Get Cursor Position
int86(0x10, ®s, ®s); //Call BIOS
oldstart=regs.h.ch; //Save starting scan line
oldstop=regs.h.cl; //Save ending scan line
regs.h.ah=0x01; //BIOS Set Cursor Type
regs.h.ch=0x20; //Set bit 5 in CH
int86(0x10, ®s, ®s); //Call BIOS
hidden=1; //Cursor is hidden now
}
}
void screeninit(void)
{
int i,j;
if(SCREENMODE==1){
textmode(BW40);
Columns=40;
ScreenBG=BLACK;
ScreenFiller=WHITE;
WindowBG=WHITE;
WindowShadow=BLACK;
WindowBorder=BLACK;
WindowText=BLACK;
ButtonBG=BLACK;
ButtonText=WHITE;
}else if(SCREENMODE==2){
textmode(C40);
Columns=40;
ScreenBG=LIGHTGRAY;
ScreenFiller=BLUE;
WindowBG=LIGHTGRAY;
WindowShadow=BLACK;
WindowBorder=WHITE;
WindowText=WHITE;
ButtonBG=CYAN;
ButtonText=WHITE;
}else if(SCREENMODE==3){
textmode(BW80);
Columns=80;
ScreenBG=BLACK;
ScreenFiller=WHITE;
WindowBG=WHITE;
WindowShadow=BLACK;
WindowBorder=BLACK;
WindowText=BLACK;
ButtonBG=BLACK;
ButtonText=WHITE;
}else if(SCREENMODE==4){
textmode(C80);
Columns=80;
ScreenBG=LIGHTGRAY;
ScreenFiller=BLUE;
WindowBG=LIGHTGRAY;
WindowShadow=BLACK;
WindowBorder=WHITE;
WindowText=WHITE;
ButtonBG=CYAN;
ButtonText=WHITE;
}else if(SCREENMODE==5){
textmode(MONO);
Columns=80;
ScreenBG=LIGHTGRAY;
ScreenFiller=BLACK;
WindowBG=LIGHTGRAY;
WindowShadow=BLACK;
WindowBorder=WHITE;
WindowText=WHITE;
ButtonBG=BLACK;
ButtonText=WHITE;
}
cursor(0);
textbackground(ScreenBG);
clrscr();
gotoxy(1,2);
textcolor(ScreenFiller);
for(i=1; i<24; i++){
for(j=0; j<Columns; j++){
cprintf("%c", 177);
}
}
}
void screenreset(void)
{
cursor(1);
textbackground(BLACK);
textcolor(WHITE);
clrscr();
}
void drawwindow(void)
{
int x, y;
int i, j;
x=(Columns-32)/2;
y=10;
gotoxy(x, y);
textcolor(WindowBorder);
textbackground(WindowBG);
cprintf(" %c", 201);
for(j=0; j<28; j++){
cprintf("%c", 205);
}
cprintf("%c ", 187);
gotoxy(x+6, y);
cprintf(" MS-DOS Startup Menu ");
y++;
for(i=0; i<3; i++){
gotoxy(x, y);
textbackground(WindowBG);
cprintf(" %c", 186);
for(j=0; j<28; j++){
cprintf(" ", 205);
}
cprintf("%c ", 186);
textbackground(WindowShadow);
cprintf(" ");
y++;
}
gotoxy(x, y);
textbackground(WindowBG);
cprintf(" %c", 200);
for(j=0; j<28; j++){
cprintf("%c", 205);
}
cprintf("%c ", 188);
textbackground(WindowShadow);
cprintf(" ");
y++;
x++;
gotoxy(x, y);
for(j=0; j<33; j++){
cprintf(" ");
}
}
void drawbuttons (int selection)
{
int x, y;
x=(Columns-26)/2;
y=11;
gotoxy(x, y);
if(selection==0){
textbackground(ButtonBG);
textcolor(ButtonText);
}else{
textbackground(WindowBG);
textcolor(WindowText);
}
cprintf(" MS-DOS Command Prompt ");
y++;
gotoxy(x, y);
if(selection==1){
textbackground(ButtonBG);
textcolor(ButtonText);
}else{
textbackground(WindowBG);
textcolor(WindowText);
}
cprintf(" Norton Commander ");
y++;
gotoxy(x, y);
if(selection==2){
textbackground(ButtonBG);
textcolor(ButtonText);
}else{
textbackground(WindowBG);
textcolor(WindowText);
}
cprintf(" Windows 3.11 ");
}
This is the most dodgy part that will definitely change, because I'm not even sure it will work on other computers:
switch (getch()){
case 13:
input=13;
break;
case 'H':
if (selection>0){
selection--;
} else if (selection==0){
selection=2;
}
break;
case 'P':
if (selection<2){
selection++;
} else {
selection=0;
}
break;
}
}
As you can see, I'm getting the H and P keys for up and down, because the up and down keys work differently and don't return normal ASCII characters. But they do return H and P on my computer, so this solution works. I just don't like it. I could capture the keys, using the console input cache, but that would create problems with other keys, like the enter key.
So I'll have to sleep on it for a while.
If you need a specific part of the code explained, I'd be happy to oblige. I choose not to share the executable itself, for security reasons.
P2 300MHz/Matrox Mystique/Sound Blaster AWE 32 Value
Pentium 3 733MHz/3dfx Voodoo 3 3000/Aureal Vortex 2 (Diamond Monster Sound)
Pentium 4 HT 3.0GHz/GeForce FX 5500/Creative Audigy 2
Core2 Quad Q9400/GeForce 8800GT/Creative X-Fi Titanium Fatal1ty