程序要求显示在图形界面下显示下载进度,所以今天用FtpLib临时做了一个MFC程序,运行效果如下:
大体流程:
1、输入要下载的文件以及要保存到本地的文件路径,然后触发Start;
2、把下载任务推入到utShareData的任务队列中(Queue先进先出);
3、工作线程从utShareData的任务队列中获取任务,开始FTP;
4、在Ftp过程中,通过PostMessage发送进度消息给主窗口;
5、主窗口响应此消息然后进行相应的窗口显示。
关键点:
用MyFtp.h封装了FtpLib的部分功能:
class MyFtp
{
private:
string _host;
string _user;
string _password;
string _err;
public:
MyFtp(const string& host, const string& user, const string& password);
~MyFtp();
public:
bool connect();
bool down(const string& sourceFileName, const string& targetFileName);
string getErr();
};
实现:
MyFtp* _ftp;
static netbuf *conn = NULL;
struct REMFILE {
struct REMFILE *next;
int fsz;
char *fnm;
};
static int log_progress(netbuf *ctl, int xfered, void *arg)
{
struct REMFILE *f = (struct REMFILE *) arg;
int pct = (int)(xfered*1.0/f->fsz*100);
//printf("%s %3d%%/r", f->fnm, pct);
//fflush(stdout);
::PostMessage((HWND)(AfxGetApp()->GetMainWnd()->GetSafeHwnd()),WM_PROGRESS,pct,NULL);
return 1;
}
MyFtp::MyFtp(const string& host, const string& user, const string& password)
{
_host = host;
_user = user;
_password = password;
FtpInit();
}
MyFtp::~MyFtp()
{
if (conn)
FtpClose(conn);
}
bool MyFtp::connect()
{
if (!FtpConnect(_host.c_str(), &conn))
{
_err = ftplib_lastresp;
return false;
}
if (!FtpLogin(_user.c_str(), _password.c_str(), conn))
{
_err = FtpLastResponse(conn);
return false;
}
return true;
}
bool MyFtp::down(const string& sourceFileName, const string& targetFileName)
{
int sts=0;
int fsz;
if (!connect())
return false;
FtpOptions(FTPLIB_CALLBACK, (long) NULL, conn);
struct REMFILE *f;
f = (struct REMFILE *) malloc(sizeof(struct REMFILE));
memset(f,0,sizeof(struct REMFILE));
f->fnm = strdup(sourceFileName.c_str());
if (!FtpSize(f->fnm, &fsz, 'I', conn))
fsz = 0;
f->fsz = fsz;
fsz = fsz/100;
if (fsz)
{
FtpOptions(FTPLIB_CALLBACK, (long) log_progress, conn);
FtpOptions(FTPLIB_IDLETIME, (long) 1000, conn);
FtpOptions(FTPLIB_CALLBACKARG, (long) f, conn);
FtpOptions(FTPLIB_CALLBACKBYTES, (long) fsz, conn);
}
sts = FtpGet(targetFileName.c_str(),f->fnm,'I',conn);
if (sts)
::PostMessage((HWND)(AfxGetApp()->GetMainWnd()->GetSafeHwnd()),WM_PROGRESS,100,NULL);
//printf("%s retrieved/n",f->fnm);
free(f->fnm);
free(f);
if (!sts)
{
_err = "ftp error: ";
_err = _err + FtpLastResponse(conn);
return false;
}
return true;
}
string MyFtp::getErr()
{
return _err;
}
这其中利用了PostMessage向主窗口发送进度消息:
::PostMessage((HWND)(AfxGetApp()->GetMainWnd()->GetSafeHwnd()),WM_PROGRESS,100,NULL);
线程还是用我一直使用的WorkThread来实现。
主窗口中响应进度消息的函数如下:
LRESULT CFtpAppDlg::OnProgress(WPARAM wParam,LPARAM lParam)
{
int progress=(int)wParam;
string str = "have download ";
str = str + TPub::intToString(progress) + "%";
m_list.ResetContent();
m_list.AddString(str.c_str());
UpdateData(FALSE);
return 0;
}