Why this crashes? tiny code for listing all files

It doesn't crash immediately, the forloop lists a few file paths then this "Unhandled exception at 0x76F05608 in testpath.exe: Microsoft C++ exception: std::filesystem::filesystem_error at memory location 0x0044F8A8."

But it doesn't crash if its CSIDL_DESKTOP instead of CSIDL_PROGRAM_FILESX86
How to fix.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 #include <iostream>
#include <filesystem>
#include <shlobj.h>


#pragma comment(lib, "shell32.lib")


namespace fs = std::filesystem;


int main()
{
	CHAR programx86[MAX_PATH];
	HRESULT result = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_CURRENT, programx86);

	for (auto& p : fs::recursive_directory_iterator(programx86))
		{
			std::cout << p.path().u8string() << std::endl;
		}

}

If you try to run the code and you get error, make sure you have c++ --> Language --> language standard : c++ latest draft standard.
Thank you.
Last edited on
It's a filesystem_error that is being thrown, which is a type of C++ exception. Try putting a try-catch outside your for loop to catch the exception.

1
2
3
4
5
6
7
8
9
10
11
try
{
	for (auto& p : fs::recursive_directory_iterator(programx86))
	{
		std::cout << p.path().u8string() << std::endl;
	}
}
catch (const std::filesystem::filesystem_error& ex)
{
	std::cout << "Exception: " << ex.what() << '\n';
}


Once you know what the exception is, more troubleshooting might be possible.
Last edited on
Cool thanks!!!
i get this "Exception: recursive_directory_iterator::operator++: Accكs refusل."

so i guess the program has no premission to read the file or something, (i don't know im just a guessing newbie)
Do you have any idea what i should do next, either ignore those files or smth.
I don't really have a good idea for you to try. I can't test the code myself right now, but I might be able to later.

Well actually, instead of .what(), since that appears to print some jibberish, you could try ex.code() or ex.code().value() instead, which will print a windows error code.

https://en.cppreference.com/w/cpp/filesystem/recursive_directory_iterator/recursive_directory_iterator#Exceptions
It looks like one of the constructors for recursive_directory_iteration accepts a reference to a std::error_code, and this fills information in the error_code object instead of throwing an exception, which might be preferred.

You could also try looking in the file explorer around the last successfully printed path and any nearby parent or subdirectories to see if you get any sort of permission error when attempting to navigate.
Last edited on
Nice, so yeah you are right, it was this folder, C:\Program Files (x86)\Google\CrashReports

When i go there with explorer, box popped up and said click continue to authorize access. something like that.

and when i authorized, i run code again and this time no crash, so now im gonna have to figure out how to ignore such files somehow.
Hello neuronic,

I see that you figured out your problem, but when I tried it I could not duplicate the error.

After look into your code I did find this:
https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpatha?redirectedfrom=MSDN&f1url=%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(SHLOBJ_CORE%252FSHGetFolderPath);k(SHGetFolderPath);k(DevLang-C%252B%252B);k(TargetOS-Windows)%26rd%3Dtrue

And at the beginning it says "Deprecated. Gets the path of a folder identified by a CSIDL value."

Then it did not give me the answer I was hoping for.

I made some changes to your code so I could use it with the 2014 standards:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
//#include <filesystem>
#include <experimental/filesystem>
#include <shlobj.h>


//#pragma comment(lib, "shell32.lib")

//namespace fs = std::filesystem;
namespace fs = std::experimental::filesystem;


int main()
{
    int lineNum{ 1 };
    char programx86[MAX_PATH]/*{ "F:/VS 2017" }*/;
    HRESULT result = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_CURRENT, programx86);

    for (auto& p : fs::recursive_directory_iterator(programx86))
    {
        //if (lineNum == 21)break;

        std::cout << lineNum++ << ") " << p.path().u8string() << std::endl;
    }

    return 0;  // <--- Not required, but makes a good break point.
}

Line 7 may be included even if you do not. With MSVS 2017 it made no difference.

