Microsoft KB Archive/39536
Calling the MS-DOS EXEC Service from within a TSR Application ID Number: Q39536
3.x 4.00 4.01 MS-DOS
We are writing a terminate-and-stay-resident (TSR) software application and would like to use the MS-DOS EXEC function (MS-DOS Interrupt 21H, Function 4BH), but we are not able to get it to work. Will this function work from within a TSR application? In other words, is there any difference between executing a child process by using the EXEC service from a TSR application as opposed to a normal application?
There are many considerations for using the MS-DOS EXEC function from a TSR application. This is not a simple issue. We have to make the following assumptions:
- You have a TSR application residing in memory that wants to call the MS-DOS EXEC function to execute another child application.
- The TSR is written in assembly language. Working from such a theoretical base, we don’t have to worry about idiosyncrasies and abstractions of the run-time library functions of high-level languages (e.g. how the Microsoft C Compiler is handling its spawn, EXEC, or system functions). For applications working this close to the system, it’s a good idea to program in assembly language anyway, since you have to be very familiar with every machine instruction that you make.
- Your program is intelligent enough to know when it can and cannot issue MS-DOS services–reentrancy problems will bring a TSR application to a quick halt if the program is not careful. The application must be able to detect when MS-DOS is in a critical section and must refrain from issuing MS-DOS calls; otherwise, the application will have problems. One of the best sources of information on how to do this is article 11 of “The MS-DOS Encyclopedia.”
- The program is running under the proper environment (i.e., PSP or PHP). This, like the reentrancy issues, is described in detail in article 11 of “The MS-DOS Encyclopedia.” Without this, there is a good chance that MS-DOS will be confused as to who is issuing MS-DOS calls: the foreground application or your TSR application.
At this point, we can hopefully assume that we have a “well-behaved” TSR application that knows when to attempt calling MS-DOS, and how to save and restore its environment to avoid any confusion with the foreground application; also, we don’t have to be concerned with the limitations of an HLL (High Level Language) run-time library.
These, of course, are a lot of limitations.
From this point, your TSR should be able to safely call the MS-DOS EXEC function.
At this point, your TSR application will most likely run into problems when it is not able to find enough memory to EXEC a program. A TSR is almost always at the mercy of the current foreground application’s environment, and how the environment is controlling the system. These programs often allocate the largest chunk of free memory when they are invoked, and they do not leave you enough to use for your EXEC. An example of this is COMMAND.COM, which allocates all available memory so that it can place its transient portion at the top of memory. Most .COM files allocate all of memory; the only way that you could have free space is if the program issues MS-DOS Interrupt 21H Service 4AH, SETBLOCK. This would free up some of the memory it has allocated for this process, perhaps giving you enough room to EXEC your program. Many .EXE files have this allocation size set to a smaller value; this field is in the EXE header.
The result of all of this careful planning and coding is that you may be able to EXEC a program, depending on the current application running, how much memory it has allocated, and how much memory is free. Thus, writing a TSR that uses EXEC is possible if it is done carefully, but it is dependent on the foreground application. That is, the success of the EXEC is based on the currently running program and how much memory is available (which is largely a factor of the currently running program).
Another example of how a TSR application may foul up the foreground application is if it does something such as allocating memory to perform an EXEC operation. If the foreground application has freed up enough memory to allow you to work with, it very well may be that the foreground application is planning on using this memory for its own purposes, for example, EXECing its own child process. It will not expect a background TSR application to allocate this memory and use it for its own use. This may have unpredictable results in the operation of the foreground application.
MS-DOS is a single-tasking environment that does not have the proper support for multiple processes. Instead of the operating system performing time slicing between processes, more than one process is able to occupy memory only by hooking onto interrupts and interrupting another application. How successful a background application is at interrupting this foreground application is almost entirely up to the background application, and MS-DOS has no control over this. Once the background application is in control of the system, it may not be able to perform what it wants, since it is at the mercy of the current environment in which the foreground application is running. Writing TSR applications is a haphazard and risky thing to do.