OS/2 1.2 DOS.SYS interface


 * ibm.os2/long.messages #200, from jgilliland, 11358 chars, Wed Sep 12 09:55:43 1990

Yet another of OS/2's mysteries has been unravelled. OS/2 1.2 allows the Task Manager to initiate programs in the DOS box, but does not document the mechanism that is used, so it has not been possible to do the same thing from other applications. Here is set of messages from the FidoNet OS/2 echo that documents the DOS.SYS driver interface that performs this magic, and sample code to show its use. You'll also find a paragraph from Peter Fitzsimmons describing how he figured this all out.

Credit goes to Peter Fitzsimmons for doing the original research, and to Bill Andrus for tying together the loose ends and creating a usable program out of it.


 * 309/366 09 Sep 90 08:12:06
 * From: Peter Fitzsimmons
 * To: All
 * Subj: new trick
 * Attr:

I've figured out a little bit about DOS.SYS....

This little sample program uses DOS.SYS to change to C:, change to \OS2, and run "edlin \config.sys".

When you Q)uit edlin, the session that was in the foreground prior to flipping to the dos box (not nec the session that 2dos.exe was running in) is restored to the foreground.

I have not yet figured out how to reboot through DOS.SYS -- but this is an easy thing to code yourself (such a program is included with Maximus).

2dos.c

 * 1) include
 * 2) include
 * 3) include
 * 4) define INCL_DOS
 * 5) define INCL_DOSERRORS
 * 6) define INCL_WINSWITCHLIST
 * 7) include

void jump2dos(void);

static char *cmd = "\x80 C:\r" "\x80 CD\\OS2\r" "\x80 edlin \\config.sys\r";

void cdecl main(void) { HFILE hf; USHORT rc, dummy;

rc = DosOpen("DOS$", &hf, &dummy, 0L, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_FAIL_ON_ERROR, 0L); if(!rc){ rc = DosWrite(hf, cmd, strlen(cmd)+1, &dummy); DosClose(hf); if(!rc) jump2dos; else if(rc == ERROR_NOT_READY) printf("A program is already running in the DOS box\n"); else printf("Unexpected OS/2 error SYS%04u\n", rc); } else printf("DOS.SYS not installed (sys%04u)\n", rc); DosBeep(1000, 100); }

void jump2dos(void) { USHORT num, i; void *buf = malloc(32000); SWENTRY *swe; HSWITCH fgHandle; SEL selGlobalSeg, selLocalSeg; GINFOSEG FAR * volatile pgis; UCHAR sgDos;

/* find out who is in the foregound, so we know who to switch DosGetInfoSeg(&selGlobalSeg, &selLocalSeg); pgis = MAKEPGINFOSEG(selGlobalSeg); fgHandle = WinQuerySwitchHandle(0L, pgis->pidForeground);
 * back to after the dos box is done. This method only works
 * if the foreground session is NOT a pm program. If it is a
 * pm program, the "Task List" will be the active app after
 * the task switch

/* Find the switch list handle of the DOS box: */ num = WinQuerySwitchList(0L, buf, 32000); swe = (SWENTRY *)((USHORT *)buf + 1); for(i=0; i if(!strcmp("DOS", swe[i].swctl.szSwtitle)){ WinSwitchToProgram(swe[i].hswitch); break; } } free(buf); if(i==num){ printf("This system is configured without a dos box!\n"); return; } if(fgHandle){ DosSleep(100L); /* give a moment for the task switch */ sgDos = pgis->sgCurrent;

/*
 * Wait (poll) current screen group -- waiting for the DOS
 * program to end. I don't like polling, but this is the only
 * solution I can come up with. If you don't mind the "Task
 * List" always being brought the the fore after the dos progam
 * ends, you can forget about all of this and exit after the
 * WinSwitchToProgram, above.

while( sgDos == pgis->sgCurrent ) DosSleep(500L);

WinSwitchToProgram(fgHandle); /* back to where we started */ } }

Comments
 * 1) if 0

The only reason this program works is because WinSwitchToProgram allows you to:

1) Switch a session to the foreground which is not one of your own child sessions.

2) Switch a session to the foreground when you are not running in the foreground yourself.

According to the documentation (IBM, v1.20), you are not supposed to be able to do either of these things. However, the "File Manager", from what I can figure out, uses this method to switch to the DOS box too, so I am confident that this program will continue to work under OS/2 1.2x.

Peter Fitzsimmons, A:WARE Inc. Thu 09-06-1990 22:15:11


 * Origin: Pete's Point (1:250/628.1)


 * 311/366 09 Sep 90 08:12:29
 * From: Peter Fitzsimmons
 * To: All
 * Subj: new trick part 2
 * Attr:

And here is how to reboot via dos.sys:

reboot.c

 * 1) include
 * 2) define INCL_DOS
 * 3) include

void cdecl main(void) { HFILE hf; USHORT rc, dummy;

rc = DosOpen("DOS$", &hf, &dummy, 0L, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_FAIL_ON_ERROR, 0L); if(!rc){ DosShutdown(0L); DosDevIOCtl(NULL, NULL, 0xab, 0xd5, hf); /* reboot */ DosClose(hf); } else printf("DOS.SYS not installed (sys%04u)\n", rc); }

