atldlgs.h
来自「一个与传统电子字典不同的字典」· C头文件 代码 · 共 2,367 行 · 第 1/5 页
H
2,367 行
{
m_ofn.Flags |= OFN_ALLOWMULTISELECT; // Force multiple selection mode
#ifndef _UNICODE
OSVERSIONINFO ovi = { sizeof(ovi) };
::GetVersionEx(&ovi);
m_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT);
if (m_bIsNT)
{
// On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there
// is absolutely nothing we can do except to start off with a large buffer.
ATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH));
}
#endif
}
~CMultiFileDialogImpl()
{
if (m_ofn.lpstrFile != m_szFileName) // Free the buffer if we allocated it
delete[] m_ofn.lpstrFile;
}
// Operations
// Get the directory that the files were chosen from.
// The function returns the number of characters copied, not including the terminating zero.
// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
// If the function fails, the return value is zero.
int GetDirectory(LPTSTR pBuffer, int nBufLen) const
{
if (m_ofn.lpstrFile == NULL)
return 0;
LPCTSTR pStr = m_ofn.lpstrFile;
int nLength = lstrlen(pStr);
if (pStr[nLength + 1] == 0)
{
// The OFN buffer contains a single item so extract its path.
LPCTSTR pSep = _strrchr(pStr, _T('\\'));
if (pSep != NULL)
nLength = (int)(DWORD_PTR)(pSep - pStr);
}
int nRet = 0;
if (pBuffer == NULL) // If the buffer is NULL, return the required length
{
nRet = nLength + 1;
}
else if (nBufLen > nLength)
{
SecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength);
nRet = nLength;
}
return nRet;
}
#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
bool GetDirectory(_CSTRING_NS::CString& strDir) const
{
bool bRet = false;
int nLength = GetDirectory(NULL, 0);
if (nLength > 0)
{
bRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0);
strDir.ReleaseBuffer(nLength - 1);
}
return bRet;
}
#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
// Get the first filename as a pointer into the buffer.
LPCTSTR GetFirstFileName() const
{
if (m_ofn.lpstrFile == NULL)
return NULL;
m_pNextFile = NULL; // Reset internal buffer pointer
LPCTSTR pStr = m_ofn.lpstrFile;
int nLength = lstrlen(pStr);
if (pStr[nLength + 1] != 0)
{
// Multiple items were selected. The first string is the directory,
// so skip forwards to the second string.
pStr += nLength + 1;
// Set up m_pNext so it points to the second item (or null).
m_pNextFile = pStr;
GetNextFileName();
}
else
{
// A single item was selected. Skip forward past the path.
LPCTSTR pSep = _strrchr(pStr, _T('\\'));
if (pSep != NULL)
pStr = pSep + 1;
}
return pStr;
}
// Get the next filename as a pointer into the buffer.
LPCTSTR GetNextFileName() const
{
if (m_pNextFile == NULL)
return NULL;
LPCTSTR pStr = m_pNextFile;
// Set "m_pNextFile" to point to the next file name, or null if we
// have reached the last file in the list.
int nLength = lstrlen(pStr);
m_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL;
return pStr;
}
// Get the first filename as a full path.
// The function returns the number of characters copied, not including the terminating zero.
// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
// If the function fails, the return value is zero.
int GetFirstPathName(LPTSTR pBuffer, int nBufLen) const
{
LPCTSTR pStr = GetFirstFileName();
int nLengthDir = GetDirectory(NULL, 0);
if((pStr == NULL) || (nLengthDir == 0))
return 0;
// Figure out the required length.
int nLengthTotal = nLengthDir + lstrlen(pStr);
int nRet = 0;
if(pBuffer == NULL) // If the buffer is NULL, return the required length
{
nRet = nLengthTotal + 1;
}
else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
{
GetDirectory(pBuffer, nBufLen);
SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
SecureHelper::strcat_x(pBuffer, nBufLen, pStr);
nRet = nLengthTotal;
}
return nRet;
}
#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
bool GetFirstPathName(_CSTRING_NS::CString& strPath) const
{
bool bRet = false;
int nLength = GetFirstPathName(NULL, 0);
if (nLength > 0)
{
bRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0);
strPath.ReleaseBuffer(nLength - 1);
}
return bRet;
}
#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
// Get the next filename as a full path.
// The function returns the number of characters copied, not including the terminating zero.
// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
// If the function fails, the return value is zero.
// The internal position marker is moved forward only if the function succeeds and the buffer was large enough.
int GetNextPathName(LPTSTR pBuffer, int nBufLen) const
{
if (m_pNextFile == NULL)
return 0;
int nRet = 0;
LPCTSTR pStr = m_pNextFile;
// Does the filename contain a backslash?
if (_strrchr(pStr, _T('\\')) != NULL)
{
// Yes, so we'll assume it's a full path.
int nLength = lstrlen(pStr);
if (pBuffer == NULL) // If the buffer is NULL, return the required length
{
nRet = nLength + 1;
}
else if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename
{
SecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName());
nRet = nBufLen;
}
}
else
{
// The filename is relative, so construct the full path.
int nLengthDir = GetDirectory(NULL, 0);
if (nLengthDir > 0)
{
// Calculate the required space.
int nLengthTotal = nLengthDir + lstrlen(pStr);
if(pBuffer == NULL) // If the buffer is NULL, return the required length
{
nRet = nLengthTotal + 1;
}
else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
{
GetDirectory(pBuffer, nBufLen);
SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
SecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName());
nRet = nLengthTotal;
}
}
}
return nRet;
}
#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
bool GetNextPathName(_CSTRING_NS::CString& strPath) const
{
bool bRet = false;
int nLength = GetNextPathName(NULL, 0);
if (nLength > 0)
{
bRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0);
strPath.ReleaseBuffer(nLength - 1);
}
return bRet;
}
#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
// Implementation
bool ResizeFilenameBuffer(DWORD dwLength)
{
if (dwLength > m_ofn.nMaxFile)
{
// Free the old buffer.
if (m_ofn.lpstrFile != m_szFileName)
{
delete[] m_ofn.lpstrFile;
m_ofn.lpstrFile = NULL;
m_ofn.nMaxFile = 0;
}
// Allocate the new buffer.
LPTSTR lpstrBuff = NULL;
ATLTRY(lpstrBuff = new TCHAR[dwLength]);
if (lpstrBuff != NULL)
{
m_ofn.lpstrFile = lpstrBuff;
m_ofn.lpstrFile[0] = 0;
m_ofn.nMaxFile = dwLength;
}
}
return (m_ofn.lpstrFile != NULL);
}
void OnSelChange(LPOFNOTIFY /*lpon*/)
{
#ifndef _UNICODE
// There is no point resizing the buffer in ANSI builds running on NT.
if (m_bIsNT)
return;
#endif
// Get the buffer length required to hold the spec.
int nLength = GetSpec(NULL, 0);
if (nLength <= 1)
return; // no files are selected, presumably
// Add room for the directory, and an extra terminating zero.
nLength += GetFolderPath(NULL, 0) + 1;
if (!ResizeFilenameBuffer(nLength))
{
ATLASSERT(FALSE);
return;
}
// If we are not following links then our work is done.
if ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0)
return;
// Get the file spec, which is the text in the edit control.
if (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0)
return;
// Get the ID-list of the current folder.
int nBytes = GetFolderIDList(NULL, 0);
CTempBuffer<ITEMIDLIST> idlist;
idlist.AllocateBytes(nBytes);
if ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0))
return;
// First bind to the desktop folder, then to the current folder.
ATL::CComPtr<IShellFolder> pDesktop, pFolder;
if (FAILED(::SHGetDesktopFolder(&pDesktop)))
return;
if (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder)))
return;
// Work through the file spec, looking for quoted filenames. If we find a shortcut file, then
// we need to add enough extra buffer space to hold its target path.
DWORD nExtraChars = 0;
bool bInsideQuotes = false;
LPCTSTR pAnchor = m_ofn.lpstrFile;
LPCTSTR pChar = m_ofn.lpstrFile;
for ( ; *pChar; ++pChar)
{
// Look for quotation marks.
if (*pChar == _T('\"'))
{
// We are either entering or leaving a passage of quoted text.
bInsideQuotes = !bInsideQuotes;
// Is it an opening or closing quote?
if (bInsideQuotes)
{
// We found an opening quote, so set "pAnchor" to the following character.
pAnchor = pChar + 1;
}
else // closing quote
{
// Each quoted entity should be shorter than MAX_PATH.
if (pChar - pAnchor >= MAX_PATH)
return;
// Get the ID-list and attributes of the file.
USES_CONVERSION;
int nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor);
TCHAR szFileName[MAX_PATH];
SecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength);
LPITEMIDLIST pidl = NULL;
DWORD dwAttrib = SFGAO_LINK;
if (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib)))
{
// Is it a shortcut file?
if (dwAttrib & SFGAO_LINK)
{
// Bind to its IShellLink interface.
ATL::CComPtr<IShellLink> pLink;
if (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink)))
{
// Get the shortcut's target path.
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0)))
{
// If the target path is longer than the shortcut name, then add on the number
// of extra characters that are required.
int nNewLength = lstrlen(szPath);
if (nNewLength > nFileNameLength)
nExtraChars += nNewLength - nFileNameLength;
}
}
}
// Free the ID-list returned by ParseDisplayName.
::CoTaskMemFree(pidl);
}
}
}
}
// If we need more space for shortcut targets, then reallocate.
if (nExtraChars > 0)
ATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars));
}
// Helper for _ATM_MIN_CRT
static const TCHAR* _strrchr(const TCHAR* p, TCHAR ch)
{
#ifndef _ATL_MIN_CRT
return _tcsrchr(p, ch);
#else // _ATL_MIN_CRT
const TCHAR* lpsz = NULL;
while (*p != 0)
{
if (*p == ch)
lpsz = p;
p = ::CharNext(p);
}
return lpsz;
#endif // _ATL_MIN_CRT
}
};
class CMultiFileDialog : public CMultiFileDialogImpl<CMultiFileDialog>
{
public:
CMultiFileDialog(
LPCTSTR lpszDefExt = NULL,
LPCTSTR lpszFileName = NULL,
DWORD dwFlags = OFN_HIDEREADONLY,
LPCTSTR lpszFilter = NULL,
HWND hWndParent = NULL)
: CMultiFileDialogImpl<CMultiFileDialog>(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
{ }
BEGIN_MSG_MAP(CMultiFileDialog)
CHAIN_MSG_MAP(CMultiFileDialogImpl<CMultiFileDialog>)
END_MSG_MAP()
};
#endif // !_WIN32_WCE
///////////////////////////////////////////////////////////////////////////////
// Shell File Dialog - new Shell File Open and Save dialogs in Vista
// Note: Use GetPtr() to access dialog interface methods.
// Example:
// CShellFileOpenDialog dlg;
// dlg.GetPtr()->SetTitle(L"MyFileOpenDialog");
#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
///////////////////////////////////////////////////////////////////////////////
// CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl
template <class T>
class ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents
{
public:
// Operations
INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
{
INT_PTR nRet = -1;
T* pT = static_cast<T*>(this);
if(pT->m_spFileDlg == NULL)
{
ATLASSERT(FALSE);
return nRet;
}
DWORD dwCookie = 0;
pT->_Advise(dwCookie);
HRESULT hRet = pT->m_spFileDlg->Show(hWndParent);
if(SUCCEEDED(hRet))
nRet = IDOK;
else if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED))
nRet = IDCANCEL;
else
ATLASSERT(FALSE); // error
pT->_Unadvise(dwCookie);
return nRet;
}
bool IsNull() const
{
const T* pT = static_cast<const T*>(this);
return (pT->m_spFileDlg == NULL);
}
// Operations - get file path after dialog returns
HRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength)
{
T* pT = static_cast<T*>(this);
ATLASSERT(pT->m_spFileDlg != NULL);
ATL::CComPtr<IShellItem> spItem;
HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
if(SUCCEEDED(hRet))
hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength);
return hRet;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?