ycvodzf 发表于 2015-5-27 13:19:09

wininet实现ftp客户端关于传输进度的分析

  

















标题
wininet实现ftp客户端关于传输进度的分析   选择自 flyelf 的 Blog


关键字
wininet实现ftp客户端关于传输进度的分析


出处








  wininet提供了接口FtpGetFile实现从ftp服务器下载文件;提供了接口FtpPutFile实现把文件上传到ftp服务器上。通过这两个接口,我们能够完成基本的ftp文件传输客户端功能。但是在传输的同时,我们希望知道当前大概传输了多少,传输完整个文件大概需要多长时间,当前进度是多少,大概还有多长时间才能传输完毕。
  单纯依靠这两个接口,我们无法实现这个功能。仔细翻阅msdn,发现wininet还提供了这样一个接口:InternetSetStatusCallback。该函数就是设置文件传输的回调函数,其原型如下:

INTERNET_STATUS_CALLBACK InternetSetStatusCallback(
HINTERNET hInternet,
INTERNET_STATUS_CALLBACK lpfnInternetCallback
);
  该接口为internet会话设置一个状态回调函数:lpfnInternetCallback,该回调函数的原型声明如下:

void CALLBACK InternetStatusCallback(
HINTERNET hInternet,
DWORD_PTR dwContext,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength
);
  通过这个回调函数,我们可以实现对当前传输进度的控制:可以统计出到目前已经传输了多少字节,并且计算出传输速率,从而可以得知大概还剩下多少时间。
  下面这个类就是实现对ftp文件传输客户端的封装:
  
  //////////////////////////////////////////////////////////////////////////
  // 模块名称:文件传输状态控制
  // 模块功能:实现对界面时时报告当前文件传输的进度状态,并且实现上传和下载
  //             文件的客户端功能。
  // 文件名称:ftpclientctrl.h
  //________________________________________________________________________
  #ifndef _WININET_
  #include
  #endif
  
  class CFtpClientCtrl
  {
  public:
  CFtpClientCtrl();
  virtual ~CFtpClientCtrl();
  enum
  {
  ftp_begin,            // 对于该事件,wparam = ftp_begin,lparam表示要传输的文件大小
  ftp_transfer,    // 对于该事件,wparam = ftp_transfer,lParam表示已经传输的大小
  ftp_end               // 对于该事件,wparam = ftp_end,lparam表示结果,0--失败,1--成功
  };
  
  // 设置ftp服务器的连接参数
  BOOL   SetServerParam(    LPCTSTR lpszIpAddr,   // IP地址
  LPCTSTR lpszUser,      // 登录名称
  LPCTSTR lpszPwd,      // 登录口令
  WORD    wPort = INTERNET_DEFAULT_FTP_PORT,   // FTP服务器端口
  LPCTSTR lpszProxyName = NULL,    // 代理名称
  LPCTSTR lpszProxyPwd = NULL);   // 代理口令
  
  // 开始下载文件
  BOOL   BeginDownload(   HWND hWnd,                     // 接收消息的窗口
  LPCTSTR lpszRemote,// 远程文件名称
  LPCTSTR lpszLocal,   // 保存本地的文件
  DWORD dwFileType = FTP_TRANSFER_TYPE_UNKNOWN);      // 文件传输
  BOOL   BeginDownload(   DWORD dwThread,                  // 接收消息的线程
  LPCTSTR lpszRemote,// 远程文件名称
  LPCTSTR lpszLocal,   // 保存本地的文件
  DWORD dwFileType = FTP_TRANSFER_TYPE_UNKNOWN);      // 文件传输
  
  // 开始上传文件
  BOOL   BeginUpload(HWND hWnd,                     // 接收消息的窗口
  LPCTSTR lpszRemote,// 远程文件名称
  LPCTSTR lpszLocal,   // 本地文件名称
  DWORD dwFileType = FTP_TRANSFER_TYPE_UNKNOWN);      // 文件传输
  BOOL   BeginUpload(DWORD dwThread,                  // 接收消息的线程
  LPCTSTR lpszRemote,// 远程文件名称
  LPCTSTR lpszLocal,   // 本地文件名称
  DWORD dwFileType = FTP_TRANSFER_TYPE_UNKNOWN);      // 文件传输
  // 结束传输文件
  BOOL   EndFtpFile();
  
  // 得到当前ftp的会话句柄
  HINTERNETGetCurrentSession() const{return m_hSession;}
  // 得到当前的连接句柄
  HINTERNETGetCurrentConnect() const{return m_hConnect;}
  // 获取远程文件名称
  LPCTSTR             GetCurrentRemoteFile() const{return m_szRemote;}
  // 获取本地文件名称
  LPCTSTR             GetCurrentLocalFile() const{return m_szLocal;}
  // 获取当前传输的文件类型
  DWORD      GetCurrentFileType() const{return m_dwFileType;}
  // 获取当前传输接收消息窗口
  HWND         GetCurrentFtpWnd() const{return m_hWnd;}
  // 获取当前传输接收消息线程
  DWORD      GetCurrentFtpThread() const{return m_dwThread;}
  // 获取当前已经传输的大小
  DWORD      GetCurrentFtpSize() const{return m_dwCurrentFtpSize;}
  // 递增已经传输的大小
  DWORD      IncreaseFtpSize(DWORD dwStep);
  // 注册一个消息
  void      RegisterMsgHandle(UINT uMsgHandle){m_uMsgHandle = uMsgHandle;}
  // 获取已经注册的消息
  UINT             GetRegisterMsgHandle() const{return m_uMsgHandle;}
  // 获取文件总长度
  DWORD      GetTotalFileSize() const{return m_dwTotalFileSize;}
  // 清除FTP
  void      ClearFtpSession();
  // 设置FTP传输方向
  void      SetFtpDirect(BOOL bDownload = TRUE){m_bFtpDirect = bDownload;}
  // 获取FTP传输方向
  BOOL            GetFtpDirect() const{return m_bFtpDirect;}
  // 判断文件类型是否是ASCII
  static BOOL         IsFileAscii(LPCTSTR lpszFile);
  protected:
  // 获取远程文件的大小
  DWORD GetRemoteFileSize();
  // 获取本地文件的大小
  DWORD GetLocalFileSize();
  // 下载文件
  BOOL   DownloadFile(       LPCTSTR lpszRemote,// 远程文件名称
  LPCTSTR lpszLocal,   // 保存本地的文件
  DWORD dwFileType = FTP_TRANSFER_TYPE_UNKNOWN);      // 文件传输
  // 上传文件
  BOOL   UploadFile(   LPCTSTR lpszRemote,// 远程文件名称
  LPCTSTR lpszLocal,   // 保存本地的文件
  DWORD dwFileType = FTP_TRANSFER_TYPE_UNKNOWN);      // 文件传输
  
  protected:
  HINTERNETm_hSession;          // 应用于InternetOpen
  HINTERNETm_hConnect;         // 应用于InternetConnect
  
  TCHAR          m_szFtpSrvIp; // FTP服务器的ip地址
  TCHAR          m_szFtpSrvUser;    // FTP服务器的登录用户
  TCHAR          m_szFtpSrvPwd;    // FTP服务器的登录口令
  TCHAR          m_szProxyName;    // 代理的名称
  TCHAR          m_szProxyPwd;             // 代理的口令
  WORD         m_wFtpSrvPort;         // FTP服务器的监听端口
  
  HANDLE      m_hFtpThread;             // FTP传输的线程句柄
  DWORD      m_dwFtpThread;          // FTP传输的线程编号
  
  TCHAR          m_szRemote;          // 远程文件
  TCHAR          m_szLocal;             // 本地文件
  DWORD      m_dwFileType;             // 传输的文件类型
  
  HWND         m_hWnd;                     // 接收传输进度消息的窗口
  DWORD      m_dwThread;      // 接收传输进度消息的线程
  
  DWORD      m_dwCurrentFtpSize;    // 当前传输的大小
  DWORD      m_dwTotalFileSize;       // 文件总大小
  
  UINT             m_uMsgHandle;   // 消息句柄,由外界定义
  
  BOOL            m_bFtpDirect;       // 传输方向,TRUE为下载,FALSE为上传,默认为TRUE
  
  public:
  DWORD      m_dwFtpHead;      // FTP传输头--自从InternetConnect之后发送的次数
  private:
  BOOL            m_bTransfering;    // 是否正在传输
  };
  
  //////////////////////////////////////////////////////////////////////////
  // 模块名称:文件传输状态控制
  // 模块功能:实现对界面时时报告当前文件传输的进度状态,并且实现上传和下载
  //             文件的客户端功能。
  // 文件名称:ftpclientctrl.cpp
  //________________________________________________________________________
  #include "FtpClientCtrl.h"
  #pragma comment(lib, "wininet.lib")
  #define INTERNET_STATUS_USER_INPUT_REQUIRED         0x00000040
  #define INTERNET_STATUS_DETECTING_PROXY               80
  
  
  #define FTP_FILE_ASCII_COUNT      12
  LPCTSTR g_lpszAsciiFileFtp =
  {
  _T(".txt"),
  _T(".ini"),
  _T(".c"),
  _T(".cpp"),
  _T(".h"),
  _T(".hpp"),
  _T(".bat"),
  _T(".html"),
  _T(".java"),
  _T(".htm"),
  _T(".jav"),
  _T(".doc")
  };
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:IsFtpAscii
  // 描述:经验判断一个要进行文件传输的文件是否是ASCII方式的
  // 原型:BOOL IsFtpAscii(LPCTSTR lpszExt)    // 文件后缀
  // 参数:
  //             lpszExt:要判断的文件的后缀名称
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL IsFtpAscii(LPCTSTR lpszExt)
  {
  if(lpszExt == NULL)
  return FALSE;
  for(int nIndex = 0; nIndex < FTP_FILE_ASCII_COUNT; nIndex ++)
  {
  if(_tcsicmp(lpszExt, g_lpszAsciiFileFtp) == 0)
  return TRUE;
  }
  return FALSE;
  }// End IsFtpAscii
  // IsFtpAscii结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:FormatFtpError
  // 描述:获取系统的错误描述
  // 原型:void FormatFtpError(DWORD dwError,      // 错误码
  //                                                LPTSTR *lpMsg)   // 描述信息
  // 参数:
  //             dwError:要查询的系统错误码
  //             *lpMsg:获取得到的错误描述信息,在使用结束后,请调用LocalFree
  //                                  来释放该空间
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  static void FormatFtpError(    DWORD dwError,      // 系统错误码
  LPTSTR *lpMsg)   // 错误描述
  {
  if(lpMsg == NULL)return;
  if(dwError > INTERNET_ERROR_BASE)
  {
  // 对于Internet的错误,要特殊处理
  DWORD dwBufLen = 0;
  InternetGetLastResponseInfo(&dwError, NULL, &dwBufLen);
  LPTSTR pMsg = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, dwBufLen + 1);
  InternetGetLastResponseInfo(&dwError, pMsg, &dwBufLen);
  *lpMsg = pMsg;
  }
  else
  {
  // 查询普通的错误
  FormatMessage(    FORMAT_MESSAGE_ALLOCATE_BUFFER |
  FORMAT_MESSAGE_IGNORE_INSERTS |
  FORMAT_MESSAGE_FROM_SYSTEM,
  NULL,
  dwError,
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  (LPSTR)lpMsg,
  0,
  NULL);
  }
  }// End FormatFtpError
  // FormatFtpError结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:FtpCtrl_CallbackStatus
  // 描述:文件传输过程中的状态回调函数,用于报告当前文件传输的进度等消息
  // 原型:void CALLBACK FtpCtrl_CallbackStatus(   HINTERNET hInternet,// 句柄
  //                                                                            DWORD dwContext, // 上下文
  //                                                                            DWORD dwInternetStatus, // 状态
  //                                                                            LPVOID lpvStatusInformation,// 信息
  //                                                                            DWORD dwStatusInformationLength)
  // 参数:
  //             hInternet:Internet连接的句柄,从InternetOpen中得到
  //             dwContext:自定义的上下文数据
  //             dwInternetStatus:当前回调的状态
  //             lpvStatusInformation:当前回调的信息,根据dwInternetStatus的不同
  //                                       状态代表不同的意思
  //             dwStatusInformationLength:回调信息lpvStatusInformation的长度
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  void CALLBACK FtpCtrl_CallbackStatus(   HINTERNET hInternet,
  DWORD dwContext,
  DWORD dwInternetStatus,
  LPVOID lpvStatusInformation,
  DWORD dwStatusInformationLength)
  {
  // 获取上下文信息
  CFtpClientCtrl *pcFtpMsg = reinterpret_cast(dwContext);
  if(pcFtpMsg == NULL)
  {
  return;
  }
  LPDWORD pdwInformation(NULL);
  TRACE("FtpCtrl_CallbackStatus's Internet Status is %d\n", dwInternetStatus);
  // 查询当前文件传输状态
  switch(dwInternetStatus)
  {
  case INTERNET_STATUS_RESOLVING_NAME:      // 10
  TRACE("Looking up the IP address for %s\n", (LPCTSTR)lpvStatusInformation);
  break;
  case INTERNET_STATUS_NAME_RESOLVED:      // 11
  TRACE("Name resolved %s\n", (LPCTSTR)lpvStatusInformation);
  break;
  case INTERNET_STATUS_CONNECTING_TO_SERVER:       // 20
  // lpvStatusInformation是一个SOCKADDR的指针
  TRACE("Connecting to server--%s...\n", (LPCTSTR)lpvStatusInformation);
  break;
  case INTERNET_STATUS_CONNECTED_TO_SERVER:// 21
  // lpvStatusInformation是一个SOCKADDR的指针
  TRACE("Connected to server--%s\n", (LPCTSTR)lpvStatusInformation);
  break;
  case INTERNET_STATUS_SENDING_REQUEST:         // 30
  TRACE("Sending request\n");
  break;
  case INTERNET_STATUS_REQUEST_SENT:                  // 31
  {
  // 发送数据到服务器
  if(!pcFtpMsg->GetFtpDirect())
  {
  // 只有当处于上传状态的时候,才处理
  if(pcFtpMsg->m_dwFtpHead > 0 && pcFtpMsg->m_dwFtpHead < 5)
  {
  // 5这个值是一个经验值,具体为什么,由于没有深入研究rfc的协议
  // 所以还不知道,将来如果知道原因,可以补充上
  pcFtpMsg->m_dwFtpHead ++;
  }
  pdwInformation = (LPDWORD)lpvStatusInformation;
  if(pcFtpMsg->m_dwFtpHead == 5)
  {
  DWORD dwCurrentSize = pcFtpMsg->IncreaseFtpSize(*pdwInformation);
  TRACE("本次发送的数据大小为: %d,总共数据为:%d\n", *pdwInformation,
  dwCurrentSize);
  if(pcFtpMsg->GetCurrentFtpWnd() != NULL)
  {
  // 首先的第一选择是给窗口发送消息
  ::PostMessage(       pcFtpMsg->GetCurrentFtpWnd(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_transfer,
  dwCurrentSize);
  }
  else if(pcFtpMsg->GetCurrentFtpThread() != 0)
  {
  ::PostThreadMessage(pcFtpMsg->GetCurrentFtpThread(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_transfer,
  dwCurrentSize);
  }
  }// End if 5,经验值
  }// end if 文件上传
  }
  break;
  case INTERNET_STATUS_RESPONSE_RECEIVED:      // 41
  {
  // 从服务器接收到的响应
  if(pcFtpMsg->GetFtpDirect())
  {
  // 只有当处于下载状态的时候,才处理
  pdwInformation = (LPDWORD)lpvStatusInformation;
  if(pcFtpMsg->m_dwFtpHead > 0 && pcFtpMsg->m_dwFtpHead < 6)
  {
  // 6这个值是一个经验值,具体为什么,由于没有深入研究rfc的协议
  // 所以还不知道,将来如果知道原因,可以补充上
  pcFtpMsg->m_dwFtpHead ++;
  //                                  TRACE("在连接之后第%d次接收数据!\n", pcFtpMsg->m_dwFtpHead);
  }
  if(pcFtpMsg->m_dwFtpHead == 6)
  {
  DWORD dwCurrentSize = pcFtpMsg->IncreaseFtpSize(*pdwInformation);
  TRACE("Response received: %d, TotalReceived is %d\n",
  *pdwInformation, dwCurrentSize);
  if(pcFtpMsg->GetCurrentFtpWnd() != NULL)
  {
  ::PostMessage(       pcFtpMsg->GetCurrentFtpWnd(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_transfer,
  dwCurrentSize);
  }
  else if(pcFtpMsg->GetCurrentFtpThread() != 0)
  {
  ::PostThreadMessage(pcFtpMsg->GetCurrentFtpThread(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_transfer,
  dwCurrentSize);
  }
  }// End if 6,经验值
  }// End if 文件下载
  }
  break;
  case INTERNET_STATUS_RECEIVING_RESPONSE:             // 40
  // 等待服务器的响应,lpvStatusInformation = NULL
  TRACE("等待服务器的响应!\n");
  break;
  case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:            // 42
  case INTERNET_STATUS_PREFETCH:                                 // 43
  case INTERNET_STATUS_CLOSING_CONNECTION:         // 50
  TRACE("Closing connection\n");
  break;
  case INTERNET_STATUS_CONNECTION_CLOSED:                  // 51
  TRACE("Connection closed\n");
  break;
  case INTERNET_STATUS_HANDLE_CREATED:                  // 60
  {
  LPINTERNET_ASYNC_RESULT ptIAR =
  reinterpret_cast(lpvStatusInformation);
  if(hInternet == pcFtpMsg->GetCurrentConnect())
  {
  TRACE("Connect Handle Created!\n");
  pcFtpMsg->m_dwFtpHead = 1;
  }
  else if(hInternet == pcFtpMsg->GetCurrentSession())
  {
  TRACE("Session handle created!\n");
  }
  }
  break;
  case INTERNET_STATUS_HANDLE_CLOSING:                  // 70
  pcFtpMsg->m_dwFtpHead = 0;
  TRACE("Handle closed with dif %d!\n",
  pcFtpMsg->GetCurrentFtpSize() - pcFtpMsg->GetTotalFileSize());
  break;
  case INTERNET_STATUS_DETECTING_PROXY:                  // 80
  TRACE("Detecting proxy\n");
  break;
  case INTERNET_STATUS_REQUEST_COMPLETE:               // 100
  // 一个异步操作已经完成,lpvStatusInformation是INTERNET_ASYNC_RESULT的指针
  {
  LPINTERNET_ASYNC_RESULT ptIAR =
  reinterpret_cast(lpvStatusInformation);
  TRACE("一个异步操作完成,错误为:%d,结果为:%d\n",
  ptIAR->dwError, ptIAR->dwResult);
  }
  break;
  case INTERNET_STATUS_REDIRECT:                                  // 110
  TRACE("HTTP request redirected to \n");
  break;
  case INTERNET_STATUS_INTERMEDIATE_RESPONSE:             // 120
  TRACE("Received intermediate status message from the server.\n");
  break;
  case INTERNET_STATUS_STATE_CHANGE:                         // 200
  TRACE("'Moved between a secure and a nonsecure site\n");
  {
  LPDWORD pdwRead = (LPDWORD)lpvStatusInformation;
  switch(*pdwRead)
  {
  case INTERNET_STATE_CONNECTED:                  // 0x00000001
  TRACE("Connected state moved between secure and nonsecure site\n");
  break;
  case INTERNET_STATE_DISCONNECTED:            // 0x00000002
  TRACE("Disconnected from network\n");
  break;
  case INTERNET_STATE_DISCONNECTED_BY_USER:   // 0x00000010
  TRACE("Disconnected by user request\n");
  break;
  case INTERNET_STATE_IDLE:                        // 0x00000100
  TRACE("No network requests are being made (by Wininet).\n");
  break;
  case INTERNET_STATE_BUSY:                     // 0x00000200
  TRACE("Network requests are being made (by Wininet).\n");
  break;
  case INTERNET_STATUS_USER_INPUT_REQUIRED:    // 0x00000040
  TRACE("The request requires user input to complete\n");
  break;
  default:
  break;
  }
  }
  break;
  default:
  break;
  }
  }// End Ftp_CallbackStatus
  // Ftp_CallbackStatu结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:FtpClientDnloadThread
  // 描述:文件传输——下载客户端线程
  // 原型:DWORD WINPAI FtpClientDnloadThread(LPVOID pParam)   // 入口参数
  // 参数:
  //             pParam:下载文件的入口参数
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  DWORD WINAPI FtpClientDnloadThread(LPVOID pParam)   // 入口参数
  {
  CFtpClientCtrl *pcFtpMsg = reinterpret_cast(pParam);
  if(pcFtpMsg == NULL)
  {
  return -1;
  }
  
  // 获取文件
  BOOL bRet = FtpGetFile(      pcFtpMsg->GetCurrentConnect(),
  pcFtpMsg->GetCurrentRemoteFile(),
  pcFtpMsg->GetCurrentLocalFile(),
  FALSE,
  FILE_ATTRIBUTE_NORMAL,
  pcFtpMsg->GetCurrentFileType() |
  INTERNET_FLAG_RELOAD |
  INTERNET_FLAG_RESYNCHRONIZE,
  (DWORD)pcFtpMsg);
  LPTSTR lpMsg = NULL;
  DWORD dwErr = GetLastError();
  FormatFtpError(dwErr, &lpMsg);
  TRACE("FtpGetFile Error with %d--%s\n", dwErr, lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  
  if(pcFtpMsg->GetCurrentFtpWnd() != NULL)
  {
  ::PostMessage(       pcFtpMsg->GetCurrentFtpWnd(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_end,
  dwErr);
  }
  else if(pcFtpMsg->GetCurrentFtpThread() != 0)
  {
  ::PostThreadMessage(pcFtpMsg->GetCurrentFtpThread(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_end,
  dwErr);
  }
  
  pcFtpMsg->ClearFtpSession();
  
  TRACE("FtpGetFile Thread with id 0x%x end!\n", GetCurrentThreadId());
  
  if(!bRet)
  return -1;
  
  return 0;
  }// End FtpClientDnloadThread
  // FtpClientDnloadThread结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:FtpClientUploadThread
  // 描述:文件传输——上传文件线程
  // 原型:DWORD WINAPI FtpClientUploadThread(LPVOID pParam)   // 入口参数
  // 参数:
  //             pParam:上传文件需要的参数
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  DWORD WINAPI FtpClientUploadThread(LPVOID pParam)
  {
  CFtpClientCtrl *pcFtpMsg = reinterpret_cast(pParam);
  if(pcFtpMsg == NULL)
  {
  return -1;
  }
  
  // 上传文件
  BOOL bRet = FtpPutFile(      pcFtpMsg->GetCurrentConnect(),
  pcFtpMsg->GetCurrentLocalFile(),
  pcFtpMsg->GetCurrentRemoteFile(),
  pcFtpMsg->GetCurrentFileType() |
  INTERNET_FLAG_RESYNCHRONIZE,
  (DWORD)pcFtpMsg);
  LPTSTR lpMsg = NULL;
  DWORD dwErr = GetLastError();
  FormatFtpError(dwErr, &lpMsg);
  TRACE("FtpPutFile Error with %d--%s\n", dwErr, lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  
  if(pcFtpMsg->GetCurrentFtpWnd() != NULL)
  {
  ::PostMessage(       pcFtpMsg->GetCurrentFtpWnd(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_end,
  dwErr);
  }
  else if(pcFtpMsg->GetCurrentFtpThread() != 0)
  {
  ::PostThreadMessage(pcFtpMsg->GetCurrentFtpThread(),
  pcFtpMsg->GetRegisterMsgHandle(),
  CFtpClientCtrl::ftp_end,
  dwErr);
  }
  
  pcFtpMsg->ClearFtpSession();
  TRACE("FtpPutFile Thread with id 0x%x end!\n", GetCurrentThreadId());
  
  if(!bRet)
  {
  return -1;
  }
  
  return 0;
  }// End FtpClientUploadThread
  // FtpClientUploadThread结束
  //////////////////////////////////////////////////////////////////////////
  
  CFtpClientCtrl::CFtpClientCtrl()
  :m_wFtpSrvPort(INTERNET_DEFAULT_FTP_PORT)
  ,m_hSession(NULL)
  ,m_hConnect(NULL)
  ,m_hFtpThread(NULL)
  ,m_dwFtpThread(0)
  ,m_dwCurrentFtpSize(0)
  ,m_hWnd(NULL)
  ,m_dwFileType(FTP_TRANSFER_TYPE_UNKNOWN)
  ,m_uMsgHandle(0)
  ,m_bFtpDirect(TRUE)
  ,m_dwFtpHead(0)
  ,m_bTransfering(FALSE)
  {
  ::ZeroMemory(m_szFtpSrvIp, 24);
  ::ZeroMemory(m_szFtpSrvPwd, 32);
  ::ZeroMemory(m_szFtpSrvUser, 32);
  ::ZeroMemory(m_szProxyName, 64);
  ::ZeroMemory(m_szProxyPwd, 32);
  ::ZeroMemory(m_szRemote, MAX_PATH);
  ::ZeroMemory(m_szLocal, MAX_PATH);
  }
  
  CFtpClientCtrl::~CFtpClientCtrl()
  {
  InternetCloseHandle(m_hConnect);
  InternetCloseHandle(m_hSession);
  }
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:SetServerParam
  // 描述:设置文件传输的FTP服务器参数,包括服务器的地址、端口、用户和,口令等
  // 原型:BOOL SetServerParam(LPCTSTR lpszIpAddr,   // 服务器地址
  //                                                LPCTSTR lpszUser,             // 用户
  //                                                LPCTSTR lpszPwd,             // 口令
  //                                                WORD wPort,                     // 端口
  //                                                LPCTSTR lpszProxyName,   // 代理名称
  //                                                LPCTSTR lpszProxyPwd)    // 代理口令
  // 参数:
  //             lpszIpAddr:FTP服务器的地址
  //             lpszUser:FTP服务器的用户名称
  //             lpszPwd:FTP服务器的用户口令
  //             wPort:FTP服务器的侦听端口
  //             lpszProxyName:FTP服务器的代理用户
  //             lpszProxyPwd:FTP服务器的代理对应口令
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::SetServerParam(LPCTSTR lpszIpAddr,
  LPCTSTR lpszUser,
  LPCTSTR lpszPwd,
  WORD wPort,
  LPCTSTR lpszProxyName,
  LPCTSTR lpszProxyPwd)
  {
  if(    lpszIpAddr == NULL ||
  lpszUser == NULL ||
  lpszPwd == NULL ||
  wPort == 0)
  return FALSE;
  ::ZeroMemory(m_szFtpSrvIp, 24);
  _sntprintf(m_szFtpSrvIp, 24, _T("%s"), lpszIpAddr);
  ::ZeroMemory(m_szFtpSrvUser, 32);
  _sntprintf(m_szFtpSrvUser, 32, _T("%s"), lpszUser);
  ::ZeroMemory(m_szFtpSrvPwd, 32);
  _sntprintf(m_szFtpSrvPwd, 32, _T("%s"), lpszPwd);
  m_wFtpSrvPort = wPort;
  ::ZeroMemory(m_szProxyName, 64);
  _sntprintf(m_szProxyName, 64, _T("%s"), lpszProxyName);
  ::ZeroMemory(m_szProxyPwd, 32);
  _sntprintf(m_szProxyPwd, 32, _T("%s"), lpszProxyPwd);
  
  return TRUE;
  }// End SetServerParam
  // SetServerParam结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:DownloadFile
  // 描述:下载文件
  // 原型:BOOL DownloadFile(   LPCTSTR lpszRemote,// 远程文件
  //                                                LPCTSTR lpszLocal,   // 本地文件
  //                                                DWORD dwFileType)   // 文件类型
  // 参数:
  //             lpszRemote:要下载的文件名称
  //             lpszLocal:文件下载后保存到本地的路径
  //             dwFileType:文件传输的方式
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::DownloadFile(LPCTSTR lpszRemote,
  LPCTSTR lpszLocal,
  DWORD dwFileType)
  {
  ::ZeroMemory(m_szRemote, MAX_PATH);
  _sntprintf(m_szRemote, MAX_PATH, _T("%s"), lpszRemote);
  ::ZeroMemory(m_szLocal, MAX_PATH);
  _sntprintf(m_szLocal, MAX_PATH, _T("%s"), lpszLocal);
  m_dwFileType = dwFileType;
  
  m_dwFtpHead = 0;
  
  m_bFtpDirect = TRUE;
  
  // 设置文件传输方式
  if(dwFileType == FTP_TRANSFER_TYPE_UNKNOWN)
  {
  LPCTSTR lpszExt = _tcsrchr(lpszRemote, '.');
  if(IsFtpAscii(lpszExt))
  m_dwFileType = FTP_TRANSFER_TYPE_ASCII;
  else
  m_dwFileType = FTP_TRANSFER_TYPE_BINARY;
  }
  // 获取远程文件的大小,有的时候不能成功
  m_dwTotalFileSize = GetRemoteFileSize();
  TRACE("Remote File size is %d\n", m_dwTotalFileSize);
  
  m_dwCurrentFtpSize = 0;
  
  LPTSTR lpMsg = NULL;      // 错误信息
  // 打开Internet连接
  m_hSession = InternetOpen( _T("Ftp_Ctrl"),
  INTERNET_OPEN_TYPE_DIRECT,
  m_szProxyName,
  m_szProxyPwd,
  INTERNET_FLAG_NO_CACHE_WRITE);
  if(m_hSession == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetOpen Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  return FALSE;
  }
  
  // 设置状态回调函数
  if(InternetSetStatusCallback(m_hSession, FtpCtrl_CallbackStatus) ==
  INTERNET_INVALID_STATUS_CALLBACK)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetSetStatusCallback Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  InternetCloseHandle(m_hSession);
  return FALSE;
  }
  
  // 连接到对方
  m_hConnect = InternetConnect(   m_hSession,
  m_szFtpSrvIp,
  m_wFtpSrvPort,
  m_szFtpSrvUser,
  m_szFtpSrvPwd,
  INTERNET_SERVICE_FTP,
  INTERNET_FLAG_PASSIVE |
  INTERNET_FLAG_EXISTING_CONNECT,
  (DWORD)this);
  if(m_hConnect == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetConnect Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  InternetCloseHandle(m_hSession);
  return FALSE;
  }
  
  if(m_hWnd != NULL)
  {
  // 发送消息,开始下载了
  ::PostMessage(       m_hWnd, m_uMsgHandle,
  (WPARAM)ftp_begin, (LPARAM)m_dwTotalFileSize);
  }
  else if(m_dwThread != 0)
  {
  ::PostThreadMessage(m_dwThread, m_uMsgHandle,
  (WPARAM)ftp_begin, (LPARAM)m_dwTotalFileSize);
  }
  
  // 创建文件下载线程
  m_hFtpThread = CreateThread(NULL,
  0,
  FtpClientDnloadThread,
  this,
  0,
  &m_dwFtpThread);
  if(m_hFtpThread == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("CreateThread Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  InternetCloseHandle(m_hConnect);
  InternetCloseHandle(m_hSession);
  return FALSE;
  }
  
  m_bTransfering = TRUE;
  return TRUE;
  }// End DownloadFile
  // DownloadFile结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:BeginDownload
  // 描述:开始下载文件
  // 原型:BOOL BeginDownload(HWND hWnd,   // 接收消息的窗口
  //                                                LPCTSTR lpszRemote,// 远程文件
  //                                                LPCTSTR lpszLocal,   // 本地文件
  //                                                DWORD dwFileType)   // 文件类型
  // 参数:
  //             hWnd:用于接收文件传输状态报告的窗口句柄
  //             lpszRemote:要下载的文件名称,保存在服务器上的
  //             lpszLocal:文件下载后保存到本地的路径
  //             dwFileType:文件传输的方式
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::BeginDownload(HWND hWnd,
  LPCTSTR lpszRemote,
  LPCTSTR lpszLocal,
  DWORD dwFileType)
  {
  if(    lpszRemote == NULL ||
  lpszLocal == NULL ||
  (dwFileType != FTP_TRANSFER_TYPE_BINARY &&
  dwFileType != FTP_TRANSFER_TYPE_ASCII &&
  dwFileType != FTP_TRANSFER_TYPE_UNKNOWN) ||
  hWnd == NULL)
  return FALSE;
  
  if(m_bTransfering)
  return FALSE;
  m_hWnd = hWnd;
  
  return DownloadFile(lpszRemote,
  lpszLocal,
  dwFileType);
  }// End BeginDownload
  // BeginDownload结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:BeginDownload
  // 描述:开始下载文件
  // 原型:BOOL BeginDownload(DWORD dwThread, // 接收消息的线程
  //                                                LPCTSTR lpszRemote,// 远程文件
  //                                                LPCTSTR lpszLocal,   // 本地文件
  //                                                DWORD dwFileType)   // 文件类型
  // 参数:
  //             dwThread:用于接收文件传输状态报告的线程句柄
  //             lpszRemote:要下载的文件名称,保存在服务器上的
  //             lpszLocal:文件下载后保存到本地的路径
  //             dwFileType:文件传输的方式
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::BeginDownload(DWORD dwThread,
  LPCTSTR lpszRemote,
  LPCTSTR lpszLocal,
  DWORD dwFileType)
  {
  if(    lpszRemote == NULL ||
  lpszLocal == NULL ||
  (dwFileType != FTP_TRANSFER_TYPE_BINARY &&
  dwFileType != FTP_TRANSFER_TYPE_ASCII &&
  dwFileType != FTP_TRANSFER_TYPE_UNKNOWN) ||
  dwThread == 0)
  return FALSE;
  if(m_bTransfering)
  return FALSE;
  m_dwThread = dwThread;
  
  return DownloadFile(lpszRemote,
  lpszLocal,
  dwFileType);
  }// End BeginDownload
  // BeginDownload结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:UploadFile
  // 描述:上传文件
  // 原型:BOOL UploadFile(   LPCTSTR lpszRemote,// 远程文件
  //                                                LPCTSTR lpszLocal,   // 本地文件
  //                                                DWORD dwFileType)   // 文件类型
  // 参数:
  //             lpszRemote:上传后保存的文件名称
  //             lpszLocal:要上传的本地文件路径
  //             dwFileType:文件传输的方式
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::UploadFile(LPCTSTR lpszRemote,
  LPCTSTR lpszLocal,
  DWORD dwFileType)
  {
  m_dwFtpHead = 0;
  
  
  m_bFtpDirect = FALSE;
  
  ::ZeroMemory(m_szRemote, MAX_PATH);
  _sntprintf(m_szRemote, MAX_PATH, _T("%s"), lpszRemote);
  ::ZeroMemory(m_szLocal, MAX_PATH);
  _sntprintf(m_szLocal, MAX_PATH, _T("%s"), lpszLocal);
  m_dwFileType = dwFileType;
  
  // 设置文件传输的方式
  if(dwFileType == FTP_TRANSFER_TYPE_UNKNOWN)
  {
  LPCTSTR lpszExt = _tcsrchr(lpszLocal, '.');
  if(IsFtpAscii(lpszExt))
  m_dwFileType = FTP_TRANSFER_TYPE_ASCII;
  else
  m_dwFileType = FTP_TRANSFER_TYPE_BINARY;
  }
  // 计算本地文件的大小,只要该文件存在,就能够得到大小
  m_dwTotalFileSize = GetLocalFileSize();
  if(m_dwTotalFileSize == (DWORD)-1)
  {
  m_dwTotalFileSize = 0;
  return FALSE;
  }
  TRACE("Local File size is %d\n", m_dwTotalFileSize);
  
  m_dwCurrentFtpSize = 0;
  
  LPTSTR lpMsg = NULL;      // 消息描述
  // 打开Internet连接会话
  m_hSession = InternetOpen( _T("Ftp_Ctrl"),
  INTERNET_OPEN_TYPE_DIRECT,
  m_szProxyName,
  m_szProxyPwd,
  INTERNET_FLAG_NO_CACHE_WRITE);
  if(m_hSession == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetOpen Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  return FALSE;
  }
  
  // 设置文件传输状态回调函数
  if(InternetSetStatusCallback(m_hSession, FtpCtrl_CallbackStatus) ==
  INTERNET_INVALID_STATUS_CALLBACK)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetSetStatusCallback Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  InternetCloseHandle(m_hSession);
  return FALSE;
  }
  
  // 开始建立文件传输的连接
  m_hConnect = InternetConnect(   m_hSession,
  m_szFtpSrvIp,
  m_wFtpSrvPort,
  m_szFtpSrvUser,
  m_szFtpSrvPwd,
  INTERNET_SERVICE_FTP,
  INTERNET_FLAG_PASSIVE |
  INTERNET_FLAG_EXISTING_CONNECT,
  (DWORD)this);
  if(m_hConnect == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetConnect Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  lpMsg = NULL;
  InternetCloseHandle(m_hSession);
  return FALSE;
  }
  
  // 发送消息,通知界面开始传输了
  if(m_hWnd != NULL)
  {
  ::PostMessage(       m_hWnd, m_uMsgHandle,
  (WPARAM)ftp_begin, (LPARAM)m_dwTotalFileSize);
  }
  else if(m_dwThread != 0)
  {
  ::PostThreadMessage(m_dwThread, m_uMsgHandle,
  (WPARAM)ftp_begin, (LPARAM)m_dwTotalFileSize);
  }
  
  // 创建文件上传线程
  m_hFtpThread = CreateThread(NULL,
  0,
  FtpClientUploadThread,
  this,
  0,
  &m_dwFtpThread);
  if(m_hFtpThread == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("CreateThread Error with %s\n", lpMsg);
  LocalFree(lpMsg);
  InternetCloseHandle(m_hConnect);
  InternetCloseHandle(m_hSession);
  return FALSE;
  }
  
  m_bTransfering = TRUE;
  return TRUE;
  }// End UploadFile
  // UploadFile结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:BeginUpload
  // 描述:开始文件上传
  // 原型:BOOL BeginUpload(HWND hWnd,       // 用于接收消息的窗口句柄
  //                                       LPCTSTR lpszRemote,// 上传后保存的文件名称
  //                                       LPCTSTR lpszLocal,   // 要上传的文件
  //                                       DWORD dwFileType)   // 文件传输类型
  // 参数:
  //             hWnd:接收文件上传状态报告的窗口句柄
  //             lpszRemote:文件上传后在服务器端保存的文件名称
  //             lpszLocal:要上传的本地文件路径
  //             dwFileType:文件上传的类型
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::BeginUpload(HWND hWnd,
  LPCTSTR lpszRemote,
  LPCTSTR lpszLocal,
  DWORD dwFileType)
  {
  if(    lpszRemote == NULL ||
  lpszLocal == NULL ||
  (dwFileType != FTP_TRANSFER_TYPE_BINARY &&
  dwFileType != FTP_TRANSFER_TYPE_ASCII &&
  dwFileType != FTP_TRANSFER_TYPE_UNKNOWN) ||
  hWnd == NULL)
  return FALSE;
  if(m_bTransfering)
  return FALSE;
  m_hWnd = hWnd;
  
  return UploadFile(   lpszRemote,
  lpszLocal,
  dwFileType);
  }// End BeginUpload
  // BeginUpload结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:BeginUpload
  // 描述:开始文件上传
  // 原型:BOOL BeginUpload(DWORD dwThread,      // 用于接收消息的线程句柄
  //                                       LPCTSTR lpszRemote,// 上传后保存的文件名称
  //                                       LPCTSTR lpszLocal,   // 要上传的文件
  //                                       DWORD dwFileType)   // 文件传输类型
  // 参数:
  //             dwThread:接收文件上传状态报告的线程句柄
  //             lpszRemote:文件上传后在服务器端保存的文件名称
  //             lpszLocal:要上传的本地文件路径
  //             dwFileType:文件上传的类型
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::BeginUpload(DWORD dwThread,
  LPCTSTR lpszRemote,
  LPCTSTR lpszLocal,
  DWORD dwFileType)
  {
  if(    lpszRemote == NULL ||
  lpszLocal == NULL ||
  (dwFileType != FTP_TRANSFER_TYPE_BINARY &&
  dwFileType != FTP_TRANSFER_TYPE_ASCII &&
  dwFileType != FTP_TRANSFER_TYPE_UNKNOWN) ||
  dwThread == 0)
  return FALSE;
  if(m_bTransfering)
  return FALSE;
  m_dwThread = dwThread;
  
  return UploadFile(   lpszRemote,
  lpszLocal,
  dwFileType);
  }// End BeginUpload
  // BeginUpload结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:EndFtpFile
  // 描述:结束文件传输进行的操作
  // 原型:BOOL EndFtpFile()
  // 参数:
  //   
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::EndFtpFile()
  {
  if(m_hConnect)
  {
  InternetCloseHandle(m_hConnect);
  m_hConnect = NULL;
  }
  return TRUE;
  }// End EndFtpFile
  // EndFtpFile结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:ClearFtpSession
  // 描述:清除文件传输会话资源
  // 原型:void ClearFtpSession()
  // 参数:
  //   
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  void CFtpClientCtrl::ClearFtpSession()
  {
  if(m_hConnect != NULL)
  {
  InternetCloseHandle(m_hConnect);
  m_hConnect = NULL;
  }
  if(m_hSession != NULL)
  {
  InternetCloseHandle(m_hSession);
  m_hSession = 0;
  }
  m_hWnd = NULL;
  m_dwThread = 0;
  m_bTransfering = FALSE;
  }
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:IncreaseFtpSize
  // 描述:在文件传输过程中,设置实际已经传输的文件大小
  // 原型:DWORD IncreaseFtpSize(DWORD dwStep)       // 本地大小
  // 参数:
  //             dwStep:本次状态中传输的大小
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  DWORD CFtpClientCtrl::IncreaseFtpSize(DWORD dwStep)
  {
  if(m_dwCurrentFtpSize < m_dwTotalFileSize)
  m_dwCurrentFtpSize += dwStep;
  return m_dwCurrentFtpSize;
  }// End IncreaseFtpSize
  // IncreaseFtpSize结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:GetRemoteFileSize
  // 描述:获取远程文件的大小
  // 原型:DWORD GetRemoteFileSize()
  // 参数:
  //   
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  DWORD CFtpClientCtrl::GetRemoteFileSize()
  {
  if(m_szRemote == NULL)
  {
  return 0;
  }
  LPTSTR lpMsg = NULL;
  // 开始连接网络
  HINTERNET hInternet = InternetOpen(      _T("Ftp_Ctrl"),
  INTERNET_OPEN_TYPE_DIRECT,
  m_szProxyName,
  m_szProxyPwd,
  INTERNET_FLAG_NO_CACHE_WRITE);//INTERNET_FLAG_ASYNC
  if(hInternet == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetOpen Error With %d--%s\n", GetLastError(), lpMsg);
  LocalFree(lpMsg);
  return 0;
  }
  
  // 连接
  HINTERNET hConnect = InternetConnect( hInternet,
  m_szFtpSrvIp,
  m_wFtpSrvPort,
  m_szFtpSrvUser,
  m_szFtpSrvPwd,
  INTERNET_SERVICE_FTP,
  INTERNET_FLAG_PASSIVE |
  INTERNET_FLAG_EXISTING_CONNECT,
  0);
  if(hConnect == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("InternetConnect Error With %d--%s\n", GetLastError(), lpMsg);
  LocalFree(lpMsg);
  InternetCloseHandle(hInternet);
  return 0;
  }
  
  // 打开文件
  HINTERNET hFile = FtpOpenFile(       hConnect,
  m_szRemote,
  GENERIC_READ,
  m_dwFileType |
  INTERNET_FLAG_RELOAD |
  INTERNET_FLAG_RESYNCHRONIZE,
  0);
  if(hFile == NULL)
  {
  FormatFtpError(GetLastError(), &lpMsg);
  TRACE("FtpOpen Error With %d--%s\n", GetLastError(), lpMsg);
  LocalFree(lpMsg);
  InternetCloseHandle(hConnect);
  InternetCloseHandle(hInternet);
  return 0;
  }
  typedef DWORD (WINAPI *FtpGetFileSize_Proc)(HINTERNET, LPDWORD);
  HINSTANCE hInst = LoadLibrary("wininet.dll");
  if(hInst == NULL)
  {
  TRACE("Load Library failed!\n");
  InternetCloseHandle(hFile);
  InternetCloseHandle(hConnect);
  InternetCloseHandle(hInternet);
  return 0;
  }
  FtpGetFileSize_Proc pfnFtpGetFileSize =
  (FtpGetFileSize_Proc)GetProcAddress(hInst, "FtpGetFileSize");
  if(pfnFtpGetFileSize == NULL)
  {
  TRACE("Get Proc FtpGetFileSize Failed!\n");
  InternetCloseHandle(hFile);
  InternetCloseHandle(hConnect);
  InternetCloseHandle(hInternet);
  FreeLibrary(hInst);
  return 0;
  }
  DWORD dwSize = pfnFtpGetFileSize(hFile, NULL);
  FreeLibrary(hInst);
  InternetCloseHandle(hFile);
  InternetCloseHandle(hConnect);
  InternetCloseHandle(hInternet);
  
  return dwSize;
  }// End GetRemoteFileSize
  // GetRemoteFileSize结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:GetLocalFileSize
  // 描述:获取本地文件的大小
  // 原型:DWORD GetLocalFileSize()
  // 参数:
  //   
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  DWORD CFtpClientCtrl::GetLocalFileSize()
  {
  HANDLE hFile = CreateFile(m_szLocal,
  0,
  0,
  NULL,
  OPEN_EXISTING,
  FILE_ATTRIBUTE_NORMAL,
  NULL);
  if(hFile == INVALID_HANDLE_VALUE)
  {
  return -1;
  }
  DWORD dwSize = GetFileSize(hFile, NULL);
  CloseHandle(hFile);
  
  return dwSize;
  }// End GetLocalFileSize
  // GetLocalFileSize结束
  //////////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////
  // 名称:IsFileAscii
  // 描述:判断文件的传输方式是否为ASCII
  // 原型:BOOL IsFileAscii(LPCTSTR lpszFile)   // 文件名称
  // 参数:
  //             lpszFile:要判断的文件名称
  // 备注:
  //
  // 修改记录
  //             日期            版本                            修改人                         修改内容
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //2003/09/08      V2.00               wjr                创建
  //________________________________________________________________________
  BOOL CFtpClientCtrl::IsFileAscii(LPCTSTR lpszFile)   // 文件名称
  {
  if(lpszFile == NULL)
  return FALSE;
  LPCTSTR lpszExt = _tcsrchr(lpszFile, '.');// 得到文件后缀
  return IsFtpAscii(lpszExt);
  }// End IsFileAscii
  // IsFileAscii结束
  //////////////////////////////////////////////////////////////////////////
  
  使用方法:
  // 注册文件传输控件必要的参数
  m_cFtpCtrl.SetServerParam( szNmsIp),             // 网管服务器地址
  szFtpUser,      // ftp服务器用户
  szFtpPwd);   // ftp服务器口令
  m_cFtpCtrl.RegisterMsgHandle(WM_ FTP_PROGRESS);
  
  // 设置文件传输控件的传输方向
  m_cFtpCtrl.SetFtpDirect(FALSE);
  
  if(!m_cFtpCtrl.BeginUpload(GetSafeHwnd(),
  m_strRemote,
  m_strLocalFile))
  {
  AfxMessageBox(_T("文件开始上传失败!"));
  PostMessage(WM_CLOSE);
  return TRUE;

            }






页: [1]
查看完整版本: wininet实现ftp客户端关于传输进度的分析