プログレスバーとxmlをサーバーにアップロードするボタンを備えたフォームがあります。ボタンが押されている間、ソケットを作成する新しいスレッドが作成され、データがチャンクでサーバーに送信され、その間に進行状況バーが更新されます。ここで、アップロード ボタンをもう一度押すと、アクセス違反が発生し、デバッガーでプログレス バー オブジェクトのアドレスが NULL になります。プログレス バーが解放される理由がわかりません。
PS ターゲット OS は Windows PS2 です。同じコードがスレッドを使用せずにメイン スレッドで実行される場合、この問題はないようです。スレッド全体でプログレス バーの使用をスキップしても、アップロード ボタンを最初に押した後、再び null に設定されます。
スレッド コンストラクター:
__fastcall UploadRouteThread::UploadRouteThread(bool CreateSuspended) : TThread(CreateSuspended)
{
this->OnTerminate = OnTerminateHandler;
ioHandlerStack = new TIdIOHandlerStack();
tcpClient = new TIdTCPClient();
tcpClient->ReadTimeout = -1;
tcpClient->UseNagle = true;
tcpClient->IOHandler = ioHandlerStack;
tcpClient->OnConnected = OnConnectedHandler;
}
OnTerminate ハンドラー:
void __fastcall UploadRouteThread::OnTerminateHandler(TObject *Sender)
{
TabbedwithNavigationForm->UploadButton->Text = "Upload";
TabbedwithNavigationForm->UploadButton->Enabled = false;
TabbedwithNavigationForm->ProgressBar->Visible = false;
tcpClient->DisconnectNotifyPeer();
ShowMessage("Data uploaded.");
delete ioHandlerStack;
delete tcpClient;
TabbedwithNavigationForm->OptionButton->Enabled = true;
TabbedwithNavigationForm->RetrieveRoutesButton->Enabled = true;
TabbedwithNavigationForm->TrackButton->Enabled = true;
TabbedwithNavigationForm->MediaButton->Enabled = true;
}
実行方法:
void __fastcall UploadRouteThread::Execute()
{
FreeOnTerminate = true;
tcpClient->Connect();
}
2 つの補助機能:
void __fastcall UploadRouteThread::SetHostPort(UnicodeString host, unsigned short port)
{
tcpClient->Host = host;
tcpClient->Port = port;
}
void __fastcall UploadRouteThread::SetXML(AnsiString xmlString)
{
this->xmlString = xmlString;
}
OnConnect ハンドラー:
void __fastcall UploadRouteThread::OnConnectedHandler(TObject *Sender)
{
NextPacketSize nps;
TIdBytes bytes;
int chunks;
int bytesLength;
nps.PacketID = BasicPacket::DATA_UPLOAD;
nps.size = xmlString.Length();
tcpClient->IOHandler->WriteDirect(RawToBytes(&nps, sizeof(nps)), sizeof(NextPacketSize));
bytes = RawToBytes(xmlString.c_str(), xmlString.Length());
bytesLength = bytes.get_length();
chunks = ceil(float(bytesLength) / 256.0);
int previousSizeSent(0);
for(int i = 1; i <= chunks; i++)
{
if(Terminated)
break;
int bytesToSend = 256;
TByteDynArray byteDynArray;
if((bytesToSend > bytesLength))
{
bytesToSend = bytesLength;
}
byteDynArray = bytes.CopyRange(previousSizeSent, bytesToSend);
tcpClient->IOHandler->WriteDirect(ToBytes(byteDynArray, byteDynArray.get_length(), 0),
byteDynArray.get_length());
sent = (float(i) / float(chunks)) * 100;
TThread::Synchronize(this, UpdateProgressBarInternal);
previousSizeSent += bytesToSend;
bytesLength -= bytesToSend;
}
}
そして進行状況バーの Update メソッド:
void __fastcall UploadRouteThread::UpdateProgressBarInternal()
{
if(!TabbedwithNavigationForm->ProgressBar->Visible)
{
TabbedwithNavigationForm->ProgressBar->Visible = true;
TabbedwithNavigationForm->ProgressBar->Max = 100;
}
TabbedwithNavigationForm->ProgressBar->Value = sent;
}