2016-06-26 42 views
5

Nella versione Windows del mio progetto personale corrente, sto cercando di supportare extended length filepaths. Di conseguenza, sono un po 'confuso su come utilizzare l'API GetFullPathNameW per risolvere il nome completo di un percorso file lungo.GetFullPathNameW e lunghi percorsi file Windows

Secondo MSDN (per quanto riguarda il parametro lpFileName):

Nella versione ANSI di questa funzione, il nome è limitato a caratteri MAX_PATH. Per estendere questo limite a 32.767 caratteri di larghezza, chiamare la versione Unicode della funzione e anteporre "\? \" Al percorso. Per ulteriori informazioni, vedere Denominazione di un file.

se sto capire questo modo corretto, al fine di utilizzare una lunghezza percorso file estesa con GetFullPathNameW, ho bisogno di specificare un percorso con il prefisso di \\?\ allegato. Poiché il prefisso \\?\ è valido solo prima delle lettere di volume o dei percorsi UNC, ciò significherebbe che l'API non è utilizzabile per la risoluzione del nome completo di un percorso relativo alla directory corrente.

In questo caso, esiste un'altra API che posso utilizzare per risolvere il nome completo di un percorso file come ..\somedir\somefile.txt se la lunghezza del nome risultante supera MAX_PATH? In caso contrario, sarei in grado di combinare GetCurrentDirectory con il relativo filepath (\\?\C:\my\cwd\..\somedir\somefile.txt) e usarlo con GetFullPathNameW oppure dovrei gestire tutta la risoluzione del percorso file da solo?

+0

Non sembra ragionevole che una funzione per trovare il percorso completo, si richiede di fornire il percorso completo. Quindi, perché non provare ciò che dicono i documenti. Forse sarai piacevolmente sorpreso. –

+2

GetCurrentDirectory() è un unixism che è fondamentalmente MAX_PATH ingombrato. Il sistema operativo nativo non ha nozioni relative ai percorsi relativi o alle directory di default, è necessario * sempre * fornirgli un nome di percorso completo. Dovrai sbarazzartene per andare avanti. –

+0

@ Cheersandhth.-Alf non era molto chiaro se si stesse insinuando provo '\\ \ C:? \ Mio \ cwd \ .. \ somedir \ somefile.txt' o' \\ \ .. \ somedir \ somefile .txt', quindi ho provato entrambi. Il primo risolve correttamente '\\? \ C: \ my \ somedir \ somefile.txt', (che risponde a parte della mia domanda) mentre il secondo risolve erroneamente in' \\? \ Somedir \ somefile.txt'. –

risposta

6
  1. GetFullPathNameA è limitata a MAX_PATH caratteri, perché converte il nome ANSI per un nome UNICODE anticipo utilizzando un hardcoded MAX_PATH -sized (in caratteri) UNICODE tampone. Se la conversione non riesce a causa delle limitazioni di lunghezza, viene chiamato GetFullPathNameW (o diretto GetFullPathName_U[Ex]) e il nome risultante UNICODE viene convertito in ANSI.

  2. GetFullPathNameW è un guscio molto sottile su GetFullPathName_U. È limitato alla lunghezza MAXSHORT (0x7fff) in WCHAR, indipendentemente dal prefisso del file \\?\. Anche senza \\?\, funzionerà a lungo (>MAX_PATH) nomi relativi. Tuttavia, se il parametro lpFileName non inizia con il prefisso \\?\, il nome del risultato nel parametro lpBuffer non inizierà neanche con \\?\.

  3. se si sarà utilizzare lpBuffer con funzioni come CreateFileW - questa funzione convertire internamente Win32Name-NtName. e il risultato dipenderà dal tipo della nuca (RTL_PATH_TYPE). se il nome non inizia con \\?\ prefisso, la conversione non riesce perché RtlDosPathNameToRelativeNtPathName_U[_WithStatus] fallisce (perché se il percorso non inizia con \\?\ sarà chiamata internamente GetFullPathName_U (stessa funzione chiamata da GetFullPathNameW) con nBufferLength preimpostato a MAX_PATH (esattamente 2*MAX_PATH in byte - NTDLL le funzioni utilizzano la dimensione del buffer in byte, non in WCHAR s).Se il nome inizia con \\?\ prefisso, un altro caso in RtlDosPathNameToRelativeNtPathName_U[_WithStatus] viene eseguito - RtlpWin32NtNameToNtPathName, che sostituisce \\?\ con \??\ e non ha alcun MAX_PATH limitazione

Quindi la soluzione può apparire come segue:

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

Così abbiamo è necessario specificare un percorso con il prefisso \\?\ allegato, ma non prima di GetFullPathName - after!

Per ulteriori informazioni, leggere questo - The Definitive Guide on Win32 to NT Path Conversion

+0

Upvoted solo per il livello di dettaglio, la condivisione della conoscenza. Pensiamo che sia un po 'rischioso presumere che l'implementazione interna sia la stessa in tutte le versioni di Windows. È? –

+1

Win32 to NT Path Conversion sarà sempre. tuttavia i dettagli sottili di questa conversione possono essere realmente modificati da una versione all'altra. alcuni percorsi win32 a tutti i convertiti non corretti. in generale, se si usa il percorso Win32 - abbiamo LIMIT_FATICA di MAX_PATH. per esempio non possiamo creare un processo da exe, se la lunghezza del percorso assoluto ha superato MAX_PATH. se è necessario utilizzare nomi di percorso lunghi senza limitazioni o percorsi speciali, è necessario utilizzare i percorsi NT (nativo) e l'API ntdll – RbMm

+0

Grazie, è stato di grande aiuto. Spero non ti dispiaccia: ho inviato una modifica per ripulire un po 'l'inglese sui primi due punti. –