1181 lines
26 KiB
C++
1181 lines
26 KiB
C++
|
#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;
|
|||
|
}
|
|||
|
|
|||
|
|