/*
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 *%       Copyright (C) 1991, by WATCOM Systems Inc. All rights     %
 *%       reserved. No part of this software may be reproduced      %
 *%       in any form or by any means - graphic, electronic or      %
 *%       mechanical, including photocopying, recording, taping     %
 *%       or information storage and retrieval systems - except     %
 *%       with the written permission of WATCOM Systems Inc.        %
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  Modified:     By:             Reason:
  ---------     ---             -------
  18-mar-92     Craig Eisler    defined for NT
  10-apr-92     Craig Eisler    made it work
  25-sep-92     Craig Eisler    handle thread/process specific stuff
  28-sep-92     G. Coschi       fixed problems with DLLs
  21-oct-92     Craig Eisler    use thread local storage
  16-dec-92     G. Coschi       call __InitMultipleThread() when LibMain()
                                called with DLL_PROCESS_ATTACH
  05-feb-93     Craig Eisler    check __NTInit for failure
  26-sep-94     Greg Bentz      added pRawDllMain for MFC 3.0 support
  06-jan-95     John Dahms      better support for win32s
                Greg Bentz
  17-feb-95     Greg Bentz      limit support for single DGROUP
  03-nov-95     T. Schiller     now properly initializes signal table
--------------------------------------------------------Version-11.0---------
  05-jul-96     M. Hildebrand   Use __lib_ versions of ...W Win32 functions.
  19-nov-96     Greg Bentz      -br libs need granular linkage for _LpDllname
--------------------------------------------------------Version-11.0c--------
  18-feb-00     J.B.Schueler    Added call to __NTFini.
  23-feb-00     J.B.Schueler    Multiple calls to __InitMultipleThread() would
                                screw up thread data list. Now fixed.
*/
#include "variety.h"
#include <windows.h>
#include <process.h>
#include <stdlib.h>
#include "initfini.h"
#include "libwin32.h"

extern int APIENTRY LibMain( HANDLE, DWORD, LPVOID );
extern void __CommonInit( void );
extern BOOL __disallow_single_dgroup( HANDLE );

#ifdef __SW_BR
    extern int          __Is_DLL;       /* TRUE => DLL, else not a DLL */
    extern char *       _LpDllName;
    extern wchar_t *    _LpwDllName;
#else
    extern int  __NTInit( int, void *, HANDLE );
    extern void __NTFini( void );
    extern BOOL __NTThreadInit( void );
    extern void __InitMultipleThread( void );
    extern BOOL __NTAddThread(void *);
    extern void __NTRemoveThread( int );
#endif

_WCRTLINK extern void (*__sig_init_rtn)(void);


int APIENTRY _LibMain( HANDLE hdll, DWORD reason, LPVOID reserved )
{
    int rc;
    static int processes;

    switch( reason ) {
    case DLL_THREAD_ATTACH:
        #ifndef __SW_BR
            if( !__NTAddThread( NULL ) ) {
                return( FALSE );
            }
        #endif
        rc = LibMain( hdll, reason, reserved );
        break;
    case DLL_PROCESS_ATTACH:
        ++processes;
        if( processes > 1 ) {
            if( __disallow_single_dgroup( hdll ) ) {
                rc = FALSE;
                break;
            }
        }
        #ifdef __SW_BR
            __Is_DLL = 1;
            __InitRtns( 15 );
        #else
            // The following initializers are called: (in the CLIB run-time DLL):
            //      nothing is called
            __InitRtns( 1 );
            // allocate some thread data storage and initialize run-time variables
            if( !__NTInit( TRUE, NULL, hdll ) ) {
                rc = FALSE;
                break;
            }
            // set up TLSIndex thingee
            if( !__NTThreadInit() ) {   // safe to call multiple times
                rc = FALSE;
                break;
            }
            // The following initializers are called: (in the CLIB run-time DLL):
            //      __chk8087
            //      __verify_pentium_fdiv_bug
            //      __Init_Argv
            //      __imthread_fn (which calls _NTThreadInit and __InitMultipleThread)
            __InitRtns( 15 );
            // sets up semaphores and starts linked list of thread data storage
            __InitMultipleThread();     // now safe to call multiple times
        #endif
        if( _pRawDllMain != NULL ) {
            if( !_pRawDllMain( hdll, reason, reserved ) ) {
                __FiniRtns( 0, FINI_PRIORITY_EXIT-1 );
                rc = FALSE;
                break;
            }
        }
        // The following initializers are called: (in the CLIB run-time DLL):
        //      profilog_init
        //      __InitWinLinesSem
        //      dbgdata@do_it
        //      __setenvp
        //      __mbInitOnStartup
        //      __sig_init
        //      __is_nonIBM
        //      (??) in STK
        //      __InitFiles
        //      __clock_init
        __InitRtns( 255 );
        #ifdef __SW_BR
        {
            static char    fn[_MAX_PATH];
            GetModuleFileNameA( hdll, fn, sizeof( fn ) );
            _LpDllName = fn;
        }
        {
            static wchar_t wfn[_MAX_PATH];
            __lib_GetModuleFileNameW( hdll, wfn, sizeof( wfn ) );
            _LpwDllName = wfn;
        }
        #endif
        __CommonInit();
        __sig_init_rtn();
        rc = LibMain( hdll, reason, reserved );
        if( !rc ) {
            __FiniRtns( 0, 255 );
        }
        break;
    case DLL_THREAD_DETACH:
        rc = LibMain( hdll, reason, reserved );
        #ifndef __SW_BR
            __NTRemoveThread( TRUE );
        #endif
        break;
    case DLL_PROCESS_DETACH:
        rc = LibMain( hdll, reason, reserved );
        __FiniRtns( FINI_PRIORITY_EXIT, 255 );
        if( _pRawDllMain != NULL ) {
            _pRawDllMain( hdll, reason, reserved );
        }
        #ifndef __SW_BR
            __NTFini(); // must be done before following finalizers get called
        #endif
        __FiniRtns( 0, FINI_PRIORITY_EXIT-1 );
        #ifndef __SW_BR
            __NTRemoveThread( TRUE );
        #endif
        --processes;
    }
    return( rc );
}
