// EmManager.cpp : Implementation of CEmManager
#include "stdafx.h"
#include "Emsvc.h"
#include "EmManager.h"
#include "Processes.h"
#include "sahlp.h"
#include "EmDebugSession.h"
#include "EmFile.h"

/////////////////////////////////////////////////////////////////////////////
// CEmManager

STDMETHODIMP CEmManager::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] = 
	{
		&IID_IEmManager
	};
	for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		if (::InlineIsEqualGUID(*arr[i],riid))
			return S_OK;
	}
	return S_FALSE;
}

BOOL CALLBACK
CallbackFunc
(
IN	long	lPID,
IN	LPCTSTR lpszImagePath,
IN	LPCTSTR lpszShortName,
IN	LPCTSTR lpszDescription,
IN	LPARAM	lParam,
IN  LONG    lItem
)
{

	HRESULT		hr				=	E_FAIL;
    CEmManager  *pEMMgr			=   (CEmManager *)lParam;
	VARIANT		*pVariant		=	(VARIANT *)(pEMMgr->m_lpVariant);
	EmObject	item;
    BSTR        bstrVal			=   NULL,
				bstrTemp		=	NULL;
    PEmObject   pEmObj			=   NULL;
	BOOL		bSessPresent	=	FALSE;
	PEMSession	pEmSess			=	NULL;

	do
	{

        ZeroMemory((PVOID)&item, sizeof EmObject);

        item.hr = E_FAIL;

        if(lPID != INVALID_PID) {

            item.nId = lPID;
		    item.nStatus = pEMMgr->m_nStatus;
		    item.type = (short)pEMMgr->m_nType;

            if(lpszImagePath) {
                
                _tcsncpy(item.szName, lpszImagePath, sizeof item.szName / sizeof TCHAR);
            }

            if(lpszShortName) {
                
                _tcsncpy(item.szSecName, lpszShortName, sizeof item.szSecName / sizeof TCHAR);
            }

            if(lpszDescription) {
                
                _tcsncpy(item.szBucket1, lpszDescription, sizeof item.szBucket1 / sizeof TCHAR);
            }

            bstrTemp = CopyBSTR((LPBYTE)item.szName, _tcslen(item.szName) * sizeof TCHAR);
		    _ASSERTE(bstrTemp != NULL);

            if( bstrTemp == NULL ) { hr = E_OUTOFMEMORY; break; }

            item.hr = S_OK;

            hr = pEMMgr->m_pASTManager->GetSession(item.nId, bstrTemp, &pEmSess);
		    FAILEDHR_BREAK(hr);

            if( bstrTemp ){ ::SysFreeString ( bstrTemp ); bstrTemp = NULL; }

    		bSessPresent = (hr == S_OK);
        }

        if( bSessPresent && // We will point to this only if it present in the
                            // AST and the state is "BEING DEBUGGED"
            pEmSess->pEmObj->nStatus & STAT_SESS_DEBUG_IN_PROGRESS )
        {
            pEmObj = pEmSess->pEmObj;
        }
        else
        {
            pEmObj = &item;
        }

        bstrVal = CopyBSTR ( (LPBYTE)pEmObj, sizeof EmObject );

        if( bstrVal == NULL ) { hr = E_OUTOFMEMORY; break; }

        hr = ::SafeArrayPutElement ( pVariant->parray, &lItem, bstrVal );
        FAILEDHR_BREAK(hr);

        if( bstrVal ) { ::SysFreeString ( bstrVal ); bstrVal = NULL; }
    }
    while ( false );

    if( bstrVal ) { ::SysFreeString ( bstrVal ); bstrVal = NULL; }
    if( bstrTemp ) { ::SysFreeString( bstrTemp ); bstrTemp = NULL; }
    if( FAILED(hr) ){ return FALSE; }

    return TRUE;
}

