PathGetArgs / PathRemoveArgs与CommandLineToArgvW - 有区别吗?

时间:2013-11-20 18:11:21

标签: c++ parsing winapi path

我正在研究一些解析路径的C ++代码,并且我一直在尝试使用很多Windows API。 PathGetArgs / PathRemoveArgs与略微按摩CommandLineToArgvW之间是否存在差异?

换句话说,除了长度/清洁之外,是这样的:

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

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

  return tempPath;
}

与此不同:

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

是这个

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

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

  return tempArgs;
}

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

?在我看来,PathGetArgs / PathRemoveArgs只是提供了一个更简洁,更简单的CommandLineToArgvW解析的特殊情况实现,但我想知道是否有任何角落情况API的行为会有所不同。

2 个答案:

答案 0 :(得分:4)

函数类似但不完全相同 - 主要与引用字符串的处理方式有关。

PathGetArgs返回指向输入字符串中第一个空格后面的第一个字符的指针。如果在第一个空格之前遇到引号字符,则在函数再次开始查找空格之前需要另一个引号。如果没有找到空格,则该函数返回指向字符串末尾的指针。

PathRemoveArgs调用PathGetArgs然后使用返回的指针终止字符串。如果遇到的第一个空格恰好位于该行的末尾,它也会剥离一个尾随空格。

CommandLineToArgvW获取提供的字符串并将其拆分为数组。它使用空格来描绘数组中的每个项目。可以引用数组中的第一项以允许空格。第二个和后续项也可以引用,但它们支持稍微复杂的处理 - 参数也可以包括嵌入式引号,前缀为反斜杠。例如:

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

这将生成一个包含四个条目的数组:

  • argv[0] - c:\ program files \ my app \ my app.exe
  • argv[1] - arg1
  • argv[2] - 参数2
  • argv[3] - arg&#34; number&#34; 3

有关解析规则的完整说明,请参阅CommandLineToArgVW文档,包括如何在参数中嵌入反斜杠和引号。

答案 1 :(得分:2)

是的我观察到当前SDK的不同行为(VS2015 Update 3 + Windows 1607 Anniversary SDK,SDK版本设置为8.1):

  1. 使用空的lpCmdLine调用CommandLineToArgvW(当没有传递参数时从wWinMain获得的内容)返回程序路径和文件名,它将在每个空格中拆分。但是这没有在参数中指定,它必须自己完成,但没有考虑忽略路径本身的间距:

    lpCmdLine = ""
    argv[0] = C:\Program
    argv[1] = Files\Vendor\MyProgram.exe
    
  2. 使用包含参数的lpCmdLine调用CommandLineToArgvW,不包括程序路径和名称,因此按预期工作(只要参数中没有其他空格......):

    lpCmdLine = "One=1 Two=\"2\""
    argv[0] = One=1
    argv[1] = Two=2
    
  3. 请注意,它在传递参数时也会删除参数内的任何其他引号。

    1. CommandLineToArgvW不喜欢Text=\"Quoted spaces\"格式的第一个参数,所以如果你试图直接将lpCmdLine传递给它,它会错误地分割key = value对,如果它们有空格:

      lpCmdLine = "One=\"Number One\" Two=\"Number Two\""
      argv[0] = One=\"Number
      argv[1] = One\"
      argv[2] = Two=\"Number
      argv[3] = Two\"
      
    2. 这里有记录:

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

      但是这种在程序路径中有空格的行为并不是预期的。这对我来说似乎是个错误。我更喜欢在两种情况下处理相同的数据。因为如果我真的想要可执行文件的路径,我会调用GetCommandLineW()。

      我认为唯一明智的一致解决方案是完全忽略lpCmdLine并调用GetCommandLineW(),将结果传递给CommandLineToArgvW(),如果您对程序路径不感兴趣,则跳过第一个参数。这样,支持所有组合,即带和不带空格的路径,带有和没有空格的嵌套引号的参数。

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