ShellExecuteで実行したプロセスを終了させるには
どうすればいいのでしょうか?
関連づけによる起動が必要なのでできればCreateProcessは
使いたくありません。
お願いします。
> 関連づけによる起動が必要なので
ここが参考になるかもしれません。
https://www.petitmonte.com/bbs/answers?question_id=1600
レスありがとうございます。
でもすでにその記事は読んでいましてそして解決には至りませんでした。
ウインドウハンドルHWNDを使用したプロセスの終了方法を知りたいのですが
ご存じな方はいないでしょうか?
ウィンドウハンドルがわかっているのなら、
PostMessage(Wnd, WM_SYSCOMMAND, SC_CLOSE, 0);
ではどうでしょうか?
こんな感じで起動して
FHWnd := ShellExecute(0,'open',Params,nil,nil,SW_SHOWNORMAL);
言われるとおりとして終了させてみようと試み見ましたがだめでした。
PostMessage(FHWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
今回起動するアプリケーションはメディアプレイヤーですが
使用環境で変わります。
ShellExecute() の戻り値はウィンドウハンドルではありませんよ。
jokさんの言われるとおり、ウィンドウハンドルではありません。
インスタンスハンドルのようです。
もし、ShellExecuteの戻り値が正しいインスタンスハンドルであれば、
1.FindWindow(またはEnumWindow)
2.GetWindowLongでGWL_HINSTANCEを取得
3.取得したインスタンスと、ShellExecuteの戻り値を比較
4.一致しなかったら探し直す
5.一致したらPostMessageして終了。
というような手順でできそうですが、未確認です。
ShellExecuteExでプロセス終了した方が簡単ですよ。
> 2.GetWindowLongでGWL_HINSTANCEを取得
ShellExecute() の戻り値は、エラー番号以外は Win32 では意味がないようです。
例えば、Delphi でつくられたアプリはすべてデフォルトでは $00400000 が
hInstance の値になります。これは、[プロジェクト]-[オプション]-[リンカ] の
イメージベースの値です。
こんばんわです。
力技ですが。
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でプロセス終了」の方はわかりません。
あぁぁ〜。
つっかさんがいきなりResしたスレッドで思いっきり語られてるじゃぁないですか。(x_x)
ごめんなさぃ〜。
> 「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;
すみません、上のコードは流用したのでちょっと変です。
以下のようにします。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;
jokさまフォーローありがとうございます。
TerminateProcess(hProcess,0);
CloseHandle(hProcess);
なるへそです。
TerminateProcess初めて使わせていただきました。
確かに終了できますし、こっちの方法の方が製作者側としてはスマートですね。
でも、これって『強制』終了ですね^^;
プロセスの終了ですから当然のですが…。
プロセスからWinodowハンドルを取得する方法は以前DelphiMLで話題になってます。
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=051925
どうもありがとうございました。
> プロセスからWinodowハンドルを取得する方法は以前DelphiMLで話題になってます。
そうですね、強制終了より、オーナのないトップレベルウィンドウハンドルを取得して
PostMessage() で終了した方がいいですね。ありがとうございました。
遅くなりました。
今、試したのですがjokさんのサンプルソース通り
ShellExecuteExを使用して得られたhProcessを記憶しておき
終わらせたいときに
TerminateProcess(hProcess,0);
CloseHandle(hProcess);
hProcess := 0;
とすることで終了することができました。
ありがとうございます。
これで解決としたいと思います。
でもPostMessage(hProcess, WM_SYSCOMMAND, SC_CLOSE, 0);
では終了させることが出来ませんでした。
なにか間違ってるのかな・・・
> でもPostMessage(hProcess, WM_SYSCOMMAND, SC_CLOSE, 0);
> では終了させることが出来ませんでした。
PostMessage() の第一引数はウィンドウハンドルです。プロセスハンドルを設定
してもダメです。
メモ帳を終了するサンプル
PostMessage(FindWindow(nil,'無題 - メモ帳'), WM_SYSCOMMAND, SC_CLOSE, 0);
>スタテツ
>プロセスからWinodowハンドルを取得する方法
プロセスハンドルとプロセスIDは別物です。
ShellExecuteExからウィンドウハンドルを取得する事はできません。
るるとん@毛さん、そのハンドルやめて頂けないでしょうか?
ツイート | ![]() |