// DirTreeView.cpp : implementation file // #include "stdafx.h" #include "myExplorer.h" #include "DirTreeView.h" #include "MainFrm.h" #include "myexplorerView.h" #include "myExplorerDoc.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // DirTreeView CString DirTreeView::g_path_selected = ""; IMPLEMENT_DYNCREATE(DirTreeView, CTreeView) DirTreeView::DirTreeView() { } DirTreeView::~DirTreeView() { } BOOL DirTreeView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs //设置风格 cs.style |=TVS_EDITLABELS|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT; return CTreeView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // DirTreeView drawing ///////////////////////////////////////////////////////////////////////////// // DirTreeView printing BOOL DirTreeView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void DirTreeView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void DirTreeView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } void DirTreeView::OnInitialUpdate() { CTreeView::OnInitialUpdate(); CTreeCtrl &Tree=GetTreeCtrl(); LPSHELLFOLDER lpsf=NULL; //IShellFolder接口 LPITEMIDLIST lpi=NULL; //ITERMIDLSIT结构体指针 HRESULT hr; TV_ITEM tvi; CImageList m_Image;//记录的是与树型控件关联的图像列表 SHFILEINFO sfi;//存放文件信息的结构 HIMAGELIST sys_small_icon; sys_small_icon = (HIMAGELIST)SHGetFileInfo(NULL,0,&sfi,sizeof(sfi), SHGFI_SYSICONINDEX|SHGFI_SMALLICON); m_Image.Attach(sys_small_icon); Tree.SetImageList(&m_Image,TVSIL_NORMAL);//将系统图像列表设为树控件的图象列表 m_Image.Detach (); // 得到指向“桌面”的指针 hr=SHGetDesktopFolder(&lpsf); SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&lpi); if (SUCCEEDED(hr)) { Tree.DeleteAllItems(); char szBuff[MAX_PATH];//存放显示名称的缓冲区 TV_INSERTSTRUCT tvis; //向树型控件中插入节点时使用的结构 tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN ; //设置要插入的树节点信息 if(GetName(lpsf,lpi,SHGDN_NORMAL,szBuff)==FALSE) return; tvi.pszText = szBuff;//设置显示名称 GetNormalAndSelectedIcons(lpi, &tvi); tvis.item = tvi; tvis.hParent = TVI_ROOT; hParent = GetTreeCtrl().InsertItem(&tvis);//插入根节点 FillTreeView(lpsf, NULL, hParent); GetTreeCtrl().Expand (hParent,TVE_EXPAND);//展开“桌面”节点 lpsf->Release (); } } BEGIN_MESSAGE_MAP(DirTreeView, CTreeView) //{{AFX_MSG_MAP(DirTreeView) ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding) //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // DirTreeView drawing void DirTreeView::OnDraw(CDC* pDC) { CMyExplorerDoc* pDoc = (CMyExplorerDoc*)GetDocument(); // TODO: add draw code here } ///////////////////////////////////////////////////////////////////////////// // DirTreeView diagnostics #ifdef _DEBUG void DirTreeView::AssertValid() const { CTreeView::AssertValid(); } void DirTreeView::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // DirTreeView message handlers ///////////////////////////////////////////////////////////////////////////// // DirTreeView message handlers //得到所选对象在操作系统中的显示名称 BOOL DirTreeView::GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi, DWORD dwFlags, LPSTR lpFriendlyName) { BOOL bSuccess=TRUE; STRRET str; if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str)) { switch (str.uType) { case STRRET_WSTR: WideCharToMultiByte(CP_ACP, 0, str.pOleStr, -1, lpFriendlyName, MAX_PATH, NULL, NULL); break; case STRRET_OFFSET: lstrcpy(lpFriendlyName, (LPSTR)lpi+str.uOffset); break; case STRRET_CSTR: lstrcpy(lpFriendlyName, (LPSTR)str.cStr); break; default: bSuccess = FALSE; break; } } else bSuccess = FALSE; return bSuccess; } //树控件节点展开时,加入各个子节点的名称及图标 void DirTreeView::FillTreeView(LPSHELLFOLDER lpsf, LPITEMIDLIST lpifq, HTREEITEM hParent) { TV_ITEM tvi; // TreeView Item. TV_INSERTSTRUCT tvins; // TreeView Insert Struct. HTREEITEM hPrev = NULL; // Previous Item Added.// LPENUMIDLIST lpe=NULL; LPITEMIDLIST lpi=NULL, lpiTemp=NULL, lpifqThisItem=NULL; LPTVITEMDATA lptvid=NULL; LPMALLOC lpMalloc=NULL; ULONG ulFetched; HRESULT hr; char szBuff[256]; HWND hwnd=::GetParent(m_hWnd); //分配一个shell内存对象 hr=::SHGetMalloc(&lpMalloc); if (FAILED(hr)) return; //如果成功地分配了空间 if (SUCCEEDED(hr)) { hr=lpsf->EnumObjects(hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &lpe); if (SUCCEEDED(hr)) { //枚举出其中的文件夹 while (S_OK==lpe->Next(1, &lpi, &ulFetched)) { ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER; lpsf->GetAttributesOf(1, (LPCITEMIDLIST*) &lpi, &ulAttrs); if (ulAttrs & (SFGAO_HASSUBFOLDER | SFGAO_FOLDER)) { tvi.mask= TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; //如果有子文件夹 if (ulAttrs & SFGAO_HASSUBFOLDER) { tvi.cChildren=1; tvi.mask |= TVIF_CHILDREN; } lptvid = (LPTVITEMDATA)lpMalloc->Alloc(sizeof(TVITEMDATA)); if (!lptvid) goto Done; if (!GetName(lpsf, lpi, SHGDN_NORMAL, szBuff)) goto Done; //所插入项的名称 tvi.pszText = szBuff; lpifqThisItem=ConcatPidls(lpifq, lpi); lptvid->lpi=(LPITEMIDLIST)lpMalloc-> Alloc(lpi->mkid.cb+sizeof(lpi->mkid.cb)); CopyMemory((PVOID)lptvid->lpi, (CONST VOID *)lpi, lpi->mkid.cb+sizeof(lpi->mkid.cb)); GetNormalAndSelectedIcons(lpifqThisItem, &tvi); lptvid->lpsfParent=lpsf; lptvid->lpifq=ConcatPidls(lpifq, lpi); tvi.lParam = (LPARAM)lptvid; tvins.item = tvi; tvins.hInsertAfter = hPrev; tvins.hParent = hParent; //插入树的节点 hPrev = GetTreeCtrl().InsertItem(&tvins); } lpMalloc->Free(lpifqThisItem); lpifqThisItem=0; } lpMalloc->Free(lpi); return; } } else return; Done: if (lpe) lpe->Release(); if (lpi && lpMalloc) lpMalloc->Free(lpi); if (lpifqThisItem && lpMalloc) lpMalloc->Free(lpifqThisItem); if (lpMalloc) lpMalloc->Release(); } //得到文件对象在操作系统中的图标(包括普通样子及打开样子) void DirTreeView::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq,LPTV_ITEM lptvitem) { SHFILEINFO sfi; ZeroMemory(&sfi,sizeof(sfi)); UINT uFlags=SHGFI_PIDL|SHGFI_SYSICONINDEX|SHGFI_SMALLICON; SHGetFileInfo((LPCSTR)lpifq, 0,&sfi, sizeof(SHFILEINFO), uFlags); lptvitem->iImage=sfi.iIcon; uFlags|=SHGFI_OPENICON; SHGetFileInfo((LPCSTR)lpifq, 0,&sfi, sizeof(SHFILEINFO), uFlags); lptvitem->iSelectedImage=sfi.iIcon; return; } //当选中树控件的其它节点时要做的事情 void DirTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) { CMyExplorerDoc* pDoc = (CMyExplorerDoc*)GetDocument(); NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; TV_ITEM itm = pNMTreeView->itemNew; HTREEITEM hItem = pNMTreeView->itemNew.hItem; pDoc->PPathStack->Push( hItem ); CMainFrame* mFrm = (CMainFrame*)AfxGetMainWnd(); CMyExplorerView *filelist = (CMyExplorerView *)(mFrm->m_wndSplitter.GetPane(0,1)); CTreeCtrl &filetree=GetTreeCtrl(); LPTVITEMDATA lptvid; LPSHELLFOLDER lpsf=NULL; LPITEMIDLIST lpi=NULL; HRESULT hr; TCHAR szPath[MAX_PATH]; CString wholepath; CString addr_path; //要得到所选项的路径或是pidl if(itm.hItem !=NULL) { //判断是不是桌面,若是桌面,另行处理 SHGetDesktopFolder(&lpsf); SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&lpi); GetName(lpsf,lpi,SHGDN_NORMAL,szPath); //如果是“桌面”的话 addr_path=filetree.GetItemText (itm.hItem); if(szPath==addr_path) filelist->AddListItem (lpsf,lpi,itm.hItem); //如果不是“桌面” else { lptvid=(LPTVITEMDATA)itm.lParam; if (lptvid) { //lptvid->lpi为一个pidl hr=lptvid->lpsfParent->BindToObject(lptvid->lpi, 0, IID_IShellFolder,(LPVOID *)&lpsf); if (SUCCEEDED(hr)) { //可以得到树控件所选项的真实路径 if(SHGetPathFromIDList(lptvid->lpifq ,szPath)) { g_path_selected.Format("%s",szPath); CString wholepath; wholepath.Format ("%s",szPath); filelist->AddListItem (wholepath); } //树控件所选项为虚拟文件夹 else { filelist->AddListItem(lpsf,lptvid->lpifq,itm.hItem); lpsf->Release (); } } } } } *pResult = 0; } //树控件的节点展开 void DirTreeView::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; LPTVITEMDATA lptvid; HRESULT hr; LPSHELLFOLDER lpsf=NULL; if ((pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE)) return; lptvid=(LPTVITEMDATA)pNMTreeView->itemNew.lParam; if (lptvid) { hr=lptvid->lpsfParent->BindToObject(lptvid->lpi, 0, IID_IShellFolder,(LPVOID *)&lpsf); if (SUCCEEDED(hr)) { FillTreeView(lpsf,lptvid->lpifq,pNMTreeView->itemNew.hItem); } } *pResult = 0; } //得到下一个元素标识符列表指针 LPITEMIDLIST DirTreeView::Next(LPCITEMIDLIST pidl) { LPSTR lpMem=(LPSTR)pidl; lpMem+=pidl->mkid.cb; return (LPITEMIDLIST)lpMem; } //得到参数列表的长度 UINT DirTreeView::GetPidlSize(LPCITEMIDLIST pidl) { UINT cbTotal = 0; if (pidl) { cbTotal += sizeof(pidl->mkid.cb); // Null terminator while (pidl->mkid.cb) { cbTotal += pidl->mkid.cb; pidl = Next(pidl); } } return cbTotal; } //实现两个列表的串接 LPITEMIDLIST DirTreeView::ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { LPITEMIDLIST pidlNew; LPMALLOC lpMalloc; UINT cb1; UINT cb2; if (pidl1) cb1 = GetPidlSize(pidl1) - sizeof(pidl1->mkid.cb); else cb1 = 0; cb2 = GetPidlSize(pidl2); SHGetMalloc(&lpMalloc); pidlNew = (LPITEMIDLIST)lpMalloc->Alloc(cb1+cb2); if (pidlNew) { if (pidl1) memcpy(pidlNew, pidl1, cb1); memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2); } lpMalloc->Release (); return pidlNew; }