Solved

Return filenames to ListBox from array

Posted on 2004-10-26
290 Views
Last Modified: 2012-06-27
I got some code from here and modified it to implement it myself in an MFC project I have.  I can't seem to get it to return the file names to my listbox.  What it seems to be doing is sending the address in memory of the pointer of the last file it looks at rather than returning the correct filenames.  Any ideas?

void Readcfgini()
{
      char **dirarray;
      char *scandir;

      scandir = "C:\\UI Code and Executable\\UIMFC\\UIMFC\\Debug\\programs";
      dirarray = 0;
      dirarray = ScanDir( scandir , 0);

      CString temp;
      for(int i=0;i<sizeof(dirarray);i++){

                  /*(int k[sizeof(dirarray)],j;
                  for(j=0;j<sizeof(dirarray);j++)
                  {
                        k[j]=(int)dirarray[j];
                        //cout<<i[j]<<" "; //output the ascii chars
                        temp.Format("%d", k[j]);
                  }*/


            temp.Format("%d", dirarray);
            m_list.AddString(temp);
}



}

char ** ScanDir(char* dirname, int indent)
{
    BOOL            fFinished;
    HANDLE          hList;
    TCHAR           szDir[MAX_PATH+1];
    WIN32_FIND_DATA FileData;
    char ** names = NULL;
    int count = 0 , maxnames = 0;


    // Get the proper directory path
    sprintf(szDir, "%s\\*", dirname);

    // Get the first file
    hList = FindFirstFile(szDir, &FileData);
    if (hList == INVALID_HANDLE_VALUE)
    {
        return NULL;     // No files, return empty list
    }
    else
    {
        // Traverse through the directory structure
        fFinished = FALSE;
        while (!fFinished)
        {
            // Make sure we have enough room in array to add another name
            if (count >= maxnames)
                 names = (char **)realloc(names, (maxnames+=1024)*sizeof(char*));

            // Check the object is a directory or not
            if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                if ((strcmp(FileData.cFileName, ".") != 0) &&
(strcmp(FileData.cFileName, "..") != 0))
                {
                      names[count] = (char *)malloc(strlen(FileData.cFileName)+2);
                      strcpy(names[count], FileData.cFileName);
                      // add a trailing slash to indicate directory
                      strcat(names[count], "\\");
                      count++;
                }
            }
            else
                        names[count++] = (FileData.cFileName);                  

            if (!FindNextFile(hList, &FileData))
            {
                if (GetLastError() == ERROR_NO_MORE_FILES)
                {
                    fFinished = TRUE;
                }
            }
        }
    }

    return names;
}
0
Question by:vivekpara
    7 Comments
     
    LVL 2

    Author Comment

    by:vivekpara
    I think its THIS line that is incorrect in some way...but I'm not sure how:

    names[count++] = (FileData.cFileName);  

    Or it could be something in my Readcfgini function that is returning the data to the listbox.

    Sigh!
    0
     
    LVL 86

    Assisted Solution

    by:jkr
    It is indded incorrect, since it only copies a pointer to the struct entry that is reused in the loop, thus having all pointers point to the string that was read last.. Try

    names[count++] = strdup(FileData.cFileName);  

    (you might need to #include <string.h>).

    Apart from that, since you mentioned MFC, you'd better use a CStringList for that, e.g.

     CStringList names;

     names.AddTail(CString(FileData.cFileName));
    0
     
    LVL 86

    Expert Comment

    by:jkr
    BTW, http://www.codeproject.com/dialog/searchfolders.asp ("Browse Folder dialog, search folder and all sub folders using C/C++") seems to really cover your issue.
    0
     
    LVL 39

    Expert Comment

    by:itsmeandnobodyelse
    jkr has it right. You need an allocation for names[count] and a string copy. Instead of strdup you also could repeat the sequence you have in the if branch:
     
           names[count] = (char *)malloc(strlen(FileData.cFileName)+1);
           strcpy(names[count++], FileData.cFileName);

    If you later want to change to C++ operator new (replacing malloc) and/or  C++ containers like CStringList, CStringArray or std::vector<string>, you shouldn't forget to replace strdup as well, as strdup uses malloc.
                         
    Regards, Alex
    0
     
    LVL 2

    Author Comment

    by:vivekpara
    I'm trying it, but it seemed easier to recode than to use the old stuff now.  Now how do I return file names in this new code, though?  What I need is a way to store it in the stringarray and then be able to loop through my collection to read each of the files.   I think my sizeof line will not work properly...but I'm not sure.  Also, my knowledge of handles is useless...so if you have any suggestions on how to use them properly...please interject.

          CStringArray astrPaths;
          LPCTSTR name = "C:\\UI Code and Executable\\UIMFC\\UIMFC\\Debug\\programs\\*.cfg";
          WIN32_FIND_DATA data;
          HANDLE fileHandle = FindFirstFile(name, &data);

          for(int i=0;i<sizeof(fileHandle);i++)
                {
                
                if(fileHandle == INVALID_HANDLE_VALUE) {

                      if(GetLastError() == ERROR_FILE_NOT_FOUND)
                      {
                      }
                      else
                      {
                            //astrPaths.Add((LPCTSTR)fileHandle);
                      }
                }
          }
    0
     
    LVL 39

    Accepted Solution

    by:
        CStringArray astrPaths;
         LPCTSTR name = "C:\\UI Code and Executable\\UIMFC\\UIMFC\\Debug\\programs\\*.cfg";
         WIN32_FIND_DATA data;
         HANDLE fileHandle = FindFirstFile(name, &data);

         while (fileHandle != INVALID_HANDLE_VALUE)
         {
                 astrPaths.Add(data.cFileName);
                 if (!FindNextFile(fileHandle, &data))
                       break;
         }
         DWORD err;
         if((err = GetLastError()) != ERROR_NO_MORE_FILES)
         {
               cout << "error = " << err << endl;
               return;
         }


    Regards, Alex


    0
     
    LVL 2

    Author Comment

    by:vivekpara
    This is what I ended up with:

    void Readcfgini()
    {
          
         CStringArray astrPaths;
         LPCTSTR name = "C:\\UI Code and Executable\\UIMFC\\UIMFC\\Debug\\programs\\*.txt";
         WIN32_FIND_DATA data;
         HANDLE fileHandle = FindFirstFile(name, &data);

         while (fileHandle != INVALID_HANDLE_VALUE)
         {
                 astrPaths.Add(data.cFileName);
                 m_list.AddString(data.cFileName);
                      
                 if (!FindNextFile(fileHandle, &data))
                       break;
         }
         DWORD err;
         if((err = GetLastError()) != ERROR_NO_MORE_FILES)
         {
               return;
         }


    }
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    How to run any project with ease

    Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
    - Combine task lists, docs, spreadsheets, and chat in one
    - View and edit from mobile/offline
    - Cut down on emails

    Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
    Article by: SunnyDark
    This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
    The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
    The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

    913 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    18 Experts available now in Live!

    Get 1:1 Help Now