#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 m_FileInfo; // @cmember:(INTERNAL) Elenco dei database aperti CMap 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

vale FIRM // lo trasforma nel codice ditta corrispondente // a

, 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

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

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 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 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

// della ditta

. 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

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 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

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*)"ìpÙˆ¬cê<"; 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; }