STDMETHODIMP
CEmManager::EnumObjects
(
IN	EmObjectType	eObjectType,
OUT	VARIANT			*lpVariant
)
{
    ATLTRACE(_T("CEmManager::EnumObjects\n"));

	_ASSERTE( lpVariant != NULL );

    HRESULT	hr	=	E_FAIL;

	m_pcs->WriteLock();

	__try {

		do
		{
			if( lpVariant == NULL ){
				hr = E_INVALIDARG;
				break;
			}

			switch( eObjectType )
			{
			case EMOBJ_SERVICE:
				m_lpVariant = lpVariant;
				hr = EnumSrvcs();
				break;

			case EMOBJ_PROCESS:
				m_lpVariant = lpVariant;
				hr = EnumProcs();
                hr = S_OK;
				break;

			case EMOBJ_LOGFILE:
				hr = EnumLogFiles ( lpVariant );
				break;

			case EMOBJ_MINIDUMP:
			case EMOBJ_USERDUMP:
                hr = EnumDumpFiles ( lpVariant );
				break;

			case EMOBJ_CMDSET:
				hr = EnumCmdSets ( lpVariant );
				break;

            case EMOBJ_MSINFO:
                hr = EnumMsInfoFiles( lpVariant );
                break;

			default:
				hr = E_INVALIDARG;
			}
		}
		while( false );

	}
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

		hr = E_UNEXPECTED;
		_ASSERTE( false );
	}

	m_pcs->WriteUnlock();

	return hr;
}

HRESULT
CEmManager::EnumProcs()
{
    ATLTRACE(_T("CEmManager::EnumProcs\n"));

    _ASSERTE( m_lpVariant != NULL );

    USES_CONVERSION;

	HRESULT	        hr			    =	E_FAIL;
	DWORD	        dwLastRet	    =	0L;
	DWORD	        dwNumbProcs	    =	0L,
                    dwNumbStpSess   =   0L;
    POSITION        pos             =   NULL;
    BSTR            bstrVal         =   NULL;
    LONG            lItem           =   0L;
    PEMSession      pEmSess         =   NULL;
	BOOL			bSACreated		=	FALSE;
    EmObject        TempEmObj;

	m_pcs->WriteLock();

    __try {

		do
		{
			if( m_lpVariant == NULL ){
				hr = E_UNEXPECTED;
				break;
			}

			dwLastRet = GetNumberOfRunningApps( &dwNumbProcs );
			FAILEDDW_BREAK(dwLastRet);

			hr = m_pASTManager->GetNumberOfStoppedSessions(&dwNumbStpSess);
			FAILEDHR_BREAK(hr);

			hr = Variant_CreateOneDim ( m_lpVariant, (dwNumbProcs + dwNumbStpSess), VT_BSTR );
			FAILEDHR_BREAK(hr);
			bSACreated = TRUE;

            m_nStatus = STAT_SESS_NOT_STARTED_RUNNING;
			m_nType = EMOBJ_PROCESS;

   			dwLastRet = EnumRunningProcesses( CallbackFunc, (LPARAM)this );

			if(dwLastRet != 0){

				hr = HRESULT_FROM_WIN32( dwLastRet );
			}

            hr = m_pASTManager->GetFirstStoppedSession(&pos, NULL, &pEmSess);
			lItem = dwNumbProcs;

            ZeroMemory( (void *)&TempEmObj, sizeof EmObject );
            TempEmObj.hr = E_FAIL;

			while( dwNumbStpSess ){

                if( pEmSess->pEmObj->type & EMOBJ_PROCESS ){

    				bstrVal = CopyBSTR ( (LPBYTE)pEmSess->pEmObj, sizeof EmObject );
                }
                else {

    				bstrVal = CopyBSTR ( (LPBYTE)&TempEmObj, sizeof EmObject );
                }

				if( bstrVal == NULL ){
					hr = E_OUTOFMEMORY;
					break;
				}

				hr = ::SafeArrayPutElement ( m_lpVariant->parray, &lItem, bstrVal );
				FAILEDHR_BREAK(hr);

				if( bstrVal ){
					::SysFreeString ( bstrVal );
                    bstrVal = NULL;
				}

                ++lItem;
				--dwNumbStpSess;
				m_pASTManager->GetNextStoppedSession(&pos, NULL, &pEmSess);
			}
		}
		while ( false );

		if( FAILED(hr) ) {

			Variant_DestroyOneDim(m_lpVariant);
			bSACreated = FALSE;
		}

		if( bstrVal ){
			::SysFreeString ( bstrVal );
		}

	}
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

		hr = E_UNEXPECTED;

		if(bSACreated) {

			Variant_DestroyOneDim(m_lpVariant);
			bSACreated = FALSE;
		}

		if( bstrVal ){
			::SysFreeString ( bstrVal );
            bstrVal = NULL;
		}

		_ASSERTE( false );
	}

	m_pcs->WriteUnlock();

	return hr;
}

