1181 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1181 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include "StdAfx.h"
 | ||
| 
 | ||
| #include "errno.h"
 | ||
| #include "iserrors.h"
 | ||
| 
 | ||
| #include "connect.h"
 | ||
| #include "server.h"
 | ||
| #include "tracing.h"
 | ||
| 
 | ||
| #ifndef NO_MFC
 | ||
| #ifdef _DEBUG
 | ||
| #define new DEBUG_NEW
 | ||
| #undef THIS_FILE
 | ||
| static char THIS_FILE[] = __FILE__;
 | ||
| #endif
 | ||
| #endif
 | ||
| 
 | ||
| // @doc INTERNAL
 | ||
| 
 | ||
| // @rdesc Ritorna il valore corrispondente alla chiave appartenente
 | ||
| //        ad una sezione del file di configurazione
 | ||
| 
 | ||
| static CString GetIniString(LPCSTR sec, // @parm Sezione
 | ||
| 		 			        LPCSTR key, // @parm Chiave
 | ||
| 					        LPCSTR def) // @parm Valore di default
 | ||
| {
 | ||
| 	// Nome del file .ini
 | ||
| 	static CString m_strIniFile;
 | ||
| 	
 | ||
| 	// Lunghezza massima di un nome di directory
 | ||
| 	// o di un valore del file .ini
 | ||
| 	const DWORD dwSize = _MAX_DIR + 1;
 | ||
| 
 | ||
| 	// Costruisce il nome del file .ini se necessario
 | ||
| 	if (m_strIniFile.IsEmpty())
 | ||
| 	{
 | ||
| 		GetCurrentDirectory(dwSize, m_strIniFile.GetBuffer(dwSize));
 | ||
| 		m_strIniFile.ReleaseBuffer();
 | ||
| 		m_strIniFile += "\\prawin.ini";
 | ||
| 	}
 | ||
| 
 | ||
| 	// Legge il valore della chiave nella sezione specificata
 | ||
| 	CString tmp;
 | ||
| 	char* buf = tmp.GetBuffer(dwSize);
 | ||
| 	GetPrivateProfileString(sec, key, def, buf, dwSize, m_strIniFile);
 | ||
| 	tmp.ReleaseBuffer();
 | ||
| 	return tmp;
 | ||
| }
 | ||
| 
 | ||
| // @doc INTERNAL
 | ||
| 
 | ||
| // @class TFileInfo | Informazioni generali su di un file
 | ||
| //
 | ||
| // @base public | CObject
 | ||
| 
 | ||
| class TFileInfo : public CObject
 | ||
| // @author:(INTERNAL) Guido
 | ||
| 
 | ||
| // @access:(INTERNAL) Private Member
 | ||
| {
 | ||
| 	// @cmember:(INTERNAL) Nome del file
 | ||
| 	CString m_strName;			
 | ||
| 	// @cmember:(INTERNAL) Nome del data source
 | ||
| 	CString m_strDataSource;	
 | ||
| 	// @cmember:(INTERNAL) Descrizione del file
 | ||
| 	CString m_strDescription;	
 | ||
| 
 | ||
| public:
 | ||
| 	// @cmember Ritorna il nome del file
 | ||
| 	const CString& GetName() const 
 | ||
| 	{ return m_strName; }		
 | ||
| 
 | ||
| 	// @cmember Ritorna il nome del data source
 | ||
| 	const CString& GetDataSource() const 
 | ||
| 	{ return m_strDataSource; }	
 | ||
| 	
 | ||
| 	// @cmember Ritorna la descrizione del file
 | ||
| 	const CString& GetDescription() const 
 | ||
| 	{ return m_strDescription; } 
 | ||
| 
 | ||
| 	// @cmember Setta il nome del file
 | ||
| 	void SetName(LPCSTR sName)
 | ||
| 	{ m_strName = sName; }
 | ||
| 
 | ||
| 	// @cmember Setta il nome del data source
 | ||
| 	void SetDataSource(LPCSTR sDataSource)
 | ||
| 	{ m_strDataSource = sDataSource; }
 | ||
| 
 | ||
| 	// @cmember Setta la descrizione
 | ||
| 	void SetDescription(LPCSTR sDescription)
 | ||
| 	{ m_strDescription = sDescription; }
 | ||
| 
 | ||
| 	// @cmember Costruttore
 | ||
| 	TFileInfo() { }
 | ||
| 	// @cmember Distruttore
 | ||
| 	virtual ~TFileInfo() { }
 | ||
| };
 | ||
| 
 | ||
| // @doc INTERNAL
 | ||
| 
 | ||
| // @class TDataSources | Informazioni generali sui file
 | ||
| //
 | ||
| // @base public | CObject
 | ||
| 
 | ||
| class TDataSources : public CObject
 | ||
| // @author:(INTERNAL) Guido
 | ||
| 
 | ||
| // @access:(INTERNAL) Private Member
 | ||
| {
 | ||
| 	// @cmember:(INTERNAL) Motore di database DAO
 | ||
| 	CdbDBEngine m_dbEngine;
 | ||
| 	// @cmember:(INTERNAL) Nome del database principale
 | ||
| 	CString m_strDatabase;
 | ||
| 	// @cmember:(INTERNAL) Stringa di connsessione ODBC
 | ||
| 	CString m_strConnect;
 | ||
| 	// @cmember:(INTERNAL) Si tratta di una vera connessione ODBC
 | ||
| 	BOOL m_bODBC;
 | ||
| 	// @cmember:(INTERNAL) Elenco delle informazioni sui file
 | ||
| 	CMap<CString,LPCSTR,TFileInfo*,TFileInfo*> m_FileInfo;
 | ||
| 	// @cmember:(INTERNAL) Elenco dei database aperti
 | ||
| 	CMap<CString,LPCSTR,CdbDatabase*,CdbDatabase*> m_Databases;
 | ||
| 
 | ||
| protected:
 | ||
| 	// @cmember Carica tutte le descrizioni dei file
 | ||
| 	BOOL FillFileInfo();
 | ||
| 	// @cmember Ritorna le informazioni su di un file
 | ||
| 	const TFileInfo& GetFileInfo(int nLogicNumber) const;
 | ||
| 	
 | ||
| 	// @cmember Costruisce il nome del database di un datasource
 | ||
| 	CString BuildDatabaseName(LPCSTR sName, int nFirm) const;
 | ||
| 	// @cmember Ritorna il database corrispondente ad un datasource
 | ||
| 	CdbDatabase* GetDatabase(LPCSTR sName, int nFirm);
 | ||
| 	// @cmember Ritorna il nome della tabella di un file
 | ||
| 	CString GetTableName(int nFirm, int nLogicNumber) const;
 | ||
| 
 | ||
| public:
 | ||
| 	// @cmember Ritorna TRUE se si tratta di una connessione ODBC
 | ||
| 	BOOL IsODBC() const { return m_bODBC; }
 | ||
| 	// @cmember Verifica l'esistenza di un datasource
 | ||
| 	BOOL TestDataSource(LPCSTR sName, int nFirm) const;
 | ||
| 	// @cmember Ritorna database e nome di un file
 | ||
| 	CdbDatabase* GetDataSource(int nFirm, int nLogicNum,      
 | ||
| 							   CString& strTableName);
 | ||
| 	// @cmember Toglie un riferimento al database
 | ||
| 	void ReleaseDataSource(int nFirm, int nLogicNum);
 | ||
| 
 | ||
| 	// @cmember Verifica la corretta inizializzazione
 | ||
| 	BOOL IsOk() const 
 | ||
| 	{ return !m_FileInfo.IsEmpty(); }
 | ||
| 
 | ||
| 	// @cmember Costruttore
 | ||
| 	TDataSources();
 | ||
| 	// @cmember Distruttore
 | ||
| 	virtual ~TDataSources();
 | ||
| };
 | ||
