//------------------------------------------------------------------------------
//
//  File: dllentry.cpp
//	Copyright (C) 1995-1997 Microsoft Corporation
//	All rights reserved.
//
//	Purpose:
//  Defines the initialization routines for the DLL.
//
//  This file needs minor changes, as marked by TODO comments. However, the
//  functions herein are only called by the system, Espresso, or the framework,
//  and you should not need to look at them extensively.
//
//	Owner:
//
//------------------------------------------------------------------------------


#include "stdafx.h"

#include "clasfact.h"

#include "win32sub.h"

#include "impbin.h"

#include "misc.h"

#include "resource.h"
#define __DLLENTRY_CPP
#include "dllvars.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

LONG g_lActiveClasses = 0;	//Glbal count of active class in the DLL

static AFX_EXTENSION_MODULE g_parseDLL = { NULL, NULL };
CItemSetException g_SetException(FALSE);

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	DLL Main entry
//
//------------------------------------------------------------------------------
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	UNREFERENCED_PARAMETER(lpReserved);
	int nRet = 1; //OK
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		LTTRACE("BMOF.DLL Initializing!\n");  //TODO - change name
		
		// Extension DLL one-time initialization
		AfxInitExtensionModule(g_parseDLL, hInstance);

		// Insert this DLL into the resource chain
		new CDynLinkLibrary(g_parseDLL);
		g_hDll = hInstance;


	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		LTTRACE("BMOF.DLL Terminating!\n");  //TODO - change name

		// Remove this DLL from MFC's list of extensions
		AfxTermExtensionModule(g_parseDLL);

		//
		//  If there are active classes, they WILL explode badly once the
		//  DLL is unloaded...
		//
		LTASSERT(DllCanUnloadNow() == S_OK);
		AfxTermExtensionModule(g_parseDLL);
	}
	return nRet;
}

// TODO: Use GUIDGEN.EXE to replace this class ID with a unique one.
// GUIDGEN is supplied with MSDEV (VC++ 4.0) as part of the OLE support stuff.
// Run it and you'll get a little dialog box. Pick radio button 3, "static
// const struct GUID = {...}". Click on the "New GUID" button, then the "Copy"
// button, which puts the result in the clipboard. From there, you can just
// paste it into here. Just remember to change the type to CLSID!