HRESULT
CEmManager::EnumSrvcs()
{
    ATLTRACE(_T("CEmManager::EnumSrvcs\n"));

	_ASSERTE( m_lpVariant != NULL );

    USES_CONVERSION;

	HRESULT	hr			        =	E_FAIL;
	DWORD	dwLastRet	        =	0L;
	DWORD	dwNumbSrvcs	        =	0L,
            dwNumbStoppedSrvcs  =   0L;
	BOOL	bSACreated	        =	FALSE;


    DWORD	    dwNumbStpSess	=	0L;
    POSITION    pos             =   NULL;
    BSTR        bstrVal         =   NULL;
    LONG        lItem           =   0L;
    PEMSession  pEmSess         =   NULL;
    EmObject    TempEmObj;

	m_pcs->WriteLock();

	__try {

		do
		{
			if( m_lpVariant == NULL ){
				hr = E_INVALIDARG;
				break;
			}

			m_nType = EMOBJ_SERVICE;

            dwLastRet = GetNumberOfServices( &dwNumbStoppedSrvcs, SERVICE_WIN32, SERVICE_INACTIVE );
			FAILEDDW_BREAK(dwLastRet);

            dwLastRet = GetNumberOfServices( &dwNumbSrvcs, SERVICE_WIN32, SERVICE_ACTIVE );
			FAILEDDW_BREAK(dwLastRet);

			hr = m_pASTManager->GetNumberOfStoppedSessions(&dwNumbStpSess);
			FAILEDHR_BREAK(hr);

			hr = Variant_CreateOneDim ( m_lpVariant, dwNumbSrvcs + dwNumbStoppedSrvcs + dwNumbStpSess, VT_BSTR );
			FAILEDHR_BREAK(hr);
			bSACreated = TRUE;

			m_nStatus = STAT_SESS_NOT_STARTED_RUNNING;
   			dwLastRet = EnumServices( CallbackFunc, (LPARAM)this, SERVICE_ACTIVE, 0L );
			m_nStatus = STAT_SESS_NOT_STARTED_NOTRUNNING;
   			dwLastRet = EnumServices( CallbackFunc, (LPARAM)this, SERVICE_INACTIVE, dwNumbSrvcs );

            hr = m_pASTManager->GetFirstStoppedSession(&pos, NULL, &pEmSess);
			lItem = dwNumbSrvcs + dwNumbStoppedSrvcs;

            ZeroMemory( (void *)&TempEmObj, sizeof EmObject );
            TempEmObj.hr = E_FAIL;

			while( dwNumbStpSess ){

                if( pEmSess->pEmObj->type & EMOBJ_SERVICE ){

    				bstrVal = CopyBSTR ( (LPBYTE)pEmSess->pEmObj, sizeof EmObject );
                }
                else {

    				bstrVal = CopyBSTR ( (LPBYTE)&TempEmObj, sizeof EmObject );
                }

				if( bstrVal == NULL ){
					hr = E_OUTOFMEMORY;
					break;
				}

				hr = ::SafeArrayPutElement ( m_lpVariant->parray, &lItem, bstrVal );
				FAILEDHR_BREAK(hr);

				if( bstrVal ){
					::SysFreeString ( bstrVal );
                    bstrVal = NULL;
				}

                ++lItem;
				--dwNumbStpSess;
				m_pASTManager->GetNextStoppedSession(&pos, NULL, &pEmSess);
			}

			if(dwLastRet == FALSE){ // The callback returned false.. otherwise we would
									// get the error value (GetLastError())
				hr = S_FALSE;
			}
			else {

                hr = HRESULT_FROM_WIN32( dwLastRet );
			}

		}
		while ( false );

		if(FAILED(hr)) {

            if( bSACreated ) Variant_DestroyOneDim(m_lpVariant);
			bSACreated = FALSE;
		}
	}

	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

		hr = E_UNEXPECTED;

		if(bSACreated) {

			Variant_DestroyOneDim(m_lpVariant);
			bSACreated = FALSE;
		}

		_ASSERTE( false );
	}


	m_pcs->WriteUnlock();

	return hr;
}

