打印本文 打印本文 关闭窗口 关闭窗口
仿Explorer的目录树视图类
作者:武汉SEO闵涛  文章来源:敏韬网  点击数5113  更新时间:2009/4/25 0:44:57  文章录入:mintao  责任编辑:mintao
{
 CTreeCtrl* pCtrl = (CTreeCtrl*) lParamSort;

 LPFOLDERNODE lpfn1 = (LPFOLDERNODE)lParam1;
 LPFOLDERNODE lpfn2 = (LPFOLDERNODE)lParam2;
 if(lpfn1 == NULL || lpfn2 == NULL) return 0;

 // 虚拟文件夹排在前面,并且不改变原顺序
 if((lpfn1->dwAttributes & SFGAO_FILESYSTEM) == 0 &&
  (lpfn2->dwAttributes & SFGAO_FILESYSTEM) == 0)
  return 0;
 else if((lpfn1->dwAttributes & SFGAO_FILESYSTEM) == 0)
  return -1;
 else if((lpfn2->dwAttributes & SFGAO_FILESYSTEM)==0)
  return 1;
 // 真正的文件夹排在虚拟文件夹之后,且按字母顺序(不区分大小写)
 else if((lpfn1->dwAttributes & SFGAO_FOLDER) &&
  (lpfn1->dwAttributes & SFGAO_FOLDER))
  return stricmp(lpfn1->cPath, lpfn2->cPath);
 else if(lpfn1->dwAttributes & SFGAO_FOLDER)
  return -1;
 else if(lpfn2->dwAttributes & SFGAO_FOLDER)
  return 1;
 else
  // 其它的排在最后面,按字母序(不区分大小写)
  return stricmp(lpfn1->cPath, lpfn2->cPath);
}

// AttachFolders unconditionally attaches child folders to the
// node passed in Node. If there are any, it also starts a thread
// to watch for changes in the tree structure.
BOOL CShellFolderView::AttachFolders(HTREEITEM hNode)
{
 CWaitCursor   cur; // 显示等待光标
 BOOL  bRet = FALSE;

 BOOL bChildren = TRUE;
 CTreeCtrl& tree = GetTreeCtrl();
 tree.SetRedraw(FALSE);    // 禁止控件更新窗口,以免插入时闪烁
 //tree.EnableWindow(FALSE);

 CString strPath = GetPath(hNode); // The full path for the node.
 LPFOLDERNODE  lpfn = (LPFOLDERNODE)tree.GetItemData(hNode);

 // If the node being expanded is a root, get the volume serial number
 // and lop off the backslash.
 if(strPath.GetLength() <= 3)
 {
  lpfn->Vol_Ser = GetVol_Ser(strPath);
 }

 // Enumerate the folder''''s contents.
 IEnumIDList*    pEnum = NULL;
 if(lpfn->pShellFolder->EnumObjects(m_hWnd, SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN,
  &pEnum) == NOERROR)
 {
  bChildren = FALSE;
  pEnum->Reset();      // Reset the enumerate interface
  ULONG   u = 1;       // Enumerate context.
  LPITEMIDLIST   lpidlChild = NULL;
  while(pEnum->Next(1, &lpidlChild, &u) == NOERROR)
  {
   // 为每个PIDL创建对应的树结点(包含其中的虚拟文件夹)
   HTREEITEM  hChild = CreateFolderNode(lpidlChild, hNode, TRUE);
   // 释放PIDL
   m_pMalloc->Free(lpidlChild);
   if(hChild != NULL)
   {
    // 调整结点的类型
    bChildren = TRUE;
    LPFOLDERNODE  lpfnChild = (LPFOLDERNODE)tree.GetItemData(hChild);
    switch(lpfnChild->fType)
    {
    case ftMyComputer:
    case ftNetNode:
     lpfnChild->Vol_Ser = GetVol_Ser(lpfnChild->cPath);
     break;
    default:
     lpfnChild->Vol_Ser = lpfn->Vol_Ser;
     bRet = TRUE;
     break;
    }
   }
  }
  // 释放枚举接口
  pEnum->Release();
 }
 // 调整父结点的属性
 TVITEM tvi;
 tvi.mask = TVIF_CHILDREN;
 tvi.cChildren = bChildren?1:0;
 tvi.hItem = hNode;
 tree.SetItem(&tvi);

 // Alphabetize the nodes, unless the parent is MyComputer or
 // Network Neighborhood.
 switch(lpfn->fType)
 {
 case ftMyComputer:
 case ftNetworkNeighborhood:
  break;
 default:{   // 排序所有子结点(根据给定的回调函数)
  TVSORTCB tvs;
  tvs.hParent = hNode;
  tvs.lpfnCompare = ShortItemProc;
  tvs.lParam = (LPARAM)&tree;
  tree.SortChildrenCB(&tvs);
  }break;
 }

 if(bRet)
 {
  // 如果还没有的话,则启动一个线程,开始监视该文件夹的变化
  if(lpfn->pMonitorThread == NULL)
  {
   lpfn->pMonitorThread = new CFolderChangeMonitor(strPath, m_hWnd, (WPARAM)hNode);
  }
 }

 // 可以更新窗口了
 tree.SetRedraw(TRUE);
// tree.EnableWindow(TRUE);
 return bRet;
}