// {8B75CD76-DFC1-4356-AC04-AF088B448AB3}
static const CLSID ciImpParserCLSID = 
{ 0x8b75cd76, 0xdfc1, 0x4356, { 0xac, 0x4, 0xaf, 0x8, 0x8b, 0x44, 0x8a, 0xb3 } };

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Return the CLSID of the parser
//
//------------------------------------------------------------------------------
STDAPI_(void)
DllGetParserCLSID(
		CLSID &ciParserCLSID)
{
	ciParserCLSID = ciImpParserCLSID;
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Entry point to register this parser. Calls base implementation in ESPUTIL.
//------------------------------------------------------------------------------
STDAPI
DllRegisterParser()
{
	LTASSERT(g_hDll != NULL);

	HRESULT hr = ResultFromScode(E_UNEXPECTED);

	try
	{
		hr = RegisterParser(g_hDll);
	}
	catch (CException* pE)
	{
		pE->Delete();
	}
	catch (...)
	{
	}

	return ResultFromScode(hr);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Entry point to unregister this parser. Calls the base implementation in
//  ESPUTIL.
//------------------------------------------------------------------------------
STDAPI
DllUnregisterParser()
{
	LTASSERT(g_hDll != NULL);

	HRESULT hr = ResultFromScode(E_UNEXPECTED);

	try
	{
		//TODO**: Change pidBMOF to real sub parser ID
		hr = UnregisterParser(pidBMOF, pidWin32);   
	}
	catch (CException* pE)
	{
		pE->Delete();
	}
	catch (...)
	{
	}

	return ResultFromScode(hr);
}

	
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Return the class factory for the requested class ID
//
//------------------------------------------------------------------------------
STDAPI
DllGetClassObject(
		REFCLSID cidRequestedClass,
		REFIID iid,
		LPVOID *ppClassFactory)
{
	SCODE sc = E_UNEXPECTED;

	*ppClassFactory = NULL;

	if (cidRequestedClass != ciImpParserCLSID)
	{
		sc = CLASS_E_CLASSNOTAVAILABLE;
	}
	else
	{
		try
		{
			CLocImpClassFactory *pClassFactory;

			pClassFactory = new CLocImpClassFactory;

			sc = pClassFactory->QueryInterface(iid, ppClassFactory);

			pClassFactory->Release();
		}
		catch (CMemoryException *pMem)
		{
			sc = E_OUTOFMEMORY;
			pMem->Delete();
		}
		catch (CException* pE)
		{
			sc = E_UNEXPECTED;
			pE->Delete();
		}
		catch (...)
		{
			sc = E_UNEXPECTED;
		}
	}
	
	return ResultFromScode(sc);
}

   

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Return true if the parser can be unloaded
//
//------------------------------------------------------------------------------
STDAPI
DllCanUnloadNow(void)
{
	SCODE sc = (g_lActiveClasses == 0) ? S_OK : S_FALSE;

	return ResultFromScode(sc);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Increment the global count of active classes
//
//------------------------------------------------------------------------------
void
IncrementClassCount(void)
{
	InterlockedIncrement(&g_lActiveClasses);
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Decrement the global count of active classes
//
//------------------------------------------------------------------------------
void
DecrementClassCount(void)
{
	LTASSERT(g_lActiveClasses != 0);
	
	InterlockedDecrement(&g_lActiveClasses);

}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Throw a item set exception 
//
//------------------------------------------------------------------------------
void
ThrowItemSetException()
{
	throw &g_SetException;
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  Report a error through the reporter.  This function will never
//  fail or throw an exception out of the function.
//
//------------------------------------------------------------------------------
void
ReportException(
	CException* pExcep,		//May be null
	C32File* p32File, 		//May be null
	CLocItem* pItem, 		//May be null
	CReporter* pReporter)
{

	LTASSERT(NULL != pReporter);
	
	//Don't let this function throw an exception since it is normally called
	//within exception catch blocks

	try
	{
		CLString strContext;

		if (NULL != p32File)
		{
			strContext = p32File->GetFile()->GetFilePath();
		}
		else
		{
			LTVERIFY(strContext.LoadString(g_hDll, IDS_IMP_DESC));
		}

		CLString strExcep;
		BOOL bErrorFormatted = FALSE;

		if (NULL != pExcep)
		{
			bErrorFormatted = 
				pExcep->GetErrorMessage(strExcep.GetBuffer(512), 512);
			strExcep.ReleaseBuffer();
		}

		if (!bErrorFormatted || NULL == pExcep)
		{
			LTVERIFY(strExcep.LoadString(g_hDll, IDS_IMP_UNKNOWN_ERROR));
		}

		CLString strResId;
		if (NULL != pItem)
		{
			CPascalString pasResId;
			pItem->GetUniqueId().GetResId().GetDisplayableId(pasResId);
			pasResId.ConvertToCLString(strResId, CP_ACP);
		}

		CLString strMsg;
		strMsg.Format(g_hDll, IDS_ERR_EXCEPTION, (LPCTSTR)strResId,
			(LPCTSTR)strExcep);

		CContext ctx(strContext, pItem->GetMyDatabaseId(), otResource, vProjWindow);
		
		pReporter->IssueMessage(esError, ctx, strMsg);

	}
	catch(CException* pE)
	{
		LTASSERT(0 && _T("Could not issue a exception message"));
		pE->Delete();
	}
	catch(...)
	{
		LTASSERT(0 && _T("Could not issue a exception message"));
	}

}


////////////////////////////////////////////////////////////////////////////////
//  CItemSetException
//

IMPLEMENT_DYNAMIC(CItemSetException, CException)

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// 	Default contructor
//
//------------------------------------------------------------------------------
CItemSetException::CItemSetException()
{
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Constructor
//
//------------------------------------------------------------------------------
CItemSetException::CItemSetException(BOOL bAutoDelete)
    :CException(bAutoDelete)
{
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Fill passed buffer with a error message for this exception.
// The message is cached and only retrieved 1 time. 
//
//------------------------------------------------------------------------------
BOOL
CItemSetException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
		PUINT pnHelpContext)
{
	LTASSERT(lpszError != NULL && AfxIsValidString(lpszError, nMaxError));

	if (NULL != pnHelpContext)
	{
		*pnHelpContext = 0;  //unused
	}

	if (m_strMsg.IsEmpty())
	{
		LTVERIFY(m_strMsg.LoadString(g_hDll, IDS_EXCEP_ITEMSET));
	}

	int nMax = min(nMaxError, (UINT)m_strMsg.GetLength() + 1);
	_tcsncpy(lpszError, m_strMsg, nMax - 1);

	lpszError[nMax] = _T('\0');

	return TRUE;
}