STDMETHODIMP
CEmManager::OpenSession
(
IN OUT  BSTR            bstrEmObj,
OUT     IEmDebugSession **ppEmDebugSession
)
{
    ATLTRACE(_T("CEmManager::OpenSession\n"));

    _ASSERTE(bstrEmObj != NULL);
    _ASSERTE(ppEmDebugSession != NULL);

    HRESULT			hr              =   E_FAIL;
    PEmObject		pEmNewSessObj   =   NULL;
    PEMSession      pNewEmSess      =   NULL;
	BOOL			bBeingDebugged	=	FALSE;
    PEmObject       pEmObj          =   NULL;

    CComObject<CEmDebugSession> *pEmDbgSess =   NULL;

	m_pcs->WriteLock();

	__try {

		do
		{
			if( bstrEmObj == NULL ||
				ppEmDebugSession == NULL ){
            
				hr = E_INVALIDARG;
				break;
			}

            pEmObj = GetEmObj(bstrEmObj);

			//
			// Check the session table if it is already being debugged
			//
//			hr = m_pASTManager->IsAlreadyBeingDebugged(pEmObj);
//            if( FAILED(hr) && hr != EMERROR_INVALIDPROCESS ) break;

            hr = CheckIfCanOpenSession( pEmObj );
            FAILEDHR_BREAK(hr);

			bBeingDebugged = (hr == S_FALSE);

			hr = CComObject<CEmDebugSession>::CreateInstance(&pEmDbgSess);
			FAILEDHR_BREAK(hr);

            pEmDbgSess->AddRef();

			if( bBeingDebugged == FALSE ){ // it is not being debugged already.

				hr = m_pASTManager->AddSession(pEmObj, &pNewEmSess);
				FAILEDHR_BREAK(hr);

				hr = S_OK;
			}
			else{ // it is already being debugged

				//
				// This will get the updated status too..
				//
				hr = m_pASTManager->GetSession(pEmObj->nId, pEmObj->szName, &pNewEmSess);
				FAILEDHR_BREAK(hr);

                hr = S_FALSE;

/**********

                hr = m_pASTManager->IsSessionOrphaned(pNewEmSess->pEmObj->guidstream);
				FAILEDHR_BREAK(hr);

                if( hr == S_OK ) {} // session is orphaned..
                else if( hr == S_FALSE ) {} // session is not orphaned..
***********/
			}

			pEmNewSessObj = pNewEmSess->pEmObj;
            pEmDbgSess->m_pEmObj = pEmNewSessObj;
			pEmDbgSess->m_pEmSessThrd = (CEMSessionThread *)pNewEmSess->pThread;

		}
		while( false );

		if(FAILED(hr)){

			if(pEmDbgSess){

				pEmDbgSess->Release();
				pEmDbgSess = NULL;
			}
		}
		else{

            //
            // This will update all the fields of EmObject..
            //
            ::SysFreeString(bstrEmObj);
            bstrEmObj = CopyBSTR((LPBYTE)pNewEmSess->pEmObj, sizeof EmObject);

			*ppEmDebugSession = pEmDbgSess; // Client will take care of Release.
		}
	} // __try

	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

		hr = E_UNEXPECTED;

		if(pEmDbgSess){

			pEmDbgSess->Release();
			pEmDbgSess = NULL;
		}

		_ASSERTE( false );
	}

	m_pcs->WriteUnlock();

    return hr;
}

STDMETHODIMP CEmManager::DeleteSession(BSTR bstrEmObj)
{
    ATLTRACE(_T("CEmManager::CloseSession\n"));

    _ASSERTE(bstrEmObj != NULL);

	HRESULT	    hr	    =	E_FAIL;
    PEmObject   pEmObj  =   NULL;

	m_pcs->ReadLock();

	__try {

		if(bstrEmObj == NULL){ 
			
			hr = E_INVALIDARG;
		}
		else {

            pEmObj = GetEmObj(bstrEmObj);
			hr = m_pASTManager->RemoveSession(pEmObj->guidstream);
		}
	}

	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

		hr = E_UNEXPECTED;
		_ASSERTE( false );
	}

	m_pcs->ReadUnlock();

	return hr;
}

