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

📄 ftpfoldr.cpp

📁 很好用的ftp源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:

    return hr;
}


/*****************************************************************************\
    FUNCTION: GetUIObjectOfHfpl

    DESCRIPTION:
        _UNDOCUMENTED_:  Nowhere is there a list of interfaces
    that "should be" supported.  You just have to add lots of
    squirties and see what interfaces are asked for.

      _UNDOCUMENTED_:  Nowhere is it mentioned that passing
    cidl = 0 (or the various other weird variants) means to
    get a UI object on the folder itself.

    _UNDOCUMENTED_:  It is not mentioned whether the folder should
    be expected to handle cidl != 1 when asked for an IExtractIcon.
    I code defensively and handle the situation properly.

    IExtractIcon(0) extracts the icon for the folder itself.
    IExtractIcon(1) extracts the icon for the indicated pidl.
    IExtractIcon(n) extracts a generic "multi-document" icon.

    IContextMenu(0) produces a context menu for the folder itself.
        (Not used by the shell, but used by ourselves internally.)
    IContextMenu(n) produces a context menu for the multi-selection.

    IDataObject(0) ?? doesn't do anything
    IDataObject(n) produces a data object for the multi-selection.

    IDropTarget(0) produces a droptarget for the folder itself.
        (Not used by the shell, but used by ourselves internally.)
    IDropTarget(1) produces a droptarget for the single item.

    IShellView(0) ?? doesn't do anything
    IShellView(1) produces a shellview for the single item.
        (Nobody tries this yet, but I'm ready for it.)
\*****************************************************************************/
HRESULT CFtpFolder::GetUIObjectOfHfpl(HWND hwndOwner, CFtpPidlList * pflHfpl, REFIID riid, LPVOID * ppvObj, BOOL fFromCreateViewObject)
{
    HRESULT hr = E_INVALIDARG;

    if (IsEqualIID(riid, IID_IExtractIconA) ||
        IsEqualIID(riid, IID_IExtractIconW) ||
        IsEqualIID(riid, IID_IQueryInfo))
    {
        hr = CFtpIcon_Create(this, pflHfpl, riid, ppvObj);
        //TraceMsg(TF_FTPISF, "CFtpFolder::GetUIObjectOfHfpl() CFtpIcon_Create() hr=%#08lx", hr);
        ASSERT(SUCCEEDED(hr));
    }
    else if (IsEqualIID(riid, IID_IContextMenu))
    {
        hr = CFtpMenu_Create(this, pflHfpl, hwndOwner, riid, ppvObj, fFromCreateViewObject);
        TraceMsg(TF_FTPISF, "CFtpFolder::GetUIObjectOfHfpl() CFtpMenu_Create() hr=%#08lx", hr);
        ASSERT(SUCCEEDED(hr));
    }
    else if (IsEqualIID(riid, IID_IDataObject))
    {
        hr = CFtpObj_Create(this, pflHfpl, riid, ppvObj);
        TraceMsg(TF_FTPISF, "CFtpFolder::GetUIObjectOfHfpl() CFtpObj_Create() hr=%#08lx", hr);
        ASSERT(SUCCEEDED(hr));
    }
    else if (IsEqualIID(riid, IID_IDropTarget))
    {
        // This will fail when someone gets a property sheet on an FTP PIDL Shortcut
        // that has a file as the destination.
        hr = CreateSubViewObject(hwndOwner, pflHfpl, riid, ppvObj);
        TraceMsg(TF_FTPISF, "CFtpFolder::GetUIObjectOfHfpl() CreateSubViewObject() hr=%#08lx", hr);
    }
    else if (IsEqualIID(riid, IID_IShellView))
    {
        ASSERT(0);  // Shouldn't happen
    }
    else if (IsEqualIID(riid, IID_IQueryAssociations))
    {
        IQueryAssociations * pqa;
        
        hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (void **)&pqa);
        if (SUCCEEDED(hr))
        {
            hr = pqa->Init(0, L"Folder", NULL, NULL);

            if (SUCCEEDED(hr))
                *ppvObj = (void *)pqa;
            else
                pqa->Release();
        }
    }
    else
    {
        //TraceMsg(TF_FTPISF, "CFtpFolder::GetUIObjectOfHfpl() E_NOINTERFACE");
        hr = E_NOINTERFACE;
    }

    if (FAILED(hr))
        *ppvObj = NULL;

    ASSERT_POINTER_MATCHES_HRESULT(*ppvObj, hr);
    return hr;
}


static const LPCTSTR pszBadAppArray[] = {TEXT("aol.exe"), TEXT("waol.exe"), TEXT("msnviewr.exe"), TEXT("cs3.exe"), TEXT("msdev.exe")};

