2013-11-20 18 views
5

Pracuję nad przetwarzaniem ścieżek kodu w języku C++ i eksperymentowałem z wieloma interfejsami API systemu Windows. Czy istnieje różnica między PathGetArgs/PathRemoveArgs a lekko masowanym CommandLineToArgvW?PathGetArgs/PathRemoveArgs vs. CommandLineToArgvW - czy jest jakaś różnica?

Innymi słowy, oprócz długości/czystości, to jest:

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

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

    return tempPath; 
} 

inny z tego:

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; 
} 

i tym

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

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

    return tempArgs; 
} 

różne od

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; 
} 

? Wygląda mi na to, że dostarczam czystszą, prostszą, specjalną implementację analizy składniowej, ale chciałbym wiedzieć, czy są jakieś przypadki narożne, w których interfejsy API będą zachowywać się inaczej.

+1

Wygląda na to, że SHLW-APIs ('Path *') nie robią nic specjalnego na znalezienie pierwszej spacji. Jest to prawdopodobnie tym, o czym w dokumentacji chodzi: "Ta funkcja nie powinna być używana w ogólnych szablonach ścieżek poleceń." * [Heurystyka używana przez 'CommandLineToArgvW'] (http://blogs.msdn.com/b /oldnewthing/archive/2010/09/16/10062818.aspx) wydaje się być [nieco bardziej zaangażowany] (http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx). – IInspectable

+0

+1 za linki do starych nowych rzeczy. – computerfreaker

Odpowiedz

3

Funkcje są podobne, ale nie do końca takie same - głównie w odniesieniu do obsługi cytowanych ciągów.

PathGetArgs zwraca wskaźnik do pierwszego znaku następującego po pierwszym spacji w łańcuchu wejściowym. Jeśli napotkany znak zostanie napotkany przed pierwszym spacją, wymagany jest inny cudzysłów, zanim funkcja rozpocznie ponowne szukanie spacji. Jeśli nie zostanie znaleziona spacja, funkcja zwraca wskaźnik do końca łańcucha.

PathRemoveArgs dzwoni PathGetArgs, a następnie używa zwróconego wskaźnika do zakończenia ciągu znaków. Usunie również końcową spację, jeśli napotkane pierwsze miejsce znajduje się na końcu linii.

CommandLineToArgvW pobiera łańcuch i dzieli go na tablicę. Używa spacji do wyznaczania każdego elementu w tablicy. Pierwszy element w tablicy można zacytować, aby zezwolić na spacje. Drugi i kolejne elementy mogą również być cytowane, ale obsługują nieco bardziej złożone przetwarzanie - argumenty mogą również zawierać osadzone cudzysłowy, poprzedzając je ukośnikiem odwrotnym. Na przykład:

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

byłoby to produkować tablicę z czterech pozycji:

  • argv[0] - c: \ program files \ Moje app \ Moje app.exe
  • argv[1] - arg1
  • argv[2] - Argument 2
  • argv[3] - arg „numer” 3

Zobacz CommandLineToArgVW docs dla pełnego opisu zasad analizowania, w tym w jaki sposób można mieć wbudowanych ukośniki a także cytatów w argumentach.

1

Tak Mam zaobserwowano różne zachowania z obecnym SDK (VS2015 Update 3 + Windows 1607-lecie SDK w wersji SDK ustawiony na 8.1):

  1. Wywołanie CommandLineToArgvW z pustym lpCmdLine (co masz z wWinMain, gdy nie podano żadnych argumentów) zwraca ścieżkę programu i nazwę pliku, które zostaną podzielone na każdą spację. Ale ten nie został określony w parametrze, musi zrobić to samo, ale nie myślę o ignorowanie rozstaw tą drogą sam:

    lpCmdLine = "" 
    argv[0] = C:\Program 
    argv[1] = Files\Vendor\MyProgram.exe 
    
  2. Wywołanie CommandLineToArgvW z parametrami lpCmdLine zawierający, nie zawiera ścieżkę programu i nazwisko, tak działa zgodnie z oczekiwaniami (tak długo jak istnieją żadne dalsze przestrzenie w parametrach ...):

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

Uwaga również pozbawia innych cytatów wewnątrz parametrów podjęcia.

  1. CommandLineToArgvW nie lubi pierwszy parametr w formacie Text=\"Quoted spaces\" więc jeśli starają się przekazać lpCmdLine do niego bezpośrednio nieprawidłowo dzieli się pary klucz = wartość, jeśli mają przestrzenie:

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

To rodzaj udokumentowane tutaj:

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

Tego rodzaju zachowanie ze spacjami w ścieżce programu nie było oczekiwane. Wydaje mi się, że to błąd. Wolałbym, aby te same dane były przetwarzane w obu sytuacjach. Ponieważ jeśli naprawdę chcę ścieżki do pliku wykonywalnego, powinienem zamiast tego nazwać GetCommandLineW().

Jedynym rozsądnym spójnym rozwiązaniem moim zdaniem jest całkowite zignorowanie lpCmdLine i wywołanie funkcji GetCommandLineW(), przekazanie wyników do CommandLineToArgvW(), a następnie pominięcie pierwszego parametru, jeśli nie interesuje Cię ścieżka programu. W ten sposób obsługiwane są wszystkie kombinacje, tj. Ścieżka z i bez spacji, parametry z zagnieżdżonymi cudzysłowami zi bez spacji.

int argumentCount; 
LPWSTR commandLine = GetCommandLineW(); 
LPWSTR *arguments = CommandLineToArgvW(commandLine, &argumentCount); 
Powiązane problemy