STDMETHODIMP CEmManager::EnumObjectsEx(BSTR bstrEmObj, VARIANT *lpVariant)
{
    ATLTRACE(_T("CEmManager::EnumObjectsEx\n"));

	_ASSERTE( lpVariant != NULL );
    _ASSERTE( bstrEmObj != NULL );

    HRESULT	    hr	                            =	E_FAIL;
    PEmObject   pEmObj                          =   NULL;
    TCHAR       szSearchString[_MAX_PATH + 1]   =   _T("");
    TCHAR       szEmDir[_MAX_PATH+1]            =   _T("");
    TCHAR       szEmFileExt[_MAX_EXT+1]     =   _T("");

	m_pcs->WriteLock();

	__try {

		do
		{
			if( bstrEmObj == NULL ||
                lpVariant == NULL ) {

                hr = E_INVALIDARG;
				break;
			}

            pEmObj = GetEmObj(bstrEmObj);
            _ASSERTE(pEmObj != NULL);

			switch( pEmObj->type )
			{
			case EMOBJ_SERVICE:
				break;

			case EMOBJ_PROCESS:
                if( pEmObj->nStatus & STAT_SESS_STOPPED ) {

                    hr = EnumSessions( pEmObj, lpVariant );
                }

				break;

			case EMOBJ_LOGFILE:
                _Module.GetEmDirectory( EMOBJ_LOGFILE, szEmDir, _MAX_PATH, szEmFileExt, _MAX_EXT );

                GetUniqueFileName(
                                    pEmObj,
                                    szSearchString,
                                    NULL,
                                    szEmFileExt,
                                    true
                                    );

                _tcsncat( szEmDir, _T("\\"), _MAX_PATH );
                _tcsncat( szEmDir, szSearchString, _MAX_PATH );

                hr = EnumLogFiles ( lpVariant, szEmDir );
				break;

			case EMOBJ_MINIDUMP:
			case EMOBJ_USERDUMP:

                _Module.GetEmDirectory( EMOBJ_MINIDUMP, szEmDir, _MAX_PATH, szEmFileExt, _MAX_EXT );

                GetUniqueFileName(
                                    pEmObj,
                                    szSearchString,
                                    NULL,
                                    szEmFileExt,
                                    true
                                    );

                _tcsncat( szEmDir, _T("\\"), _MAX_PATH );
                _tcsncat( szEmDir, szSearchString, _MAX_PATH );

                hr = EnumDumpFiles ( lpVariant, szEmDir );
				break;

			case EMOBJ_MSINFO:

                _Module.GetEmDirectory( EMOBJ_MSINFO, szEmDir, _MAX_PATH, szEmFileExt, _MAX_EXT );

                GetUniqueFileName(
                                    pEmObj,
                                    szSearchString,
                                    NULL,
                                    szEmFileExt,
                                    true
                                    );

                _tcsncat( szEmDir, _T("\\"), _MAX_PATH );
                _tcsncat( szEmDir, szSearchString, _MAX_PATH );

                hr = EnumMsInfoFiles( lpVariant, szEmDir );
				break;

			case EMOBJ_CMDSET:
				hr = EnumCmdSets ( lpVariant );
				break;

			default:
				hr = E_INVALIDARG;
			}
		}
		while( false );

	}
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

		hr = E_UNEXPECTED;
		_ASSERTE( false );
	}

	m_pcs->WriteUnlock();

	return hr;
}

HRESULT
CEmManager::EnumSessions
(
IN	PEmObject	pEmObj,
OUT VARIANT		*lpVariant
)
{
    ATLTRACE(_T("CEmManager::EnumSessions\n"));

	_ASSERTE( pEmObj != NULL );
	_ASSERTE( lpVariant != NULL );

	HRESULT	hr	=	E_FAIL;
	DWORD	dwNumbSess	=	0L;
	long    lItem		=	0L;
	PEMSession	pEmSess	=	NULL;
    POSITION    pos     =   NULL;
    BSTR        bstrVal =   NULL;
    bool        bVariantCreated =   false;
    EmObject    TempEmObj;

	m_pcs->WriteLock();

    __try {

		if( pEmObj == NULL ||
			lpVariant == NULL ) {

			hr = E_INVALIDARG;
            goto qEnumSessions;
		}

		hr = m_pASTManager->GetNumberOfSessions(&dwNumbSess);
		if(hr != S_OK) goto qEnumSessions; // S_FALSE => no sessions.

		hr = Variant_CreateOneDim ( lpVariant, dwNumbSess, VT_BSTR );
        if(FAILED(hr)) goto qEnumSessions;
        bVariantCreated = true;

		hr = m_pASTManager->GetFirstSession(&pos, &pEmSess);
		lItem = 0L;

        ZeroMemory( (void *)&TempEmObj, sizeof EmObject );
        TempEmObj.hr = E_FAIL;

		while( dwNumbSess ){

			if( HIWORD(pEmSess->pEmObj->nStatus) & HIWORD(pEmObj->nStatus) ) {

				bstrVal = CopyBSTR ( (LPBYTE)pEmSess->pEmObj, sizeof EmObject );
			}
            else {
				bstrVal = CopyBSTR ( (LPBYTE)&TempEmObj, sizeof EmObject );
            }

            if( bstrVal == NULL ) { hr = E_OUTOFMEMORY; goto qEnumSessions; }

            hr = ::SafeArrayPutElement ( lpVariant->parray, &lItem, bstrVal );
			if(FAILED(hr)) goto qEnumSessions;

			if( bstrVal ){
				::SysFreeString ( bstrVal );
				bstrVal = NULL;
			}

            ++lItem;
			--dwNumbSess;
			m_pASTManager->GetNextSession(&pos, &pEmSess);
		}

qEnumSessions:
	    if( FAILED(hr) ) {

            if( bVariantCreated == true ) Variant_DestroyOneDim(lpVariant);
	    }

	}
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

		if( bVariantCreated == true ) Variant_DestroyOneDim(lpVariant);

        hr = E_UNEXPECTED;
		_ASSERTE( false );
	}

	m_pcs->WriteUnlock();

    return hr;
}

