/*/
目的: 向CTreeCtrl控件中按实际的磁盘目录结构添加节点;
设计方案: 不使用成员变量或全局变量,由回调函数机制完成;
单击按钮,执行通用函数EnumDirectoriesFiles,
EnumDirectoriesFiles能够递归扫描磁盘目录结构,
只要搜索到任何目录时,即执行一次参数二指定的回调函数,
实现与外部操作相关联,因为EnumDirectoriesFiles是通用函数,
所有操作控件的外部具体操作均在回调函数中完成;
因回调函数procEnumedDirectoriesFiles由EnumDirectoriesFiles自动调用,
故,为了能在回调函数中使用外部参数,如树控件、根节点对象等,
EnumDirectoriesFiles提供了最后三个指针类型的参数,单击按钮时
向此三个参数传递树控件对象、根节点对象的指针,EnumDirectoriesFiles
过程中向回调函数的最后三个参数传递这三个值,实现回调函数中可以使用
外部参数的目的。
问题: 现在通用函数EnumDirectoriesFiles可以正常完成其扫描所有层次的目录工作,
回调函数在每扫描到目录时被自动执行,向树列表中添加目录节点,但现在
的问题是不能实现按层次添加节点。
要求: 不要更改现行的设计方案。//*///枚举指定目录下所有子目录
void  EnumDirectoriesFiles
(
//待搜索的目标路径
const CString& directoryParent,  
//回调函数
void(*procEnumedDirectoriesFiles)(const CString& returnPath, const bool& returnIsDirectory, void* param1, void* param2, void* param3),
//以下三个参数为任意类型,目的在于调用方向本函数的参数二指定的回调函数提供后三个参数
void* param1ProcEnum,
void* param2ProcEnum,
void* param3ProcEnum 
 )
{
CFileFind lo_finder;
BOOL lb_rstFind = lo_finder.FindFile(directoryParent + "\\*.*"); 
CString ls_string("");
bool lb_isDir = false;
while(lb_rstFind)
{
lb_rstFind = lo_finder.FindNextFile();
if (lo_finder.IsDots())continue;    

if (lo_finder.IsDirectory())
//若为目录
{
lb_isDir = true; 
ls_string = lo_finder.GetFilePath();
if(procEnumedDirectoriesFiles!=NULL)
//执行回调函数
procEnumedDirectoriesFiles(ls_string, lb_isDir, param1ProcEnum, param2ProcEnum, param3ProcEnum);
//递归调用本函数实现搜索所有子目录
EnumDirectoriesFiles(lo_finder.GetFilePath(),  procEnumedDirectoriesFiles, param1ProcEnum, param2ProcEnum, param3ProcEnum);
}
}
ls_string.Empty();
ls_string.FreeExtra();
lo_finder.Close();
}//回调函数,实现向树列表中按层次添加目录节点
void procEnumedDirectoriesFiles(const CString& returnPath, const bool& returnIsDirectory, void* param1, void* param2, void* param3)
{
//第一个参数为CTreeCtrl控件的指针
CTreeCtrl* lo_pTreeCtrl = (CTreeCtrl*)param1;
//第二个参数为父节点的指针
HTREEITEM*  lo_pNodeParent =  (HTREEITEM* )(param2) ;
//向父节点添加新的子节点
HTREEITEM lo_childNode = lo_pTreeCtrl->InsertItem(returnPath, *lo_pNodeParent); 
//将父节点的指针指向新建的子节点
param2 = &lo_childNode; //问题可能就出在上一句。
}void CXmlTestDlg::OnButton1() 
{    
//搜索的目录
CString ls_dir;
ls_dir = "d:\\a";
//创建根节点
HTREEITEM  lo_parentItem ;
lo_parentItem = ctrl_tree.InsertItem(ls_dir, TVI_ROOT);
//枚举指定目录下所有子目录
//参数二指定了回调函数,目的在于向树列表控件中添加目录结构
EnumDirectoriesFiles(ls_dir,  procEnumedDirectoriesFiles, &ctrl_tree,  &lo_parentItem, NULL); 
}