How did I figure all of this DOS.SYS stuff out, you ask? I wrote my own DOS$ device driver, and simply had it report what the programs that use the real DOS$ (boot.com, pmfile.exe) were trying to do with it. (I was bored one day at work).

Pete.


 * 361/366 10 Sep 90 23:14:13
 * From: Bill Andrus
 * To: Peter Fitzsimmons
 * Subj: new trick part 3
 * Attr:

Okay, here's the complete program that everyone says can't be done with the current documentation:

CALLDOS.C
/* Compiles with IBM C/2 1.1 and its MAKE/2 2.0 using:

model=S # use large model when debugging -- bugs JUMP out at you mode=p linklibs=$(model)libce$(mode).lib os2.lib CFLAGS=-A$(model) -Lp -Oxrn -Zpel -W3 -G2 -Gw -J -nologo LINK=D:\C\Bin\Link
 * 1) Make file for CALLDOS.C #
 * 2) use MAKE CALLDOS.C #
 * 1) use MAKE CALLDOS.C #
 * 1) use MAKE CALLDOS.C #

calldos.exe : calldos.obj $(LINK) calldos.obj,calldos.exe/A:16/FAR/NOD/PACKD/ST:3000,NUL.MAP,$(linklibs);

calldos.obj : calldos.c !CL $(CFLAGS) -c $?



/* Merge of Peter Fitzsimmons' CALLBOX.C and 2DOS.C programs */


 * 1) include
 * 2) include
 * 3) include
 * 4) define INCL_DOS
 * 5) define INCL_DOSERRORS
 * 6) define INCL_WINSWITCHLIST
 * 7) include

void jump2dos(void) { USHORT num, i; void *buf = malloc(32000); SWENTRY *swe; HSWITCH fgHandle; SEL selGlobalSeg, selLocalSeg; GINFOSEG FAR * volatile pgis; UCHAR sgDos;

/* find out who is in the foregound, so we know who to switch DosGetInfoSeg(&selGlobalSeg, &selLocalSeg); pgis = MAKEPGINFOSEG(selGlobalSeg); fgHandle = WinQuerySwitchHandle(0L, pgis->pidForeground);
 * back to after the dos box is done. This method only works
 * if the foreground session is NOT a pm program. If it is a
 * pm program, the "Task List" will be the active app after
 * the task switch

/* Find the switch list handle of the DOS box: */ num = WinQuerySwitchList(0L, buf, 32000); swe = (SWENTRY *)((USHORT *)buf + 1); for(i=0; i if(!strcmp("DOS", swe[i].swctl.szSwtitle)){ WinSwitchToProgram(swe[i].hswitch); break; } } free(buf); if(i==num){ printf("This system is configured without a dos box!\n"); return; } if(fgHandle){ DosSleep(500L); /* give a moment for the task switch */ sgDos = pgis->sgCurrent;

/*
 * Wait (poll) current screen group -- waiting for the DOS
 * program to end. I don't like polling, but this is the only
 * solution I can come up with. If you don't mind the "Task
 * List" always being brought the the fore after the dos progam
 * ends, you can forget about all of this and exit after the
 * WinSwitchToProgram, above.

while( sgDos == pgis->sgCurrent ) DosSleep(500L);

WinSwitchToProgram(fgHandle); /* back to where we started */ } }

Comments

The only reason this program works is because WinSwitchToProgram allows you to:

1) Switch a session to the foreground which is not one of your own child sessions.

2) Switch a session to the foreground when you are not running in the foreground yourself.

According to the documentation (IBM, v1.20), you are not supposed to be able to do either of these things. However, the "File Manager", from what I can figure out, uses this method to switch to the DOS box too, so I am confident that this program will continue to work under OS/2 1.2x.

Peter Fitzsimmons, A:WARE Inc. Thu 09-06-1990 22:15:11

void main(int argc, char **argv) { HFILE hf; USHORT rc, dummy; static char cmd[256]; int i;

if( argc < 2 ){

printf("\nUsage CALLDOS \n\n"); printf(" Each with blanks should be enclosed by quotes\n\n"); printf("For example:\n"); printf("CALLDOS C: \"CD \\OS2\" \"DIR > \\DIR.LST\" \"CD \\\"\n\n"); printf("Will make C:\\OS2 current, list the files to C:\\DIR.LST,\n"); printf("and switch back to C:\\.\n\n"); printf("If invoked while a PM session is current, the focus returns,\n"); printf("to the Task List, else returns to the current session.\n\n"); exit (255); } cmd[0] = '\0'; for(i=1; i strcat(cmd, "\x80 "); strcat(cmd, argv[i]); strcat(cmd, "\r"); if( i != (argc-1) ) strcat(cmd, " "); } rc = DosOpen("DOS$", &hf, &dummy, 0L, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_FAIL_ON_ERROR, 0L); if(!rc){ rc = DosWrite(hf, cmd, strlen(cmd)+1, &dummy); DosClose(hf); if(!rc) jump2dos; else if(rc == ERROR_NOT_READY) { printf("A program is already running in the DOS box\n"); exit (1); } else { printf("Unexpected OS/2 error SYS%04u\n", rc); exit (2); } } else { printf("DOS.SYS not installed (sys%04u)\n", rc); exit (3); } DosBeep(1000, 100); }