⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpfoldr.cpp

📁 很好用的ftp源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************\
    FILE: ftpfoldr.h

    DESCRIPTION:
        This class inherits from CBaseFolder for a base ShellFolder implementation
    of IShellFolder and overrides methods to give Ftp Specific features.

     _UNDOCUMENTED_:  The shell violates Apartment model threading
     when doing background enumeration, so even though this DLL is
     marked as Apartment model, IShellFolder and IEnumIDList must
     be written with the free threading model with respect to anything
     that IEnumIDList can do in the background.
 
     This means that you'll see lots of ENTER_CRITICAL() and
     LEAVE_CRITICAL() calls when your brain would say, "I don't
     need to do that because I'm Apartment-model."  I'll try to
     point them out as they occur; look for the marker _MT_.
 
     CAUTION!  Internally, our property sheet handler also invokes
     methods on CFtpFolder on the wrong thread, so it's not just the
     shell that is weird.
\*****************************************************************************/

#include "priv.h"
#include "ftpfoldr.h"
#include "ftpurl.h"
#include "ftppidl.h"
#include "ftpicon.h"
#include "view.h"
#include "proxycache.h"
#include <idhidden.h>

#define FEATURE_SOFTLINK_SHORTCUT_ICONOVERLAY

// {A11501B3-6EA4-11d2-B679-006097DF5BD4}   Private to msieftp.dll
const GUID IID_CFtpFolder = { 0xa11501b3, 0x6ea4, 0x11d2, { 0xb6, 0x79, 0x0, 0x60, 0x97, 0xdf, 0x5b, 0xd4 } };


/*****************************************************************************
 *
 *    More const statics.
 *
 *****************************************************************************/

#pragma BEGIN_CONST_DATA

WORD c_wZero = 0;        /* As promised in ftpview.h */

/*
 *  String separator used when building relative names.
 */
char c_szSlash[] = "/";


#pragma END_CONST_DATA


HRESULT CFtpFolder::_AddToUrlHistory(LPCWSTR pwzUrl)
{
    HRESULT hr = S_OK;

    if (!m_puhs)
        hr = CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER, IID_IUrlHistoryStg, (void **)&m_puhs);

    if (EVAL(m_puhs))
        EVAL(SUCCEEDED(hr = m_puhs->AddUrl(pwzUrl, pwzUrl, 0)));

    return hr;
}

/* Not yet needed
HRESULT CFtpFolder::AddToUrlHistory(LPCTSTR pszUrl)
{
    return _AddToUrlHistory(wzUrl);
}
*/

HRESULT CFtpFolder::AddToUrlHistory(LPCITEMIDLIST pidl)
{
    WCHAR wzUrl[MAX_URL_STRING];
    HRESULT hr = UrlCreateFromPidlW(pidl, SHGDN_FORPARSING, wzUrl, ARRAYSIZE(wzUrl), (ICU_ESCAPE | ICU_USERNAME), TRUE);

    // BUGBUG This is used across threads, so make it thread safe.    
    if (EVAL(SUCCEEDED(hr)))
        EVAL(SUCCEEDED(hr = _AddToUrlHistory(wzUrl)));

    return hr;
}


CWireEncoding * CFtpFolder::GetCWireEncoding(void)
{
    // GetFtpDir() may return NULL when we aren't rooted in an FTP server.
    CFtpDir * pfd = GetFtpDir();
    CWireEncoding * pwe = NULL;

    if (pfd)
    {
        pwe = pfd->GetFtpSite()->GetCWireEncoding();
        pfd->Release();
    }

    return pwe;
}

HRESULT CFtpFolder::_FixQuestionablePidl(LPCITEMIDLIST pidl)
{
    HRESULT hr = S_OK;

    // BUGBUG: Nuke comment if we can.
    // TODO: In the future, we may want to hit the server to
    //   disambiguate this.
/*
    BOOL fIsDir = TRUE;
    LPCSTR pszName = FtpPidl_GetLastItemName(pidl);

    // Can we get the name?
    if (EVAL(pszName))
    {
        // Is the file extension non-NULL? (Meaning it exists)
        if ('\0' != *PathFindExtensionA(pszName))
            fIsDir = FALSE;     // Yes, so asume it's a file.
    }

    hr = FtpPidl_SetFileItemType((LPITEMIDLIST) pidl, fIsDir);
*/
    return hr;
}


