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

时间:2014-03-10 16:40:33

标签: delphi createprocess

我们需要在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;

有什么想法吗?

2 个答案:

答案 0 :(得分:8)

您无需检索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);

答案 1 :(得分:1)

我认为没有任何真正的理由在这里使用cmd.exe。它只是增加了一层额外的复杂性来灼烧你。您要求cmd.exe致电CreateProcess以启动ffmpeg,为什么不直接这样做?

尽管如此,一个廉价而愉快的解决问题的方法是利用工作目录。将'C:\Program Files\My application\utils\bin'传递给新流程的工作目录,然后只需PChar('cmd.exe /C ffmpeg.exe '+sParameters)