/*****************************************************************************\
    FUNCTION: IsAppFTPCompatible

    DESCRIPTION:
        Some apps (WebOC hosts) fail to navigate to FTP directories.
    We check the app here and see if it's one of those incompatible apps.

    I don't worry about perf because we can do the work only once and cache
    the result because our globals will be re-inited for each process.

    GOOD:
    ========================================================================
    iexplore.exe:   Good of course.
    explorer.exe:   Good of course.
    msdev.exe (v6): The HTML help works but folder navigations happen in
                    a new window.  I don't care because the same happens in
                    the shell (File System case).
    <Default Case>: These are apps built with VB's WebOC that work fine, but
                    they also have the open in new folder behavior.

    BAD and UGLY:
    ========================================================================
    msdev.exe (v5): You can navigate their Moniker help to FTP which will
                    cause a hang.
    [MSN] (msnviewr.exe): For some reason MSN calls IPersistFolder::Initialize with an invalid value.
           Navigating to the folder works but launching other folders cause them
           to appear in their own window and they immediately close.  This was
           on browser only so it may be because internet delegate folders aren't
           supported.

    [aol]: (waol.exe) This doesn't work either.
    cs3.exe (CompuServ): ????
    [ATT WorldNet]: ????
    [Protigy]: ????
    [SNAP]: ????
\*****************************************************************************/
BOOL IsAppFTPCompatible(void)
{
    static BOOL s_fIsAppCompatible;
    static BOOL s_fIsResultCached = FALSE;
//
    if (!s_fIsResultCached)
    {
        TCHAR szAppPath[MAX_PATH];

        s_fIsAppCompatible = TRUE;  // Assume all Web OC Hosts are fine...

        if (EVAL(GetModuleFileName(NULL, szAppPath, ARRAYSIZE(szAppPath))))
        {
            int nIndex;
            LPTSTR pszAppFileName = PathFindFileName(szAppPath);

            for (nIndex = 0; nIndex < ARRAYSIZE(pszBadAppArray); nIndex++)
            {
                if (!StrCmpI(pszAppFileName, pszBadAppArray[nIndex]))
                {
                    // This one is bad/
                    s_fIsAppCompatible = FALSE;
                    break;
                }
            }
        }

        s_fIsResultCached = TRUE;
    }

    return s_fIsAppCompatible;
}


/*****************************************************************************\
    FUNCTION: CreateSubViewObject

    DESCRIPTION:
        Somebody is asking for a UI object of a subobject, which is
    better handled by the subobject than by the parent.

    Bind to the subobject and get the requested UI object thence.

    If the pidl list is empty, then we are talking about ourselves again.
\*****************************************************************************/
HRESULT CFtpFolder::CreateSubViewObject(HWND hwndOwner, CFtpPidlList * pflHfpl, REFIID riid, LPVOID * ppvObj)
{
    HRESULT hr = E_INVALIDARG;
    DWORD dwItemsSelected = pflHfpl->GetCount();
    IShellFolder * psf = NULL;

    if (EVAL(ppvObj))             // I wouldn't be surprised if
        *ppvObj = NULL;            // somebody relied on this

    if (1 == dwItemsSelected)
    {
        LPITEMIDLIST pidl = pflHfpl->GetPidl(0);    // This doesn't clone the pidl so we don't need to free it.
        if (EVAL(pidl))
            hr = BindToObject(pidl, 0, IID_IShellFolder, (LPVOID *)&psf);
    }
    else if (EVAL(0 == dwItemsSelected))
        hr = this->QueryInterface(IID_IShellFolder, (void **) &psf);

    ASSERT_POINTER_MATCHES_HRESULT(psf, hr);
    if (EVAL(SUCCEEDED(hr)))
    {
        // CreateViewObject will AddRef the psfT if it wants it
        hr = psf->CreateViewObject(hwndOwner, riid, ppvObj);
    }
    
    ASSERT_POINTER_MATCHES_HRESULT(*ppvObj, hr);
    ATOMICRELEASE(psf);
    return  hr;
}



/*****************************************************************************\
      GetSiteMotd
\*****************************************************************************/

CFtpGlob * CFtpFolder::GetSiteMotd(void)
{
    CFtpGlob * pGlob = NULL;

    _InitFtpSite(); // Okay if it fails.
    if (m_pfs)
        pGlob = m_pfs->GetMotd();

    return pGlob;
}


HRESULT CFtpFolder::_Initialize(LPCITEMIDLIST pidlTarget, LPCITEMIDLIST pidlRoot, int nBytesToPrivate)
{
    IUnknown_Set(&m_pfs, NULL);
    return CBaseFolder::_Initialize(pidlTarget, pidlRoot, nBytesToPrivate);
}


