ShellExecute(Handle, 'OPEN', 'で起動したアプリを閉じるには。

解決


新米  2008-10-23 10:40:03  No: 32344

以前「Windows画像とFAXビューアーを使えませんか」で質問させて頂いた新米です。
やっとFAXビューアーを使ったスライドショーのひな形を
「美味しい草なら 」さんのサンプルを元に、元来同一フォルダ内の再生用を
任意のフォルダのファイルを集めて
ファイルをListboxに取得してスライドショーをするように作りました。
質問は
(1)このアプリがFAXビューアーに隠れた状態で動くのが運命なので
キーアクションを取得するのにいろいろやってタイマーを付けておけばキーアクションを
取得してショーができましたが、タイマーのアクションに頼るのでレスポンスが悪い。
何かいい方法はないでしょうか。
(2)ShellExecute(Handle, 'OPEN', 'Rundll32.exe',PChar(・・で起動したFAXビューアーを
キーアクション(この例ではQ)で閉じることができないでしょうか。
参考サイトを見てやりましたが閉じてくれません。
以上2点ですっきりしません。よりよい方法をお願いします。

見苦しいコードですが最低動く要点を書いてみます。
var  ListNo:integer;
//画像ファイルパスをListboxに登録する
procedure TForm1.Button1Click(Sender: TObject);
var
    i:integer;
begin
    Application.OnMessage := MsgHandler;  //スライドショーのキーアクションキャッチ
    ListBox1.Sorted:=true;
    OpenDialog1.Options:=[ofAllowMultiSelect]; //複数のファイルを選択する
    if OpenDialog1.Execute then
        for i := 0 to OpenDialog1.Files.Count - 1 do
            Listbox1.Items.Add(OpenDialog1.Files[i]);

    ListNo:=0;
end;
//キーアクションの取得
procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean);
var KeyNo:integer;
begin   //次へZ
        if (GetAsyncKeyState(90) <> 0) then begin Sleep(250);SlideShowDisp(1);exit;end
        else  //前へ A
        if  (GetAsyncKeyState(65) <> 0) then begin Sleep(250);SlideShowDisp(2);exit;end
        else  //Qは終了
        if  GetAsyncKeyState(81)<>0   then begin Sleep(250);SlideShowDisp(8);exit;end;
end;
//画像の表示
procedure TForm1.SlideShowDisp(const c:integer);
var
    hd:HWND;
    Path:string;
begin
    if ListBox1.Items.Count=0 then exit;
    case  c of
        1:  begin ListNo:=ListNo+1;end;  //------次へ  Z
        2:  begin ListNo:=ListNo-1;end;  //------前へ  A
        8:  begin
              hd := FindWindow('Rundll32.exe',nil);
              SendMessage(hd, WM_CLOSE, 0, 0);
              exit;
            end;
        else exit;
    end;
    if ListNo<0 then ListNo:=0;
    if ListNo>ListBox1.Items.Count-1 then ListNo:=ListBox1.Items.Count-1;
    Path:= 'shimgvw.dll,ImageView_Fullscreen '+ListBox1.Items.Strings[ListNo];
    ShellExecute(Handle, 'OPEN', 'Rundll32.exe',PChar(Path), nil, SW_SHOW);
end;
//画面が隠れてもキーアクションをキャッチできるように
procedure TForm1.Timer1Timer(Sender: TObject);
begin
    {nathing}
end;


新米  2008-10-23 20:08:09  No: 32345

だぶりました。すみません。自己レスです。
最初送信したら、サーバーがビジーです。と出たので
しばらくしてから、送信したら、二重になりました。
ご迷惑かけました。


monaa  2008-10-23 21:49:42  No: 32346

とりあえず
1) Hotkey
2) CreateProcess
で実現可能だと思います。

1)KeyHook案もありますが、vistaの管理者制限を受けるため少ないキー数なら私はHotkeyをお勧めします。
2)ネットで調べた限りですが、ShellExecuteは投げ捨て関数らしくその後の制御はほぼできないらしいです。


うんと  2008-10-24 06:39:12  No: 32347

1) タイマーで自分にメッセージを送って、無理やりメッセージループを回す
のはいかにも非効率ですね。自分でメッセージループを真似てループを回すと
いいです。

2)  ビューワのクラス名は ShImgVw:CPreviewWnd  なので

>hd := FindWindow('Rundll32.exe',nil);

ではなく

hd := FindWindow('ShImgVw:CPreviewWnd',nil);

とすると成功しますね。(Xp で確認)

とりあえずテストコードを示します。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    procedure GetKeyLoop;
    procedure SlideShowDisp(const c:integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  ShellAPI;

var
  ListNo:integer;
  flag :Boolean;

procedure TForm1.Button1Click(Sender: TObject);
var
    i:integer;
begin
    ListBox1.Sorted:=true;
    OpenDialog1.Options:=[ofAllowMultiSelect]; //複数のファイルを選択する
    if OpenDialog1.Execute then
        for i := 0 to OpenDialog1.Files.Count - 1 do
            Listbox1.Items.Add(OpenDialog1.Files[i]);

    ListNo:=0;

    flag := true;
    GetKeyLoop;
end;

function IsKeyPushed(ch : Char): Boolean;
begin
  result := (GetAsyncKeyState(ord(ch)) and $8000) <> 0;
end;

procedure TForm1.GetKeyLoop;
begin
  while flag do
  begin
    Application.ProcessMessages;
    Sleep(10);
    if IsKeyPushed('Z') then begin Sleep(250);SlideShowDisp(1);end
    else
    if IsKeyPushed('A') then begin Sleep(250);SlideShowDisp(2);end
    else
    if IsKeyPushed('Q') then begin Sleep(250);SlideShowDisp(8);end

  end;

end;

procedure TForm1.SlideShowDisp(const c:integer);
var
    hd:HWND;
    Path:string;
begin
    if ListBox1.Items.Count=0 then exit;
    case  c of
        1:  begin ListNo:=ListNo+1;end;  //------次へ  Z
        2:  begin ListNo:=ListNo-1;end;  //------前へ  A
        8:  begin
              hd := FindWindow('ShImgVw:CPreviewWnd',nil);
              SendMessage(hd, WM_CLOSE, 0, 0);
              flag := false;
              exit;
            end;
        else exit;
    end;
    if ListNo<0 then ListNo:=0;
    if ListNo>ListBox1.Items.Count-1 then ListNo:=ListBox1.Items.Count-1;
    Path:= 'shimgvw.dll,ImageView_Fullscreen '+ListBox1.Items.Strings[ListNo];
    ShellExecute(Handle, 'OPEN', 'Rundll32.exe',PChar(Path), nil, SW_SHOW);
end;

end.


新米  2008-10-24 10:44:51  No: 32348

皆さん有り難うございます。
monaaさんHOTkeyとはcontrolやshiftキーと組み合わせて登録する
ことですか、できれば一個のキーですませたいですが。
ShellExecuteはそれを覚えて閉じるとき使えないとサイトに書いてありました。起動した条件を覚えておいてそれを閉じるにはCreateProcess
でと書いてありましたが、C言語で理解できませんでした。
結構、「終了を知るには」はサイトが多くありますが、
閉じてしまうというのは意外とないです。

うんとさん、詳細な説明を有り難うございました。
正直まだまだ概論での説明では理解できないので助かりますし、
同時に実際のコードは勉強になります。
有り難うございました。


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

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






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