0

In my VC++ application, I am selecting a couple of text files by invoking File Explorer and using the GetFileAttributesW() API to retrieve file system attributes.

GetFileAttributesW() is failing to process, reporting a ‘system does not find the file specified’ error.

I know it is, because the file name exceeds MAX_PATH characters, which is 260 characters, but every file name count is less than 260 characters, and both of the file count exceeds 260 characters. Which means I have created 2 text files in the name of

erererererererertytytytytytytytyghjlmkjhnbvrevrnthgenothandbgelonhebgaqwebasdfghjklpoiuytrewqazsxdcfvgbhnjmklpoiuytrewqasdfghjklmnbvcxzasdfghjklpoiuytrewqasdfghjklmnbvcxzasdfghjklpoiuytrewqasdfghjk.txt

bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbg.txt

and selected both of the files.

Kindly refer to the source code below and assist me on this.

CFileDialog fd(TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT, NULL, CWnd::FromHandle(m_hWnd));

CString strTitle = L"test";
fd.m_ofn.lpstrTitle = (LPCTSTR)strTitle;

if (fd.DoModal() == IDOK)
{
    POSITION pos = fd.GetStartPosition();

    while (pos)
    {
        CString strFullPath(fd.GetNextPathName(pos));

        DWORD dwAttr = ::GetFileAttributesW(strFullPath);

        /// ////////////////////////////////////////////////////////////
        DWORD errorMessageID = ::GetLastError();

        LPSTR messageBuffer = nullptr;

        size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);

        std::string message(messageBuffer, size);

        LocalFree(messageBuffer);
        ///////////////////////////////////////////////////////////////
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
sivanesan1
  • 779
  • 4
  • 20
  • 44
  • 1
    _"...To extend this limit to 32,767 wide characters, call the Unicode version of the function (GetFileAttributesW), and prepend "\\?\" to the path..."_ https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesw – Richard Critten Jun 24 '22 at 05:13
  • 2
    "*the file name exceeds MAX_PATH characters*" - please read the documentation on MSDN, it explains why this limit exists and how to work around it: [Naming Files, Paths, and Namespaces](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file), and especially [Maximum Path Length Limitation](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation) – Remy Lebeau Jun 24 '22 at 05:18
  • @RemyLebeau I tried to prepend like CString strFullPath = L"\\?\\"; strFullPath += fd.GetNextPathName(pos); but it is not working – sivanesan1 Jun 24 '22 at 06:33
  • @sivanesan1 you are missing an (escaped) ```\``` character. You are prepending ```\?\``` rather than ```\\?\```. Use this instead: `CString strFullPath = L"\\\\?\\";` or you can use a raw-string literal instead: `CString strFullPath = LR"(\\?\)";` – Remy Lebeau Jun 24 '22 at 06:50
  • @RemyLebeau : i tried what you suggested, it is working fine if i select 1 file but throws error if i select 2 files which is mentioned in question.I dont know why it is throwing error if i select 2 files – sivanesan1 Jun 24 '22 at 07:08
  • @RemyLebeau : if the length of text file names are less and then it is working fine if i select multiple files also – sivanesan1 Jun 24 '22 at 07:10
  • @RemyLebeau : Because you cannot use the "\\?\" prefix with a relative path, relative paths are always limited to a total of MAX_PATH characters. This is what mentioned in msdn document – sivanesan1 Jun 24 '22 at 07:11
  • @sivanesan1 When you say it isn't working, what is the actual error you are getting? Please update your question to show the updated code you have tried that is not working for you. Don't ever use relative paths to access files, always use absolute paths. `fd.GetNextFilePath()` should be giving you absolute paths, regardless of how many files you have selected. Prepend ```\\?\``` to each path you retrieve. It should work fine, as long as you have permissions to access the files. `GetFileAttributesW()` will tell you when you don't. – Remy Lebeau Jun 24 '22 at 07:52
  • @RemyLebeau CFileDialog does not have member GetNextFilePath() – sivanesan1 Jun 24 '22 at 07:59
  • 1
    @sivanesan1 obviously, I meant `GetNextPathName()`, the one you are calling in your code. Also, something else to be aware of: [Why CFileDialog::GetNextPathName doesn't work when the file path is long?](https://stackoverflow.com/questions/14903496/) – Remy Lebeau Jun 24 '22 at 08:18

1 Answers1

0

After long analysis i found answer for this. Here there is problem with GetNextPathName API

#define MAX_FILE_NAMES 10000
CString data;
fd.m_pOFN->nMaxFile = (MAX_FILE_NAMES*(MAX_PATH+1))+1;
fd.m_pOFN->lpstrFile = data.GetBuffer((MAX_FILE_NAMES*(MAX_PATH+1))+1);
data.ReleaseBuffer();
sivanesan1
  • 779
  • 4
  • 20
  • 44