| 
 | ||
| 
 | ||
| // @mfunc Costruisce il nome del database associato ad un 
 | ||
| //        determinato data source se <p sName> vale FIRM 
 | ||
| //        lo trasforma nel codice ditta corrispondente 
 | ||
| //        a <p nFirm>, es: 00883
 | ||
| CString TDataSources::BuildDatabaseName(
 | ||
| 	LPCSTR sName,	 // @parm Nome del data source
 | ||
| 	int nFirm) const // @parm Codice della ditta
 | ||
| {
 | ||
| 	CString strDataSource = m_strDatabase;
 | ||
| 	if (IsODBC())
 | ||
| 	{
 | ||
| 		// In ODBC esiste un unico database ad un livello
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		CString strName(sName);
 | ||
| 		if (strName == "FIRM")
 | ||
| 			strName.Format("%05dA", nFirm);
 | ||
| 		if (!strName.IsEmpty())
 | ||
| 		{
 | ||
| 			strDataSource += '\\';
 | ||
| 			strDataSource += strName;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return strDataSource;
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Verifica l'esistenza di un data source
 | ||
| BOOL TDataSources::TestDataSource(
 | ||
| 	LPCSTR sName,	 // @parm Nome del data source
 | ||
| 	int nFirm) const // @parm Codice della ditta
 | ||
| {
 | ||
| 	CString strDataSource = BuildDatabaseName(sName, nFirm);
 | ||
| 	BOOL bOk = TRUE;
 | ||
| 	try
 | ||
| 	{
 | ||
| 		CdbDBEngine dbEngine;
 | ||
| 		dbEngine.OpenDatabase(strDataSource, 
 | ||
| 							  FALSE, FALSE, 
 | ||
| 							  m_strConnect);
 | ||
| 	}
 | ||
| 	catch(...)
 | ||
| 	{
 | ||
| 		bOk = FALSE;
 | ||
| 	}
 | ||
| 	return bOk;
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Apre il database corrispondenete ad un data source
 | ||
| CdbDatabase* TDataSources::GetDatabase(
 | ||
| 	LPCSTR sName,	// @parm Nome del data source
 | ||
| 	int nFirm)		// @parm Codice della ditta
 | ||
| {
 | ||
| 	CString strDataSource = BuildDatabaseName(sName, nFirm);
 | ||
| 	CdbDatabase* pDatabase;
 | ||
| 	BOOL ok = m_Databases.Lookup(strDataSource, pDatabase);
 | ||
| 	if (!ok)
 | ||
| 	{
 | ||
| 		pDatabase = new CdbDatabase;
 | ||
| 		try
 | ||
| 		{
 | ||
| 		  *pDatabase = m_dbEngine.OpenDatabase(strDataSource, 
 | ||
| 			                                   FALSE, FALSE, 
 | ||
| 											   m_strConnect);
 | ||
| 		  m_Databases.SetAt(strDataSource, pDatabase);
 | ||
| 		}
 | ||
| 		catch(...)
 | ||
| 		{
 | ||
| 			delete pDatabase;
 | ||
| 			pDatabase = NULL;
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	return pDatabase;
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Ritorna le informazioni sul file <p nLogicNumber>
 | ||
| const TFileInfo& TDataSources::GetFileInfo(int nLogicNumber) const
 | ||
| {
 | ||
| 	char codice[16]; itoa(nLogicNumber, codice, 10);
 | ||
| 	TFileInfo* fi;
 | ||
| 	BOOL ok = m_FileInfo.Lookup(codice, fi);
 | ||
| 	ASSERT(ok);
 | ||
| 	return *fi;
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Ritorna il nome della tabella SQL contenete i dati
 | ||
| //        del file ISAM  <p nLogicNumber>
 | ||
| CString TDataSources::GetTableName(int nFirm, int nLogicNumber) const
 | ||
| {
 | ||
| 	const TFileInfo& fi = GetFileInfo(nLogicNumber);
 | ||
| 	CString strName;
 | ||
| 	if (IsODBC())
 | ||
| 	{
 | ||
| 		strName = fi.GetDataSource();
 | ||
| 		if (strName == "FIRM")
 | ||
| 			strName.Format("%05dA", nFirm);
 | ||
| 		strName += '_';
 | ||
| 		strName += fi.GetName();
 | ||
| 	}
 | ||
| 	else
 | ||
| 		strName = fi.GetName();
 | ||
| 	
 | ||
| 	return strName;
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Carica le informazioni relative a tutti i file ISAM
 | ||
| BOOL TDataSources::FillFileInfo()
 | ||
| {
 | ||
| 	CdbDatabase* pDatabase = GetDatabase("", 0);
 | ||
| 	if (pDatabase)
 | ||
| 	{
 | ||
| 		try
 | ||
| 		{
 | ||
| 			CdbRecordset rstDir = pDatabase->OpenRecordset("DIR", dbOpenDynaset);
 | ||
| 
 | ||
| 			COleVariant oleVariant;
 | ||
| 			for (rstDir.MoveFirst(); !rstDir.GetEOF(); rstDir.MoveNext())
 | ||
| 			{
 | ||
| 				oleVariant = rstDir.GetField("CODICE");
 | ||
| 				
 | ||
| 				TFileInfo* fi = new TFileInfo;
 | ||
| 				m_FileInfo.SetAt((LPCSTR)oleVariant.pbVal, fi);
 | ||
| 
 | ||
| 				oleVariant = rstDir.GetField("NOME");
 | ||
| 				fi->SetName((LPCSTR)oleVariant.pbVal);
 | ||
| 
 | ||
| 				oleVariant = rstDir.GetField("SORGENTE");
 | ||
| 				fi->SetDataSource((LPCSTR)oleVariant.pbVal);
 | ||
| 
 | ||
| 				oleVariant = rstDir.GetField("DESCR");
 | ||
| 				fi->SetDescription((LPCSTR)oleVariant.pbVal);
 | ||
| 			}
 | ||
| 		}
 | ||
| 		catch(...)
 | ||
| 		{
 | ||
| 			pDatabase = NULL;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return pDatabase != NULL;
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Ritorna il database ed il nome
 | ||
| CdbDatabase* TDataSources::GetDataSource(int nFirm, int nLogicNumber,
 | ||
| 									     CString& strTableName)
 | ||
| {
 | ||
| 	const TFileInfo& fi = GetFileInfo(nLogicNumber);
 | ||
| 	const CString& strDataSource = fi.GetDataSource();
 | ||
| 	strTableName = GetTableName(nFirm, nLogicNumber);
 | ||
| 	return GetDatabase(strDataSource, nFirm);
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Chiude un database inutilizzato
 | ||
| //        Per il momemnto non si sa come implementarla 
 | ||
| void TDataSources::ReleaseDataSource(int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	// TODO:
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Costruttore del'insieme dei data source
 | ||
| TDataSources::TDataSources()
 | ||
| {
 | ||
|     const char* const odbc = "ODBC";
 | ||
| 
 | ||
| 	m_dbEngine.SetDefaultUser(GetIniString(odbc, "User", odbc));
 | ||
| 	m_dbEngine.SetDefaultPassword(GetIniString(odbc, "Pwd", odbc));
 | ||
| 
 | ||
| 	m_strDatabase = GetIniString(odbc, "Database", odbc);
 | ||
| 	m_strConnect  = GetIniString(odbc, "Connect", odbc);
 | ||
| 
 | ||
| 	m_bODBC = m_strConnect.Mid(0, 4) == odbc;
 | ||
| 
 | ||
| 	FillFileInfo();
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Distruttore del'insiemde dei data source
 | ||
| TDataSources::~TDataSources()
 | ||
| {
 | ||
| 	POSITION pos;		// Posizione corrente nella lista
 | ||
| 	CString strKey;		// Chiave dell'elemento corrente della lista
 | ||
| 
 | ||
| 	// Vuota la lista dei database
 | ||
| 	for (pos = m_Databases.GetStartPosition(); pos; )
 | ||
| 	{
 | ||
| 		CdbDatabase* pDatabase; // Database corrente
 | ||
| 		m_Databases.GetNextAssoc(pos, strKey, pDatabase);
 | ||
| 		pDatabase->Close();
 | ||
| 		delete pDatabase;
 | ||
| 	}
 | ||
| 	m_Databases.RemoveAll();
 | ||
| 
 | ||
| 	// Vuota la lista delle informazioni sui file
 | ||
| 	for (pos = m_FileInfo.GetStartPosition(); pos; )
 | ||
| 	{
 | ||
| 		TFileInfo* pFileInfo;	// File corrente
 | ||
| 		m_FileInfo.GetNextAssoc(pos, strKey, pFileInfo);
 | ||
| 		delete pFileInfo;
 | ||
| 	}
 | ||
| 	m_FileInfo.RemoveAll();
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| /////////////////////////////////////////////////////////////////////////////
 | ||
| // TTableDef
 | ||
| 
 | ||
| class TTableDef : public CObject
 | ||
| {
 | ||
| 	CdbDatabase* m_db;
 | ||
| 	CString      m_strTableName;
 | ||
| 	
 | ||
| 	CdbRecordset m_Dynaset;
 | ||
| 	
 | ||
| 	clock_t      m_tModifyTime;
 | ||
| 	int          m_nReferences;
 | ||
| 
 | ||
| 	CMap<CString,LPCSTR,DWORD,DWORD> m_Locks;
 | ||
| 	DWORD        m_dwExclusiveLocker;
 | ||
| 
 | ||
| protected:
 | ||
| 	friend class TTableDefPool;
 | ||
| 	int AddReference() { return ++m_nReferences; }
 | ||
| 	int RemoveReference() { return --m_nReferences; }
 | ||
| 	void ZeroReferences() { m_nReferences = 0; }
 | ||
| 
 | ||
| public:
 | ||
| 	BOOL IsChangedSince(clock_t t) const
 | ||
| 	{ return t <= m_tModifyTime; }
 | ||
| 
 | ||
| 	CdbDatabase& GetDatabase() { return *m_db; }
 | ||
| 	const CString& GetTableName() { return m_strTableName; }
 | ||
| 
 | ||
| 	CdbTableDef GetTableDef();
 | ||
| 	CdbRecordset& GetDynaset();
 | ||
| 
 | ||
| 	int Lock(const char* strKey, DWORD dwConnection);
 | ||
| 	int Unlock(const char* strKey, DWORD dwConnection);
 | ||
| 
 | ||
| 	int ExclusiveLock(DWORD dwConnection);
 | ||
| 	BOOL IsLocked() const { return m_dwExclusiveLocker != 0; } 
 | ||
| 	int ExclusiveUnlock(DWORD dwConnection);
 | ||
| 
 | ||
|     TTableDef(CdbDatabase* db, LPCSTR strTableName);
 | ||
| 	virtual ~TTableDef();
 | ||
| };
 | ||
| 
 | ||
| CdbTableDef TTableDef::GetTableDef()
 | ||
| {
 | ||
| 	return (*m_db)[m_strTableName];
 | ||
| }
 | ||
| 
 | ||
| CdbRecordset& TTableDef::GetDynaset()
 | ||
| {
 | ||
| 	if (!m_Dynaset.Exists())
 | ||
| 	{
 | ||
| 		// Genera la query basata sulla chiave primaria = 0
 | ||
| 		CString strQuery;
 | ||
| 		strQuery = "SELECT * FROM ";
 | ||
| 		strQuery += m_strTableName;
 | ||
| 		strQuery = " ORDER BY ";
 | ||
| 
 | ||
| 		CdbTableDef dbTable = (*m_db)[m_strTableName];
 | ||
| 		CdbIndex dbIndex = dbTable.Indexes[0L];
 | ||
| 		CdbFields& idxFields = dbIndex.Fields;
 | ||
| 		for (int f = 0; f < idxFields.GetCount(); f++)
 | ||
| 		{
 | ||
| 			if (f) strQuery += ",";
 | ||
| 			strQuery += idxFields[f].GetName();
 | ||
| 		}
 | ||
| 		strQuery += ";";
 | ||
| 		m_Dynaset = m_db->OpenRecordset(strQuery, dbOpenDynaset);
 | ||
| 	}
 | ||
| 	return m_Dynaset;
 | ||
| }
 | ||
| 
 | ||
| int TTableDef::Lock(const char* strKey, DWORD dwConnection)
 | ||
| {
 | ||
| 	DWORD dwLocker;
 | ||
| 	if (!m_Locks.Lookup(strKey, dwLocker))
 | ||
| 	{
 | ||
| 		m_Locks[strKey] = dwConnection;
 | ||
| 		dwLocker = dwConnection;
 | ||
| 	}
 | ||
| 	return dwLocker == dwConnection ? NOERR : _islocked;
 | ||
| }
 | ||
| 
 | ||
| int TTableDef::Unlock(LPCSTR strKey, DWORD dwConnection)
 | ||
| {
 | ||
| 	int err = NOERR;
 | ||
| 
 | ||
| 	if (strKey)
 | ||
| 	{
 | ||
| 		DWORD dwLocker;
 | ||
| 		if (m_Locks.Lookup(strKey, dwLocker))
 | ||
| 		{
 | ||
| 			if (dwLocker == dwConnection)
 | ||
| 				m_Locks.RemoveKey(strKey);
 | ||
| 			else
 | ||
| 				err = _islocked;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		for (POSITION pos = m_Locks.GetStartPosition(); pos; )
 | ||
| 		{
 | ||
| 			CString strKey;
 | ||
| 			DWORD dwLocker;
 | ||
| 			m_Locks.GetNextAssoc(pos, strKey, dwLocker);
 | ||
| 			if (dwLocker == dwConnection)
 | ||
| 				m_Locks.RemoveKey(strKey);
 | ||
| 		}
 | ||
| 	}
 | ||
| 	
 | ||
| 	return err;
 | ||
| }
 | ||
| 
 | ||
| int TTableDef::ExclusiveLock(DWORD dwConnection)
 | ||
| {
 | ||
| 	if (m_dwExclusiveLocker == dwConnection)
 | ||
| 		return NOERR;
 | ||
| 	if (m_dwExclusiveLocker != 0 || m_nReferences > 1)
 | ||
| 		return _islocked;
 | ||
| 	m_dwExclusiveLocker = dwConnection;
 | ||
| 	return NOERR;
 | ||
| }
 | ||
| 
 | ||
| int TTableDef::ExclusiveUnlock(DWORD dwConnection)
 | ||
| {
 | ||
| 	if (m_dwExclusiveLocker == dwConnection)
 | ||
| 		m_dwExclusiveLocker = 0;
 | ||
| 	return m_dwExclusiveLocker == 0 ? NOERR : _islocked;
 | ||
| }
 | ||
| 
 | ||
| TTableDef::TTableDef(CdbDatabase* db, LPCSTR strTableName)
 | ||
| 		 : m_db(db), m_strTableName(strTableName), 
 | ||
| 		   m_nReferences(0), m_dwExclusiveLocker(0)
 | ||
| {
 | ||
| 	m_tModifyTime = clock();
 | ||
| }
 | ||
| 
 | ||
| TTableDef::~TTableDef()
 | ||
| {
 | ||
| 	ASSERT(m_nReferences == 0);
 | ||
| 	if (m_Dynaset.Exists())
 | ||
| 		m_Dynaset.Close();
 | ||
| }
 | ||
| 
 | ||
| /////////////////////////////////////////////////////////////////////////////
 | ||
| // TTableDefPool
 | ||
| 
 | ||
| class TTableDefPool : public CObject
 | ||
| {
 | ||
| 	CMap<DWORD,DWORD,TTableDef*, TTableDef*> m_Tables;
 | ||
| 
 | ||
| protected:
 | ||
| 	enum { FIRM_MULTIPLIER = 10000 };
 | ||
| 	DWORD LogToIndex(int nFirm, int nLogicNumber) const;
 | ||
| 
 | ||
| public:
 | ||
| 	TTableDef* Find(int nFirm, int nLogicNumber) const;
 | ||
| 
 | ||
| 	void Add(int nFirm, int nLogicNumber, TTableDef* pTable);
 | ||
| 	
 | ||
| 	void AddReference(int nFirm, int nLogicNumber);
 | ||
| 	
 | ||
| 	TTableDef& TableDef(int nFirm, int nLogicNumber) const;
 | ||
| 
 | ||
| 	int RemoveReference(int nFirm, int nLogicNumber);
 | ||
| 
 | ||
| 	BOOL FindFirm(int nFirm) const;
 | ||
| 
 | ||
| 	TTableDefPool();
 | ||
| 	virtual ~TTableDefPool();
 | ||
| };
 | ||
| 
 | ||
| DWORD TTableDefPool::LogToIndex(int nFirm, int nLogicNumber) const
 | ||
| {
 | ||
| 	DWORD dwIndex = (nFirm * FIRM_MULTIPLIER) + nLogicNumber;
 | ||
| 	return dwIndex;
 | ||
| }
 | ||
| 
 | ||
| TTableDef* TTableDefPool::Find(int nFirm, int nLogicNumber) const
 | ||
| {
 | ||
| 	const DWORD dwIndex = LogToIndex(nFirm, nLogicNumber);
 | ||
| 	TTableDef* pTable;
 | ||
| 	BOOL bOk = m_Tables.Lookup(dwIndex, pTable);
 | ||
| 	return bOk ? pTable : NULL;
 | ||
| }
 | ||
| 
 | ||
| TTableDef& TTableDefPool::TableDef(int nFirm, int nLogicNumber) const
 | ||
| {
 | ||
| 	return *Find(nFirm, nLogicNumber);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void TTableDefPool::Add(int nFirm, int nLogicNumber, TTableDef* pTable)
 | ||
| {
 | ||
| 	ASSERT(Find(nFirm, nLogicNumber) == NULL);
 | ||
| 	const DWORD dwIndex = LogToIndex(nFirm, nLogicNumber);
 | ||
| 	m_Tables.SetAt(dwIndex, pTable);
 | ||
| }
 | ||
| 
 | ||
| void TTableDefPool::AddReference(int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	TTableDef* pTable = Find(nFirm, nLogicNumber);
 | ||
| 	pTable->AddReference();
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Decrementa il numero di riferimenti al file <p nLogicNumber>
 | ||
| //        della ditta <p nFirm>. Se questo numero e' zero allora
 | ||
| //        rimuove la definizione dalla lista 
 | ||
| int TTableDefPool::RemoveReference(int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	const DWORD dwIndex = LogToIndex(nFirm, nLogicNumber);
 | ||
| 	int nRef = 0;
 | ||
| 	TTableDef* pTable;
 | ||
| 	if (m_Tables.Lookup(dwIndex, pTable))
 | ||
| 	{
 | ||
| 		nRef = pTable->RemoveReference();
 | ||
| 		if (nRef == 0)
 | ||
| 		{
 | ||
| 			delete pTable;
 | ||
| 			m_Tables.RemoveKey(dwIndex);
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return nRef;
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Verifica l'esistenza di almeno un file appartenente
 | ||
| //        alla ditta <p nFirm>  
 | ||
| BOOL TTableDefPool::FindFirm(int nFirm) const
 | ||
| {
 | ||
| 	POSITION pos;
 | ||
| 	for (pos = m_Tables.GetStartPosition(); pos;) 
 | ||
| 	{
 | ||
| 		DWORD dwIndex;
 | ||
| 		TTableDef* pTable;
 | ||
| 		m_Tables.GetNextAssoc(pos, dwIndex, pTable);
 | ||
| 		if (int(dwIndex / FIRM_MULTIPLIER) == nFirm)
 | ||
| 			break;
 | ||
| 	}
 | ||
| 	return pos != NULL;
 | ||
| }
 | ||
| 
 | ||
| TTableDefPool::TTableDefPool()
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Vuota la lista delle definizioni delle tabelle SQL
 | ||
| TTableDefPool::~TTableDefPool()
 | ||
| {
 | ||
| 	for (POSITION pos = m_Tables.GetStartPosition(); pos;) 
 | ||
| 	{
 | ||
| 		DWORD dwIndex;
 | ||
| 		TTableDef* pTable;
 | ||
| 		m_Tables.GetNextAssoc(pos, dwIndex, pTable);
 | ||
| 		// Azzera i riferimenti prima di distruggere
 | ||
| 		pTable->ZeroReferences();    
 | ||
| 		delete pTable;
 | ||
| 	}
 | ||
| 	m_Tables.RemoveAll();
 | ||
| }
 | ||
| 
 | ||
| /////////////////////////////////////////////////////////////////////////////
 | ||
| // TSnapshot
 | ||
| 
 | ||
| class TSnapshot : public CObject
 | ||
| {
 | ||
| 	CdbDatabase*  m_db;
 | ||
| 	CString       m_strQuery;
 | ||
| 	CdbRecordset* m_Snapshot;
 | ||
| 	long          m_nPosition;
 | ||
| 
 | ||
| 	BOOL          m_bReusable;
 | ||
| 
 | ||
| 	clock_t       m_tCreationTime;
 | ||
| 	clock_t       m_tAccessTime;
 | ||
| 
 | ||
| public:
 | ||
| 	clock_t GetCreationTime() const { return m_tCreationTime; }
 | ||
| 	clock_t GetAccessTime() const { return m_tAccessTime; }
 | ||
| 
 | ||
| 	BOOL IsEqual(const CdbDatabase* pDatabase, LPCSTR sQuery) const;
 | ||
| 
 | ||
| 	BOOL IsOpen() const;
 | ||
| 	CdbRecordset& GetSnapshot();
 | ||
| 	void Update();
 | ||
| 	void Close();
 | ||
| 
 | ||
| 	void MakeReusable();
 | ||
| 	BOOL Reusable() const { return m_bReusable; }
 | ||
| 	void Reuse();
 | ||
| 
 | ||
|     TSnapshot(CdbDatabase* db, LPCSTR strQuery);
 | ||
| 	virtual ~TSnapshot();
 | ||
| };
 | ||
| 
 | ||
| BOOL TSnapshot::IsOpen() const
 | ||
| {
 | ||
| 	return m_Snapshot != NULL;
 | ||
| }
 | ||
| 
 | ||
| CdbRecordset& TSnapshot::GetSnapshot()
 | ||
| {
 | ||
| 	if (!IsOpen())
 | ||
| 	{
 | ||
| 		m_tCreationTime = clock();
 | ||
| 		m_Snapshot = new CdbRecordset;
 | ||
| 		try
 | ||
| 		{
 | ||
| 			*m_Snapshot = m_db->OpenRecordset(m_strQuery, dbOpenSnapshot);
 | ||
| 		}
 | ||
| 		catch(...)
 | ||
| 		{
 | ||
| 			TRACE("Can't open snapshot!");
 | ||
| 			ASSERT(0);
 | ||
| 		}
 | ||
| 		if (m_nPosition > 0)
 | ||
| 		{
 | ||
| 			try
 | ||
| 			{
 | ||
| 				m_Snapshot->Move(m_nPosition);
 | ||
| 			}
 | ||
| 			catch(...)
 | ||
| 			{
 | ||
| 				TRACE("Can't restore snapshot position!");
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 	m_tAccessTime = clock();
 | ||
| 	return *m_Snapshot;
 | ||
| }
 | ||
| 
 | ||
| void TSnapshot::Update()
 | ||
| {
 | ||
| 	if (IsOpen())
 | ||
| 	{
 | ||
| 		m_tCreationTime = clock();
 | ||
| 		m_Snapshot->Requery();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void TSnapshot::MakeReusable()
 | ||
| {
 | ||
| 	ASSERT(!m_bReusable);
 | ||
| 	m_bReusable = TRUE;
 | ||
| }
 | ||
| 
 | ||
| void TSnapshot::Reuse()
 | ||
| {
 | ||
| 	ASSERT(m_bReusable);
 | ||
| 	m_bReusable = FALSE;
 | ||
| }
 | ||
| 
 | ||
| void TSnapshot::Close()
 | ||
| {
 | ||
| 	if (IsOpen())
 | ||
| 	{
 | ||
| 		m_nPosition = m_Snapshot->GetAbsolutePosition();
 | ||
| 		m_Snapshot->Close();
 | ||
| 		delete m_Snapshot;
 | ||
| 		m_Snapshot = NULL;
 | ||
| 		m_tCreationTime = 0;
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| BOOL TSnapshot::IsEqual(const CdbDatabase* pDatabase, 
 | ||
| 						LPCSTR sQuery) const
 | ||
| {
 | ||
| 	return m_db == pDatabase && m_strQuery == sQuery;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| TSnapshot::TSnapshot(CdbDatabase* db, LPCSTR strQuery)
 | ||
| 		 : m_db(db), m_Snapshot(NULL), m_strQuery(strQuery), 
 | ||
| 		   m_tAccessTime(0), m_tCreationTime(0), m_nPosition(-1),
 | ||
| 		   m_bReusable(FALSE)
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| TSnapshot::~TSnapshot()
 | ||
| {
 | ||
| 	Close();
 | ||
| }
 | ||
| 
 | ||
| /////////////////////////////////////////////////////////////////////////////
 | ||
| // TSnapshotPool
 | ||
| 
 | ||
| class TSnapshotPool : public CObject
 | ||
| {
 | ||
| 	CMap<DWORD,DWORD,TSnapshot*,TSnapshot*> m_Snapshots;
 | ||
| 	DWORD m_dwNextId;
 | ||
| 
 | ||
| protected:
 | ||
| 	DWORD RecycleSnapshot(CdbDatabase* pDatabase, LPCSTR sQuery);
 | ||
| 
 | ||
| public:
 | ||
| 	DWORD AddSnapshot(CdbDatabase* pDatabase, LPCSTR sQuery);
 | ||
| 	
 | ||
| 	TSnapshot& operator[](DWORD nHandle)
 | ||
| 	{ return *m_Snapshots[nHandle]; }
 | ||
| 
 | ||
| 	void RemoveSnapshot(DWORD nHandle);
 | ||
| 
 | ||
| 	TSnapshotPool();
 | ||
| 	virtual ~TSnapshotPool();
 | ||
| };
 | ||
| 
 | ||
| 
 | ||
| TSnapshotPool::TSnapshotPool()
 | ||
| 			 : m_dwNextId(0)
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| // @mfunc Data <p sQuery> cerca uno snapshot inutilizzato che
 | ||
| //        abbia la stessa query: se lo trova lo riutilizza
 | ||
| DWORD TSnapshotPool::RecycleSnapshot(CdbDatabase* pDatabase,
 | ||
| 	 							     LPCSTR sQuery)
 | ||
| {
 | ||
| 	for (POSITION pos = m_Snapshots.GetStartPosition(); pos; )
 | ||
| 	{
 | ||
| 		DWORD dwId;
 | ||
| 		TSnapshot* pSnapshot;
 | ||
| 		m_Snapshots.GetNextAssoc(pos, dwId, pSnapshot);
 | ||
| 		if (pSnapshot->Reusable() && 
 | ||
| 			pSnapshot->IsEqual(pDatabase, sQuery))
 | ||
| 		{
 | ||
| 			pSnapshot->Reuse();
 | ||
| 			return dwId;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return 0;
 | ||
| }
 | ||
| 
 | ||
| DWORD TSnapshotPool::AddSnapshot(CdbDatabase* pDatabase, 
 | ||
| 								 LPCSTR sQuery)
 | ||
| {
 | ||
| 	// Tenta di riciclare uno Snapshot precedente gia' aperto
 | ||
| 	DWORD dwId = RecycleSnapshot(pDatabase, sQuery);
 | ||
| 	if (dwId)
 | ||
| 		return dwId;
 | ||
| 
 | ||
| 	TSnapshot* pNew = new TSnapshot(pDatabase, sQuery);
 | ||
| 	
 | ||
| 	const int MAX_OPEN = 32;
 | ||
| 	if (m_Snapshots.GetCount() > MAX_OPEN)
 | ||
| 	{
 | ||
| 		TSnapshot* pOld = NULL;
 | ||
| 		DWORD dwOldId = 0;
 | ||
| 		
 | ||
| 		int nReallyOpen = 0;
 | ||
| 		for (POSITION pos = m_Snapshots.GetStartPosition(); pos; )
 | ||
| 		{
 | ||
| 			DWORD dwId;
 | ||
| 			TSnapshot* pSnapshot;
 | ||
| 			m_Snapshots.GetNextAssoc(pos, dwId, pSnapshot);
 | ||
| 			if (pSnapshot->IsOpen())
 | ||
| 			{
 | ||
| 				nReallyOpen++;
 | ||
| 				if (pOld == NULL || 
 | ||
| 				    pSnapshot->GetAccessTime() < pOld->GetAccessTime())
 | ||
| 				{
 | ||
| 					pOld = pSnapshot;
 | ||
| 					dwOldId = dwId;
 | ||
| 				}
 | ||
| 			}
 | ||
| 		}
 | ||
| 		if (nReallyOpen > MAX_OPEN);
 | ||
| 		{
 | ||
| 			pOld->Close();
 | ||
| 			if (pOld->Reusable())
 | ||
| 				RemoveSnapshot(dwOldId);
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	m_dwNextId++;
 | ||
| 	m_Snapshots.SetAt(m_dwNextId, pNew);
 | ||
| 
 | ||
| 	return m_dwNextId;
 | ||
| }
 | ||
| 
 | ||
| void TSnapshotPool::RemoveSnapshot(DWORD nHandle)
 | ||
| {
 | ||
| 	TSnapshot* pSnapshot = m_Snapshots[nHandle];
 | ||
| 	if (pSnapshot->IsOpen())
 | ||
| 		pSnapshot->MakeReusable();
 | ||
| 	else
 | ||
| 	{
 | ||
| 		delete pSnapshot;
 | ||
| 		m_Snapshots.RemoveKey(nHandle);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| TSnapshotPool::~TSnapshotPool()
 | ||
| {
 | ||
| 	for (POSITION pos = m_Snapshots.GetStartPosition(); pos; )
 | ||
| 	{
 | ||
| 		DWORD dwId;
 | ||
| 		TSnapshot* pSnapshot;
 | ||
| 		m_Snapshots.GetNextAssoc(pos, dwId, pSnapshot);
 | ||
| 		delete pSnapshot;
 | ||
| 	}
 | ||
| 	m_Snapshots.RemoveAll();
 | ||
| }
 | ||
| 
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| // TPrassiServer
 | ||
| 
 | ||
| TConnection* TPrassiServer::OnCreateConnection(DWORD id)
 | ||
| {
 | ||
| 	Trace(0, "Connecting %lu", id);
 | ||
| 	return new TPrassiConnection(this, id);
 | ||
| }
 | ||
| 
 | ||
| BOOL TPrassiServer::OnRemoveConnection(DWORD id)
 | ||
| {
 | ||
| 	Trace(0, "Disconnecting %lu", id);
 | ||
| 	return BASE_SERVER::OnRemoveConnection(id);
 | ||
| }
 | ||
| 
 | ||
| BOOL TPrassiServer::TestFirm(int nFirm) const
 | ||
| {
 | ||
| 	BOOL bOk = m_pTables->FindFirm(nFirm);
 | ||
| 	if (!bOk)
 | ||
| 		bOk = m_pDataSources->TestDataSource("FIRM", nFirm);
 | ||
| 	return bOk;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| BOOL TPrassiServer::OpenTableDef(int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	if (pTable == NULL)
 | ||
| 	{
 | ||
| 		CString strTableName;
 | ||
| 		CdbDatabase* db = 
 | ||
| 			m_pDataSources->GetDataSource(nFirm, 
 | ||
| 										  nLogicNumber,
 | ||
| 										  strTableName);
 | ||
| 		if (db == NULL)
 | ||
| 			return FALSE;
 | ||
| 		try 
 | ||
| 		{
 | ||
| 			(*db)[strTableName].Exists();
 | ||
| 		}
 | ||
| 		catch(...)
 | ||
| 		{
 | ||
| 			m_pDataSources->ReleaseDataSource(nFirm, nLogicNumber);
 | ||
| 			return FALSE;
 | ||
| 		}
 | ||
| 
 | ||
| 		pTable = new TTableDef(db, strTableName);
 | ||
| 		m_pTables->Add(nFirm, nLogicNumber, pTable);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (pTable != NULL)
 | ||
| 	{
 | ||
| 		if (pTable->IsLocked())
 | ||
| 			return FALSE;
 | ||
| 		m_pTables->AddReference(nFirm, nLogicNumber);
 | ||
| 	}
 | ||
| 	
 | ||
| 	return pTable != NULL;
 | ||
| }
 | ||
| 
 | ||
| CdbTableDef TPrassiServer::GetTableDef(int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	return pTable->GetTableDef();
 | ||
| }
 | ||
| 
 | ||
| CdbRecordset& TPrassiServer::GetDynaset(int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	return pTable->GetDynaset();
 | ||
| }
 | ||
| 
 | ||
| void TPrassiServer::CloseTableDef(int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	int nRef = m_pTables->RemoveReference(nFirm, nLogicNumber);
 | ||
| 	if (nRef == 0)
 | ||
| 		m_pDataSources->ReleaseDataSource(nFirm, nLogicNumber);
 | ||
| }
 | ||
| 
 | ||
| DWORD TPrassiServer::OpenSnapshot(int nFirm, int nLogicNumber, 
 | ||
| 								  LPCSTR sWhere, LPCSTR sOrder)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	
 | ||
| 	CString strQuery;
 | ||
| 	if (sOrder || sWhere)
 | ||
| 	{
 | ||
| 		strQuery = "SELECT * FROM ";
 | ||
| 		strQuery += pTable->GetTableName();
 | ||
| 		if (sWhere)
 | ||
| 		{
 | ||
| 			strQuery += " WHERE ";
 | ||
| 			strQuery += sWhere;
 | ||
| 		}
 | ||
| 		if (sOrder)
 | ||
| 		{
 | ||
| 			strQuery += " ORDER BY ";
 | ||
| 			int nKey = atoi(sOrder);
 | ||
| 			if (nKey > 0)
 | ||
| 			{
 | ||
| 				CdbTableDef dbTable = pTable->GetTableDef();
 | ||
| 				CdbIndex dbIndex = dbTable.Indexes[nKey-1];
 | ||
| 				CdbFields& idxFields = dbIndex.Fields;
 | ||
| 				for (int f = 0; f < idxFields.GetCount(); f++)
 | ||
| 				{
 | ||
| 					if (f) strQuery += ",";
 | ||
| 					strQuery += idxFields[f].GetName();
 | ||
| 				}
 | ||
| 			}
 | ||
| 			else
 | ||
| 				strQuery += sOrder;
 | ||
| 		}
 | ||
| 		strQuery += ";";
 | ||
| 	}
 | ||
| 	else
 | ||
| 		strQuery = pTable->GetTableName();
 | ||
| 
 | ||
| 	CdbDatabase* pDatabase = &pTable->GetDatabase();
 | ||
| 	DWORD dwHandle = m_pSnapshots->AddSnapshot(pDatabase, strQuery);
 | ||
| 	return dwHandle;
 | ||
| }
 | ||
| 
 | ||
| CdbRecordset& TPrassiServer::GetSnapshot(DWORD nHandle)
 | ||
| {
 | ||
| 	return (*m_pSnapshots)[nHandle].GetSnapshot();
 | ||
| }
 | ||
| 
 | ||
| BOOL TPrassiServer::UpdateSnapshot(DWORD nHandle, 
 | ||
| 								   int nFirm, int nLogicNumber)
 | ||
| {
 | ||
| 	TSnapshot& snap = (*m_pSnapshots)[nHandle];
 | ||
| 	const clock_t tCreationTime = snap.GetCreationTime();
 | ||
| 	const TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	ASSERT(pTable);
 | ||
| 	BOOL bChanged = pTable->IsChangedSince(tCreationTime);
 | ||
| 	if (bChanged)
 | ||
| 		snap.Update();
 | ||
| 	return bChanged;
 | ||
| }
 | ||
| 
 | ||
| void TPrassiServer::CloseSnapshot(DWORD nHandle)
 | ||
| {
 | ||
| 	m_pSnapshots->RemoveSnapshot(nHandle);
 | ||
| }
 | ||
| 
 | ||
| int TPrassiServer::Lock(int nFirm, int nLogicNumber, 
 | ||
| 						 LPCSTR sKey, DWORD dwLocker)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	ASSERT(pTable);
 | ||
| 	return pTable->Lock(sKey, dwLocker);
 | ||
| }
 | ||
| 
 | ||
| int TPrassiServer::Unlock(int nFirm, int nLogicNumber, 
 | ||
| 						   LPCSTR sKey, DWORD dwLocker)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	ASSERT(pTable);
 | ||
| 	return pTable->Unlock(sKey, dwLocker);
 | ||
| }
 | ||
| 
 | ||
| int TPrassiServer::ExclusiveLock(int nFirm, int nLogicNumber, DWORD dwLocker)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	ASSERT(pTable);
 | ||
| 	return pTable->ExclusiveLock(dwLocker);
 | ||
| }
 | ||
| 
 | ||
| int TPrassiServer::ExclusiveUnlock(int nFirm, int nLogicNumber, DWORD dwLocker)
 | ||
| {
 | ||
| 	TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
 | ||
| 	ASSERT(pTable);
 | ||
| 	return pTable->ExclusiveUnlock(dwLocker);
 | ||
| }
 | ||
| 
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| // Dongle Management
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| 
 | ||
| #include "hlapi_c.h"
 | ||
| 
 | ||
| WORD TPrassiServer::m_DongleNumber;
 | ||
| WORD TPrassiServer::m_DongleModules[DONGLE_WORDS];
 | ||
| 
 | ||
| WORD TPrassiServer::DongleLogin()
 | ||
| {
 | ||
| 	unsigned char* REFKEY = (unsigned char*)"CAMPOKEY";
 | ||
| 	unsigned char* VERKEY = (unsigned char*)"<EFBFBD>pو<EFBFBD>c<EFBFBD><";
 | ||
|     const int status = HL_LOGIN(26952, LOCAL_DEVICE, REFKEY, VERKEY);
 | ||
| 
 | ||
| 	Trace(-1, "Hardlock login %s: %d",
 | ||
| 		      status == STATUS_OK ? "OK" : "Failed", status);
 | ||
| 
 | ||
| 	m_DongleNumber = 0xFFFF;
 | ||
| 
 | ||
|     if (status == STATUS_OK)
 | ||
| 	{
 | ||
| 		Word Val[4] = { 0, 0, 0, 0 }; 
 | ||
| 		for (int i = 0; i < 4; i++)
 | ||
| 			HL_READ(i, &Val[i]);
 | ||
| 		HL_CODE(Val, 1);
 | ||
| 		if (Val[0] == 0xFAE8)
 | ||
| 			m_DongleNumber = Val[1];
 | ||
| 		else
 | ||
| 			m_DongleNumber = 0;
 | ||
| 	}
 | ||
| 	
 | ||
| 	Trace(-1, "Hardlock serial number is %s: %d", 
 | ||
| 		      (m_DongleNumber == 0xFFFF) ? "Bad" : "OK", (int)m_DongleNumber);
 | ||
| 
 | ||
| 	switch(m_DongleNumber)
 | ||
| 	{
 | ||
| 	case 0x0000:
 | ||
| 		memset(m_DongleModules, 0xFF, sizeof(m_DongleModules));
 | ||
| 		break;
 | ||
| 	case 0xFFFF:
 | ||
| 		memset(m_DongleModules, 0x00, sizeof(m_DongleModules));
 | ||
| 		break;
 | ||
| 	default:
 | ||
| 		{
 | ||
| 			int i;
 | ||
| 			for (i = 0; i < DONGLE_WORDS; i++)
 | ||
| 			{
 | ||
| 				HL_READ(48+i, &m_DongleModules[i]);
 | ||
| 				if (i % 4 == 3)
 | ||
| 					HL_CODE(&m_DongleModules[i-3], 1);
 | ||
| 			}
 | ||
| 			for (i = 0; i < DONGLE_WORDS; i++) 
 | ||
| 				m_DongleModules[i] ^= m_DongleNumber;
 | ||
| 		}
 | ||
| 		break;
 | ||
| 	}
 | ||
| 	
 | ||
| 	return m_DongleNumber;
 | ||
| }
 | ||
| 
 | ||
| void TPrassiServer::DongleLogout()
 | ||
| {
 | ||
|     HL_LOGOUT();
 | ||
| 	m_DongleNumber = 0xFFFF;
 | ||
| 	memset(m_DongleModules, 0x00, sizeof(m_DongleModules));
 | ||
| }
 | ||
| 
 | ||
| BOOL TPrassiServer::IsOk() const
 | ||
| {
 | ||
| 	BOOL ok = BASE_SERVER::IsOk();
 | ||
| 	if (ok)
 | ||
| 		ok &= m_pDataSources->IsOk();
 | ||
| 	return ok;
 | ||
| }
 | ||
| 
 | ||
| TPrassiServer::TPrassiServer() 
 | ||
|              : BASE_SERVER("PRASSI")
 | ||
| {
 | ||
| 	m_pDataSources = new TDataSources;
 | ||
| 	m_pTables      = new TTableDefPool;
 | ||
| 	m_pSnapshots   = new TSnapshotPool;
 | ||
| }
 | ||
| 
 | ||
| TPrassiServer::~TPrassiServer()
 | ||
| {
 | ||
| 	delete m_pSnapshots;
 | ||
| 	delete m_pTables;
 | ||
| 	delete m_pDataSources;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| // Start/Get/Stop server
 | ||
| 
 | ||
| static TPrassiServer* pServer = NULL;
 | ||
| 
 | ||
| BOOL StopServer()
 | ||
| {
 | ||
| 	BOOL ok = pServer != NULL;
 | ||
| 	if (ok)
 | ||
| 	{
 | ||
| 		TPrassiServer::DongleLogout();
 | ||
| 		delete pServer;
 | ||
| 		pServer = NULL;
 | ||
| 	}
 | ||
| 	return ok;
 | ||
| }
 | ||
| 
 | ||
| BOOL StartServer()
 | ||
| {
 | ||
| 	BOOL ok = pServer == NULL;
 | ||
| 	if (ok)
 | ||
| 	{
 | ||
| 		ok = TPrassiServer::DongleLogin() != 0xFFFF;
 | ||
| 		if (ok)
 | ||
| 		{
 | ||
| 			pServer = new TPrassiServer;
 | ||
| 			if (!pServer->IsOk())
 | ||
| 			{
 | ||
| 				StopServer();
 | ||
| 				AfxMessageBox("ODBC initialization failure.",
 | ||
| 							  MB_OK | MB_ICONERROR);
 | ||
| 			}
 | ||
| 		}
 | ||
| 		else
 | ||
| 		{
 | ||
| 			AfxMessageBox("Error connecting to the dongle.",
 | ||
| 						  MB_OK | MB_ICONERROR);
 | ||
| 		}
 | ||
| 		ok = pServer != NULL;
 | ||
| 	}
 | ||
| 	return ok;
 | ||
| }
 | ||
| 
 | ||
| TPrassiServer& GetServer()
 | ||
| {
 | ||
| 	if (pServer == NULL);
 | ||
| 		StartServer();
 | ||
| 	ASSERT(pServer);
 | ||
| 	return *pServer;
 | ||
| }
 | ||
| 
 | ||
| 
 |