BOOL CFtpFolder::_IsServerVMS(LPCITEMIDLIST pidl)
{
    BOOL fIsServerVMS = FALSE;    // Assume TRUE
    CFtpSite * pfs;

    // Some caller's don't pass the Server ID so let's assume
    // that they already made it past that point.
    if (FtpID_IsServerItemID(pidl) &&
        EVAL(SUCCEEDED(SiteCache_PidlLookup(pidl, FALSE, m_pm, &pfs))))
    {
        fIsServerVMS = pfs->IsServerVMS();
        pfs->Release();
    }

    return fIsServerVMS;
}


/****************************************************\
    FUNCTION: _IsProxyBlockingSite

    DESCRIPTION:
        We need to detect if we cannot connect to the
    site because the proxy is a CERN or CERN type proxy
    that blocks ALL ftp access.  If this is true, we
    need to inform the user can fall all
    IShellFolder::BindToObject() calls.

        We will detect this case by doing the normal
    WININET FTP InternetConnect().  If that returns
    hr=0x80002EE7 (ERROR_INTERNET_NAME_NOT_RESOLVED)
    then it could either be that the name doesn't exist,
    or there is a CERN proxy blocking the call.  We will
    then try connect the CERN method which will tell us
    if it's the proxy that is blocking us.
\****************************************************/
BOOL CFtpFolder::_IsProxyBlockingSite(LPCITEMIDLIST pidl)
{
    BOOL fCacheResult;
    BOOL fResult = TRUE;    // Assume TRUE
    CFtpDir * pfd;

    if (ProxyCache_IsProxyBlocking(pidl, &fCacheResult))
        return fCacheResult;

    if (EVAL(pfd = GetFtpDirFromPidl(pidl)))
    {
        HRESULT hr = pfd->WithHint(NULL, NULL, NULL, NULL, NULL, this);

        // WithHint() often fails if a CERN style proxy blocks REAL wininet
        // access to the server.  If the server name is a DNS name, the error
        // returned will be ERROR_INTERNET_NAME_NOT_RESOLVED because that is
        // what is returned by the CERN proxy.  If the server name is an IP
        // Address, wininet will skip the CERN proxy and try to find it on the
        // intranet.  If not found (because it's past the firewall), then,
        // the attempt will timeout with ERROR_INTERNET_TIMEOUT.  We need
        // to treat this as a proxy block if and ONLY if the server name is an
        // IP address because DNS names can timeout for other reasons.  Us
        // treating IP server name timeouts as proxy blocks is going to have
        // to be tolerated because wininet won't handle this case.  It happens
        // very infrequently so I don't care that much.
        //
        // Some authentication proxies fail with: ERROR_INTERNET_CANNOT_CONNECT
        // We would like to fall back in that case, however, that may include
        // other cases like the server refusing to allow us in.
        // (password or too many logged in users?)
        // It would be great if ERROR_INTERNET_INVALID_PROXY_REQUEST or
        // ERROR_INTERNET_CLIENT_AUTH_NOT_SETUP could be used.
        //
        if ((HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED) == hr) ||
            (HRESULT_FROM_WIN32(ERROR_INTERNET_CANNOT_CONNECT) == hr) ||
            ((HRESULT_FROM_WIN32(ERROR_INTERNET_TIMEOUT) == hr) && !FtpPidl_IsDNSServerName(pidl)))
        {
            TCHAR szUrl[MAX_URL_STRING];

            if (EVAL(SUCCEEDED(UrlCreateFromPidl(pidl, SHGDN_FORPARSING, szUrl, ARRAYSIZE(szUrl), ICU_ESCAPE | ICU_USERNAME, FALSE))))
            {
                HINTERNET hintTemp;
                ASSERT(GetWininetSessionHandle());

                // For Web Proxies, InternetOpenUrl should work.  The problem is that
                // some (Netscape's) don't work.
                if (SUCCEEDED(InternetOpenUrlWrap(GetWininetSessionHandle(), TRUE, szUrl, NULL, 0, INTERNET_FLAG_NO_UI, NULL, &hintTemp)))
                {
                    InternetCloseHandle(hintTemp);  // This did work, so we must have a CERN proxy.
                }
                else
                    fResult = FALSE;    // We aren't blocked by the proxy. (Wrong IP Addr or Name?)
            }
        }
        else
            fResult = FALSE;    // We aren't blocked by the proxy.

        // Cache the result since finding out is so expensive.
        ProxyCache_SetProxyBlocking(pidl, fResult);
        pfd->Release();
    }

    return fResult;
}


