📄 dirtree.cpp
字号:
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
说明:本类在编写时参考了Code Jockey所写的MFC扩展类CShellTree,
特此说明。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
//////////////////////////////////////////////////////////////////////
#include "fclstd.h"
#include "DirTree.h"
#include <shellapi.h>
//////////////////////////////////////////////////////////////////////
// 构造函数和析构函数
//////////////////////////////////////////////////////////////////////
CDirTree::CDirTree()
{
m_strCurDir[0] = '\0';
}
CDirTree::~CDirTree()
{
}
////////////////////////////////////////////////////////////////////////////
BOOL CDirTree::Create(CFBWnd* pParent,UINT nID)
{
if(pParent == NULL)return FALSE;
DWORD style = WS_VISIBLE| WS_CHILD| TVS_HASLINES | TVS_LINESATROOT |
TVS_HASBUTTONS | TVS_SHOWSELALWAYS |
CCS_NOPARENTALIGN|CCS_NODIVIDER|CCS_NORESIZE;
return CFBTreeView::Create(pParent,style,nID);
}
/////////////////////////////////////////////////////////////////////////////////////////////
BOOL CDirTree::OnCreate()
{
SHFILEINFO sfi;
LPSHELLFOLDER lpsf=NULL; //IShellFolder 接口指针
LPITEMIDLIST lpi=NULL; //ITEMIDLIST 结构指针
HRESULT hr;
TV_SORTCB tvscb; //TV_SORTCB 结构
//得到系统图像列表(系统图标)
HIMAGELIST himl = (HIMAGELIST)SHGetFileInfo((LPCSTR)"C:\\",
0,
&sfi,
sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
//拷贝之
HIMAGELIST him = ImageList_Duplicate(himl);
//将这个个图像列表分配给TreeCtrl
if (him)
SetImageList(him);
//图像列表背景透明
ImageList_SetBkColor(him,CLR_NONE);
// 得到桌面文件夹
hr=SHGetDesktopFolder(&lpsf);
if (SUCCEEDED(hr))
{
FillDirTree(lpsf,NULL,TVI_ROOT);//拼接目录树
lpsf->Release();// 释放IShellFolder接口指针.
}
//排序
tvscb.hParent = TVI_ROOT; //父节点
tvscb.lParam = 0; //自定义
tvscb.lpfnCompare = SortCBProc; //回调函数
SortChildrenCB(&tvscb); //排序
//展开根项目
HTREEITEM hItem;
hItem = GetRoot();
Expand(hItem,TVE_EXPAND);
return TRUE;
}
/****************************************************************************
*
* 函数: TreeViewCmpProc(LPARAM, LPARAM, LPARAM)
*
* 用途: 排列目录树的回叫函数
*
****************************************************************************/
int CALLBACK CDirTree::SortCBProc(LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort)
{
LPTVITEMDATA lptvid1=(LPTVITEMDATA)lparam1;
LPTVITEMDATA lptvid2=(LPTVITEMDATA)lparam2;
HRESULT hr;
hr = lptvid1->lpsfParent->CompareIDs(0,lptvid1->lpi,lptvid2->lpi);
if (FAILED(hr))
return 0;
return (short)SCODE_CODE(GetScode(hr));
}
/****************************************************************************
*
* 函数: FillDirTree( LPSHELLFOLDER lpsf,
* LPITEMIDLIST lpifq,
* HTREEITEM hParent)
*
* 用途: 拼装目录树
*
* 参数: lpsf - IShellFolder 接口指针.
* lpifq - TreeCtrl 的项目 ID 列表指针 (指向一个 ITEMIDLIST 结构).
* hParent - 父节点
*
****************************************************************************/
void CDirTree::FillDirTree(LPSHELLFOLDER lpsf,LPITEMIDLIST lpifq,HTREEITEM hParent)
{
TV_ITEM tvi; // TreeCtrl 项目的 TV_ITEM 结构.
TV_INSERTSTRUCT tvins; // TreeCtrl 插入项目的 TV_INSERTSTRUCT 结构.
HTREEITEM hPrev = NULL; // 上一个添加项目的句柄.
LPSHELLFOLDER lpsf2=NULL; //第二个 IShellFolder 接口指针
LPENUMIDLIST lpe=NULL; //IEnumIDList接口指针
LPITEMIDLIST lpi=NULL, lpiTemp=NULL, lpifqThisItem=NULL;
LPTVITEMDATA lptvid=NULL;
LPMALLOC lpMalloc=NULL;//IMalloc 指针
ULONG ulFetched;
UINT uCount=0;//计数
HRESULT hr;
char szBuff[_MAX_PATH];
HWND hwnd = GetParent(m_hWnd);//父窗口句柄
// 分配 shell 内存对象.
hr = SHGetMalloc(&lpMalloc);
if (FAILED(hr))
return;
// 得到 IShellFolder 接口的 IEnumIDList 对象.
hr = lpsf->EnumObjects(hwnd, SHCONTF_FOLDERS /*| SHCONTF_NONFOLDERS */| SHCONTF_INCLUDEHIDDEN, &lpe);
if (SUCCEEDED(hr))//如果成功
{
while (S_OK == lpe->Next(1, &lpi, &ulFetched))
{
ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER;//属性: 文件夹和子文件夹
lpsf->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lpi, &ulAttrs);
if (ulAttrs & SFGAO_FOLDER)//如果是文件夹
{
tvi.mask= TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
if (ulAttrs & SFGAO_HASSUBFOLDER)//如果是子文件夹
{
tvi.cChildren=1;
tvi.mask |= TVIF_CHILDREN;
}
//为 ITEMDATA 结构分配内存
lptvid = (LPTVITEMDATA)lpMalloc->Alloc(sizeof(TVITEMDATA));
if (!lptvid)//如果失败
goto Done;
if (!GetName(lpsf, lpi, SHGDN_NORMAL, szBuff))//得到文件夹名
goto Done;
tvi.pszText = szBuff;
tvi.cchTextMax = _MAX_PATH;
lpifqThisItem = ConcatPidls(lpifq, lpi);
//拷贝 ITEMIDLIST 结构
lptvid->lpi = CopyITEMID(lpMalloc, lpi);
tvi.iImage = GetItemIcon(lpifqThisItem, SHGFI_PIDL |
SHGFI_SYSICONINDEX |
SHGFI_SMALLICON);
tvi.iSelectedImage = GetItemIcon(lpifqThisItem, SHGFI_PIDL |
SHGFI_SYSICONINDEX |
SHGFI_SMALLICON |
SHGFI_OPENICON);
lptvid->lpsfParent = lpsf; //保存父文件夹
lpsf->AddRef();
lptvid->lpifq = ConcatPidls(lpifq, lpi);
tvi.lParam = (LPARAM)lptvid;
//插入项目
tvins.item = tvi;
tvins.hInsertAfter = hPrev;
tvins.hParent = hParent;
hPrev = InsertItem(&tvins);
}
// 释放内存.
lpMalloc->Free(lpifqThisItem);
lpifqThisItem=0;
}
lpMalloc->Free(lpi);
lpi=0;
}
Done://打扫战场, 释放内存.
if (lpe)
lpe->Release();
if (lpi && lpMalloc)
lpMalloc->Free(lpi);
if (lpifqThisItem && lpMalloc)
lpMalloc->Free(lpifqThisItem);
if (lpMalloc)
lpMalloc->Release();
}
/****************************************************************************
*
* FUNCTION: TunnelTree(LPTSTR szFindPath)
*
* PURPOSE: Too crude to explain, just use it
*
* WARNING: Only works if you use the default PopTree()
* Not guaranteed to work on any future or existing
* version of windows. Use with caution. Pretty much
* ok if you're using on local drives
*
****************************************************************************/
void CDirTree::TunnelTree(LPCTSTR szFindPath)
{
HTREEITEM subNode = GetRoot();
LPTSTR szPathHop;
char szPath[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
char delimiter[]="\\";
int i = 0;
//CSHFileInfo checkPath(szFindPath);
//if(!checkPath.Exist())
// return;
ZeroMemory(szPath,_MAX_PATH);
lstrcpy(szPath,szFindPath);
i = lstrlen(szPath);
if(szPath[i-1] != '\\')
{
szPath[i] = '\\';
szPath[i+1] = '\0';
}
_splitpath(szPath,drive,dir,fname,ext);
//search the drive first
szPathHop=drive;
subNode = GetChildItem(subNode);
if(subNode)
{
if(SearchTree(subNode,szPathHop, SHELL_DRIVE))
{
//break down subfolders and search
char *p=strtok(dir,delimiter);
while(p)
{
subNode = (HTREEITEM)SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0);
subNode = GetChildItem(subNode);
if(SearchTree(subNode,p, SHELL_FOLDER))
p=strtok(NULL,delimiter);
else
p=NULL;
}
}
}
}
//===========================================================================
/****************************************************************************
*
* FUNCTION: SearchTree( HTREEITEM treeNode,
* LPTSTR szSearchName )
*
* PURPOSE: Too crude to explain, just use it
*
* WARNING: Only works if you use the default PopulateTree()
* Not guaranteed to work on any future or existing
* version of windows. Use with caution. Pretty much
* ok if you're using on local drives
*
****************************************************************************/
bool CDirTree::SearchTree(HTREEITEM treeNode,
LPTSTR szSearchName,
FindAttribs attr)
{
LPTVITEMDATA lptvid; //Long pointer to TreeView item data
LPSHELLFOLDER lpsf2=NULL;
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
bool bRet=false;
HRESULT hr;
char szPath[_MAX_PATH];
ZeroMemory(szPath,_MAX_PATH);
LPTSTR szCompare = szPath;
strupr(szSearchName);
while(treeNode && bRet==false)
{
lptvid=(LPTVITEMDATA)GetItemData(treeNode);
if (lptvid && lptvid->lpsfParent && lptvid->lpi)
{
hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
0,IID_IShellFolder,(LPVOID *)&lpsf2);
if (SUCCEEDED(hr))
{
ULONG ulAttrs = SFGAO_FILESYSTEM;
lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
if (ulAttrs & (SFGAO_FILESYSTEM))
{
if(SHGetPathFromIDList(lptvid->lpifq,szCompare))
{
switch(attr)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -