COM はスレッドごとに 1 回だけ初期化する必要がありますが、OnExecute
イベントはクライアントの存続期間中に複数回トリガーされます。
(コンポーネントをプロパティにTIdTCPServer
アタッチすることにより)でスレッド プールを使用していない場合は、およびイベントを使用して ADO オブジェクトを初期化/終了し、必要に応じてイベントで使用できます。次に例を示します。TIdSchedulerOfThreadPool
TIdTCPServer::Scheduler
TIdTCPServer::OnConnect
TIdTCPServer::OnDisconnect
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...
}