STDMETHODIMP CEmManager::GetEmFileInterface(BSTR bstrEmObj, IStream **ppstrm)
{
    _ASSERTE( bstrEmObj != NULL );
    _ASSERTE( ppstrm != NULL );

    HRESULT     hr                      =   E_FAIL;
    PEmObject   pEmObj                  =   NULL;
    TCHAR       szEmDir[_MAX_PATH+1]    =   _T("");

    CComObject<CEmFile> *pEmFile        =   NULL;

	m_pcs->WriteLock();

    __try
    {
        if( bstrEmObj == NULL || ppstrm == NULL ) {

            hr = E_INVALIDARG; goto qGetEmFileInterface;
        }

        pEmObj = GetEmObj(bstrEmObj);
        *ppstrm = NULL;

		hr = CComObject<CEmFile>::CreateInstance(&pEmFile);
        if( FAILED(hr) ) { goto qGetEmFileInterface; }

        pEmFile->AddRef();

        hr = _Module.GetEmDirectory( (EmObjectType)pEmObj->type, szEmDir, _MAX_PATH, NULL, 0L );
        if( FAILED(hr) ) { goto qGetEmFileInterface; }

        _tcsncat( szEmDir, _T("\\"), _MAX_PATH ); 
        _tcsncat( szEmDir, pEmObj->szName, _MAX_PATH ); 

        hr = pEmFile->InitFile( szEmDir );
        if( FAILED(hr) ) { goto qGetEmFileInterface; }

        *ppstrm = pEmFile;
        hr = S_OK;

qGetEmFileInterface:

        if( FAILED(hr) ) {

            if( pEmFile ) { pEmFile->Release(); }
        }
	}
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

        hr = E_UNEXPECTED;
		_ASSERTE( false );
	}

	m_pcs->WriteUnlock();

    return hr;
}

STDMETHODIMP
CEmManager::GenerateDumpFile
(
IN  BSTR bstrEmObj,
IN  UINT nDumpType
)
{
    _ASSERTE( bstrEmObj != NULL );

    HRESULT         hr              =   E_FAIL;
    IEmDebugSession *pIEmDbgSess    =   NULL;
    bool            bCallDeleteSess =   false;

	m_pcs->ReadLock();

    __try
    {
        if( bstrEmObj == NULL ) { hr = E_INVALIDARG; goto qGenerateDumpFile; }

        hr = OpenSession( bstrEmObj, &pIEmDbgSess );
        bCallDeleteSess = (hr == S_OK);

        if( pIEmDbgSess ) {

            hr = pIEmDbgSess->GenerateDumpFile( nDumpType );
        }

qGenerateDumpFile:
        if( FAILED(hr) ) {

            if( pIEmDbgSess ) { pIEmDbgSess->Release(); pIEmDbgSess = NULL; }
        }

//        if( bCallDeleteSess ) { DeleteSession( bstrEmObj ); }
    }
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

        hr = E_UNEXPECTED;

        if( pIEmDbgSess ) { pIEmDbgSess->Release(); pIEmDbgSess = NULL; }
//        if( bCallDeleteSess ) { DeleteSession( bstrEmObj ); }

        _ASSERTE( false );
	}

	m_pcs->ReadUnlock();

	return hr;
}

