ShellExecuteで実行したプロセスを終了させるには

解決


take  2004-04-25 17:19:47  No: 8612

ShellExecuteで実行したプロセスを終了させるには
どうすればいいのでしょうか?
関連づけによる起動が必要なのでできればCreateProcessは
使いたくありません。
お願いします。


つっか  2004-04-25 19:42:39  No: 8613

> 関連づけによる起動が必要なので

ここが参考になるかもしれません。

https://www.petitmonte.com/bbs/answers?question_id=1600


take  2004-04-26 01:52:38  No: 8614

レスありがとうございます。
でもすでにその記事は読んでいましてそして解決には至りませんでした。

ウインドウハンドルHWNDを使用したプロセスの終了方法を知りたいのですが
ご存じな方はいないでしょうか?


ふぐちゃん  2004-04-26 02:04:40  No: 8615

ウィンドウハンドルがわかっているのなら、
PostMessage(Wnd, WM_SYSCOMMAND, SC_CLOSE, 0);
ではどうでしょうか?


take  2004-04-27 05:28:09  No: 8616

こんな感じで起動して
  FHWnd := ShellExecute(0,'open',Params,nil,nil,SW_SHOWNORMAL);

言われるとおりとして終了させてみようと試み見ましたがだめでした。
  PostMessage(FHWnd, WM_SYSCOMMAND, SC_CLOSE, 0);

今回起動するアプリケーションはメディアプレイヤーですが
使用環境で変わります。


jok  2004-04-27 05:47:04  No: 8617

ShellExecute() の戻り値はウィンドウハンドルではありませんよ。


にしの  2004-04-27 06:01:39  No: 8618

jokさんの言われるとおり、ウィンドウハンドルではありません。
インスタンスハンドルのようです。

もし、ShellExecuteの戻り値が正しいインスタンスハンドルであれば、
1.FindWindow(またはEnumWindow)
2.GetWindowLongでGWL_HINSTANCEを取得
3.取得したインスタンスと、ShellExecuteの戻り値を比較
4.一致しなかったら探し直す
5.一致したらPostMessageして終了。
というような手順でできそうですが、未確認です。

ShellExecuteExでプロセス終了した方が簡単ですよ。


jok  2004-04-27 06:50:19  No: 8619

> 2.GetWindowLongでGWL_HINSTANCEを取得

ShellExecute() の戻り値は、エラー番号以外は Win32 では意味がないようです。
例えば、Delphi でつくられたアプリはすべてデフォルトでは $00400000 が
hInstance の値になります。これは、[プロジェクト]-[オプション]-[リンカ] の
イメージベースの値です。


スタテツ  2004-04-27 07:49:37  No: 8620

こんばんわです。
力技ですが。
var
  Form1: TForm1;
  hMyAppWnd : HWND;

implementation

{$R *.dfm}
function EnumWindowsProc(hwnd : THandle; lParam : longint):BOOL; stdcall;
var
  dwProcessId : integer;
begin
  Result := true;
  if (GetWindow(hwnd, GW_OWNER) = 0) and IsWindowVisible(hwnd) then begin
    GetWindowThreadProcessId(hwnd,@dwProcessId);
    if dwProcessId=lParam then begin
      hMyAppWnd := hwnd;
      Result := false;
    end;
  end;
end;

