📄 ftppidl.cpp
字号:
*ppidl = (LPITEMIDLIST) pbMemory;
hr = pbMemory ? S_OK : E_OUTOFMEMORY;
ASSERT(IsValidPIDL(*ppidl));
ASSERT_POINTER_MATCHES_HRESULT(*ppidl, hr);
return hr;
}
/*****************************************************************************\
FUNCTION: FtpItemID_CreateReal
DESCRIPTION:
Cook up a pidl based on a WIN32_FIND_DATA.
The cFileName field is itself MAX_PATH characters long,
so its length cannot possibly exceed MAX_PATH...
\*****************************************************************************/
HRESULT FtpItemID_CreateReal(const LPFTP_FIND_DATA pwfd, LPCWSTR pwzDisplayName, LPITEMIDLIST * ppidl)
{
HRESULT hr;
FTPIDLIST fi = {0};
// Fill in fi.
fi.dwIDType = (IDTYPE_ISVALID | IDVALID_FILESIZE | IDVALID_MOD_DATE);
fi.uliFileSize.LowPart = pwfd->nFileSizeLow;
fi.uliFileSize.HighPart = pwfd->nFileSizeHigh;
fi.ftModified = pwfd->ftLastWriteTime;
fi.dwAttributes = pwfd->dwFileAttributes;
fi.dwUNIXPermission = pwfd->dwReserved0; // Set by WININET
StrCpyNA(fi.szWireName, pwfd->cFileName, ARRAYSIZE(fi.szWireName));
StrCpyN(fi.wzDisplayName, pwzDisplayName, ARRAYSIZE(fi.wzDisplayName));
if (pwfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
fi.dwIDType |= IDTYPE_DIR;
else
fi.dwIDType |= IDTYPE_FILE;
hr = FtpItemID_Alloc(&fi, ppidl);
ASSERT(IsValidPIDL(*ppidl));
return hr;
}
/****************************************************\
FUNCTION: FtpItemID_CreateFake
DESCRIPTION:
Create a ItemID but we are only setting the
name. We don't know the true file attributes,
file size, or modification date yet because
we haven't touched the server yet. If we did,
we would use the returned WIN32_FIND_DATA struct
to create the ItemID by using FtpItemID_CreateReal().
\****************************************************/
HRESULT FtpItemID_CreateFake(LPCWSTR pwzDisplayName, LPCWIRESTR pwWireName, BOOL fTypeKnown, BOOL fIsFile, BOOL fIsFragment, LPITEMIDLIST * ppidl)
{
HRESULT hr;
DWORD dwType = IDTYPE_ISVALID;
FTPIDLIST fi = {0};
// Is it unknown?
if (!fTypeKnown)
{
// HACK: We will assume everything w/o a file extension is a Dir
// and everything w/an extension is a file.
fTypeKnown = TRUE;
fIsFile = (0 != *PathFindExtension(pwzDisplayName)) ? TRUE : FALSE;
}
if (fTypeKnown)
{
if (fIsFile)
dwType |= IDTYPE_FILE;
else if (fIsFragment)
dwType |= IDTYPE_FRAGMENT;
else
dwType |= IDTYPE_DIR;
}
else
{
// You need to know if it's a fragment because there is no
// heuristic to find out.
ASSERT(!fIsFragment);
dwType |= IDTYPE_FILEORDIR;
}
fi.dwIDType = dwType;
fi.dwAttributes = (fIsFile ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_DIRECTORY);
fi.uliFileSize.QuadPart = 0;
StrCpyNW(fi.wzDisplayName, pwzDisplayName, ARRAYSIZE(fi.wzDisplayName));
StrCpyNA(fi.szWireName, pwWireName, ARRAYSIZE(fi.szWireName));
hr = FtpItemID_Alloc(&fi, ppidl);
ASSERT(IsValidPIDL(*ppidl));
ASSERT_POINTER_MATCHES_HRESULT(*ppidl, hr);
return hr;
}
/*****************************************************************************\
FUNCTION: FtpItemID_SetName
DESCRIPTION:
The user chose a new name for the ftp file or dir (in unicode). We
now need to create the name in wire bytes and we will use the original
wire byte name to decide how to do that (from pidl).
\*****************************************************************************/
HRESULT FtpItemID_CreateWithNewName(LPCITEMIDLIST pidl, LPCWSTR pwzDisplayName, LPCWIRESTR pwWireName, LPITEMIDLIST * ppidlOut)
{
HRESULT hr;
FTPIDLIST fi;
const FTPIDLIST * pfi = FtpItemID_GetData(pidl);
CWireEncoding cWireEncoding;
CopyMemory(&fi, pfi, sizeof(FTPIDLIST) - sizeof(fi.szWireName) - sizeof(fi.wzDisplayName));
StrCpyNW(fi.wzDisplayName, pwzDisplayName, ARRAYSIZE(fi.wzDisplayName));
StrCpyNA(fi.szWireName, pwWireName, ARRAYSIZE(fi.szWireName));
hr = FtpItemID_Alloc(&fi, ppidlOut);
ASSERT(IsValidPIDL(*ppidlOut));
return hr;
}
HRESULT Private_GetFileInfo(SHFILEINFO *psfi, DWORD rgf, LPCTSTR pszName, DWORD dwFileAttributes)
{
HRESULT hr = E_FAIL;
if (SHGetFileInfo(pszName, dwFileAttributes, psfi, sizeof(*psfi), rgf | SHGFI_USEFILEATTRIBUTES))
hr = S_OK;
return hr;
}
/*****************************************************************************\
FUNCTION: FtpPidl_GetFileInfo
DESCRIPTION:
_UNDOCUMENTED_: We strip the Hidden and System bits so
that SHGetFileInfo won't think that we're passing something
that might be a junction.
We also force the SHGFI_USEFILEATTRIBUTES bit to remind the shell
that this isn't a file.
\*****************************************************************************/
HRESULT FtpPidl_GetFileInfo(LPCITEMIDLIST pidl, SHFILEINFO *psfi, DWORD rgf)
{
HRESULT hr;
TCHAR szDisplayName[MAX_PATH];
psfi->iIcon = 0;
psfi->hIcon = NULL;
psfi->dwAttributes = 0;
psfi->szDisplayName[0] = 0;
psfi->szTypeName[0] = 0;
ASSERT(IsValidPIDL(pidl));
if (FtpID_IsServerItemID(pidl))
{
FtpServerID_GetServer(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
hr = Private_GetFileInfo(psfi, rgf, szDisplayName, FILE_ATTRIBUTE_DIRECTORY);
if (psfi->hIcon)
DestroyIcon(psfi->hIcon);
psfi->hIcon = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(IDI_FTPFOLDER));
ASSERT(psfi->hIcon);
// Now replace the type (szTypeName) with "FTP Server" because
// it could go in the Properties dialog
EVAL(LoadString(HINST_THISDLL, IDS_ITEMTYPE_SERVER, psfi->szTypeName, ARRAYSIZE(psfi->szTypeName)));
}
else
{
LPFTPIDLIST pfi = FtpItemID_GetData(pidl);
FtpItemID_GetDisplayName(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
hr = Private_GetFileInfo(psfi, rgf, szDisplayName, (pfi->dwAttributes & ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)));
}
return hr;
}
HRESULT FtpPidl_GetFileType(LPCITEMIDLIST pidl, LPTSTR pszType, DWORD cchSize)
{
SHFILEINFO sfi;
HRESULT hr;
ASSERT(IsValidPIDL(pidl));
hr = FtpPidl_GetFileInfo(pidl, &sfi, SHGFI_TYPENAME);
if (EVAL(SUCCEEDED(hr)))
{
StrCpyN(pszType, sfi.szTypeName, cchSize);
if (sfi.hIcon)
DestroyIcon(sfi.hIcon);
}
return hr;
}
HRESULT FtpPidl_GetFileTypeStrRet(LPCITEMIDLIST pidl, LPSTRRET pstr)
{
WCHAR szType[MAX_URL_STRING];
HRESULT hr;
ASSERT(IsValidPIDL(pidl));
hr = FtpPidl_GetFileType(pidl, szType, ARRAYSIZE(szType));
if (EVAL(SUCCEEDED(hr)))
StringToStrRetW(szType, pstr);
return hr;
}
/*****************************************************************************\
FUNCTION: _FtpItemID_CompareOneID
DESCRIPTION:
ici - attribute (column) to compare
Note! that UNIX filenames are case-*sensitive*.
We make two passes on the name. If the names are different in other
than case, we return the result of that comparison. Otherwise,
we return the result of a case-sensitive comparison.
This algorithm ensures that the items sort themselves in a
case-insensitive way, with ties broken by a case-sensitive
comparison. This makes ftp folders act "mostly" like normal
folders.
_UNDOCUMENTED_: The documentation says that the ici parameter
is undefined and must be zero. In reality, it is the column
number (defined by IShellView) for which the comparison is to
be made.
\*****************************************************************************/
HRESULT _FtpItemID_CompareOneID(LPARAM ici, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwCompFlags)
{
int iRc = 0; // 0 means we don't know.
HRESULT hr = S_OK;
ASSERT(IsValidPIDL(pidl1));
ASSERT(IsValidPIDL(pidl2));
// Are they both the same type? (Both Dirs or both files?)
if (!(dwCompFlags & FCMP_GROUPDIRS) || (!FtpPidl_IsDirectory(pidl1, FALSE) == !FtpPidl_IsDirectory(pidl2, FALSE)))
{
switch (ici & SHCIDS_COLUMNMASK)
{
case COL_NAME:
{
// Yes they are the same, so we will key off the name...
WIRECHAR szName1[MAX_PATH];
WIRECHAR szName2[MAX_PATH];
szName1[0] = TEXT('\0');
szName2[0] = TEXT('\0');
FtpPidl_GetWireName(pidl1, szName1, ARRAYSIZE(szName1));
FtpPidl_GetWireName(pidl2, szName2, ARRAYSIZE(szName2));
iRc = StrCmpIA(szName1, szName2);
if (0 == iRc)
{
if (!(dwCompFlags & FCMP_CASEINSENSE))
iRc = StrCmpA(szName1, szName2);
/*
// They are the same name, so now lets check on the username
// if they are Server IDs.
if ((0 == iRc) && (FtpID_IsServerItemID(pidl1)))
{
FtpPidl_GetUserName(pidl1, szName1, ARRAYSIZE(szName1));
FtpPidl_GetUserName(pidl2, szName2, ARRAYSIZE(szName2));
iRc = StrCmp(szName1, szName2);
}
*/
}
}
break;
case COL_SIZE:
if (FtpPidl_GetFileSize(pidl1) < FtpPidl_GetFileSize(pidl2))
iRc = -1;
else if (FtpPidl_GetFileSize(pidl1) > FtpPidl_GetFileSize(pidl2))
iRc = +1;
else
iRc = 0; // I don't know
break;
case COL_TYPE:
if (!FtpID_IsServerItemID(pidl1) && !FtpID_IsServerItemID(pidl2))
{
TCHAR szType1[MAX_PATH];
hr = FtpPidl_GetFileType(pidl1, szType1, ARRAYSIZE(szType1));
if (EVAL(SUCCEEDED(hr)))
{
TCHAR szType2[MAX_PATH];
hr = FtpPidl_GetFileType(pidl2, szType2, ARRAYSIZE(szType2));
if (EVAL(SUCCEEDED(hr)))
iRc = StrCmpI(szType1, szType2);
}
}
break;
case COL_MODIFIED:
{
FILETIME ft1 = FtpPidl_GetFileTime(pidl1);
FILETIME ft2 = FtpPidl_GetFileTime(pidl2);
iRc = CompareFileTime(&ft1, &ft2);
}
break;
default:
hr = E_NOTIMPL;
break;
}
}
else
{
// No they are different. We want the Folder to always come first.
// This doesn't seam right, but it forces folders to bubble to the top
// in the most frequent case and it matches DefView's Behavior.
if (FtpPidl_IsDirectory(pidl1, FALSE))
iRc = -1;
else
iRc = 1;
}
if (EVAL(S_OK == hr))
hr = HRESULT_FROM_SUCCESS_VALUE(iRc); // encode the sort value in the return code.
return hr;
}
/*****************************************************************************\
FUNCTION: FtpItemID_CompareIDs
DESCRIPTION:
ici - attribute (column) to compare
Note! that we rely on the fact that IShellFolders are
uniform; we do not need to bind to the shell folder in
order to compare its sub-itemids.
_UNDOCUMENTED_: The documentation does not
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -