COM只應初始化每個線程一次,但在客戶的整個生命週期中,多次觸發事件OnExecute
。
如果你不使用線程與TIdTCPServer
池(通過附加一個TIdSchedulerOfThreadPool
組件到TIdTCPServer::Scheduler
屬性),那麼你可以使用TIdTCPServer::OnConnect
和TIdTCPServer::OnDisconnect
事件來初始化/完成您的ADO對象,然後在TIdTCPServer::OnExecute
事件作爲使用它們需要,如:
class TMyContextData
{
public:
TADOConnection *sql_conn;
TADOQuery *pos_q;
TMyContextData();
~TMyContextData();
};
TMyContextData::TMyContextData()
{
sql_conn = new TADOConnection(NULL);
pos_q = new TADOQuery(NULL);
}
TMyContextData::~TMyContextData()
{
delete pos_q;
delete sql_conn;
}
void __fastcall TMyForm::tcp_serverConnect(TIdContext *AContext)
{
::CoInitialize(NULL);
AContext->Data = new TMyContextData;
}
void __fastcall TMyForm::tcp_serverDisconnect(TIdContext *AContext)
{
delete static_cast<TMyContextData*>(AContext->Data);
AContext->Data = NULL;
::CoUninitialize();
}
void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext)
{
TMyContextData *pData = static_cast<TMyContextData*>(AContext->Data);
// use pData->sql_conn and pData->pos_q as needed...
}
或者,從TIdServerContext
派生一個新類來代替:
class TMyContext : public TIdServerContext
{
public:
TADOConnection *sql_conn;
TADOQuery *pos_q;
__fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL);
__fastcall ~TMyContext();
};
__fastcall TMyContext::TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList)
: TIdServerContext(AConnection, AYarn, AList)
{
::CoInitialize(NULL);
sql_conn = new TADOConnection(NULL);
pos_q = new TADOQuery(NULL);
}
__fastcall TMyContext::~TMyContext()
{
delete pos_q;
delete sql_conn;
::CoUninitialize();
}
__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
// do this before activating TIdTCPServer
tcp_server->ContextClass = __classid(TMyContext);
}
void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext)
{
TMyContext *pContext = static_cast<TMyContext*>(AContext);
// use pContext->sql_conn and pContext->pos_q as needed...
}
但是,如果喲您正在使用線程池,那麼多個客戶端可以由相同的物理線程提供服務,因此您應該將您的COM初始化移動到管理TIdContext
對象的實際線程對象(您還應該將ADO對象移動到線程中,以便可以重用它們對於多個客戶),例如:
class TMyADOThread : public TIdThreadWithTask
{
protected:
virtual void __fastcall AfterExecute();
virtual void __fastcall BeforeExecute();
public:
TADOConnection *sql_conn;
TADOQuery *pos_q;
__fastcall TMyADOThread(TIdTask *ATask = NULL, const String AName = "");
};
__fastcall TMyADOThread::TMyADOThread(TIdTask *ATask, const String AName)
: TIdThreadWithTask(ATask, AName)
{
}
void __fastcall TMyADOThread::BeforeExecute()
{
TIdThreadWithTask::BeforeExecute();
::CoInitialize(NULL);
sql_conn = new TADOConnection(NULL);
pos_q = new TADOQuery(NULL);
}
void __fastcall TMyADOThread::AfterExecute()
{
delete pos_q;
delete sql_conn;
::CoUninitialize();
TIdThreadWithTask::AfterExecute();
}
__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
// do this before activating TIdTCPServer
IdSchedulerOfThreadPool1->ThreadClass = __classid(TMyADOThread);
}
void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext)
{
TMyADOThread *pThread = static_cast<TMyADOThread*>(static_cast<TIdYarnOfThread*>(AContext->Yarn)->Thread);
// use pThread->sql_conn and pThread->pos_q as needed...
}
爲什麼你認爲有泄漏?進程內存的增加不能保證是真實泄漏的指示。請記住,RTL緩存並重新使用釋放的內存,但不會返回到操作系統。你可能會看到內存碎片,而不是內存泄漏。如果您尚未安裝,則應安裝[FastMM](http://fastmm.sourrceforge.net)或其他設計用於防止碎片的內存管理器。 –