How to Change the Attributes of a Directory Through Visual C++

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

I have read such questions in many forums, but didn't see an exact and implemented solution, so I am here to explain different possible solutions in detail.

For example, if you want to remove the read-only attribute of a directory programmatically, one way is to use the DOS command 'attrib' with -r. You can run this command from your C++ code by using system().

system("attrib -r C:\\MyFolder\\*.* /S /D");

When you use system() to run a DOS command, the command prompt screen will open for a moment and close when the operation has completed. If you want to run a command but the command prompt screen remains invisible to the end user, you can use WinExec() with the SW_HIDE parameter.

WinExec("attrib -r C:\\MyFolder\\*.* /S /D", SW_HIDE);

Microsoft recommends that you use CreateProcess() instead of WinExec() because you cannot get as much control of your desired operation if you are using WinExec(), so it's better to use CreateProcess(). When you use ATTRIB, you must double quote any file names that contain white space or special characters.

Normally, the scripting engine sees double quotes as marking the beginning or end of a string. To include double quotes inside a double-quoted string, you need to escape them with backslashes. This tells the scripting engine that you want to include an actual quote character in the string. So, in C++ you would write

char* str = "attrib -r \"C:\\Program Files\\MyFolder\\*.*\" /D /S";

and now you can execute this command by using system(str) or WinExec(str,SW_HIDE).

To change the attribute of a file, there is a function named SetFileAttributes() available in the Windows API, but to change the attribute of a directory, there is no such function available; you have to do this yourself. To accomplish this task, you have to write a recursive function that will do this for all files and sub directories.

So, if you want to develop a generic solution, the most efficient and recommended way is to use the FindFirstFile() function with the FindNextFile() function to find all the files and sub directories in a directory. Then, use the SetFileAttributes() function to change the attributes of every file and sub directory one by one. For more information about these functions, please read in the MSDN library.

For a demonstration of this solution, I made a simple Win32 console project in Visual C++ .NET 2003. In the .cpp file, I write a function ChangeDirectoryAttribute() that takes the directory path as input and removes the read-only attribute of all the files and sub directories. This function first uses FindFirstFile() to get the handle of the first file or folder and then checks whether it is a file or directory. If it's a file, it just removes the read-only attribute; but, if it is a folder, you call this function recursively to change the attribute of that sub folder's files. Finally, you change the attribute of that folder itself. Otherwise, only the inner part of the folder's attribute will change but the folder itself's attribute remains unchanged.

// DirectoryAttributeChange.cpp : Defines the entry point for the
// console application.
//

#include "stdafx.h"
#include "windows.h"

void ChangeDirectoryAttribute(TCHAR* m_szFdPath)
{
   HANDLE hFile;                       // Handle to directory
   WIN32_FIND_DATA FileInformation;    // File information
   TCHAR m_szPath[MAX_PATH];
   TCHAR m_szFolderInitialPath[MAX_PATH];
   TCHAR wildCard[MAX_PATH] = "\\*.*";

   strcpy(m_szPath,m_szFdPath);
   strcpy(m_szFolderInitialPath,m_szFdPath);
   strcat(m_szFolderInitialPath,wildCard);

   hFile = ::FindFirstFile(m_szFolderInitialPath, &FileInformation);
   if(hFile != INVALID_HANDLE_VALUE)
   {
      do{
         if(FileInformation.cFileName[0] != '.')
         {
            strcpy(m_szPath,m_szFdPath);
            strcat(m_szPath,"\\");
            strcat(m_szPath,FileInformation.cFileName);
            if(FileInformation.dwFileAttributes &
               FILE_ATTRIBUTE_DIRECTORY)
            {
               //it is a sub directory
               ::SetFileAttributes(m_szPath,FILE_ATTRIBUTE_NORMAL);
               ChangeDirectoryAttribute(m_szPath);
            }
            else
            {
               //it is a file
               ::SetFileAttributes(m_szPath,FILE_ATTRIBUTE_NORMAL);
            }
         }
      }while(::FindNextFile(hFile, &FileInformation) == TRUE);
      // Close handle
      ::FindClose(hFile);
      DWORD dwError = ::GetLastError();
      if(dwError == ERROR_NO_MORE_FILES)
      {
         //Attributes successfully changed
      }
   }
}
int _tmain(int argc, _TCHAR* argv[])
{
   //method 1
   //char* str = "attrib -r \"C:\\Program Files\\MyFolder\\*.*\"
                  /D /S";
   //system(str);
   //WinExec(str,SW_HIDE);

   //method 2
   TCHAR m_szFolderPath[MAX_PATH] = "C:\\Program Files\\MyFolder";
   ChangeDirectoryAttribute(m_szFolderPath);
   ::SetFileAttributes(m_szFolderPath,FILE_ATTRIBUTE_NORMAL);

   return 0;
}


About the Author

Najam ul Hassan

I have done Masters in Computer Sciences and for last Six years, working in Visual C++ in different Software Houses. Keep programming in Visual C++ :)

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Chuze Fitness is a fast-growing fitness chain with over 21 locations spanning California, Arizona and Colorado. Chief information and marketing officer, Kris Peterson, explains why access to fast and reliable Wi-Fi is a "must have" service at their gyms and why they switched to Ruckus Cloud Wi-Fi. Chuze Fitness needed to provide a good user experience to the hundreds of guests streaming music, podcasts and videos as they worked out. They also needed to adequately cover their sprawling 20-40,000 square foot …

  • On-demand webcast Continuous integration and continuous deployment (CI/CD) allow DevOps teams to be more efficient. When starting from a production environment, the use of Microsoft SQL Server 2017 in Docker containers and Kubernetes clusters can facilitate a DevOps CI/CD pipeline. Using SQL Server tools also allows you to easily integrate core DevOps application lifecycle management practices to database development. Watch this on-demand presentation to learn how defining the database dependency as …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date