HRESULT
CEmManager::CheckIfCanOpenSession
(
IN  PEmObject pEmObj
)
{
    HRESULT hr          =   E_FAIL,
            hrTemp      =   E_FAIL;
    DWORD   dwLastRet   =   0L;
    bool    bValidImage =   false;
    PEMSession  pEmSess =   NULL;
    POSITION    pos     =   NULL;

	m_pcs->ReadLock();

    __try
    {

        if( pEmObj->type != EMOBJ_SERVICE && pEmObj->type != EMOBJ_PROCESS ) {

            hr = E_INVALIDARG;
            goto qCheckIfCanOpenSession;
        }

        if( pEmObj->type == EMOBJ_PROCESS ) {

            IsValidProcess( pEmObj->nId, pEmObj->szName, &bValidImage );
    
            hrTemp = m_pASTManager->GetSession(
                                        pEmObj->nId,
                                        pEmObj->szName,
                                        &pEmSess
                                        );

            if( !bValidImage ) { // pid and image name does not match.. :(

                if( hrTemp == S_FALSE ) { // Not present in the AST, as well.

                    hr = EMERROR_INVALIDPROCESS;
                }
                else { // is present in the AST..

                    hr = S_FALSE;
                }

                goto qCheckIfCanOpenSession;
            }

            if( bValidImage ) { // pid and image name match..

                if( hrTemp == S_FALSE ) { // not present in the AST, so it can be added..

                    hr = S_OK;
                }
                else { // present in the AST..

                    if( HIWORD(pEmSess->pEmObj->nStatus) >= HIWORD(STAT_SESS_DEBUG_IN_PROGRESS) )
                        hr = S_FALSE;
                    else
                        hr = S_OK;
                }

                goto qCheckIfCanOpenSession;
            }
        }

        if( pEmObj->type == EMOBJ_SERVICE ) {

            hr = m_pASTManager->GetNumberOfSessions( &dwLastRet );
            if( FAILED(hr) ) { goto qCheckIfCanOpenSession; }

		    hr = m_pASTManager->GetFirstSession(&pos, &pEmSess);
            if( FAILED(hr) ) { goto qCheckIfCanOpenSession; }

            hr = S_OK;
		    while( dwLastRet ) {

                if( _tcsicmp( pEmObj->szName, pEmSess->pEmObj->szName ) == 0 &&
                    _tcsicmp( pEmObj->szSecName, pEmSess->pEmObj->szSecName ) == 0 ) {

                    hr = S_FALSE;
                    goto qCheckIfCanOpenSession;
                }

			    --dwLastRet;
			    m_pASTManager->GetNextSession(&pos, &pEmSess);
		    }
        }

qCheckIfCanOpenSession:
        if(FAILED(hr)){}
    }
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

        hr = E_UNEXPECTED;

        _ASSERTE( false );
	}

	m_pcs->ReadUnlock();

	return hr;
}

STDMETHODIMP CEmManager::DeleteFile(BSTR bstrEmObj)
{
    _ASSERTE( bstrEmObj != NULL );

    HRESULT     hr                  =   E_FAIL;
    LPTSTR      lpszFullFileName    =   NULL;
    PEmObject   pEmObj              =   NULL;
    ULONG       lStrLen             =   0L;

    m_pcs->ReadLock();
    
    __try
    {
        if( bstrEmObj == NULL ) {

            hr = E_INVALIDARG;
            goto qDeleteFile;
        }

        pEmObj = GetEmObj(bstrEmObj);

        if( pEmObj->type != EMOBJ_LOGFILE &&
            pEmObj->type != EMOBJ_MINIDUMP &&
            pEmObj->type != EMOBJ_USERDUMP &&
            pEmObj->type != EMOBJ_MSINFO
            ) {

            hr = E_INVALIDARG;
            goto qDeleteFile;
        }
        
        lStrLen = _tcslen(pEmObj->szName);
        lStrLen += _tcslen(pEmObj->szSecName) + 1;

        lpszFullFileName = new TCHAR[lStrLen + 1];
        if( !lpszFullFileName ) {

            hr = HRESULT_FROM_WIN32(GetLastError());
            goto qDeleteFile;
        }

        _stprintf( lpszFullFileName, _T("%s\\%s"), pEmObj->szSecName, pEmObj->szName );
        if(!::DeleteFile( lpszFullFileName )) {

            hr = HRESULT_FROM_WIN32(GetLastError());
            goto qDeleteFile;
        }

        hr = S_OK;

qDeleteFile:
        if( lpszFullFileName ) { delete [] lpszFullFileName; lpszFullFileName = NULL; }
        if(FAILED(hr)){}

    }
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

        hr = E_UNEXPECTED;
        if( lpszFullFileName ) { delete [] lpszFullFileName; lpszFullFileName = NULL; }

        _ASSERTE( false );
	}

	m_pcs->ReadUnlock();

	return hr;
}

