// localDirView.cpp : implementation file // #include "stdafx.h" #include "myFtpClient.h" #include "localDirView.h" #include "MainFrm.h" #include "myftpclientview.h" #include "myFtpClientDoc.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define DRAG_DELAY 60 ///////////////////////////////////////////////////////////////////////////// // localDirView IMPLEMENT_DYNCREATE(localDirView, CTreeView) localDirView::localDirView() { m_bDragging = false; } localDirView::~localDirView() { } BEGIN_MESSAGE_MAP(localDirView, CTreeView) //{{AFX_MSG_MAP(localDirView) ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding) ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // localDirView drawing void localDirView::OnDraw(CDC* pDC) { CMyFtpClientDoc * pDoc = GetDocument(); // TODO: add draw code here } CMyFtpClientDoc* localDirView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyFtpClientDoc))); return (CMyFtpClientDoc*)m_pDocument; } ///////////////////////////////////////////////////////////////////////////// // localDirView diagnostics #ifdef _DEBUG void localDirView::AssertValid() const { CTreeView::AssertValid(); } void localDirView::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // localDirView message handlers void localDirView::OnInitialUpdate() { CTreeView::OnInitialUpdate(); CTreeCtrl &Tree = GetTreeCtrl(); LPSHELLFOLDER lpsf = NULL; LPITEMIDLIST lpi = NULL; HRESULT hr; TV_ITEM tvi; char szPath[MAX_PATH]; 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; m_curItem = hParent = GetTreeCtrl().InsertItem(&tvis); FillTreeView(lpsf,NULL,hParent); GetTreeCtrl().Expand(hParent,TVE_EXPAND); if(SHGetPathFromIDList(lpi ,szPath)) { g_path_selected.Format("%s",szPath); } lpsf->Release(); } } bool localDirView::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 localDirView::FillTreeView(LPSHELLFOLDER lpsf, LPITEMIDLIST lpifq, HTREEITEM hParent) { TV_ITEM tvi; // 树形视图的结点 TV_INSERTSTRUCT tvins; // 树形视图插入结点的结构体 HTREEITEM hPrev = NULL; //插入结点的父结点句柄 LPENUMIDLIST lpe=NULL; LPITEMIDLIST lpi=NULL, lpiTemp=NULL, lpifqThisItem=NULL; LPTVITEMDATA lptvid=NULL; LPMALLOC lpMalloc=NULL; ULONG ulFetched; HRESULT hr; char szBuff[256]; LPSHELLFOLDER lpsfsub = lpsf; HWND hwnd=::GetParent(m_hWnd); //分配一个shell内存对象 m_curLpsf = lpsf; m_curLpifq = lpifq; m_curItem = hParent; 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; } hr=lpsfsub->EnumObjects(hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &lpe); 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; 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 localDirView::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; } LPITEMIDLIST localDirView::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; } //得到参数列表的长度 UINT localDirView::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 localDirView::Next(LPCITEMIDLIST pidl) { LPSTR lpMem=(LPSTR)pidl; lpMem+=pidl->mkid.cb; return (LPITEMIDLIST)lpMem; } BOOL localDirView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Add your specialized code here and/or call the base class cs.style |= TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT|TVS_EDITLABELS; return CTreeView::PreCreateWindow(cs); } void localDirView::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView; pNMTreeView = (NM_TREEVIEW*)pNMHDR; LPTVITEMDATA lptvid; HRESULT hr; LPSHELLFOLDER lpsf=NULL; static char szBuff[MAX_PATH]; char szPath[MAX_PATH]; if ((pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE)) return; lptvid=(LPTVITEMDATA)pNMTreeView->itemNew.lParam; m_curItem = pNMTreeView->itemNew.hItem; if (lptvid) { hr=lptvid->lpsfParent->BindToObject(lptvid->lpi, 0, IID_IShellFolder,(LPVOID *)&lpsf); if (SUCCEEDED(hr)) { FillTreeView(lpsf,lptvid->lpifq,pNMTreeView->itemNew.hItem); } if(SHGetPathFromIDList(lptvid->lpifq ,szPath)) { g_path_selected.Format("%s",szPath); CString wholepath; wholepath.Format ("%s",szPath); } } *pResult = 0; } void localDirView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; // TODO: Add your control notification handler code here LPTVITEMDATA lptvid; HRESULT hr; LPSHELLFOLDER lpsf=NULL; char szBuff[MAX_PATH]; char szPath[MAX_PATH]; if ((pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE)) return; lptvid=(LPTVITEMDATA)pNMTreeView->itemNew.lParam; m_curItem = pNMTreeView->itemNew.hItem; if (lptvid) { hr=lptvid->lpsfParent->BindToObject(lptvid->lpi, 0, IID_IShellFolder,(LPVOID *)&lpsf); if (SUCCEEDED(hr)) { FillTreeView(lpsf,lptvid->lpifq,pNMTreeView->itemNew.hItem); } if(SHGetPathFromIDList(lptvid->lpifq ,szPath)) { g_path_selected.Format("%s",szPath); } } GetTreeCtrl().Expand(pNMTreeView->itemNew.hItem,TVE_EXPAND); *pResult = 0; } void localDirView::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; *pResult = 0; //如果是无意拖动,则放弃操作 if( (GetTickCount() - m_dwDragStart) < DRAG_DELAY ) return; m_hItemDragS = pNMTreeView->itemNew.hItem; m_hItemDragD = NULL; //得到用于拖动时显示的图象列表 m_pDragImage = GetTreeCtrl().CreateDragImage( m_hItemDragS ); if( !m_pDragImage ) return; m_bDragging = true; m_pDragImage->BeginDrag ( 0,CPoint(8,8) ); CPoint pt = pNMTreeView->ptDrag; ClientToScreen( &pt ); m_pDragImage->DragEnter ( NULL,pt ); //"this"将拖动操作限制在该窗口 SetCapture(); m_nScrollTimerID = SetTimer( 2,40,NULL ); LPTVITEMDATA lptvid; //获取拖动文件的完整路径 char szPath[MAX_PATH]; lptvid=(LPTVITEMDATA)pNMTreeView->itemNew.lParam; CString fileCopy; if(SHGetPathFromIDList(lptvid->lpifq ,szPath)) { fileCopy.Format("%s",szPath); } m_copyName = fileCopy.Right(fileCopy.GetLength() - fileCopy.ReverseFind('\\') - 1); m_copyPath = fileCopy; } void localDirView::OnMouseMove(UINT nFlags, CPoint point) { HTREEITEM hItem; UINT flags; m_HoverPoint = point; CMainFrame* mFrm = (CMainFrame*)AfxGetMainWnd(); CMyFtpClientView *pEView = (CMyFtpClientView *)(mFrm->m_splitterWnd2.GetPane(0,1)); CRect rect; ::GetClientRect(AfxGetMainWnd()->GetSafeHwnd(),&rect); CPoint pt = point; ClientToScreen(&pt); CRgn listRgn,treeRgn; CRect listRt,treeRt; pEView->GetCtrlRect(&listRt); GetCtrlRect(&treeRt); listRgn.CreateRectRgn(listRt.left,listRt.top, listRt.right,listRt.bottom); treeRgn.CreateRectRgn(treeRt.left,treeRt.top, treeRt.right,treeRt.bottom); if( m_bDragging && (listRgn.PtInRegion(pt) || treeRgn.PtInRegion(pt) ) ) { CImageList::DragMove( pt ); CImageList::DragShowNolock( true ); } else { //鼠标经过时高亮显示 CImageList::DragShowNolock( false ); //避免鼠标经过时留下难看的痕迹 if( (hItem = GetTreeCtrl().HitTest(point,&flags)) != NULL ) { GetTreeCtrl().SelectDropTarget( hItem ); m_hItemDragD = hItem; } } } void localDirView::OnLButtonUp(UINT nFlags, CPoint point) { CMainFrame* mFrm = (CMainFrame*)AfxGetMainWnd(); CMyFtpClientView *pEView = (CMyFtpClientView *)(mFrm->m_splitterWnd2.GetPane(0,1)); if( m_bDragging ) { m_bDragging = FALSE; CImageList::DragLeave( this ); CImageList::EndDrag(); ReleaseCapture(); delete m_pDragImage; GetTreeCtrl().SelectDropTarget( NULL ); CPoint pt = point; ClientToScreen(&pt); CRgn listRgn; CRect listRt; pEView->GetCtrlRect(&listRt); listRgn.CreateRectRgn(listRt.left,listRt.top, listRt.right,listRt.bottom); if( listRgn.PtInRegion(pt) ) { pEView->putFile(m_copyPath, m_copyName); } } } void localDirView::GetCtrlRect(CRect *rt) { GetTreeCtrl().GetClientRect(rt); ClientToScreen(*rt); } void localDirView::Update() { HTREEITEM hNext; HTREEITEM hChild=GetTreeCtrl().GetChildItem(m_curItem);//获取所选节点子节点的句柄, while(hChild!=NULL) { hNext =GetTreeCtrl().GetNextItem(hChild,TVGN_NEXT); GetTreeCtrl().DeleteItem(hChild); hChild=hNext; } FillTreeView(m_curLpsf,m_curLpifq,m_curItem); }