// Sometimes the user will enter incorrect information without knowing.
// We would catch this if we verified everything that was entered, but
// we don't, we just take it on faith until we do the IEnumIDList.
// This is great for perf but sucks for catching these kinds of things.
// An example of this is the user using the File.Open dialog and going to
// "ftp://myserver/dir/".  They then enter "ftp://myserver/dir/file.txt"
// which will try to parse relative but it's an absolute path.
HRESULT CFtpFolder::_FilterBadInput(LPCTSTR pszUrl, LPITEMIDLIST * ppidl)
{
    HRESULT hr = S_OK;

    // If pidlPrivate isn't empty, then we aren't at the
    // root, so reject any urls that are absolute (i.e. have
    // ftp: scheme).
    if (!IsRoot() && (URL_SCHEME_FTP == GetUrlScheme(pszUrl)))
        hr = E_FAIL;
    // More may come here...

    if (FAILED(hr) && *ppidl)
        Pidl_Set(ppidl, NULL);

    return hr;
}


/*****************************************************************************\
    FUNCTION: _ForPopulateAndEnum

    DESCRIPTION:
        This function exists to detect the following case and if it's true,
    populate the cache (pfd) and return the pidl from that cache in ppidl.

     There is one last thing we need to try, we need to detect if:
    1) the URL has an URL path, and 
    2) the last item in the path doesn't have an extension and doesn't
       end in a slash ('/') to indicate it's a directory.
    If this case is true, we then need to find out if it is a directory
    or file by hitting the server.  This is needed because by the time
    we bind, it's too late to fall back to the other thing (IEnumIDList).
    The one thing we might need to be careful about is AutoComplete because
    they may call :: ParseDisplayName() for every character a user types.
    This won't be so bad because it's on a background thread, asynch, and
    the first enum within a segment will cause the cache to be populated
    within a that segment so subsequent enums will be fast.  The problem
    it that it's not uncommon for users to enter between 2 and 5 segments,
    and there would be 1 enum per segment.
\*****************************************************************************/
HRESULT CFtpFolder::_ForPopulateAndEnum(CFtpDir * pfd, LPCITEMIDLIST pidlBaseDir, LPCTSTR pszUrl, LPCWIRESTR pwLastDir, LPITEMIDLIST * ppidl)
{
    HRESULT hr = E_FAIL;

    *ppidl = NULL;
    // We only care if the URL Path isn't empty AND it doesn't end in a '/' AND
    // it doesn't have an extension.
    if (!ILIsEmpty(pfd->GetPathPidlReference()) && (0 == *PathFindExtensionA(pwLastDir)))
    {
        IEnumIDList * penumIDList;

        // NULL hwnd needs to suppress all UI.
        hr = CFtpEidl_Create(pfd, this, NULL, (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN), &penumIDList);
        if (EVAL(SUCCEEDED(hr)))
        {
            hr = penumIDList->Reset();
            ASSERT(SUCCEEDED(hr));
            // We are working off of the assumption that calling Reset will force it to hit the server and pull down all of the contents.

            LPITEMIDLIST pidlFromCache = (LPITEMIDLIST) pfd->GetPidlFromWireName(pwLastDir);
            if (pidlFromCache)
            {
                // It was found, this means that it exists now in the cache after we
                // forced it to be populated.
                *ppidl = ILCombine(pidlBaseDir, pidlFromCache);
                ILFree(pidlFromCache);
            }
            else
                hr = E_FAIL;

            penumIDList->Release();
        }
    }

    return hr;
}


HRESULT CFtpFolder::_GetCachedPidlFromDisplayName(LPCTSTR pszDisplayName, LPITEMIDLIST * ppidl)
{
    HRESULT hr = E_FAIL;
    if (ppidl)
    {
        CFtpDir * pfd = GetFtpDir();

        if (pfd)
        {
            // We may have a pointer but the cache may still be empty, as in case NT #353324
            CFtpPidlList * pfl = pfd->GetHfpl();
            if (pfl)
            {
                // Yes, so we will continue to use the cache.  Now let's get rid of that
                // temp pointer.
                pfl->Release();
            }
            else
            {
                // No we don't have it cashed, so pretend the pfd was returned NULL.
                pfd->Release();
                pfd = NULL;
            }
        }

        *ppidl = NULL;
        if (!pfd)
        {
            LPITEMIDLIST pidlBaseDir;

            hr = CreateFtpPidlFromUrl(pszDisplayName, GetCWireEncoding(), NULL, &pidlBaseDir, m_pm, FALSE);
            if (SUCCEEDED(hr))  // May fail because of AutoComplete.
            {
                // If it's not pointing to just a server, then we can enum the contents and
                // find out if it's is a file or directory.
                if (!ILIsEmpty(pidlBaseDir) && !FtpID_IsServerItemID(ILFindLastID(pidlBaseDir)))

⌨️ 快捷键说明

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