?? shelltree.cpp
字號:
#include "stdafx.h"
#include "shelltree.h"
#include "shfileinfo.h"
#include "fpattern.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#pragma warning ( disable : 4711 )
////////////////////////////////////////////////////////////////////////////////
// CShellTree
//
CShellTree::CShellTree ()
{
m_flags = SHLT_FOLDERS;
}
CShellTree:: ~ CShellTree ()
{
}
BEGIN_MESSAGE_MAP (CShellTree, CTreeCtrl)
//{{AFX_MSG_MAP(CShellTree)
ON_MESSAGE (SHLT_GETFLAGS, OnGetFlags)
ON_MESSAGE (SHLT_MODIFYFLAGS, OnModifyFlags)
ON_MESSAGE (SHLT_MODIFYPATTERN, OnModifyPattern)
//}}AFX_MSG_MAP
END_MESSAGE_MAP ()
#pragma warning ( disable : 4100 )
LRESULT CShellTree::OnGetFlags (WPARAM wParam, LPARAM lParam)
{
return GetFlags ();
}
#pragma warning ( default : 4100 )
LRESULT CShellTree::
OnModifyFlags (WPARAM wParam, LPARAM lParam)
{
ModifyFlags (wParam, lParam);
return 0;
}
#pragma warning ( disable : 4100 )
LRESULT CShellTree::
OnModifyPattern (WPARAM wParam, LPARAM lParam)
{
ModifyPattern ((LPCTSTR) lParam);
return 0;
}
#pragma warning ( default : 4100 )
DWORD CShellTree::GetFlags ()
const
{
return m_flags;
}
void CShellTree::ModifyFlags (DWORD dwRemove, DWORD dwAdd)
{
DWORD flags = m_flags;
m_flags &= ~dwRemove;
m_flags |= dwAdd;
if (m_flags != flags)
PopulateTree ();
}
void CShellTree::
ModifyPattern (CString pattern)
{
CString part;
int pos, len = pattern.GetLength ();
m_patterns.RemoveAll ();
while ((pos = pattern.Find (_T (','))) != -1)
{
part = pattern.Left (pos);
if (!part.IsEmpty () && fpattern_isvalid (part))
{
m_patterns.AddTail (part);
}
len -= pos + 1;
pattern = pattern.Right (len);
}
if (pattern.IsEmpty () && fpattern_isvalid (pattern))
{
m_patterns.AddTail (pattern);
}
if (m_flags & SHLT_FILES)
PopulateTree ();
}
/****************************************************************************
*
* FUNCTION: PopulateTree()
*
* PURPOSE: Processes the File.Fill/RefreshTree command
*
****************************************************************************/
void CShellTree::
PopulateTree ()
{
LPSHELLFOLDER lpsf = NULL;
LPITEMIDLIST lpi = NULL;
HRESULT hr;
TV_SORTCB tvscb;
// Get a pointer to the desktop folder.
hr = SHGetDesktopFolder (&lpsf);
if (SUCCEEDED (hr))
{
// Initialize the tree view to be empty.
DeleteAllItems ();
// Fill in the tree view from the root.
FillTreeView (lpsf, NULL, TVI_ROOT);
//TunnelFillTree(lpsf, NULL, TVI_ROOT);
// Release the folder pointer.
lpsf->Release ();
}
tvscb.hParent = TVI_ROOT;
tvscb.lParam = 0;
tvscb.lpfnCompare = TreeViewCompareProc;
// Sort the items in the tree view
SortChildrenCB (&tvscb /*, FALSE */ );
HTREEITEM hItem;
hItem = GetRootItem ();
Expand (hItem, TVE_EXPAND);
Select (GetRootItem (), TVGN_CARET);
}
/****************************************************************************
*
* FUNCTION: PopulateTree()
*
* PURPOSE: Processes the File.Fill/RefreshTree command
* This overload has the ability to open from a
* special folderlocation like SHBrowseForFolder()
*
* WARNING: TunnelTree() will not work if you use a special
* folderlocation
*
****************************************************************************/
void CShellTree::PopulateTree (int nFolder)
{
LPSHELLFOLDER lpsf = NULL, lpsf2 = NULL;
LPITEMIDLIST lpi = NULL;
HRESULT hr;
TV_SORTCB tvscb;
// Get a pointer to the desktop folder.
hr = SHGetDesktopFolder (&lpsf);
if (SUCCEEDED (hr))
{
// Initialize the tree view to be empty.
DeleteAllItems ();
if (!SUCCEEDED (SHGetSpecialFolderLocation (
m_hWnd, nFolder, &lpi)))
{
lpi = NULL;
FillTreeView (lpsf, NULL, TVI_ROOT);
}
else
{
hr = lpsf->BindToObject (lpi,
0, IID_IShellFolder, (LPVOID *) & lpsf2);
if (SUCCEEDED (hr))
{
// Fill in the tree view from the root.
FillTreeView (lpsf2, lpi, TVI_ROOT);
lpsf2->Release ();
}
else
FillTreeView (lpsf, NULL, TVI_ROOT);
}
// Release the folder pointer.
lpsf->Release ();
}
tvscb.hParent = TVI_ROOT;
tvscb.lParam = 0;
tvscb.lpfnCompare = TreeViewCompareProc;
// Sort the items in the tree view
SortChildrenCB (&tvscb /*, FALSE */ );
HTREEITEM hItem;
hItem = GetRootItem ();
Expand (hItem, TVE_EXPAND);
Select (GetRootItem (), TVGN_CARET);
}
/****************************************************************************
*
* FUNCTION: FillTreeView( LPSHELLFOLDER lpsf,
* LPITEMIDLIST lpifq,
* HTREEITEM hParent)
*
* PURPOSE: Fills a branch of the TreeView control. Given the
* shell folder, enumerate the subitems of this folder,
* and add the appropriate items to the tree.
*
* PARAMETERS:
* lpsf - Pointer to shell folder that we want to enumerate items
* lpifq - Fully qualified item id list to the item that we are enumerating
* items for. In other words, this is the PIDL to the item
* identified by the lpsf parameter.
* hParent - Parent node
*
* COMMENTS:
* This function enumerates the items in the folder identifed by lpsf.
* Note that since we are filling the left hand pane, we will only add
* items that are folders and/or have sub-folders. We *could* put all
* items in here if we wanted, but that's not the intent.
*
****************************************************************************/
void CShellTree::
FillTreeView (LPSHELLFOLDER lpsf, LPITEMIDLIST lpifq, HTREEITEM hParent)
{
TV_ITEM tvi; // TreeView Item.
TV_INSERTSTRUCT tvins; // TreeView Insert Struct.
HTREEITEM hPrev = NULL; // Previous Item Added.
LPSHELLFOLDER lpsf2 = NULL;
LPENUMIDLIST lpe = NULL;
LPITEMIDLIST lpi = NULL, lpiTemp = NULL, lpifqThisItem = NULL;
LPTVITEMDATA lptvid = NULL;
LPMALLOC lpMalloc = NULL;
ULONG ulFetched;
UINT uCount = 0;
HRESULT hr;
TCHAR szBuff[256];
HWND hwnd =::GetParent (m_hWnd);
// Allocate a shell memory object.
hr =::SHGetMalloc (&lpMalloc);
if (FAILED (hr))
return;
if (SUCCEEDED (hr))
{
// Get the IEnumIDList object for the given folder.
hr = lpsf->EnumObjects (hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &lpe);
if (SUCCEEDED (hr))
{
// Enumerate throught the list of folder and non-folder objects.
while (S_OK == lpe->Next (1, &lpi, &ulFetched))
{
uCount++;
//Create a fully qualified path to the current item
//The SH* shell api's take a fully qualified path pidl,
//(see GetIcon above where I call SHGetFileInfo) whereas the
//interface methods take a relative path pidl.
ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER;
// Determine what type of object we have.
lpsf->GetAttributesOf (1, (const struct _ITEMIDLIST **) &lpi, &ulAttrs);
//:original if(ulAttrs & (SFGAO_HASSUBFOLDER | SFGAO_FOLDER))
if (m_flags & SHLT_FOLDERS && ulAttrs & SFGAO_FOLDER ||
m_flags & SHLT_FILES && !(ulAttrs & (SFGAO_FOLDER | SFGAO_LINK)) ||
m_flags & SHLT_LINKS && ulAttrs & SFGAO_LINK)
{
//We need this next if statement so that we don't add things like
//the MSN to our tree. MSN is not a folder, but according to the
//shell it has subfolders.
//:original if(ulAttrs & SFGAO_FOLDER)
{
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
//:original if(ulAttrs & SFGAO_HASSUBFOLDER)
if (ulAttrs & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER))
{
//This item has sub-folders, so let's put the + in the TreeView.
//The first time the user clicks on the item, we'll populate the
//sub-folders.
tvi.cChildren = 1;
tvi.mask |= TVIF_CHILDREN;
}
//Now get the friendly name that we'll put in the treeview.
if (!GetName (lpsf, lpi, SHGDN_NORMAL, szBuff))
goto Done; // Error - could not get friendly name.
if (!(ulAttrs & (SFGAO_FOLDER | SFGAO_LINK)))
{
POSITION pos = m_patterns.GetHeadPosition ();
if (pos)
{
CString pattern;
do
{
pattern = m_patterns.GetNext (pos);
if (fpattern_matchn (pattern, szBuff))
goto found;
}
while (pos);
goto next;
found:
;
}
}
//OK, let's get some memory for our ITEMDATA struct
lptvid = (LPTVITEMDATA) lpMalloc->Alloc (sizeof (TVITEMDATA));
if (!lptvid)
goto Done; // Error - could not allocate memory.
tvi.pszText = szBuff;
tvi.cchTextMax = MAX_PATH;
lpifqThisItem = ConcatPidls (lpifq, lpi);
//Now, make a copy of the ITEMIDLIST
lptvid->lpi = CopyITEMID (lpMalloc, lpi);
GetNormalAndSelectedIcons (lpifqThisItem, &tvi);
lptvid->lpsfParent = lpsf; //Store the parent folders SF
lpsf->AddRef ();
lptvid->lpifq = ConcatPidls (lpifq, lpi);
tvi.lParam = (LPARAM) lptvid;
// Populate the TreeVeiw Insert Struct
// The item is the one filled above.
// Insert it after the last item inserted at this level.
// And indicate this is a root entry.
tvins.item = tvi;
tvins.hInsertAfter = hPrev;
tvins.hParent = hParent;
// Add the item to the tree
hPrev = InsertItem (&tvins);
}
// Free this items task allocator.
lpMalloc->Free (lpifqThisItem);
lpifqThisItem = 0;
}
next:
lpMalloc->Free (lpi); //Free the pidl that the shell gave us.
lpi = 0;
}
if (!uCount)
{
tvi.hItem = hParent;
tvi.cChildren = 0;
tvi.mask = TVIF_HANDLE | TVIF_CHILDREN;
SetItem (&tvi);
}
}
}
else
return;
Done:
if (lpe)
lpe->Release ();
//The following 2 if statements will only be TRUE if we got here on an
//error condition from the "goto" statement. Otherwise, we free this memory
//at the end of the while loop above.
if (lpi && lpMalloc)
lpMalloc->Free (lpi);
if (lpifqThisItem && lpMalloc)
lpMalloc->Free (lpifqThisItem);
if (lpMalloc)
lpMalloc->Release ();
}
/****************************************************************************
*
* FUNCTION: GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem)
*
* PURPOSE: Gets the index for the normal and selected icons for the current item.
*
* PARAMETERS:
* lpifq - Fully qualified item id list for current item.
* lptvitem - Pointer to treeview item we are about to add to the tree.
*
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -