2013-11-20 7 views
5

Sto lavorando su un codice C++ che analizza il percorso e per questo ho sperimentato molte API Windows. C'è una differenza tra PathGetArgs/PathRemoveArgs e un CommandLineToArgvW leggermente massaggiato?PathGetArgs/PathRemoveArgs vs. CommandLineToArgvW: c'è una differenza?

In altre parole, a parte la lunghezza/pulizia, è questo:

std::wstring StripFileArguments(std::wstring filePath) 
{ 
    WCHAR tempPath[MAX_PATH]; 

    wcscpy(tempPath, filePath.c_str()); 
    PathRemoveArgs(tempPath); 

    return tempPath; 
} 

diversa da questa:

std::wstring StripFileArguments(std::wstring filePath) 
{ 
    LPWSTR* argList; 
    int argCount; 
    std::wstring tempPath; 

    argList = CommandLineToArgvW(filePath.c_str(), &argCount); 

    if (argCount > 0) 
    { 
    tempPath = argList[0]; //ignore any elements after the first because those are args, not the base app 

    LocalFree(argList); 

    return tempPath; 
    } 

    return filePath; 
} 

ed è questo

std::wstring GetFileArguments(std::wstring filePath) 
{ 
    WCHAR tempArgs[MAX_PATH]; 

    wcscpy(tempArgs, filePath.c_str()); 
    wcscpy(tempArgs, PathGetArgs(tempArgs)); 

    return tempArgs; 
} 

diverso da

std::wstring GetFileArguments(std::wstring filePath) 
{ 
    LPWSTR* argList; 
    int argCount; 
    std::wstring tempArgs; 

    argList = CommandLineToArgvW(filePath.c_str(), &argCount); 

    for (int counter = 1; counter < argCount; counter++) //ignore the first element (counter = 0) because that's the base app, not args 
    { 
    tempArgs = tempArgs + TEXT(" ") + argList[counter]; 
    } 

    LocalFree(argList); 

    return tempArgs; 
} 

? Mi sembra come PathGetArgs/PathRemoveArgs solo fornire un'implementazione del caso speciale più semplice e pulita dell'analisi CommandLineToArgvW, ma mi piacerebbe sapere se ci sono casi d'angolo in cui le API si comporteranno in modo diverso.

+1

Sembra che le API SHLW ('Percorso *') non facciano nulla di speciale oltre a trovare il primo carattere di spazio. Questo è probabilmente il significato della documentazione su dove legge: * "Questa funzione non deve essere utilizzata su modelli di percorsi di comando generici." * La [euristica utilizzata da 'CommandLineToArgvW'] (http://blogs.msdn.com/b /oldnewthing/archive/2010/09/16/10062818.aspx) sembra essere [un po 'più coinvolto] (http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx). – IInspectable

+0

+1 per i link The Old New Thing. – computerfreaker

risposta

3

Le funzioni sono simili ma non esattamente la stessa, principalmente per quanto riguarda il modo in cui le stringhe tra virgolette vengono gestite.

PathGetArgs restituisce un puntatore al primo carattere che segue il primo spazio nella stringa di input. Se si incontra un carattere di citazione prima del primo spazio, è richiesta un'altra citazione prima che la funzione ricominci a cercare gli spazi. Se non viene trovato spazio, la funzione restituisce un puntatore alla fine della stringa.

PathRemoveArgs chiamate PathGetArgs e quindi utilizza il puntatore restituito per terminare la stringa. Spaccherà anche uno spazio finale se il primo spazio incontrato si trova alla fine della linea.

CommandLineToArgvW prende la stringa fornita e la divide in una matrice. Usa spazi per delineare ogni elemento dell'array. Il primo elemento dell'array può essere quotato per consentire spazi. Il secondo e gli articoli successivi possono anche essere citati, ma supportano un'elaborazione leggermente più complessa - gli argomenti possono anche includere citazioni incorporate anteponendole con una barra rovesciata. Per esempio:

"c:\program files\my app\my app.exe" arg1 "argument 2" "arg \"number\" 3" 

Ciò produrrebbe un array con quattro voci:

  • argv[0] - c: \ program files \ mia app \ mio app.exe
  • argv[1]-Arg1
  • argv[2] - argomento 2
  • argv[3] - arg "numero" 3

Vedere le CommandLineToArgVW documentazione per una descrizione completa delle regole di analisi, tra cui backslash come si può avere incorporato così come le quotazioni negli argomenti.

1

Sì ho osservato un comportamento diverso con l'SDK di corrente (VS2015 Update 3 + di Windows 1607 SDK anniversario con la versione SDK 8.1 impostato su):

  1. Calling CommandLineToArgvW con una lpCmdLine vuoto (quello che si ottiene da wWinMain quando non sono stati passati argomenti) restituisce il percorso del programma e il nome del file, che sarà suddiviso in ogni spazio. Ma questo non è stato specificato nel parametro, che deve essere fatto in sé, ma non è riuscito a pensare a ignorare spaziatura quel percorso stesso:

    lpCmdLine = "" 
    argv[0] = C:\Program 
    argv[1] = Files\Vendor\MyProgram.exe 
    
  2. Calling CommandLineToArgvW con i parametri lpCmdLine contenente, non include il percorso e il nome del programma, così funziona come previsto (fino a quando non ci sono ulteriori spazi nei parametri ...):

    lpCmdLine = "One=1 Two=\"2\"" 
    argv[0] = One=1 
    argv[1] = Two=2 
    

Nota si spoglia anche altre citazioni all'interno dei parametri quando passò.

  1. CommandLineToArgvW non piace il primo parametro nel formato Text=\"Quoted spaces\" quindi se si tenta di passare lpCmdLine ad esso direttamente si divide in modo non corretto la chiave = coppie di valori se hanno spazi:

    lpCmdLine = "One=\"Number One\" Two=\"Number Two\"" 
    argv[0] = One=\"Number 
    argv[1] = One\" 
    argv[2] = Two=\"Number 
    argv[3] = Two\" 
    

È un po 'documentato qui:

https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx

Ma questo tipo di comportamento con spazi nel percorso del programma non era previsto. Sembra un insetto per me. Preferirei elaborare gli stessi dati in entrambe le situazioni. Perché se davvero desidero il percorso dell'eseguibile chiamerei GetCommandLineW().

L'unica soluzione coerente ragionevole a mio avviso è ignorare completamente lpCmdLine e chiamare GetCommandLineW(), passare i risultati a CommandLineToArgvW() quindi saltare il primo parametro se non si è interessati al percorso del programma. In questo modo, tutte le combinazioni sono supportate, ovvero percorso con e senza spazi, parametri con virgolette nidificate con e senza spazi.

int argumentCount; 
LPWSTR commandLine = GetCommandLineW(); 
LPWSTR *arguments = CommandLineToArgvW(commandLine, &argumentCount);