2

最初は SQL テーブルに保存されているが、ShellExecuteEx を呼び出す前にディスクに保存されているファイルを開きたいと考えています。保存すると、有効なファイルパスが得られ、理論的にはこの機能を使用して目標を達成できるはずです。適切なプログラムでファイルを開き、そのプログラムが閉じるまで待ってから続行するプログラムが必要です。現在、コードは正しいアプリケーションを起動し、渡されたファイルを開きますが、待機せずにこれを実行し (アプリケーションがいつ終了するかを示すメッセージを表示するのでわかります)、正しいプログラムを起動するはずの作成したアプリが閉じます. メッセージを表示し、プログラムを起動します。私は ShellExecuteEx がどのように機能するかを完全には理解しておらず、Web で見つけたコードを自分のコードと組み合わせて使用​​して、目的の結果を達成したことを認めます。以下にコードを示します。どんな助けでも大歓迎です。

procedure Fire(FileStr: String);
var
  SEInfo: TShellExecuteInfo;
  ExitCode: DWORD;
  ExecuteFile, ParamString, StartInString: string;
begin
  ExecuteFile:= FileStr;
  FillChar(SEInfo, SizeOf(SEInfo), 0) ;
  SEInfo.cbSize := SizeOf(TShellExecuteInfo);
  with SEInfo do 
  begin
    fMask := SEE_MASK_NOCLOSEPROCESS;
    Wnd := Application.Handle;
    lpFile := PChar(ExecuteFile) ;
    nShow := SW_SHOWNORMAL;
  end;

  if ShellExecuteEx(@SEInfo) then
  begin
    repeat
      Application.ProcessMessages;
      GetExitCodeProcess(SEInfo.hProcess, ExitCode) ;
    until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
    ShowMessage('App terminated') ;
  end
    else ShowMessage('Error starting App') ;
end;

ディスクに書き込んでいたファイルが終了していないことに気付きました。そのため、プログラムの前にメッセージが表示されました。ファイルをディスクに書き込むための呼び出しの後に別の application.Processmessages を追加すると、これが解決されました。ただし、呼び出されたアプリが開いている間、GetExitCodeProcess はまだ STILL_ACTIVE の値を返しません。

さらに調査を行った後、私が達成しようとしていることをより明確に示す新しい質問を開くことにしました。興味がある人は、ここで見つけることができます

起動したプログラムがそのファイルの使用を終了するまでファイルの削除を待つにはどうすればよいですか?

4

2 に答える 2

0

あなたのrepeat..untilループはここで間違っています。アプリケーションがブロックされないようにするための使用は避けてくださいApplication.ProcessMessages()。これは悪い習慣であり、予期しない問題や奇妙なバグを引き起こす可能性があります。

代わりに、スレッドを使用してアプリの終了を待ちます。

unit uSEWaitThread;

interface

uses
  Winapi.Windows, System.Classes;

type
  TSEWaitThread = class(TThread)
  private
    FFile     : String;
    FSESuccess: Boolean;
    FExitCode : DWORD;
    FParentWnd: HWND;

  protected
    procedure Execute; override;

  public
    constructor Create(const AFile: String; const AParentWindowHandle: HWND; const AOnDone: TNotifyEvent);

    property ExitCode           : DWORD read FExitCode;
    property ShellExecuteSuccess: Boolean read FSESuccess;
  end;

implementation

uses
  Winapi.ShellApi;


constructor TSEWaitThread.Create(const AFile: String; const AParentWindowHandle: HWND; const AOnDone: TNotifyEvent);
begin
  FreeOnTerminate := TRUE;

  FFile := AFile;
  FParentWND := AParentWindowHandle;
  FSESuccess := FALSE;
  FExitCode := 0;
  OnTerminate := AOnDone;

  inherited Create;
end;

procedure TSEWaitThread.Execute;
var
  exec_info: TShellExecuteInfo;
begin
  FillChar(exec_info, SizeOf(TShellExecuteInfo), 0);
  exec_info.cbSize := SizeOf(TShellExecuteInfo);
  exec_info.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_NO_UI;
  exec_info.Wnd := FParentWnd;
  exec_info.lpFile := PChar(FFile);
  exec_info.nShow := SW_SHOWNORMAL;

  if ShellExecuteEx(@exec_info) then
  begin
    FSESuccess := TRUE;
    WaitForSingleObject(exec_info.hProcess, INFINITE);
    GetExitCodeProcess(exec_info.hProcess, FExitCode);
  end;
end;

end.

次の行は、スレッドを起動します。

TSEWaitThread.Create('C:\test.txt', Handle, SEWaitThreadDone);

スレッドの結果を処理するコールバック関数のサンプル:

procedure TForm1.SEWaitThreadDone(Sender: TObject);
var
  se_wait_thread: TSEWaitThread;
begin
  se_wait_thread := Sender as TSEWaitThread;

  if se_wait_thread.ShellExecuteSuccess then
  begin
    ShowMessage(Format('App exit code: %d', [se_wait_thread.ExitCode]));
  end
  else
    ShowMessage('Error Starting App');
end;
于 2013-10-31T18:17:49.153 に答える