//***************************************************************************
//
//  MAINDLL.CPP
//
//  Module: WBEM Framework Instance provider
//
//  Purpose: Contains DLL entry points.  Also has code that controls
//           when the DLL can be unloaded by tracking the number of
//           objects and locks as well as routines that support
//           self registration.
//
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
//***************************************************************************

#include "precomp.h"
#include <dllunreg.h>
#include <DllCommon.h>
#include <initguid.h>
#include "FactoryRouter.h"
#include "ResourceManager.h"
#include "timerqueue.h"
#include <shutdownevent.h>
#include <volumechange.h>

HMODULE ghModule;

// {04788120-12C2-498d-83C1-A7D92E677AC6}
DEFINE_GUID(CLSID_CimWinProviderA, 
0x4788120, 0x12c2, 0x498d, 0x83, 0xc1, 0xa7, 0xd9, 0x2e, 0x67, 0x7a, 0xc6);
// {A3E41207-BE04-492a-AFF0-19E880FF7545}
DEFINE_GUID(CLSID_ShutdownEventProvider, 
0xa3e41207, 0xbe04, 0x492a, 0xaf, 0xf0, 0x19, 0xe8, 0x80, 0xff, 0x75, 0x45);
// {E2CBCB87-9C07-4523-A78F-061499C83987}
DEFINE_GUID(CLSID_VolumeChangeEventProvider, 
0xe2cbcb87, 0x9c07, 0x4523, 0xa7, 0x8f, 0x6, 0x14, 0x99, 0xc8, 0x39, 0x87);


#define PROVIDER_NAME L"WMIPCIMA"

//====================================================================================
// initialize class globals
//====================================================================================
CFactoryRouterData     g_FactoryRouterData;
CShutdownEventFactory* gp_ShutdownEventFactory = NULL;
CVolumeChangeFactory*  gp_VolumeChangeFactory = NULL;

CTimerQueue CTimerQueue :: s_TimerQueue ;
CResourceManager CResourceManager::sm_TheResourceManager ;

//Count number of objects and number of locks.
long g_cLock = 0;

//***************************************************************************
//
//  DllGetClassObject
//
//  Purpose: Called by Ole when some client wants a class factory.  Return
//           one only if it is the sort of class this DLL supports.
//
//***************************************************************************

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PPVOID ppv)
{
    HRESULT hr = S_OK;

    try
    {
        if ( CLSID_CimWinProviderA == rclsid )
        {
            hr = CommonGetClassObject(riid, ppv, PROVIDER_NAME, g_cLock);
        }
        else
        {
            hr = g_FactoryRouterData.DllGetClassObject( rclsid, riid, ppv ) ;
        }
    }
    catch ( ... )
    {
        hr = E_OUTOFMEMORY;
    }

    return hr;
}

//***************************************************************************
//
// DllCanUnloadNow
//
// Purpose: Called periodically by Ole in order to determine if the
//          DLL can be freed.
//
// Return:  S_OK if there are no objects in use and the class factory
//          isn't locked.
//
//***************************************************************************

STDAPI DllCanUnloadNow()
{
    SCODE sc = S_FALSE;

    try
    {
        // It is OK to unload if there are no locks on the
        // class factory and the framework allows us to go.
        if (g_FactoryRouterData.DllCanUnloadNow())
        {
            sc = CommonCanUnloadNow(PROVIDER_NAME, g_cLock);
        }

        if ( sc == S_OK )
        {
            CTimerQueue::s_TimerQueue.OnShutDown();
            CResourceManager::sm_TheResourceManager.ForcibleCleanUp () ;

#ifdef WIN9XONLY
            HoldSingleCim32NetPtr::FreeCim32NetApiPtr() ;
#endif
        }
    }
    catch ( ... )
    {
        // sc should already be set correctly
    }

    return sc;
}

//***************************************************************************
//
// DllRegisterServer
//
// Purpose: Called during setup or by regsvr32.
//
// Return:  NOERROR if registration successful, error otherwise.
//***************************************************************************

STDAPI DllRegisterServer(void)
{
    HRESULT t_status = S_OK;

    try
    {
        t_status = RegisterServer( _T("WBEM Framework Instance Provider CIMA"), CLSID_CimWinProviderA ) ;
        if( NOERROR == t_status )
        {
            t_status = g_FactoryRouterData.DllRegisterServer() ;
        }
    }
    catch ( ... )
    {
        t_status = E_OUTOFMEMORY;
    }

    return t_status ;
}

//***************************************************************************
//
// DllUnregisterServer
//
// Purpose: Called when it is time to remove the registry entries.
//
// Return:  NOERROR if registration successful, error otherwise.
//***************************************************************************

STDAPI DllUnregisterServer(void)
{
    HRESULT t_status = S_OK;

    try
    {
        t_status = UnregisterServer( CLSID_CimWinProviderA ) ;
        if( NOERROR == t_status )
        {
            t_status = g_FactoryRouterData.DllUnregisterServer() ;
        }
    }
    catch ( ... )
    {
        t_status = E_OUTOFMEMORY;
    }

    return t_status ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL InitializeEventFactories(void)
{
	BOOL fRet = FALSE;

	gp_ShutdownEventFactory = new CShutdownEventFactory( CLSID_ShutdownEventProvider,SHUTDOWN_EVENT_CLASS ) ;
	if( gp_ShutdownEventFactory )
	{
		gp_VolumeChangeFactory = new CVolumeChangeFactory( CLSID_VolumeChangeEventProvider,VOLUME_CHANGE_EVENT ) ;
		if( gp_VolumeChangeFactory )
		{
			fRet = TRUE;
		}
	}
	return fRet;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CleanupEventFactories(void)
{
	if( gp_ShutdownEventFactory )
	{
		delete gp_ShutdownEventFactory;
		gp_ShutdownEventFactory = NULL;
	}
	if( gp_VolumeChangeFactory )
	{
		delete gp_VolumeChangeFactory;
		gp_VolumeChangeFactory = NULL;
	}
}
//***************************************************************************
//
// DllMain
//
// Purpose: Called by the operating system when processes and threads are
//          initialized and terminated, or upon calls to the LoadLibrary
//          and FreeLibrary functions
//
// Return:  TRUE if load was successful, else FALSE
//***************************************************************************

BOOL APIENTRY DllMain( HINSTANCE hInstDLL,  // handle to DLL module
                       DWORD fdwReason,     // reason for calling function
                       LPVOID lpReserved )  // reserved
{
    BOOL bRet = TRUE;

    try
    {
		LogMessage2( L"%s  -> DllMain", PROVIDER_NAME);

		// Perform actions based on the reason for calling.
		switch( fdwReason )
		{
			case DLL_PROCESS_ATTACH:
			{
				bRet = CommonProcessAttach(PROVIDER_NAME, g_cLock, hInstDLL);
				if( bRet )
				{
					bRet = InitializeEventFactories();
				}
			}
			break;

			case DLL_THREAD_ATTACH:
			{
			 // Do thread-specific initialization.
			}
			break;

			case DLL_THREAD_DETACH:
			{
			 // Do thread-specific cleanup.
			}
			break;

			case DLL_PROCESS_DETACH:
			{
					CleanupEventFactories();
					// Perform any necessary cleanup.
					LogMessage( L"DLL_PROCESS_DETACH" );
			}
			break;
		}
    }
    catch ( ... )
    {
		bRet = FALSE;
    }

    return bRet;  // Status of DLL_PROCESS_ATTACH.
}