Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
312 views
in Technique[技术] by (71.8m points)

c++ - GetFullPathNameW and long Windows file paths

In the Windows version of my current personal project, I'm looking to support extended length filepaths. As a result, I'm a little confused with how to use the GetFullPathNameW API to resolve the full name of a long filepath.

According to the MSDN (with regards to the lpFileName parameter):

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "?" to the path. For more information, see Naming a File.

If I'm understanding this correctly, in order to use an extended length filepath with GetFullPathNameW, I need to specify a path with the \? prefix attached. Since the \? prefix is only valid before volume letters or UNC paths, this would mean that the API is unusable for resolving the full name of a path relative to the current directory.

If that's the case, is there another API I can use to resolve the full name of a filepath like ..somedirsomefile.txt if the resulting name's length exceeds MAX_PATH? If not, would I be able to combine GetCurrentDirectory with the relative filepath (\?C:mycwd..somedirsomefile.txt) and use it with GetFullPathNameW, or would I need to handle all of the filepath resolution on my own?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
  1. GetFullPathNameA is limited to MAX_PATH characters, because it converts the ANSI name to a UNICODE name beforehand using a hardcoded MAX_PATH-sized (in chars) UNICODE buffer. If the conversion doesn't fail due to the length restrictions, then GetFullPathNameW (or direct GetFullPathName_U[Ex]) is called and the resulting UNICODE name is converted to ANSI.

  2. GetFullPathNameW is a very thin shell over GetFullPathName_U. It is limited to MAXSHORT (0x7fff) length in WCHARs, independent of the \? file prefix. Even without \?, it will be work for long (> MAX_PATH) relative names. However, if the lpFileName parameter does not begin with the \? prefix, the result name in the lpBuffer parameter will not begin with \? either.

  3. if you will be use lpBuffer with functions like CreateFileW - this function internally convert Win32Name to NtName. and result will be depended from nape type (RTL_PATH_TYPE). if the name does not begin with \? prefix, the conversion fails because RtlDosPathNameToRelativeNtPathName_U[_WithStatus] fails (because if the path not begin with \? it will be internally call GetFullPathName_U (same function called by GetFullPathNameW) with nBufferLength hardcoded to MAX_PATH (exactly 2*MAX_PATH in bytes – NTDLL functions use buffer size in bytes, not in WCHARs). If name begin with \? prefix, another case in RtlDosPathNameToRelativeNtPathName_U[_WithStatus] is executed – RtlpWin32NtNameToNtPathName, which replaces \? with ?? and has no MAX_PATH limitation

So the solution may look like this:

if(ULONG len = GetFullPathNameW(FileName, 0, 0, 0))
{
    PWSTR buf = (PWSTR)_alloca((4 + len) * sizeof(WCHAR));
    buf[0] = L'\', buf[1] = L'\',  buf[2] = L'?', buf[3] = L'\';
    if (len - 1 == GetFullPathName(FileName, len, buf + 4, &c))
    {
        CreateFile(buf, ...);
    }
}

So we need to specify a path with the \? prefix attached, but not before GetFullPathName - after!

For more info, read this - The Definitive Guide on Win32 to NT Path Conversion


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...