function exttoExepath(ext:string):string;
var
MyReg:TRegistry;
RleName:string;
ExePath:String;
begin
result:='';
MyReg:=TRegistry.Create;
MyReg.RootKey:=HKEY_CLASSES_ROOT;
try
  If not MyReg.OpenKey(ext,false) then ;
  RleName:=MyReg.ReadString('');
  if not MyReg.OpenKey( '\' + RleName+ '\Shell\Open\Command',false) then ;
  ExePath:=MyReg.ReadString('');
  result:=ExePath;
finally
  MyReg.Free;
end;
end;

procedure TForm1.ShellExecuteTx(path:string);
var
  StInfo : TStartupInfo;
  PrInfo : TProcessInformation;
  appPath:string;
  SystemDir: array[0..MAX_PATH - 1] of Char;
begin
  //こんなんじゃ実用に耐えませんので練りこんでください
  //-----------------------------------------------------------
  GetWindowsDirectory(SystemDir,Sizeof(SystemDir));
  appPath:=ExtractFileExt(path);
  appPath:=exttoExepath(appPath);
  appPath:=StringReplace(appPath,'%SystemRoot%',SystemDir,[]);
  appPath:=StringReplace(appPath,' %1','',[]);
  appPath:=appPath+' '+path;
  //-----------------------------------------------------------
  GetStartupInfo(StInfo);
  CreateProcess(nil, PChar(appPath),
  nil, nil, False, CREATE_DEFAULT_ERROR_MODE, nil, PChar(GetCurrentDir),
  StInfo, PrInfo);
  WaitForInputIdle(PrInfo.hProcess, INFINITE );
  EnumWindows(@EnumWindowsProc, PrInfo.dwProcessId);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecuteTx(ExtractFilePath(Application.ExeName)+'test.txt');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  SendMessage(hMyAppWnd, WM_CLOSE, 0, 0);
end;

「ShellExecuteExでプロセス終了」の方はわかりません。


スタテツ  2004-04-27 08:00:12  No: 8621

あぁぁ〜。
つっかさんがいきなりResしたスレッドで思いっきり語られてるじゃぁないですか。(x_x)
ごめんなさぃ〜。


jok  2004-04-27 08:10:12  No: 8622

> 「ShellExecuteExでプロセス終了」の方はわかりません。

こんな感じです。わたしのところでは、EmEditor が立ち上がって、10秒後に
閉じます。

uses
  ShellAPI;

var
  hProcess:THandle;

function ExecAndWaitQuit(FileOrURL:string):Boolean;
var
  sei:TShellExecuteInfo;
begin
  FillChar(sei,SizeOf(TShellExecuteInfo),#0);

  sei.cbSize := SizeOf(TShellExecuteInfo);
  sei.fMask  := SEE_MASK_NOCLOSEPROCESS;
  sei.Wnd    := Form1.Handle;
  sei.lpVerb := 'open';
  sei.lpFile := PChar(FileOrURL);
  sei.lpDirectory := PChar(ExtractFilePath(Application.Exename));
  sei.nShow  := SW_SHOWNORMAL;

  result := ShellExecuteEx(@sei);

  if result then
    hProcess := sei.hProcess
  else
    hProcess := 0;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if ExecAndWaitQuit('C:\Test.txt') then begin
    Sleep(10000);
    TerminateProcess(hProcess,0);
    CloseHandle(hProcess);
  end;
end;


jok  2004-04-27 08:20:58  No: 8623

すみません、上のコードは流用したのでちょっと変です。
以下のようにします。Button1Click で EmEditor が立ち上がり、
Button2Click で閉じます。

  public
    hProcess:THandle;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  ShellAPI;

function ExecAndGivehProcess(FileOrURL:string):THandle;
var
  sei:TShellExecuteInfo;
begin
  FillChar(sei,SizeOf(TShellExecuteInfo),#0);

  sei.cbSize := SizeOf(TShellExecuteInfo);
  sei.fMask  := SEE_MASK_NOCLOSEPROCESS;
  sei.Wnd    := Form1.Handle;
  sei.lpVerb := 'open';
  sei.lpFile := PChar(FileOrURL);
  sei.lpDirectory := PChar(ExtractFilePath(Application.Exename));
  sei.nShow  := SW_SHOWNORMAL;

  if ShellExecuteEx(@sei) then
    result := sei.hProcess
  else
    result := 0;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  hProcess := ExecAndGivehProcess('C:\Test.txt');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if hProcess <> 0 then begin
    TerminateProcess(hProcess,0);
    CloseHandle(hProcess);
    hProcess := 0;
  end;
end;


スタテツ  2004-04-27 08:49:51  No: 8624

jokさまフォーローありがとうございます。
    TerminateProcess(hProcess,0);
    CloseHandle(hProcess);
なるへそです。
TerminateProcess初めて使わせていただきました。
確かに終了できますし、こっちの方法の方が製作者側としてはスマートですね。
でも、これって『強制』終了ですね^^;
プロセスの終了ですから当然のですが…。
プロセスからWinodowハンドルを取得する方法は以前DelphiMLで話題になってます。
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=051925

どうもありがとうございました。


jok  2004-04-27 08:52:59  No: 8625

> プロセスからWinodowハンドルを取得する方法は以前DelphiMLで話題になってます。

そうですね、強制終了より、オーナのないトップレベルウィンドウハンドルを取得して
PostMessage() で終了した方がいいですね。ありがとうございました。


take  2004-04-29 06:19:56  No: 8626

遅くなりました。
今、試したのですがjokさんのサンプルソース通り
ShellExecuteExを使用して得られたhProcessを記憶しておき
終わらせたいときに
    TerminateProcess(hProcess,0);
    CloseHandle(hProcess);
    hProcess := 0;
とすることで終了することができました。

ありがとうございます。
これで解決としたいと思います。

でもPostMessage(hProcess, WM_SYSCOMMAND, SC_CLOSE, 0);
では終了させることが出来ませんでした。
なにか間違ってるのかな・・・


jok  2004-04-29 06:38:47  No: 8627

> でもPostMessage(hProcess, WM_SYSCOMMAND, SC_CLOSE, 0);
> では終了させることが出来ませんでした。

PostMessage() の第一引数はウィンドウハンドルです。プロセスハンドルを設定
してもダメです。


るるとん@K  2004-04-29 06:47:23  No: 8628

メモ帳を終了するサンプル
PostMessage(FindWindow(nil,'無題 - メモ帳'), WM_SYSCOMMAND, SC_CLOSE, 0);


るるとん@毛  2004-04-29 10:20:39  No: 8629

>スタテツ
>プロセスからWinodowハンドルを取得する方法
プロセスハンドルとプロセスIDは別物です。
ShellExecuteExからウィンドウハンドルを取得する事はできません。


るるとん@K  2004-04-29 18:33:40  No: 8630

るるとん@毛さん、そのハンドルやめて頂けないでしょうか?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加