The if statement in the for loop I used to see how it worded because "C:\Program Files (x86)" listed 121,322 files. Then again my "C:\Program Files (x86)\Google\CrashReports" is an empty sub-directory, so I do not know if it would be a problem.

In line 16 I found that "CHAR" is not needed, but works. As you see I just used "char". If you remove the block comments you can initialize the variable to whatever path you want. I would also consider changing the name to "path" or initialPath" to better describe its use.

Since it is deprecated I put a comment on line 17 and it worked fine.

See what you think about it. Switch some of the comments and you can use it with the 2017 standards.

Andy
Hello neuronic,

Had an Idea this morning.

You wrote:

so now im gonna have to figure out how to ignore such files somehow.


This is 1 possibiality:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>
//#include <filesystem>
#include <experimental/filesystem>
//#include <shlobj.h>  // <--- No longer needed.

//#pragma comment(lib, "shell32.lib")  // <--- Should be part of the compile/linker includes.

//namespace fs = std::filesystem;
namespace fs = std::experimental::filesystem;

int main()
{
    const std::string excludeDir1{ "C:\\Program Files (x86)\\Google\\CrashReports" };
    //const std::string excludeDir2{ "" };  // <--- Put directory to exclude between the "".
    const std::string initialPath{ "C:\\Program Files (x86)\\Google" };  // <--- Remove the "const" if you want to input something different at run time. Changed variable name.

    int lineNum{ 1 };
    //HRESULT result = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_CURRENT, programx86);

    for (auto& p : fs::recursive_directory_iterator(initialPath))
    {
        //if (lineNum == 21)break; // <--- Used for testing. Comment or remove when finished.

        if (p != excludeDir1 /*|| p != excludeDir2*/)
        {
            std::cout << lineNum++ << ") " << p.path().u8string() << '\n';
        }
        //else // <--- Used for testing. Comment or remove when finished.
        //{
        //    system("pause");
        //}
    }

    return 0;  // <--- Not required, but makes a good break point.
}

Other than using a try/catch I am not sure how to detect a problem during run time.

Andy
 
for (auto& p : fs::recursive_directory_iterator(initialPath))


To ignore files/folders causing the exception, use directory_options::skip_permission_denied as option for recursive_directory_iterator.

See https://en.cppreference.com/w/cpp/filesystem/directory_options

 
for (auto& p : fs::recursive_directory_iterator(initialPath, fs::directory_options::skip_permission_denied))


Why use the experimental filesystem? This was a TR released in 2015 (TS 18822:2015) and was merged into C++17 with changes.

Last edited on
@seep;us,

To answer you questions.

I do not use "filesystem" often enough to know all that is available. What I do know is more based on the I see in post and responses. Any help link your link is appreciated.

In the beginning, as best as I remember, VS 2005 was the first IDE I started with and I have stuck with it since I am use to it.

So far I have found the the VS 2017 I use and VS 2019 that I have both have the minimum standard of 2014 with the 2017 standards as an option, but that is per program not a default that I know of.

I feel lucky if most people who are new the C++ are capable of using the 2011 standards with some using pre-2011 standards.

Andy
@seeplus .... thats just perfect right there, i was definitely not gonna be able to solve it on my own lol, amazing thanks.

also @Handy Andy i'm pretty sure that still wouldn't fix it cause the exception happens in the for loop condition. before the if statement is executed.
I've had problems with std::filesystem::recursive_directory_iterator() for at least a year which I was able to just ignore. So I was quite interested when I saw this solution, so much so I was going to ask how you were able to determine that when creating this object you could pass a second optional parameter.

Wrote the the question out, then I went to
https://en.cppreference.com/w/cpp/filesystem/recursive_directory_iterator/recursive_directory_iterator
there it was clearly listed as option #4. So this question helped me with my reading of cppreference. I'll be more careful when I look at the constructors in the future.

Thanks.
Last edited on
Topic archived. No new replies allowed.