2016-06-26 59 views
5

在我目前的个人项目的Windows版本中,我期待支持extended length filepaths。因此,我对如何使用GetFullPathNameW API解决长文件路径的全名有点困惑。GetFullPathNameW和长的Windows文件路径

按照MSDN(与问候到lpFileName的对象参数):

在此功能的ANSI版本,名称是限制为MAX_PATH字符。要将此限制扩展为32,767个宽字符,请调用该函数的Unicode版本并将“\?\”前置到路径中。有关更多信息,请参阅命名文件。

如果我理解正确此,为了使用扩展长度的文件路径与GetFullPathNameW,我需要指定附加了\\?\前缀的路径。由于前缀\\?\仅在卷字母或UNC路径之前有效,这意味着该API不可用于解析相对于当前目录的路径的全名。

如果是这种情况,是否有另一个API可用于解析文件路径的全名,如..\somedir\somefile.txt,如果结果名称的长度超过MAX_PATH?如果没有,我能否将GetCurrentDirectory与相关文件路径(\\?\C:\my\cwd\..\somedir\somefile.txt)结合使用,并将它与GetFullPathNameW结合使用,还是需要我自己处理所有的文件路径分辨率?

+0

这听起来不是合理的功能找到的完整路径,需要你提供完整的路径。那么为什么不试试这些文档所说的。也许你会感到惊喜。 –

+2

GetCurrentDirectory()是基本上是MAX_PATH阻塞的unixism。本地操作系统没有相对路径或默认目录的概念,您必须*始终*提供完整的路径名称。你必须摆脱它才能超前。 –

+0

@ Cheersandhth.-Alf如果您建议我尝试'\\?\ C:\ my \ cwd \ .. \ somedir \ somefile.txt'或'\\?\ .. \ somedir \ somefile .txt',所以我尝试了两种。第一个正确解析为'\\?\ C:\ my \ somedir \ somefile.txt'(它回答了我的问题的一部分),而第二个错误地解析为'\\?\ somedir \ somefile.txt'。 –

回答

6
  1. GetFullPathNameA被限制为MAX_PATH字符,因为它的ANSI名称转换为UNICODE名称预先使用尺度的硬编码MAX_PATH(在字符)UNICODE缓冲器。如果转换未因长度限制而失败,则调用GetFullPathNameW(或直接GetFullPathName_U[Ex]),并将生成的UNICODE名称转换为ANSI。

  2. GetFullPathNameW是一个非常薄的外壳而不是GetFullPathName_U。它限制在WCHAR中的长度为MAXSHORT (0x7fff),独立于\\?\文件前缀。即使没有\\?\,它也会长时间工作(>MAX_PATH)相对名称。但是,如果lpFileName参数未以\\?\前缀开头,则lpBuffer参数中的结果名称也不会以\\?\开头。

  3. 如果你将使用lpBuffer与像CreateFileW功能 - 这一功能在内部转换Win32NameNtName。结果将取决于颈背型(RTL_PATH_TYPE)。如果名称不\\?\前缀开头,则转换失败,因为RtlDosPathNameToRelativeNtPathName_U[_WithStatus]失败(因为如果路径不是\\?\开始它会在内部调用GetFullPathName_U(由GetFullPathNameW称为相同的功能)与nBufferLength硬编码到MAX_PATH(以字节完全2*MAX_PATH - NTDLL函数使用缓冲区大小以字节为单位,而不是在WCHAR s)。如果名称与\\?\前缀开头,在RtlDosPathNameToRelativeNtPathName_U[_WithStatus]另一种情况下,执行 - RtlpWin32NtNameToNtPathName,这与\??\取代\\?\并没有MAX_PATH限制

因此,解决办法可能是这样的:

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, ...); 
    } 
} 

所以我们需要指定一个带有\\?\前缀的路径,但不能在GetFullPathName之前 - !

欲了解更多信息,请阅读本 - The Definitive Guide on Win32 to NT Path Conversion

+0

Upvoted只是为了达到纯粹的细节水平,分享知识。虽然认为假设所有Windows版本的内部实现都是相同的,但是有点冒险。是吗? –

+1

Win32到NT路径转换将一直存在。不过,这种转换的细节确实可以从版本更改为版本。一些不正确转换的win32路径。一般来说,如果使用Win32路径 - 我们有MAX_PATH的实践限制。例如,如果绝对路径长度超过MAX_PATH,我们无法从exe创建进程。如果需要使用长路径名称而没有任何限制或某些特殊路径 - 需要使用NT路径(native)和ntdll API – RbMm

+0

谢谢,这非常有帮助。希望你不介意 - 我提交了一个编辑,在头两点上清理英文。 –