/*
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 *%	  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
*/
#include <windows.h>
#include <process.h>
#include "initfini.h"

extern int APIENTRY LibMain( HANDLE, DWORD, LPVOID );
extern int __NTInit( int, void *, HANDLE );
extern void __CommonInit( void );

extern void __InitMultipleThread( void );
extern BOOL __NTAddThread(void *);
extern void __NTRemoveThread( int );
extern BOOL __NTThreadInit( void );
extern void __NTThreadFini( void );
extern BOOL __disallow_single_dgroup( HANDLE );


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

    switch( reason ) {
    case DLL_THREAD_ATTACH:
	if( !__NTAddThread( NULL ) ) {
	    return( FALSE );
	}
	rc = LibMain( hdll, reason, reserved );
	break;
    case DLL_PROCESS_ATTACH:
	++processes;
	if( processes > 1 ) {
	    if( __disallow_single_dgroup( hdll ) ) {
		rc = FALSE;
		break;
	    }
	}
	__InitRtns( 1 );
	if( !__NTInit( TRUE, NULL, hdll ) ) {
	    rc = FALSE;
	    break;
	}
	if( !__NTThreadInit() ) {
	    rc = FALSE;
	    break;
	}
	if( !__NTAddThread( NULL ) ) {
	    rc = FALSE;
	    break;
	}
	__InitRtns( 15 );
	__InitMultipleThread();
	if( _pRawDllMain != NULL ) {
	    if( !_pRawDllMain( hdll, reason, reserved ) ) {
		__FiniRtns( 0, 15 );
		rc = FALSE;
		break;
	    }
	}
	__InitRtns( 255 );
	__CommonInit();
	rc = LibMain( hdll, reason, reserved );
	if( !rc ) {
	    __FiniRtns( 0, 255 );
	}
	break;
    case DLL_THREAD_DETACH:
	rc = LibMain( hdll, reason, reserved );
	__NTRemoveThread( FALSE );
	break;
    case DLL_PROCESS_DETACH:
	rc = LibMain( hdll, reason, reserved );
	__FiniRtns( 16, 255 );
	if( _pRawDllMain != NULL ) {
	    _pRawDllMain( hdll, reason, reserved );
	}
	__FiniRtns( 0, 15 );
	__NTRemoveThread( FALSE );
	--processes;
    }
    return( rc );
}
