Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a file when file path name is over 255 characters using MFC in Windows?

I am working in Windows,using vc++2010 and MFC.

Following is my code:

CFile File;
TCHAR lpCause[1024];
CFileException eException;
CString strErrorMessage;
//  a very long file path name means a file name over 255 characters
if (!File.Open(_T("a very long file path name"), CFile::modeCreate, &eException))
{
    eException.GetErrorMessage(lpCause, 1024);
    strErrorMessage = lpCause;
}
else
    File.Close();

When I run the code, I got error message:"a very long file path name contains an incorrect path".

My questions are:

  1. How to modify my code to make it work?
  2. I learn that CreateFile() function can add "\\\\?\" in the beginning of file path, then it will extend this limit to 32767 wide characters.How can I do the same thing in MFC?
like image 898
zet Avatar asked Mar 14 '18 08:03

zet


1 Answers

Cause

In the source of CFile::Open(), there is an explicit check if the path length exceeds _MAX_PATH:

if (lpszFileName != NULL && SUCCEEDED(StringCchLength(lpszFileName, _MAX_PATH, NULL)) )

If _MAX_PATH is exceeded, the function sets pException->m_cause = CFileException::badPath and returns FALSE.

This is true even for the MFC version that comes with VS2017.

So the standard technique to circumvent the _MAX_PATH limit, that is prefixing the path with \\?\ won't work.

Possible Solutions

Call CreateFileW() directly to pass it a path with \\?\ prefix. Use the CFile constructor that accepts a HANDLE to manage the file through a CFile object. The CFile object will take ownership of the handle so you must not call CloseHandle() on the handle.

HANDLE hFile = CreateFileW( L"\\\\?\\a very long file path name", GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, NULL );
if( hFile != INVALID_HANDLE_VALUE )
{
    // Manage the handle using CFile
    CFile file( hFile );
    // Use the file...

    // The CFile destructor closes the handle here. 
}
else
{
    DWORD err = GetLastError();
    // TODO: do your error handling...
}

Another possibility is to derive a class from CFile that overrides CFile::Open() (which is virtual). For the implementation copy/paste the MFC source, but leave out the _MAX_PATH check. For a big project, this class could be a drop-in replacement for CFile to enable long paths. You could even go so far to prepend the \\?\ prefix if it isn't already there (but that is more involved as the prefix also disables the regular transformations from a Win32 path to a NT-style path, like converting / to \, resolving dots and so on).

like image 54
zett42 Avatar answered Nov 15 '22 07:11

zett42