// This routine is used only for diskettes. It returns the volume serial
// number of a disk in the drive--if there is no disk there, it returns
// -1. It''''s used whenever the user clicks on a node, to determine whether
// he has swapped diskettes, necessitating a discard of all nodes for the
// affected drive.
// For volumes other than diskettes, it returns a dummy value of 1,
// as -1 is used to signify a diskette drive that isn''''t loaded.
LONG CShellFolderView::GetVol_Ser(LPCTSTR strDriver)
{
 LONG result = -1;

 // If there is no path it''''s My Computer -- exit now
 if(strlen(strDriver) == 0)
  return result;

 // If the driver isn''''t removeable, we dont have to do this
 CString strPath = strDriver[0] + ":\\";
 strPath.MakeLower();

 if(::GetDriveType(strPath) != DRIVE_REMOVABLE)
 {
  result = 1;
  return result;
 }
 // I f there''''s no disk in the drive, bail out with a result = -1.
 DWORD dwVSN, dwMCL, dwFSF;
 if(GetVolumeInformation(strPath, NULL, 0, &dwVSN, &dwMCL, &dwFSF, NULL, 0))
 {
  result = (LONG) dwVSN;
 }
 else
  result = -1;
 return result;
}

// ShowDesktop is performed when Create posts a WM_SHOWDESKTOP
// message, so we see the correct value of fFolderOptions.
void CShellFolderView::ShowDesktop()
{
 CTreeCtrl&  tree = GetTreeCtrl();

 PATHINFO  PathInfo;
 GetSpecialFolder(CSIDL_DESKTOP, &PathInfo);
 //strDesktopPath = PathInfo.cPath;

 // 创建桌面这个根结点
 HTREEITEM hDesktop = CreateFolderNode(PathInfo.pidl, NULL, TRUE);
 LPFOLDERNODE lpfn = (LPFOLDERNODE)tree.GetItemData(hDesktop);
 FILEPATHLIST  fpl;
 GetLongFilePath(lpfn->pShellFolder, lpfn->pidl, &fpl);
 tree.SetItemText(hDesktop, fpl.cNormal);
 strcpy(lpfn->cPath , PathInfo.cPath);
 lpfn->fType = ftDesktop;

 // 展开桌面
 AttachFolders(hDesktop);

 tree.Expand(hDesktop, TVE_EXPAND);
}

// 展开指定的结点,如果需要的话,附加创建其下子结点
int CShellFolderView::Expand(HTREEITEM hNode, UINT nCode)
{
 if(GetTreeCtrl().GetChildItem(hNode) == NULL)
 {
  AttachFolders(hNode);
 }
 return GetTreeCtrl().Expand(hNode, nCode);
}

// 将路径转化为PIDL,如果失败,返回NULL
LPITEMIDLIST  PathToIDList(LPCTSTR lpszPath)
{
 OLECHAR  szOleStr[MAX_PATH];
 IShellFolder* pDesktop = NULL;
 LPITEMIDLIST  lpidl = NULL;
 // 使用桌面的IShellFolder来转换,这将生成一个绝对的PIDL
 if(SHGetDesktopFolder(&pDesktop) != NOERROR)
  return NULL;

 // 将路径转换成宽字符格式
 MultiByteToWideChar(CP_A

上一页  [1] [2] [3] [4] [5] [6]  下一页

打印本文 打印本文 关闭窗口 关闭窗口