解决CFtpFileFind在Unicode版本下GetFileURL不能正确返回路径

最近看到 CFtpFileFind GetFileURL 不能正确返回路径

在VS2008下测试了一下确实有BUG, 多字节版本下是正常的, 而UNICODE版本下没有后面的文件名
大概调试追踪了一下, 先分析GetFileURL

CString CFtpFileFind::GetFileURL() const
{
    ASSERT_VALID(this);
    ASSERT(m_hContext != NULL);

    CString str;

    if (m_hContext != NULL)
    {
        str += _afxURLftp;
        str += m_pConnection->GetServerName();
        str += GetFilePath();
    }

    return str;
}

再追踪到 GetFilePath

CString CFileFind::GetFilePath() const
{
    ASSERT(m_hContext != NULL);
    ASSERT_VALID(this);

    CString strResult = m_strRoot;
    LPCTSTR pszResult;
    LPCTSTR pchLast;
    pszResult = strResult;
    pchLast = _tcsdec( pszResult, pszResult+strResult.GetLength() );
    ENSURE(pchLast!=NULL);
    if ((*pchLast != _T('\\')) && (*pchLast != _T('/')))
        strResult += m_chDirSeparator;
    strResult += GetFileName(); //在这里发现GetFileName返回正常,但是+=后没有变化
    return strResult;
}

继续单步进入 += 操作时发现, this(strResult 字符串) 只有一个字符 '/', 但是长度却是2, 也就是后面一个字符是‘\0’,  这个字符导致追加的字符串都无法显示。看来问题是在前面的 m_strRoot 上。

在 inet.cpp 的 CFtpFileFind::FindFile 中可以找到 m_strRoot 赋值的位置,设置断点, 也确实是停在 m_strRoot = strCWD;  

BOOL CFtpFileFind::FindFile(LPCTSTR pstrName /* = NULL */,
    DWORD dwFlags /* = INTERNET_FLAG_RELOAD */)

…… 

CString strCWD;
    m_pConnection->GetCurrentDirectory(strCWD);

    if (pstrRoot == NULL)
    {
        if (m_pConnection->SetCurrentDirectory(pstrName))
        {
           ……
        }
        else
            m_strRoot = strCWD;
    }

……

}

问题看来在m_pConnection->GetCurrentDirectory,再次设置断点进入 CFtpConnection::GetCurrentDirectory, 
BOOL CFtpConnection::GetCurrentDirectory(CString& strDirName) const
{
  ASSERT_VALID(this);
  ASSERT(m_hConnection != NULL);

  DWORD dwLen = INTERNET_MAX_PATH_LENGTH;
  LPTSTR pstrTarget = strDirName.GetBufferSetLength(dwLen);
  BOOL bRet =FtpGetCurrentDirectory(m_hConnection, pstrTarget, &dwLen);

  if (bRet)
    strDirName.ReleaseBuffer(dwLen);
  else
    strDirName.ReleaseBuffer(0);

  return bRet;
}

FtpGetCurrentDirectory上设置断点, 发现返回的字符只有‘/’,  多字节版本dwLen返回1,而Unicode版本返回2,

关键就在这个2上,  导致字符串后面有一个0, 使得后面的字符再进行 += 的字符串被截断; 而 CFtpFileFind::FindFile 中的m_strRoot 就用了这个返回值做根路径,那么后面的追加操作自然会失败。

找到问题了,那想办法把m_strRoot弄正常就好了呗, 看 CFtpConnection 的函数申明, GetCurrentDirectory 都不是虚函数,再看CFtpFileFind::FindFile 的声明 virtual BOOL FindFile(LPCTSTR pstrName = NULL, DWORD dwFlags = INTERNET_FLAG_RELOAD); 可以从这里做突破口了, 我这里是从CFtpFileFind派生了一个新类, 然后FindFile中处理了一下

好了废话不多说了, 直接上好用的代码了

 


 


#include <afxinet.h>

class CMyFtpFileFind : public CFtpFileFind
{
public:
  explicit CMyFtpFileFind(CFtpConnection* pConnection, DWORD_PTR dwContext = 1)
    : CFtpFileFind(pConnection, dwContext)
  {
  }

  virtual BOOL FindFile(LPCTSTR pstrName = NULL,
		DWORD dwFlags = INTERNET_FLAG_RELOAD)
  {
    BOOL bRet = __super::FindFile(pstrName, dwFlags);
    m_strRoot.ReleaseBuffer(); //
    return bRet;
  }
};

void CDlg4Dlg::OnBnClickedButton1()
{    
  #undef _tprintf_s
  #define _tprintf_s TRACE

  CInternetSession sess(_T("My FTP Session"));

  CFtpConnection* pConnect = NULL;

  try
  {
    // Request a connection to ftp.microsoft.com. Default
    // parameters mean that we'll try with username = ANONYMOUS
    // and password set to the machine name @ domain name
    pConnect = sess.GetFtpConnection(_T("192.168.0.186"));

    // use a file find object to enumerate files
    CMyFtpFileFind finder(pConnect);

    // start looping
    BOOL bWorking = finder.FindFile(_T("*"));

    while (bWorking)
    {
      bWorking = finder.FindNextFile();
      _tprintf_s(_T("%s\n"), (LPCTSTR)finder.GetFileURL());
    }
  }
  catch (CInternetException* pEx)
  {
    TCHAR sz[1024];
    pEx->GetErrorMessage(sz, 1024);
    _tprintf_s(_T("ERROR!  %s\n"), sz);
    pEx->Delete();
  }

  // if the connection is open, close it
  if (pConnect != NULL) 
  {
    pConnect->Close();
    delete pConnect;
  }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值