2016-06-26 22 views
5

In der Windows-Version meines aktuellen persönlichen Projekts möchte ich extended length filepaths unterstützen. Daher bin ich etwas verwirrt darüber, wie die GetFullPathNameW-API zum Auflösen des vollständigen Namens eines langen Dateipfads verwendet werden kann.GetFullPathNameW und lange Windows-Dateipfade

der MSDN nach (in Bezug auf die lpFileName Parameter):

In der ANSI-Version dieser Funktion ist der Name MAX_PATH Zeichen begrenzt. Um dieses Limit auf 32.767 Zeichen zu erweitern, rufen Sie die Unicode-Version der Funktion auf und fügen Sie "\? \" Dem Pfad voran. Weitere Informationen finden Sie unter Benennen einer Datei.

Wenn ich verstehe dies, um richtig, eine erweiterte Länge Filepath mit GetFullPathNameW zu verwenden, ich brauche einen Pfad angeben, mit dem \\?\ Präfix angebracht. Da das Präfix \\?\ nur vor Volumenbuchstaben oder UNC-Pfaden gültig ist, würde dies bedeuten, dass die API zum Auflösen des vollständigen Namens eines Pfads relativ zu dem aktuellen Verzeichnis unbrauchbar ist.

Wenn das der Fall ist, gibt es eine andere API, die ich verwenden kann, um den vollständigen Namen eines Dateipfades wie ..\somedir\somefile.txt aufzulösen, wenn die resultierende Name Länge MAX_PATH überschreitet? Wenn nicht, wäre ich in der Lage, GetCurrentDirectory mit dem relativen Dateipfad (\\?\C:\my\cwd\..\somedir\somefile.txt) zu kombinieren und es mit GetFullPathNameW zu verwenden, oder müsste ich die gesamte Dateipfadauflösung alleine bewältigen?

+0

Es ist nicht vernünftig klingt, dass eine Funktion, um den vollständigen Pfad zu finden, müssen Sie den vollständigen Pfad liefern. Warum also nicht versuchen, was die Ärzte sagen? Vielleicht wirst du angenehm überrascht sein. –

+2

GetCurrentDirectory() ist ein Unixismus, der grundlegend MAX_PATH belastet ist. Da das native Betriebssystem keine relativen Pfade oder Standardverzeichnisse kennt, müssen Sie es immer mit einem vollständigen Pfadnamen versehen. Sie müssen es loswerden, um weiter zu kommen. –

+0

@ Cheersandhth.-Alf War nicht wirklich klar, wenn Sie vorschlagen, dass ich versuche, \\? \ C: \ my \ cwd \ .. \ somedir \ somefile.txt 'oder' \\? \ .. \ somedir \ somefile .txt', also habe ich beides versucht. Der erste Befehl wird korrekt in '\\? \ C: \ my \ somedir \ somefile.txt' aufgelöst (was einen Teil meiner Frage beantwortet), während der zweite falsch in' \\ \ somedir \ somefile.txt \ aufgelöst wird. –

Antwort

6
  1. GetFullPathNameA auf MAX_PATH Zeichen beschränkt, weil es den ANSI-Namen in einen UNICODE wandelt Namen zuvor ein hartkodierte MAX_PATH Verwendung -groß (in Zeichen) UNICODE Puffer. Wenn die Konvertierung aufgrund der Längenbeschränkungen nicht fehlschlägt, wird GetFullPathNameW (oder direkt GetFullPathName_U[Ex]) aufgerufen und der sich ergebende Name UNICODE wird in ANSI konvertiert.

  2. GetFullPathNameW ist eine sehr dünne Schale über GetFullPathName_U. Es ist auf MAXSHORT (0x7fff) Länge in WCHARs, unabhängig von der Datei \\?\ Dateipräfix beschränkt. Auch ohne \\?\ wird es für lange (>MAX_PATH) relative Namen funktionieren. Wenn der Parameter lpFileName jedoch nicht mit dem Präfix \\?\ beginnt, beginnt der Ergebnisname im Parameter lpBuffer ebenfalls nicht mit \\?\.

  3. wenn Sie lpBuffer mit Funktionen wie CreateFileW verwenden werden - diese Funktion intern konvertieren Win32Name-NtName. und das Ergebnis hängt vom Nacken-Typ ab (RTL_PATH_TYPE). wenn der Name mit \\?\ Präfix beginnt nicht, schlägt die Konvertierung fehl, weil RtlDosPathNameToRelativeNtPathName_U[_WithStatus] fehlschlägt (weil, wenn der Pfad nicht mit \\?\ beginnen wird es intern nennen GetFullPathName_U (gleiche Funktion durch GetFullPathNameW genannt werden) mit nBufferLength zu MAX_PATH fest einprogrammiert (genau 2*MAX_PATH in Bytes - NTDLL Funktionen verwenden Puffergröße in Bytes, nicht in WCHAR s).Wenn der Name mit \\?\ Präfix beginnen, ist ein weiterer Fall, in RtlDosPathNameToRelativeNtPathName_U[_WithStatus] ausgeführt - RtlpWin32NtNameToNtPathName, die \\?\ mit \??\ ersetzt und hat keine MAX_PATH Einschränkung

So ist die Lösung wie folgt aussehen:

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 wir Geben Sie einen Pfad mit dem Präfix \\?\ an, jedoch nicht vor GetFullPathName - after!

Für weitere Informationen, lesen Sie - The Definitive Guide on Win32 to NT Path Conversion

+0

Upvoted nur für die schiere Ebene des Details, den Austausch von Wissen. Allerdings ist es ein wenig riskant anzunehmen, dass die interne Implementierung in allen Windows-Versionen gleich ist. Ist es? –

+1

Win32 zu NT Pfad Konvertierung wird immer sein. Die Details dieser Konvertierung können jedoch wirklich von Version zu Version geändert werden. Einige Win32 Pfade wurden überhaupt nicht konvertiert. im Allgemeinen, wenn Win32-Pfad verwenden - wir haben MAX_PATH practicic Begrenzung. Zum Beispiel können wir keinen Prozess von exe erstellen, wenn die absolute Pfadlänge MAX_PATH überschreitet. Wenn nötig, verwenden Sie lange Pfadnamen ohne Einschränkungen oder einige spezielle Pfade - benötigen NT-Pfade (nativ) und ntdll API – RbMm

+0

Danke, das war super hilfreich. Ich hoffe, es macht Ihnen nichts aus - ich habe eine Bearbeitung eingereicht, um die Engländer ein wenig in den ersten beiden Punkten zu bereinigen. –