ID Number: Q43318
5.10 6.00 6.00a 6.00ax 7.00 | 5.10 6.00 6.00a
MS-DOS | OS/2
Summary:
In Microsoft C versions 5.0, 5.1, 6.0, 6.0a, 6.0ax, and C/C++ version
7.0, a program spawned with the P_WAIT modeflag can successfully call
functions within its parent. The functions must be set up in such a
way, however, that CPU registers are preserved and the data segment
register is loaded as necessary. It is also very important that all
necessary startup code and C run time library routines are present
whenever the parent functions are called.
Warning: This procedure is neither recommended nor supported. This
article is for informational purposes only. Additionally, for C/C++
7.0, this procedure works only in the large memory model.
More Information:
The programs below, PARENT.C and CHILD.C, demonstrate this technique.
This method of sharing functions may be useful as a primitive form of
overlaying when there is a need for a common set of functions to be
accessed by a sequence of spawned child processes. The method of
communication from the parent to the child is through command-line
arguments. In the parent, a far pointer to the function that will be
called is converted to a string and passed as a parameter through a
spawn. In the child, it is then converted back into a far pointer.
There are several considerations to be made when writing code of this
nature:
- For any variables in the parent to be accessed, the routines to be
called must use the _loadds keyword. Not loading DS for the called
function results in the child's DS being used rather than the DS
associated with the function in the parent.
- Even if _loadds is used, however, DS will not be equal to SS,
because the child's stack is the one that is used and there is no
mechanism in C for changing stacks. It is necessary to ensure that
the functions called by the child do not blow out the child's
stack.
- Many of the run-time library routines rely on SS equaling DS;
therefore, one must avoid those routines.
- Preservation of the child's state can be accomplished by using the
_saveregs keyword. This is not necessary when calling C from C;
however, it may be vital if C is being called from MASM.
- All calls must be far because the parent and child are loaded
separately. Different memory models may be used for parent and
child.
- This process obviously produces a general-protection fault (GP
fault) in OS/2. Use dynamic-link libraries to duplicate this
functionality with greater ease, portability, and safety.
Sample Code:
------------
The following is the parent program:
/*
* PARENT.C
*/
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
int far _saveregs _loadds foo(void);
void main(void);
int k = 0, l = 0; /* Globals to be accessed inside foo */
int far _saveregs _loadds foo(void)
{
int i, /* Return value */
j; /* Indexing */
for (j = 1; j < 10; j++) {
k = k + j;
l = k * j;
}
i = k + l;
return (i);
}
void main()
{
int (far _saveregs _loadds * fooaddr) (void); /* foo() pointer */
char address[16]; /* address to pass */
printf("Now inside parent main().\n");
fooaddr = (int (far _saveregs _loadds *) (void)) foo;
ultoa((unsigned long) fooaddr, address, 10);
printf("Address of foo(): %s\n", address);
spawnlp(P_WAIT, "child.exe", "child.exe", address, NULL);
printf("Back inside parent main().\n");
}
The following is the child program:
/*
* CHILD.C
*/
#include <stdio.h>
#include <stdlib.h>
void main(int argc, char **argv)
{
int (far _loadds _saveregs * fooaddr)(void);
/* Pointer to parent's function */
int i; /* Function return value */
printf(" Now in child.\n");
fooaddr = (int (far _loadds _saveregs *)(void))atol(argv[1]);
printf(" Received: %ld\n", fooaddr);
printf(" Calling foo().\n");
i = fooaddr();
printf(" Result of foo(): %d\n", i);
printf(" Leaving child.\n");
}
Additional reference words: 6.0 6.00 6.0a 6.00a 6.0ax 6.00ax quickc
2.0 2.00 2.01 2.5 2.50 2.51 7.00