【问题标题】:ShellExecuteEx 7z DelphiShellExecuteEx 7z 德尔福
【发布时间】:2014-12-18 07:52:21
【问题描述】:

所以我正在尝试使用 delphi 和 ShellExecuteEx 进行存档,我的代码是:

 Result := False;
  DecodeDate(now,y,m,d);
  NumeFisier := dir+'\Export_'+IntToStr(y)+'.'+IntToStr(m)+'.'+IntToStr(d)+'.zip';
  FillChar(exInfo, SizeOf(exInfo), 0);
  with exInfo do
   begin
    cbSize := SizeOf(exInfo);
    fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT;
    Wnd := GetActiveWindow();
    exInfo.lpVerb := nil;
    exInfo.lpFile  := PAnsiChar('C:\Windows\System32\cmd.exe');
   exInfo.lpParameters := PAnsiChar('C:\Program Files\7-Zip\7z.exe ' +'a ' + NumeFisier + ' ' + dir);
    nShow := SW_SHOWNORMAL;
   end;
   if ShellExecuteEx(@exInfo) then
    Ph := exInfo.hProcess
    else
     begin
     ShowMessage(SysErrorMessage(GetLastError));
     Result := true;
     exit;
    end;
   while WaitForSingleObject(exInfo.hProcess, 50) <> WAIT_OBJECT_0 do
     Application.ProcessMessages;
   CloseHandle(Ph);

  Result := true;

由于某种原因,这只会打开命令提示符而不执行存档。我怎样才能让它执行 7z.exe 文件。

我尝试使用 ShellExecute 并且效果很好,但是我必须检查该过程是否已完成,所以我坚持使用 ShellExecuteEx

【问题讨论】:

  • 不要直接调用cmd.exe,而是直接调用7z.exe。
  • 谢谢!它有效,但我必须先调用 cmd 才能执行 7z.exe :)。你的回答为我节省了很多时间。请将其发布为答案,以便我接受。
  • 既然问题需要答案,请随意回答您自己的问题。
  • 不要使用 ShellExecute。使用 CreateProcess。
  • 不要使用SEE_MASK_FLAG_DDEWAIT

标签: delphi shellexecuteex


【解决方案1】:

没有必要涉及cmd.exe。那是命令解释器。您想执行不同的可执行文件,请直接执行。

您不想使用ShellExecuteEx,因为它的通用性远远超出您的需要。 ShellExecuteEx 在这里所做的就是调用CreateProcess。你应该直接这样做,避免中间人。更重要的是,调用CreateProcess 可以让您轻松隐藏控制台窗口。通过CREATE_NO_WINDOW 来实现这一点。

最后,还有比您的代码更好的等待方式。使用MsgWaitForMultipleObjects 可以避免轮询。将此代码放入线程中可以避免调用Application.ProcessMessages

procedure WaitUntilSignaled(Handle: THandle; ProcessMessages: Boolean);
var
  retval: DWORD;
begin
  if ProcessMessages then begin
    Application.ProcessMessages;//in case there are messages already in the queue
    while True do begin
      retval := MsgWaitForMultipleObjects(1, Handle, False, INFINITE, QS_ALLEVENTS);
      case retval of
      WAIT_OBJECT_0,WAIT_ABANDONED_0:
        break;
      WAIT_OBJECT_0+1:
        Application.ProcessMessages;
      WAIT_FAILED:
        RaiseLastOSError;
      end;
    end;
  end else begin
    Win32Check(WaitForSingleObject(Handle, INFINITE)<>WAIT_FAILED);
  end;
end;

procedure ExecuteProcess(
  const ExecutablePath: string;
  const Arguments: string;
  const CurrentDirectory: string;
  const Wait: Boolean;
  const CreationFlags: DWORD
);
var
  si: TStartupInfo;
  pi: TProcessInformation;
  MyCurrentDirectory: PChar;
begin
  ZeroMemory(@si, SizeOf(si));
  si.cb := SizeOf(si);

  if CurrentDirectory <> '' then begin
    MyCurrentDirectory := PChar(CurrentDirectory);
  end else begin
    MyCurrentDirectory := nil;
  end;

  Win32Check(CreateProcess(
    nil,
    PChar('"' + ExecutablePath + '" ' + Arguments),
    nil,
    nil,
    False,
    CreationFlags,
    nil,
    MyCurrentDirectory,
    si,
    pi
  ));
  try
    if Wait then begin
      WaitUntilSignaled(pi.hProcess, True);
    end;
  finally
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
  end;
end;

【讨论】:

  • 我试过了:NumeFisier := ChangeFileExt('test.Bak', '.7z');如果 FileExists ( NumeFisier ) 然后 DeleteFile(NumeFisier); ExecuteProcess('"C:\Program Files\7-Zip\7za.exe" ' , ' a ' + NumeFisier + ' ' + 'D:\TestBK*.bak' ,'',True,0);我收到错误“无效的处理程序”
  • 这有点难以理解。您在我假设的答案中逐字使用代码?
  • 错误出现在 RaiseLastOSError 的“WaitUntilSignaled”中;
  • 您没有在我的回答中使用代码。如果您是,那么您将在对CreateProcess 的调用中获得无效参数。问题是您在双引号中引用了文件名。应该是:ExecuteProcess('C:\Program Files\7-Zip\7za.exe', 'a ' + NumeFisier + ' ' + 'D:\TestBK*.bak', '', True, 0)
  • 谢谢,我在命令提示符中使用了“”,由于程序和文件之间的空间而出现错误
猜你喜欢
  • 1970-01-01
  • 2014-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-02
  • 2011-10-04
  • 2012-12-13
相关资源
最近更新 更多