/*****************************************************************************
 *
 *    InvalidateCache
 *
 *    Invalidate the pflHfpl cache in the corresponding FtpDir.
 *
 *    _MT_:  Note that the background enumerator calls this, so it must be
 *    multithread-safe.
 *
 *****************************************************************************/

void CFtpFolder::InvalidateCache(void)
{
    CFtpDir * pfd = GetFtpDir();

    if (EVAL(pfd))
    {
        // Should have created one on the GetHint()
        pfd->SetCache(0);
        pfd->Release();
    }
}


HRESULT CFtpFolder::_InitFtpSite(void)
{
    HRESULT hr = S_OK;

    if (!m_pfs)         // If we don't already got one...
    {
        ENTERCRITICAL;
        if (!m_pfs)            // Did it get created while we were waiting
        {
            if (EVAL(GetPrivatePidlReference()))
                hr = SiteCache_PidlLookup(GetPrivatePidlReference(), TRUE, m_pm, &m_pfs);
            else
            {
                // Not initialized
                TraceMsg(TF_FTPISF, "CFtpFolder_GetFtpDir(%08x) NOT INITED", this);
                hr = E_FAIL;
            }
        }

        LEAVECRITICAL;
    }

    return hr;
}


/*****************************************************************************\
    FUNCTION: GetFtpDir

    DESCRIPTION:
        Say where our dir info is.

    We allocate the pfd only if somebody actually needs it, because
    Explorer does a lot of ILCompare's when you open a new folder,
    each of which creates a new IShellFolder for the sole purpose
    of calling CompareIDs.  We don't want to go through all the
    hubbub of creating an FtpDir and FtpSite when we don't need one.

    _MT_:  Note that the background enumerator calls this, so it must be
    multithread-safe.  In such case, however, the IShellFolder is
    marked cBusy, so we don't have to worry about the this->pfd
    getting wiped out behind our back by a change of identity.
\*****************************************************************************/
CFtpDir * CFtpFolder::GetFtpDir(void)
{
    HRESULT hres = S_OK;
    CFtpDir * pfd = NULL;

    _InitFtpSite(); // Okay if it fails.
    if (m_pfs)
        hres = m_pfs->GetFtpDir(GetPrivatePidlReference(), &pfd);

    return pfd;
}



CFtpDir * CFtpFolder::GetFtpDirFromPidl(LPCITEMIDLIST pidl)
{
    HRESULT hres = S_OK;
    CFtpDir * pfd = NULL;
    CFtpSite * pfs = NULL;

    hres = SiteCache_PidlLookup(pidl, FALSE, m_pm, &pfs);
    if (pfs)
    {
        hres = pfs->GetFtpDir(pidl, &pfd);
        pfs->Release();
    }

    return pfd;
}


CFtpDir * CFtpFolder::GetFtpDirFromUrl(LPCTSTR pszUrl)
{
    LPITEMIDLIST pidl;
    CFtpDir * pfd = NULL;

    if (EVAL(SUCCEEDED(CreateFtpPidlFromUrl(pszUrl, GetCWireEncoding(), NULL, &pidl, m_pm, FALSE))))
    {
        _InitFtpSite(); // Okay if it fails.
        m_pfs->GetFtpDir(pidl, &pfd);
        ILFree(pidl);
    }

    return pfd;
}


/*****************************************************************************\
 *    GetItemAllocator
 *
 *    Return today's pidl allocator.
\*****************************************************************************/
HRESULT CFtpFolder::GetItemAllocator(IMalloc **ppm)
{
    HRESULT hr = E_FAIL;

    *ppm = NULL;
    if (EVAL(m_pm))
    {
        IUnknown_Set(ppm, m_pm);
        hr = S_OK;
    }
    else
        TraceMsg(TF_FTPISF, "CFtpFolder_GetItemAllocator(%08x) NOT INITED", this);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -