Spawned Program Accessing Parent's Functions

Last reviewed: July 17, 1997
Article ID: Q43318
5.10 6.00 6.00a 6.00ax 7.00 | 5.10 6.00 6.00a | 1.00 1.50
MS-DOS                      | OS/2            | WINDOWS
kbprg

The information in this article applies to:

  • The C Run-time (CRT) included with:

        - Microsoft C for MS-DOS, versions 5.1, 6.0, 6.0a, and 6.0ax
        - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a
        - Microsoft C/C++ for MS-DOS, version 7.0
        - Microsoft Visual C++ for Windows, versions 1.0 and 1.5
    

SUMMARY

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.

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 myfunc(void);
void                      main(void);

int   k = 0, l = 0;   /* Globals to be accessed inside myfunc */


int far _saveregs _loadds myfunc(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 * myfuncaddr) (void);  /* myfunc()
pointer   */
   char   address[16];                               /* address to
pass */

   printf("Now inside parent main().\n");
   myfuncaddr = (int (far _saveregs _loadds *) (void)) myfunc;
   ultoa((unsigned long) myfuncaddr, address, 10);
   printf("Address of myfunc(): %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 * myfuncaddr)(void);
                            /* Pointer to parent's function */
   int i;                   /* Function return value        */

   printf("    Now in child.\n");
   myfuncaddr = (int (far _loadds _saveregs *)(void))atol(argv[1]);
   printf("    Received: %ld\n", myfuncaddr);
   printf("    Calling myfunc().\n");
   i = myfuncaddr();
   printf("        Result of myfunc(): %d\n", i);
   printf("    Leaving child.\n");
}


Additional reference words: kbinf 6.00 6.00a 6.00ax 7.00 1.00 1.50
KBCategory: kbprg
KBSubcategory: CRTIss
Keywords : kb16bitonly


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 17, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.