解决方案 »

  1.   

    在递归函数里面用个层数变量即可弄个结构体FileInfo里面有个CString szFileName;
    int Layer;在外面维护一个FileInfo结构体的链表void  EnumDirectoriesFiles 

    //待搜索的目标路径 
    const CString& directoryParent,  
    //回调函数 
    void(*procEnumedDirectoriesFiles)(const CString& returnPath, const bool& returnIsDirectory, void* param1, void* param2, void* param3), 
    //以下三个参数为任意类型,目的在于调用方向本函数的参数二指定的回调函数提供后三个参数 
    void* param1ProcEnum, 
    void* param2ProcEnum, 
    void* param3ProcEnum 

    { //定义一个int NumOfLayer=0;
    CFileFind lo_finder; 
    BOOL lb_rstFind = lo_finder.FindFile(directoryParent + "\\*.*"); 
    CString ls_string(""); 
    bool lb_isDir = false; 
    while(lb_rstFind) 

    lb_rstFind = lo_finder.FindNextFile(); 
    if (lo_finder.IsDots())continue;    if (lo_finder.IsDirectory()) 
    //若为目录 

    lb_isDir = true; 
    ls_string = lo_finder.GetFilePath(); //在这里给链表的其中一个元素的szFileName=文件名或是目录名,层数Layer=NumOfLayer;if(procEnumedDirectoriesFiles!=NULL) 
    //执行回调函数 
    procEnumedDirectoriesFiles(ls_string, lb_isDir, param1ProcEnum, param2ProcEnum, param3ProcEnum); 
    //递归调用本函数实现搜索所有子目录 NumOfLayer++;//层数+1EnumDirectoriesFiles(lo_finder.GetFilePath(),  procEnumedDirectoriesFiles, param1ProcEnum, param2ProcEnum, param3ProcEnum); 


    ls_string.Empty(); 
    ls_string.FreeExtra(); 
    lo_finder.Close(); 
      

  2.   

    明白我的意思就好,procEnumedDirectoriesFiles其实没必要在EnumDirectoriesFiles 里面做,当你递归执行完毕后,就能获得一个Struct FileInfo或是DirInfo的链表了,然后变量那个链表,再一个个的插入。
    不知道你链表的使用熟不熟的struct FileInfo
    {
      CString szFileName;
      int Layer;
      struct *Next;
    }差不多就这样,各个文件名对应的层数都会记录在这个结构体并和文件名一一对应起来
      

  3.   

    其实,问题简化一下,如下:
    把回调函数procEnumedDirectoriesFiles中的代码全部剪切到EnumDirectoriesFiles中调用它的地方,
    就可以正常加载磁盘目录结构了。
    但拿到procEnumedDirectoriesFiles中就不行了。我总结了一下,其实就是对参数p2的更改赋值好像没有生效。。。如何解决这个问题呢?//枚举指定目录下所有子目录
    void  EnumDirectoriesFiles
    (
            //待搜索的目标路径
              const CString& directoryParent,  
             //回调函数
              void(*procEnumedDirectoriesFiles)(const CString& returnPath, const bool& returnIsDirectory, void* param1, void* param2, void* param3),
            //以下三个参数为任意类型,目的在于调用方向本函数的参数二指定的回调函数提供后三个参数
             void* param1ProcEnum,
            void* param2ProcEnum,
            void* param3ProcEnum 
     )
    {
    CFileFind lo_finder;
    BOOL lb_rstFind = lo_finder.FindFile(directoryParent + "\\*.*"); 
    CString ls_string("");
    bool lb_isDir = false;
    while(lb_rstFind)
    {
    lb_rstFind = lo_finder.FindNextFile();
    if (lo_finder.IsDots())continue;    

    if (lo_finder.IsDirectory())
    //若为目录
    {
    lb_isDir = true; 
    ls_string = lo_finder.GetFilePath();
    void* p1 = param1ProcEnum;
    void* p2 = param2ProcEnum;
    void* p3 = param3ProcEnum;   
    if(procEnumedDirectoriesFiles!=NULL)
    //执行回调函数
    procEnumedDirectoriesFiles(ls_string, lb_isDir, p1, p2, p3);  
    //递归调用本函数实现搜索所有子目录
    EnumDirectoriesFiles(lo_finder.GetFilePath(),  procEnumedDirectoriesFiles, p1, p2, p3);
    }
    }
    ls_string.Empty();
    ls_string.FreeExtra();
    lo_finder.Close();
    }
     
    //回调函数,实现向树列表中按层次添加目录节点
    void procEnumedDirectoriesFiles(const CString& ls_string, const bool& returnIsDirectory, void* p1, void* p2, void* p3)


      CTreeCtrl* lo_pTreeCtrl = (CTreeCtrl*)p1;  
    HTREEITEM*  lo_pNodeParent =  (HTREEITEM* )(p2) ;
    HTREEITEM lo_childNode = lo_pTreeCtrl->InsertItem(ls_string, *lo_pNodeParent);    
      p2 = &lo_childNode;
    }void CXmlTestDlg::OnButton1() 
    {    
    //搜索的目录
    CString ls_dir;
    ls_dir = "d:\\a";
    //创建根节点
    HTREEITEM  lo_parentItem ;
    lo_parentItem = ctrl_tree.InsertItem(ls_dir, TVI_ROOT);
    //枚举指定目录下所有子目录
    //参数二指定了回调函数,目的在于向树列表控件中添加目录结构
    EnumDirectoriesFiles(ls_dir,  procEnumedDirectoriesFiles, &ctrl_tree,  &lo_parentItem, NULL); 
    }
      

  4.   

    有vc6的朋友可以直接复制调试一下,看如何让p2的更改生效