📄 shellctrls.h
字号:
#if !defined(AFX_SHELLCTRLS_H__20010531_6E5C_D354_4C09_0080AD509054__INCLUDED_)
#define AFX_SHELLCTRLS_H__20010531_6E5C_D354_4C09_0080AD509054__INCLUDED_
#pragma once
/////////////////////////////////////////////////////////////////////////////
// CShellBaseCtrl - A few controls that display shell data
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Copyright (c) 2001 Bjarke Viksoe.
//
// Thanks to Anatoly Ivasyuk for adding sorting to the controls.
// Idea from a WTL Explorer sample by Leon Finker.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name is included.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever. It's free, so don't hassle me about it.
//
// Beware of bugs.
//
#ifndef __cplusplus
#error ATL requires C++ compilation (use a .cpp suffix)
#endif
#ifndef __ATLAPP_H__
#error ShellCtrls.h requires atlapp.h to be included first
#endif
#ifndef __ATLCTRLS_H__
#error ShellCtrls.h requires atlctrls.h to be included first
#endif
#ifndef __ATLSHELLEXT_H__
#error ShellCtrls.h requires atlshellext.h to be included first
#endif
#if (_WIN32_IE < 0x0400)
#error ShellCtrls.h requires _WIN32_IE >= 0x0400
#endif
#include <shlobj.h>
// The PARAM data of all controls
typedef struct {
CComPtr<IShellFolder> spFolder;
CPidl pidlFull;
CPidl pidlNode;
DWORD dwAttribs;
} SHELLITEMINFO, *PSHELLITEMINFO;
// Shell styles for all controls
#define SCT_EX_NOFOLDERS 0x00000001
#define SCT_EX_NOFILES 0x00000002
#define SCT_EX_SHOWHIDDEN 0x00000004
#define SCT_EX_NOREADONLY 0x00000008
#define SCT_EX_LOCALCOMPUTER 0x00000010
#define SCT_EX_FILESYSTEMONLY 0x00000020
#define SCT_EX_NOROOT 0x00000040
/////////////////////////////////////////////////////////////////////////////
// Misc Shell methods
inline BOOL AtlGetFilePidl(LPCTSTR pstrFileName, LPITEMIDLIST* pidl)
{
ATLASSERT(!::IsBadStringPtr(pstrFileName, MAX_PATH));
ATLASSERT(pidl);
*pidl = NULL;
// Make sure the file name is fully qualified and in Unicode format.
TCHAR szFileName[MAX_PATH];
::GetFullPathName(pstrFileName, sizeof(szFileName)/sizeof(TCHAR), szFileName, NULL);
USES_CONVERSION;
LPOLESTR pwchPath = const_cast<LPOLESTR>(T2COLE(pstrFileName));
// Convert the path name into a PIDL relative to the desktop
CComPtr<IShellFolder> spFolder;
if( FAILED( ::SHGetDesktopFolder(&spFolder) ) ) return FALSE;
ULONG ulAttr;
if( FAILED(spFolder->ParseDisplayName(NULL, NULL, pwchPath, NULL, pidl, &ulAttr)) ) return FALSE;
return TRUE;
};
inline BOOL AtlGetShellPidl(LPCITEMIDLIST pidl, IShellFolder** ppFolder, LPITEMIDLIST* pidlRel)
{
ATLASSERT(pidl);
ATLASSERT(ppFolder);
ATLASSERT(pidlRel);
*ppFolder = NULL;
*pidlRel = NULL;
// Get the desktop folder as a starting point
CComPtr<IShellFolder> spFolder;
if( FAILED( ::SHGetDesktopFolder(&spFolder) ) ) return FALSE;
CPidl pidlMain;
pidlMain.Copy(pidl);
// Traverse each PIDL item and create a new IShellFolder for each of
// them. Eventually we get to the last IShellFolder object and is left
// with a simple (as opposed to complex) PIDL.
int nCount = pidlMain.GetCount();
while( --nCount > 0 ) {
// Get the next PIDL entry
CPidl pidlNext;
pidlNext.Attach( pidlMain.CopyFirstItem() );
if( pidlNext.IsEmpty() ) return FALSE;
// Bind to the folder specified in the new item ID list.
CComPtr<IShellFolder> spNextFolder;
if( FAILED( spFolder->BindToObject(pidlNext, NULL, IID_IShellFolder, (LPVOID*) &spNextFolder)) ) return FALSE;
spFolder = spNextFolder;
// Strip first PIDL entry and copy remaining
CPidl temp;
temp.Copy( pidlMain.GetNextItem() );
pidlMain.Attach(temp.Detach());
}
*ppFolder = spFolder.Detach();
*pidlRel = pidlMain.Detach();
return TRUE;
};
/////////////////////////////////////////////////////////////////////////////
// CShellBaseCtrl - Common shell control methods and properties
template< class T, typename TItem=int >
class CShellBaseCtrl
{
protected:
DWORD m_dwShellStyle;
public:
CShellBaseCtrl() : m_dwShellStyle(0UL)
{
}
void SetShellStyle(DWORD dwStyle)
{
m_dwShellStyle = dwStyle;
}
DWORD GetShellStyle() const
{
return m_dwShellStyle;
}
BOOL Populate(int csidl = CSIDL_DESKTOP)
{
CPidl pidl;
if( FAILED( ::SHGetSpecialFolderLocation(NULL, csidl, &pidl) ) ) return FALSE;
CComPtr<IShellFolder> spDesktop;
if( FAILED( ::SHGetDesktopFolder(&spDesktop) ) ) return FALSE;
return Populate(spDesktop, pidl, csidl == CSIDL_DESKTOP ? NULL : (LPCITEMIDLIST)pidl);
}
BOOL Populate(LPCTSTR pstrPath)
{
ATLASSERT(!::IsBadStringPtr(pstrPath,MAX_PATH));
USES_CONVERSION;
CComPtr<IShellFolder> spDesktop;
if( FAILED( ::SHGetDesktopFolder(&spDesktop) ) ) return FALSE;
CPidl pidl;
DWORD dwAttribs;
DWORD dwEaten;
LPCOLESTR pwstrPath = T2COLE(pstrPath);
if( FAILED( spDesktop->ParseDisplayName(NULL, NULL, const_cast<LPOLESTR>(pwstrPath), &dwEaten, &pidl, &dwAttribs) ) ) return FALSE;
return Populate(pidl);
}
BOOL Populate(LPCITEMIDLIST pidl)
{
CComPtr<IShellFolder> spFolder;
CPidl pidlItem;
if( !AtlGetShellPidl(pidl, &spFolder, &pidlItem) ) return FALSE;
return Populate(spFolder, pidl, pidlItem);
}
BOOL Populate(IShellFolder* pFolder, LPCITEMIDLIST pidlPath, LPCITEMIDLIST pidlNode)
{
ATLASSERT(pFolder);
ATLASSERT(pidlPath);
CComPtr<IShellFolder> spFolder;
DWORD dwAttribs = SFGAO_FILESYSANCESTOR | SFGAO_HASSUBFOLDER;
if( pFolder != NULL && !CPidl::PidlIsEmpty(pidlNode) ) {
// Get the new IShellFolder object
if( FAILED( pFolder->BindToObject(pidlNode, NULL, IID_IShellFolder, (LPVOID*)&spFolder) ) ) return 0;
// Get this folder's attributes
pFolder->GetAttributesOf(1, &pidlNode, &dwAttribs);
}
else {
// Folder is Desktop
if( FAILED( ::SHGetDesktopFolder(&spFolder) ) ) return FALSE;
dwAttribs = SFGAO_HASSUBFOLDER;
}
T* pT = static_cast<T*>(this);
return pT->_Populate(spFolder, pidlPath, dwAttribs);
}
BOOL GetItemPidl(TItem hItem, LPITEMIDLIST* pidl)
{
T* pT = static_cast<T*>(this);
pT;
ATLASSERT(::IsWindow(pT->m_hWnd));
ATLASSERT(pidl);
// NOTE: We can't really check the 'hItem' argument here because it may
// actually be 0 for some controls (i.e. ListView has 0 as index)
// so we need to rely on the argument being passed is a valid item!
*pidl = NULL;
DWORD_PTR lParam = pT->GetItemData(hItem);
if( lParam == NULL || lParam == -1 ) return FALSE;
PSHELLITEMINFO pItem = reinterpret_cast<PSHELLITEMINFO>(lParam);
*pidl = CPidl::PidlCopy(pItem->pidlFull);
return TRUE;
}
BOOL GetItemPath(TItem hItem, LPTSTR pstrPath)
{
ATLASSERT(!::IsBadWritePtr(pstrPath, MAX_PATH));
pstrPath[0]=_T('\0');
CPidl pidl;
if( !GetItemPidl(hItem, &pidl) ) return FALSE;
if( !::SHGetPathFromIDList(pidl, pstrPath) ) return FALSE;
return TRUE;
}
// Returns TRUE if PIDL should be filtered out...
BOOL _FilterItem(IShellFolder* pFolder, LPCITEMIDLIST pidl, DWORD& dwAttribs) const
{
ATLASSERT(pFolder);
ATLASSERT(pidl);
if( m_dwShellStyle == 0 && dwAttribs == 0 ) return FALSE;
dwAttribs |= SFGAO_DISPLAYATTRMASK | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR;
// A fix by Anatoly Ivasyuk to only query for limited attributes on a
// removable media (prevents floppy activity)...
DWORD dwRemovable = SFGAO_REMOVABLE;
pFolder->GetAttributesOf(1, &pidl, &dwRemovable);
if( dwRemovable & SFGAO_REMOVABLE ) dwAttribs &= ~SFGAO_READONLY;
pFolder->GetAttributesOf(1, &pidl, &dwAttribs);
// Filter some items
if( (m_dwShellStyle & SCT_EX_NOFOLDERS) && (dwAttribs & SFGAO_FOLDER) ) return TRUE;
if( (m_dwShellStyle & SCT_EX_NOFILES) && ((dwAttribs & SFGAO_FOLDER) == 0) ) return TRUE;
if( (m_dwShellStyle & SCT_EX_NOREADONLY) && (dwAttribs & SFGAO_READONLY) ) return TRUE;;
if( (m_dwShellStyle & SCT_EX_FILESYSTEMONLY) && ((dwAttribs & (SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR)) == 0) ) return TRUE;
return FALSE;
}
};
/////////////////////////////////////////////////////////////////////////////
// CShellTreeCtrl
class CShellTreeCtrl :
public CWindowImpl< CShellTreeCtrl, CTreeViewCtrl, CControlWinTraits >,
public CShellBaseCtrl< CShellTreeCtrl, HTREEITEM >
{
public:
typedef CWindowImpl< CShellTreeCtrl, CTreeViewCtrl, CControlWinTraits > parentClass;
BEGIN_MSG_MAP(CShellTreeCtrl)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_GETDISPINFO, OnGetDispInfo)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_DELETEITEM, OnDeleteItem)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_ITEMEXPANDING, OnItemExpanding)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
// Operations
BOOL SubclassWindow(HWND hWnd)
{
ATLASSERT(m_hWnd==NULL);
ATLASSERT(::IsWindow(hWnd));
BOOL bRet = parentClass::SubclassWindow(hWnd);
if( bRet ) _Init();
return bRet;
}
BOOL SelectPidl(LPCITEMIDLIST pidlTarget)
{
ATLASSERT(::IsWindow(m_hWnd));
// BUG: Assumes tree control's root is desktop!
CPidl pidlItem;
HTREEITEM hItem = GetRootItem();
ATLASSERT(hItem!=NULL);
while( !CPidl::PidlIsEmpty(pidlTarget) ) {
hItem = GetChildItem(hItem);
pidlItem.Attach( CPidl::PidlCopyFirstItem(pidlTarget) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -