CreateProcess : 应用程序路径中的转义空格

Posted

技术标签:

【中文标题】CreateProcess : 应用程序路径中的转义空格【英文标题】:CreateProcess : escape spaces in the application path 【发布时间】:2014-03-10 16:40:33 【问题描述】:

我们需要在我的 delphi 应用程序的命令窗口中执行 ffmpeg。

我们找到了使用“ExtractShortPathName”函数保护路径的解决方案。

但在某些计算机上我们无法获得 8.3 路径(HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation 为 2),我们想找到另一种方法来逃避空格。

代码如下:

sParameters := '"C:\Users\[...]\input.wav" -r 12.03 -f image2 -i "C:\Users\[...]\delphilm%d.png" -vf "scale=1024:704" -ab 96k -r 24 -b 2000k  -pass 1 -vcodec libx264 -fpre "C:\[...]\libx264-normal.ffpreset" "C:\Users\[...]\export.mp4"';
sCommand := 'C:\Program Files\My application\utils\bin\ffmpeg.exe';
Handle := CreateProcess(nil, PChar('cmd.exe /C '+ProtectPath(sCommand)+' '+sParameters),nil, nil, True, 0, nil, nil, SI, PI);

使用 ProtectPath 功能:

function ProtectPath(sCommand:Widestring):Widestring;
begin
  Result := sCommand;
  // get the 8.3 path
  Result := ExtractShortPathName(sCommand);
  // if 8.3 path is not accessible
  if(Pos(' ', Result)>0)then begin
    //Result := '"'+sCommand+'"';    --> do not work
    //Result := StrReplace(sCommand, ' ','" "');  --> do not work
    //Result := StrReplace(sCommand, ' ','^ ');  --> do not work
    //Result := StrReplace(sCommand, ' ','\ ');  --> do not work
    //Result := StrReplace(sCommand, ' ','\\ ');   --> do not work
    //Result := StrReplace(sCommand, ' ','/ ');  --> do not work
    //Result := StrReplace(sCommand, ' ','// ');  --> do not work
  end;
end;

有什么想法吗?

【问题讨论】:

用正斜杠替换反斜杠。我通常在 C++ 中使用它。仅适用于路径。没有其他的。希望它在这里工作。 OT:我仍然想知道为什么人们倾向于使用cmd.exe /C。直接执行应用程序不是更容易吗? 正斜杠不起作用。 我们使用cmd.exe来分析ffmpeg过程中的输出。 msdn.microsoft.com/en-us/library/windows/desktop/… cmets 部分指出,如果文件没有短名称,它将失败。好像有不少gotchas 在使用这个功能。某些系统没有某些路径的短名称。 【参考方案1】:

您不需要检索 8.3 文件名。您所要做的就是用一对引号括起一个长路径,如果它包含任何空格字符(就像您已经在使用一些 FFMPEG 参数一样)。然后,完全摆脱cmd.exe,直接调用ffmpeg.exe

sCommand := '"C:\Program Files\My application\utils\bin\ffmpeg.exe"';

sParameters := '"C:\Users\[...]\input.wav" -r 12.03 -f image2 -i "C:\Users\[...]\delphilm%d.png" -vf "scale=1024:704" -ab 96k -r 24 -b 2000k  -pass 1 -vcodec libx264 -fpre "C:\[...]\libx264-normal.ffpreset" "C:\Users\[...]\export.mp4"';

Handle := CreateProcess(nil, PChar(sCommand + ' ' + sParameters), nil, nil, True, 0, nil, nil, SI, PI);

如果您想动态引用,请使用(Ansi)QuotedStr(),例如:

function ProtectParam(sParam: String): String;
begin
  if LastDelimiter(' "', sParam) <> 0 then
    Result := QuotedStr(sParam)
  else
    Result := sParam;
end;

FFMPEG := 'C:\Program Files\My application\utils\bin\ffmpeg.exe';
InputFile := 'C:\Users\[...]\input.wav';
PngFile := 'C:\Users\[...]\delphilm%d.png';
PresetFile := 'C:\[...]\libx264-normal.ffpreset';
ExportFile := 'C:\Users\[...]\export.mp4';

sCommand := ProtectParam(FFMPEG) + ' ' + ProtectParam(InputFile) + ' -r 12.03 -f image2 -i ' + ProtectParam(PngFile) + ' -vf "scale=1024:704" -ab 96k -r 24 -b 2000k  -pass 1 -vcodec libx264 -fpre ' + ProtectParam(PresetFile) + ' ' + ProtectParam(ExportFile);

Handle := CreateProcess(nil, PChar(sCommand), nil, nil, True, 0, nil, nil, SI, PI);

【讨论】:

【参考方案2】:

我看不出有什么真正的理由在这里使用cmd.exe。它只是增加了一层额外的复杂性,会让你感到痛苦。你是要求cmd.exe打电话CreateProcess启动ffmpeg,那为什么不直接做呢?

也就是说,回避问题的一种廉价而愉快的方法是利用工作目录。将'C:\Program Files\My application\utils\bin' 传递给新进程的工作目录,然后PChar('cmd.exe /C ffmpeg.exe '+sParameters) 就是你所需要的。

【讨论】:

以上是关于CreateProcess : 应用程序路径中的转义空格的主要内容,如果未能解决你的问题,请参考以下文章

UNC 路径上的 VC++ Createprocess

无法启动应用程序(CreateProcess 错误=87),不能使用缩短类路径解决方法

C++ CreateProcess 无法从 Windows 7 上的套接字接收路径 (64)

用大量参数编译 GWT 代码——CreateProcess 的字符限制?

CreateProcess() 不适用于 lpCurrentDirectory

如何将带有空格的路径作为参数添加到 CreateProcess 批处理文件?