home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / crtdll.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  13KB  |  455 lines

  1. /***
  2. *crtdll.c - CRT initialization for a DLL using the MSVCRT* model of C run-time
  3. *
  4. *       Copyright (c) 1991-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       This module contains the initialization entry point for the C run-time
  8. *       stub in this DLL.  All C run-time code is located in the C Run-Time
  9. *       Library DLL "MSVCRT*.DLL", except for a little bit of start-up code in
  10. *       the EXE, and this code in each DLL.  This code is necessary to invoke
  11. *       the C++ constructors for the C++ code in this DLL.
  12. *
  13. *       This entry point should either be specified as the DLL initialization
  14. *       entry point, or else it must be called by the DLL initialization entry
  15. *       point of the DLL with the same arguments that the entry point receives.
  16. *
  17. *       MPPC note:
  18. *       This is the routine should be pulled in when building a DLL using CRT DLL
  19. *       This should be put into ppccrt30.lib
  20. *       User should either use _DllMainCRTStartup as -Init, and put their own init(if any) in _DllInit
  21. *       Or call _DllMainCRTStartup in their init specified by -Init*
  22. *
  23. *******************************************************************************/
  24.  
  25. #ifndef _MAC
  26.  
  27. #ifdef CRTDLL
  28.  
  29. /*
  30.  * SPECIAL BUILD MACRO! Note that crtexe.c (and crtexew.c) is linked in with
  31.  * the client's code. It does not go into crtdll.dll! Therefore, it must be
  32.  * built under the _DLL switch (like user code) and CRTDLL must be undefined.
  33.  */
  34. #undef  CRTDLL
  35. #define _DLL
  36.  
  37. #include <cruntime.h>
  38. #include <oscalls.h>
  39. #include <internal.h>
  40. #include <stdlib.h>
  41. #define _DECL_DLLMAIN   /* enable prototypes for DllMain and _CRT_INIT */
  42. #include <process.h>
  43. #include <dbgint.h>
  44.  
  45.  
  46. #ifdef _M_IX86
  47.  
  48. /*
  49.  * The local copy of the Pentium FDIV adjustment flag
  50.  *      and the address of the flag in MSVCRT*.DLL.
  51.  */
  52.  
  53. extern int _adjust_fdiv;
  54.  
  55. extern int * _imp___adjust_fdiv;
  56.  
  57. #endif  /* _M_IX86 */
  58.  
  59.  
  60. /*
  61.  * routine in DLL to do initialization (in this case, C++ constructors)
  62.  */
  63.  
  64. extern void __cdecl _initterm(_PVFV *, _PVFV *);
  65.  
  66. /*
  67.  * pointers to initialization sections
  68.  */
  69.  
  70. extern _PVFV __xc_a[], __xc_z[];    /* C++ initializers */
  71.  
  72. /*
  73.  * flag set iff _CRTDLL_INIT was called with DLL_PROCESS_ATTACH
  74.  */
  75. static int __proc_attached = 0;
  76.  
  77.  
  78. /*
  79.  * Pointers to beginning and end of the table of function pointers manipulated
  80.  * by _onexit()/atexit().  The atexit/_onexit code is shared for both EXE's and
  81.  * DLL's but different behavior is required.  These values are initialized to
  82.  * 0 by default and will be set to point to a malloc-ed memory block to mark
  83.  * this module as an DLL.
  84.  */
  85.  
  86. extern _PVFV *__onexitbegin;
  87. extern _PVFV *__onexitend;
  88.  
  89.  
  90. /*
  91.  * User routine DllMain is called on all notifications
  92.  */
  93.  
  94. extern BOOL WINAPI DllMain(
  95.         HANDLE  hDllHandle,
  96.         DWORD   dwReason,
  97.         LPVOID  lpreserved
  98.         ) ;
  99.  
  100. /* _pRawDllMain MUST be a common variable, not extern nor initialized! */
  101.  
  102. BOOL (WINAPI *_pRawDllMain)(HANDLE, DWORD, LPVOID);
  103.  
  104.  
  105. /***
  106. *BOOL WINAPI _CRT_INIT(hDllHandle, dwReason, lpreserved) - C++ DLL
  107. *       initialization.
  108. *BOOL WINAPI _DllMainCRTStartup(hDllHandle, dwReason, lpreserved) - C++ DLL
  109. *       initialization.
  110. *
  111. *Purpose:
  112. *       This is the entry point for DLL's linked with the C/C++ run-time libs.
  113. *       This routine does the C runtime initialization for a DLL linked with
  114. *       MSVCRT.LIB (whose C run-time code is thus in MSVCRT*.DLL.)
  115. *       It will call the user notification routine DllMain on all 4 types of
  116. *       DLL notifications.  The return code from this routine is the return
  117. *       code from the user notification routine.
  118. *
  119. *       On DLL_PROCESS_ATTACH, the C++ constructors for the DLL will be called.
  120. *
  121. *       On DLL_PROCESS_DETACH, the C++ destructors and _onexit/atexit routines
  122. *       will be called.
  123. *
  124. *Entry:
  125. *
  126. *Exit:
  127. *
  128. *******************************************************************************/
  129.  
  130. BOOL WINAPI _CRT_INIT(
  131.         HANDLE  hDllHandle,
  132.         DWORD   dwReason,
  133.         LPVOID  lpreserved
  134.         )
  135. {
  136.         /*
  137.          * If this is a process detach notification, check that there has
  138.          * been a prior (successful) process attachment.
  139.          */
  140.         if ( dwReason == DLL_PROCESS_DETACH ) {
  141.             if ( __proc_attached > 0 )
  142.                 __proc_attached--;
  143.             else
  144.                 /*
  145.                  * no prior process attach. just return failure.
  146.                  */
  147.                 return FALSE;
  148.         }
  149.  
  150. #ifdef _M_IX86
  151.  
  152.         /*
  153.          * Set the local copy of the Pentium FDIV adjustment flag
  154.          */
  155.  
  156.         _adjust_fdiv = * _imp___adjust_fdiv;
  157.  
  158. #endif  /* _M_IX86 */
  159.  
  160.         /*
  161.          * do C++ constructors (initializers) specific to this DLL
  162.          */
  163.  
  164.         if ( dwReason == DLL_PROCESS_ATTACH ) {
  165.  
  166.             /*
  167.              * create the onexit table.
  168.              */
  169.             if ( (__onexitbegin = (_PVFV *)_malloc_crt(32 * sizeof(_PVFV)))
  170.                  == NULL )
  171.                 /*
  172.                  * cannot allocate minimal required
  173.                  * size. generate failure to load DLL
  174.                  */
  175.                 return FALSE;
  176.  
  177.             *(__onexitbegin) = (_PVFV) NULL;
  178.  
  179.             __onexitend = __onexitbegin;
  180.  
  181.             /*
  182.              * Invoke C++ constructors
  183.              */
  184.             _initterm(__xc_a,__xc_z);
  185.  
  186.             /*
  187.              * Increment the process attached flag.
  188.              */
  189.             __proc_attached++;
  190.  
  191.         }
  192.         else if ( dwReason == DLL_PROCESS_DETACH ) {
  193.  
  194.             /*
  195.              * Any basic clean-up code that goes here must be
  196.              * duplicated below in _DllMainCRTStartup for the
  197.              * case where the user's DllMain() routine fails on a
  198.              * Process Attach notification. This does not include
  199.              * calling user C++ destructors, etc.
  200.              */
  201.  
  202.             /*
  203.              * do _onexit/atexit() terminators
  204.              * (if there are any)
  205.              *
  206.              * These terminators MUST be executed in
  207.              * reverse order (LIFO)!
  208.              *
  209.              * NOTE:
  210.              *  This code assumes that __onexitbegin
  211.              *  points to the first valid onexit()
  212.              *  entry and that __onexitend points
  213.              *  past the last valid entry. If
  214.              *  __onexitbegin == __onexitend, the
  215.              *  table is empty and there are no
  216.              *  routines to call.
  217.              */
  218.  
  219.             if (__onexitbegin) {
  220.                 _PVFV * pfend = __onexitend;
  221.  
  222.                 while ( -- pfend >= __onexitbegin )
  223.                     /*
  224.                      * if current table entry is not
  225.                      * NULL, call thru it.
  226.                      */
  227.                     if ( *pfend != NULL )
  228.                         (**pfend)();
  229.  
  230.                 /*
  231.                  * free the block holding onexit table to
  232.                  * avoid memory leaks.  Also zero the ptr
  233.                  * variable so that it is clearly cleaned up.
  234.                  */
  235.  
  236.                 _free_crt ( __onexitbegin ) ;
  237.  
  238.                 __onexitbegin = NULL ;
  239.             }
  240.         }
  241.  
  242.         return TRUE;
  243. }
  244.  
  245.  
  246. BOOL WINAPI _DllMainCRTStartup(
  247.         HANDLE  hDllHandle,
  248.         DWORD   dwReason,
  249.         LPVOID  lpreserved
  250.         )
  251. {
  252.         BOOL retcode = TRUE;
  253.  
  254.         /*
  255.          * If this is a process detach notification, check that there has
  256.          * been a prior process attach notification.
  257.          */
  258.         if ( (dwReason == DLL_PROCESS_DETACH) && (__proc_attached == 0) )
  259.             return FALSE;
  260.  
  261.         if ( dwReason == DLL_PROCESS_ATTACH || dwReason == DLL_THREAD_ATTACH )
  262.         {
  263.             if ( _pRawDllMain )
  264.                 retcode = (*_pRawDllMain)(hDllHandle, dwReason, lpreserved);
  265.  
  266.             if ( retcode )
  267.                 retcode = _CRT_INIT(hDllHandle, dwReason, lpreserved);
  268.  
  269.             if ( !retcode )
  270.                 return FALSE;
  271.         }
  272.  
  273.         retcode = DllMain(hDllHandle, dwReason, lpreserved);
  274.  
  275.  
  276.         if ( (dwReason == DLL_PROCESS_ATTACH) && !retcode )
  277.             /*
  278.              * The user's DllMain routine returned failure, the C runtime
  279.              * needs to be cleaned up. Do this by calling _CRT_INIT again,
  280.              * this time imitating DLL_PROCESS_DETACH. Note this will also
  281.              * clear the __proc_attached flag so the cleanup will not be
  282.              * repeated upon receiving the real process detach notification.
  283.              */
  284.             _CRT_INIT(hDllHandle, DLL_PROCESS_DETACH, lpreserved);
  285.  
  286.         if ( (dwReason == DLL_PROCESS_DETACH) ||
  287.              (dwReason == DLL_THREAD_DETACH) )
  288.         {
  289.             if ( _CRT_INIT(hDllHandle, dwReason, lpreserved) == FALSE )
  290.                 retcode = FALSE ;
  291.  
  292.             if ( retcode && _pRawDllMain )
  293.                 retcode = (*_pRawDllMain)(hDllHandle, dwReason, lpreserved);
  294.         }
  295.  
  296.         return retcode ;
  297. }
  298.  
  299. #endif  /* CRTDLL */
  300.  
  301. #else  /* _MAC */
  302.  
  303. #include <cruntime.h>
  304. #include <internal.h>
  305. #include <stdlib.h>
  306. #include <fltintrn.h>
  307. #include <dbgint.h>
  308. #include <macos\types.h>
  309. #include <macos\fragload.h>
  310.  
  311. /*
  312.  * routine in DLL to do initialization (in this case, C++ constructors)
  313.  */
  314. extern void __cdecl _initterm(PFV *, PFV *);
  315. static char * __cdecl _p2cstr_internal ( unsigned char * str );
  316. static void * memcpy_internal ( void * dst, const void * src,   size_t count);
  317. int _DllInit(InitBlockPtr pinitBlk);
  318.  
  319. /*
  320.  * pointers to initialization functions
  321.  */
  322.  
  323. extern PFV __xi_a ;
  324.  
  325. extern PFV __xi_z ;
  326.  
  327. extern PFV __xc_a ;  /* C++ initializers */
  328.  
  329. extern PFV __xc_z ;
  330.  
  331. extern PFV __xp_a ;  /* C pre-terminators */
  332.  
  333. extern PFV __xp_z ;
  334.  
  335. extern PFV __xt_a ;   /* C terminators */
  336.  
  337. extern PFV __xt_z ;
  338.  
  339. /*this globals are defined in DLL */
  340. extern int __argc;
  341.  
  342. extern char **__argv;
  343.  
  344. extern PFV *__onexitbegin;
  345. extern PFV *__onexitend;
  346.  
  347. /***
  348. *void _DllMainCRTStartup(void)
  349. *
  350. *Purpose:
  351. *       This routine does the C runtime initialization.
  352. *
  353. *Entry:
  354. *
  355. *Exit:
  356. *
  357. *******************************************************************************/
  358.  
  359. OSErr _DllMainCRTStartup(
  360.         InitBlockPtr pinitBlk
  361.         )
  362. {
  363.         int argc=1; /* three standard arguments to main */
  364.         char *argv[2];
  365.         char **environ = NULL;
  366.         char szPgmName[32];
  367.         char *pArg;
  368.  
  369.  
  370.         memcpy_internal(szPgmName, (char *)0x910, sizeof(szPgmName));
  371.         pArg = _p2cstr_internal(szPgmName);
  372.         argv[0] = pArg;
  373.         argv[1] = NULL;
  374.  
  375.         __argc = 1;
  376.         __argv = argv;
  377.  
  378.         /*
  379.          * intialize the global destruction table
  380.          */
  381.         if ( (__onexitbegin = (PFV *)_malloc_crt(32 * sizeof(PFV))) == NULL )
  382.                         {
  383.                         /*
  384.                          * cannot allocate minimal required
  385.                          * size. generate failure to load DLL
  386.                          * any non-zero value will do...
  387.                          */
  388.                         return 1;
  389.                         }
  390.  
  391.         *(__onexitbegin) = (PFV) NULL;
  392.  
  393.         __onexitend = __onexitbegin;
  394.  
  395.         /*
  396.          * Do runtime startup initializers.
  397.          */
  398.         _initterm( &__xi_a, &__xi_z );
  399.  
  400.  
  401.         /*
  402.          * do C++ constructors (initializers) specific to this DLL
  403.          */
  404.         _initterm( &__xc_a, &__xc_z );
  405.  
  406.         return _DllInit(pinitBlk);
  407. }
  408.  
  409. static char * __cdecl _p2cstr_internal (
  410.         unsigned char * str
  411.         )
  412. {
  413.         unsigned char *pchSrc;
  414.         unsigned char *pchDst;
  415.         int  cch;
  416.  
  417.         if ( str && *str )
  418.             {
  419.             pchDst = str;
  420.             pchSrc = str + 1;
  421.  
  422.             for ( cch=*pchDst; cch; --cch )
  423.                 {
  424.                 *pchDst++ = *pchSrc++;
  425.                 }
  426.  
  427.             *pchDst = '\0';
  428.             }
  429.  
  430.         return( str );
  431. }
  432.  
  433.  
  434. static void * memcpy_internal (
  435.         void * dst,
  436.         const void * src,
  437.         size_t count
  438.         )
  439. {
  440.         void * ret = dst;
  441.  
  442.         /*
  443.          * copy from lower addresses to higher addresses
  444.          */
  445.         while (count--) {
  446.             *(char *)dst = *(char *)src;
  447.             dst = (char *)dst + 1;
  448.             src = (char *)src + 1;
  449.         }
  450.  
  451.         return(ret);
  452. }
  453.  
  454. #endif  /* _MAC */
  455.