线程中的 TIdFTP 未触发 Work 方法

TIdFTP in a thread not firing Work method

我有一个用 Embarcadero 的 C++ 10 Seattle 编写的 VCL 应用程序。主线程为 运行 TIdFTP 功能生成一个线程,因为如果在传输过程中连接丢失,Get 方法将无限期挂起。这个想法是检测连接是否挂起,孤立线程,并生成 "retry"。我的问题是我已经在线程的 h 文件中声明了对象以及应该触发的方法(WorkBegin、WorkEnd、Work 等),如下所示....

class FTPThread : public TThread
{
protected:
    void __fastcall Execute();
    void __fastcall UpdateUI();
public:
    __fastcall FTPThread(bool CreateSuspended);
    String FTPhostname;
    String FTPusername;
    String FTPpassword;
    String remoteDir;
    String localDir;
    String localTempDir;
    String fileName;
    TIdFTP *FTPClnt;
    void __fastcall FTPClntWorkBegin(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCountMax);
    void __fastcall FTPClntWorkEnd(TObject *ASender, TWorkMode AWorkMode);
    void __fastcall FTPClntWork(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCount);
    void __fastcall FTPClntAfterGet(TObject *ASender, TStream *AStream);

};

然后我像这样在线程的 cpp 文件中实现了 Work 函数......

void __fastcall FTPThread::UpdateUI()
{
    if (FrmFTP) {
        //FrmFTP->FTPProg->Max = fileSizeBytes;
        FrmFTP->FTPProg->Position = ftpProgress;
        FrmFTP->BringToFront();
        Application->ProcessMessages();
    }
}

void __fastcall FTPThread::FTPClntWorkBegin(TObject *ASender,
    TWorkMode AWorkMode, __int64 AWorkCountMax) {
    ftpProgress = 0;
    if (FrmFTP) {
        FrmFTP->FTPProg->Max = fileSizeBytes;
    }
    Synchronize(&UpdateUI);
}
// ---------------------------------------------------------------------------

void __fastcall FTPThread::FTPClntWorkEnd(TObject *ASender,
    TWorkMode AWorkMode)

{
    if (FrmFTP) {
        ftpProgress = FrmFTP->FTPProg->Max;
    }
    Synchronize(&UpdateUI);
}
// ---------------------------------------------------------------------------

void __fastcall FTPThread::FTPClntWork(TObject *ASender, TWorkMode AWorkMode,
    __int64 AWorkCount)

{
   ftpProgress = AWorkCount;
   Synchronize(&UpdateUI);
}
// ---------------------------------------------------------------------------

void __fastcall FTPThread::FTPClntAfterGet(TObject *ASender,
    TStream *AStream) {
    ftpCompletionStatus = 1;
}
// ---------------------------------------------------------------------------

None 这些方法在 Get 开始、传输和完成时被触发。知道他们为什么不开火吗?我的主线程上的相同功能运行良好。我觉得我在某种程度上没有尝试我已经实现到 TIdFTP 对象的这些方法,但我不确定如何去做。

谢谢!

the Get method indefinitely hangs if the connection is lost during the transfer.

它最终应该会失败。 OS 可能需要一段时间才能真正检测到丢失的连接并使打开的套接字无效,因此 I/O 操作开始报告错误。如果您不想等那么久,请确保将 ReadTimeout 属性 设置为合理的超时(TIdFTP 默认设置为 1 分钟),以及 TransferTimeout 属性(默认为无限)。

The idea is to detect if the connection has hung, orphan the thread, and spawn a "retry".

从不 "orphan" 一个线程。您可以简单地让主线程调用 TIdFTPAbort()Disconnect() 方法,分别终止正在进行的传输并关闭命令套接字。

My problem is I've declared the object in the thread's h file as well as the methods that should fire (WorkBegin, WorkEnd, Work, etc) like follows....

不要 在同步方法中调用 Application->ProcessMessages()。该方法已经 运行 在主线程消息处理程序中,只需退出同步方法,以便控制 returns 到主消息循环。

此外,您的 OnWork... 处理程序直接从主线程外部访问 FrmFTP->FTPProg->Max。这些访问也需要同步。 任何触及主要 UI 的内容 都需要同步。

None of these methods are ever fired as the Get begins, transfers, and completes. Any idea why they wouldn't fire?

你一开始就把它们联系起来了吗?据推测 FTPClnt 是在 FTPThread::Execute() 中创建的,但是它是否在创建 FTPClnt 之后将您的处理程序分配给 FTPClnt->OnWork... 事件?他们不会为你挂钩,你必须自己做,例如:

FTPClnt = new TIdFTP;
FTPClnt->OnWorkBegin = &FTPClntWorkBegin;
FTPClnt->OnWorkEnd = &FTPClntWorkEnd;
FTPClnt->OnWork = &FTPClntWork;

The same functionality on my main thread worked fine.

如果您在设计时将一个 TIdFTP 对象放在一个表单上,并在对象检查器中分配它的 OnWork... 事件,那么当表单是在运行时创建的。

仅仅声明事件处理程序是不够的。必须有人(您或 DFM)在运行时实际 连接它们