STDMETHODIMP
CEmManager::MakeNFO
(
IN  BSTR bstrPath,
IN  BSTR bstrMachineName,
IN  BSTR bstrCategories
)
{
    _ASSERTE( bstrCategories != NULL );

    HRESULT     hr              =   E_FAIL;
    BSTR        bstrFilePath    =   NULL,
                bstrMacName     =   NULL;
    BOOL        bMsinfoCreated  =   FALSE;
    HINSTANCE   hi              =   NULL;
    
    TCHAR       szMsInfo32Path[_MAX_PATH+1] =   _T("");
    ULONG       cchMsInfo32Path             =   _MAX_PATH;
    LPTSTR      lpszCmdLine                 =   NULL;
    ULONG       lCmdLineLen                 =   0L;
    LPCTSTR     lpszNfoExt                  =   _T("/nfo ");

    m_pcs->ReadLock();

    __try
    {
        if( !bstrCategories ) { hr = E_INVALIDARG; goto qMakeNFO; }

        if( bstrPath ) {

            bstrFilePath = SysAllocString( bstrPath );
            if( !bstrFilePath ) { hr = E_OUTOFMEMORY; goto qMakeNFO; }
        }
        else {

            hr = _Module.GetTempEmFileName( EMOBJ_MSINFO, bstrFilePath );
            if( FAILED(hr) ) { goto qMakeNFO; }
        }

        if( bstrMachineName ) {

            bstrMacName = SysAllocString( bstrMachineName );
            if( !bstrMacName ) { hr = E_OUTOFMEMORY; goto qMakeNFO; }
        }
        else {

            hr = _Module.GetCompName( bstrMacName );
            if( FAILED(hr) ) { goto qMakeNFO; }
        }
/*
	    hr = CoCreateInstance(
                        CLSID_SystemInfo,
                        NULL,
                        CLSCTX_INPROC_SERVER,
                        IID_ISystemInfo,
                        (LPVOID *) &pISystemInfo
                        );

        if( FAILED(hr) ) { goto qMakeNFO; }

	    // Call the make_nfo system Interface
	    //hrReturn=pISystemInfo->make_nfo(bstrPath,bstrMachineName);
	    hr = pISystemInfo->MakeNFO(bstrFilePath, bstrMachineName, bstrCategories);
*/

        STARTUPINFO			sp;
	    PROCESS_INFORMATION pi;

        ZeroMemory(&sp, sizeof(sp));
        ZeroMemory(&pi, sizeof(pi));

        hr = _Module.GetMsInfoPath( szMsInfo32Path, &cchMsInfo32Path );
        if( FAILED(hr) ) { goto qMakeNFO; }

        //
        // msinfo32.exe /nfo <filepath> <- silent file save ( no UI ).
        // msinfo32.exe /categories: +xxx /nfo <filepath>
        //

        lCmdLineLen = _tcslen(szMsInfo32Path)
                    + SysStringLen( bstrCategories )
                    + SysStringLen( bstrFilePath )
                    + _tcslen(lpszNfoExt)
                    + 4 // This is for quotes..
                    + 1;

        lpszCmdLine = new TCHAR[ lCmdLineLen ];
        if( !lpszCmdLine ) {

            hr = HRESULT_FROM_WIN32(GetLastError());
            goto qMakeNFO;
        }

        _stprintf(  lpszCmdLine,
                    _T("\"%s\" %s %s \"%s\""),
                    szMsInfo32Path,
                    (LPCTSTR)bstrCategories,
                    lpszNfoExt,
                    (LPCTSTR)bstrFilePath
                    );

	    bMsinfoCreated = CreateProcess(// This has to be obtained from the registry...
			                        NULL,
			                        lpszCmdLine,
			                        NULL,
			                        NULL,
			                        FALSE,
			                        CREATE_NEW_PROCESS_GROUP,
			                        NULL,
			                        NULL,
			                        &sp,
			                        &pi
			                        );

        if( !bMsinfoCreated ) {

            hr = HRESULT_FROM_WIN32(GetLastError());
            goto qMakeNFO;
        }

        hr = S_OK;

qMakeNFO:

        if( lpszCmdLine ) { delete [] lpszCmdLine; lpszCmdLine = NULL; }
        if( bstrFilePath ) { SysFreeString( bstrFilePath ); }
        if( bstrMacName ) { SysFreeString( bstrMacName ); }
    }
	__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {

        hr = E_UNEXPECTED;

        if( lpszCmdLine ) { delete [] lpszCmdLine; lpszCmdLine = NULL; }
        if( bstrFilePath ) { SysFreeString( bstrFilePath ); }
        if( bstrMacName ) { SysFreeString( bstrMacName ); }

        _ASSERTE( false );
	}

	m_pcs->ReadUnlock();

	return hr;
}