ShellExecute()後のフォーカスを取り戻すには

解決


横井  2013-09-12 03:12:33  No: 45242  IP: [192.*.*.*]

みなさんよろしくお願いします。環境はWindows7  Delphi6Personalです。
やりたいこと:
Vキーを押したら、画像を表示し、最前画面にFormをだす。
次に、Zキーを押したら、画像のパスをLabelにコピーしたい。
現象:
Zキーが効かない。Form1をクリックすれば、効きます。
画像を表示した後も、引き続きキーが効くようにする方法を教えて頂けませんか。よろしくお願いします。
type
  TForm1 = class(TForm)
    Label1: TLabel;   //ココへパスをコピーする
    Edit1: TEdit;     //表示する画像のパスを置く
    Button1: TButton; //当初フォーカスを置いておく
    procedure FormCreate(Sender: TObject);
  private
    procedure MsgHandler(var Msg: TMsg; var Handled: Boolean);
  public
  end;
var
  Form1: TForm1;

implementation
uses  ShellAPI;

{$R *.dfm}
//Vキーを押すと画像を表示する。
//次にzキーを押してEdit1.textをコピーしたいがキーが効かない。
procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean);
begin
   if  (GetAsyncKeyState(Ord('V')) and $8000)<>0 then
     begin  Sleep(300);
        ShellExecute(Handle, 'OPEN', PChar(trim(Edit1.Text)+#0),nil, nil, SW_SHOWNORMAL);
        SetWindowPos(Handle,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE);//最前面に表示する
     end;

   if  (GetAsyncKeyState(Ord('Z')) and $8000)<>0 then
     begin  Sleep(300);
         Label1.Caption:=Edit1.Text;
     end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    Application.OnMessage:=  MsgHandler;
    Edit1.Text:='C:\Users\yokoi\Desktop\xxx.JPG';//サンプル画像
    ActiveControl:=Button1;//キーでEditに入力しないように
end;

編集    削除
deldel  2013-09-12 19:07:58  No: 45243  IP: [192.*.*.*]

簡単そうでなかなかうまくいかないものでした・・・
一応以下でできましたが・・・環境は同じです

procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean);
  procedure SetForceForegroundWindow(hTarget: HWND);
  var
    dwTargetID: DWORD;
    dwActiveID: DWORD;
  begin
    dwTargetID := GetWindowThreadProcessId(hTarget, nil);
    dwActiveID := GetWindowThreadProcessId(GetForegroundWindow, nil);
    SetForegroundWindow(hTarget);
    AttachThreadInput(dwTargetID, dwActiveID, True);
    BringWindowToTop(hTarget);
    AttachThreadInput(dwTargetID, dwActiveID, False);
  end;
begin
  if (GetAsyncKeyState(Ord('V')) and $8000) <> 0 then begin
    ShellExecute(Handle, 'OPEN', PChar(trim(Edit1.Text)+#0),nil, nil, SW_SHOWNORMAL);
    Sleep(300);

    SetForceForegroundWindow(Application.Handle);
    Application.ProcessMessages;
    SetForegroundWindow(Form1.Handle);
  end;

  if (GetAsyncKeyState(Ord('Z')) and $8000) <>0 then begin
    Label1.Caption:=Edit1.Text;
  end;
end;

編集    削除
Harry  2013-09-12 21:49:29  No: 45244  IP: [192.*.*.*]

おそらく横井さんのやりたいこととは違うと思いますが、ご参考までに。
(なお、、、なぜApplication.OnMessageを使っているのか、私には分からないのですが…??)

uses
  ShellAPI;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Self.FormStyle:=fsStayOnTop;
  Self.KeyPreview:=True;
  Edit1.Text:='C:\Users\yokoi\Desktop\xxx.JPG'; // サンプル画像
  Self.ActiveControl:=Button1;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  case Key of
    Ord('V'): ShellExecute(Self.Handle, 'open', PChar(Trim(Edit1.Text)), nil, nil, SW_SHOWNA); // SW_SHOWNOACTIVATE
    Ord('Z'): Label1.Caption:=Edit1.Text;
  end;
end;

編集    削除
Mr.XRAY  2013-09-12 23:05:55  No: 45245  IP: [192.*.*.*]

>簡単そうでなかなかうまくいかないものでした・・・

アプリケーションウィンドウに対応した,Vista 対応バージョンの Delphi だと
以下のようなコードでも動作しますね.
他のバージョンの Delphi をお持ちの方への参考として.
動作確認環境は,Windows 7 U64(SP1) + Delphi 2007-R2, Delphi 2009, 2010, XE
   
   if Msg.message = WM_KEYDOWN then begin
     if Chr(Msg.wParam and $FF) = 'V' then begin
       ShellExecute(Handle,
                    'OPEN',
                    PChar(Trim(Edit1.Text)),
                    nil,
                    nil,
                    SW_SHOWNA);
       //時間は起動するアプリによっては,もっと必要な場合がある        
       Sleep(100);
       SetForegroundWindow(Handle); 
       Label1.Caption := Chr(Msg.wParam and $FF);
     end else
     if Chr(Msg.wParam and $FF) = 'Z' then begin
       Label1.Caption := Edit1.Text;
     end;
   end;

編集    削除
Mr.XRAY  2013-09-13 10:22:02  No: 45246  IP: [192.*.*.*]

>アプリケーションウィンドウに対応した,Vista 対応バージョンの Delphi だと
>以下のようなコードでも動作しますね.
>他のバージョンの Delphi をお持ちの方への参考として.

ゴメンナサイ.
IDE から実行した場合はそうなりますが,EXE を直接起動した場合は
フォーカス移動しませんでした.
やっぱり工夫が必要ですね.

編集    削除
横井  2013-09-13 12:07:22  No: 45247  IP: [192.*.*.*]

deldelさん、Harryさん、Mr.XRAY さんありがとうございます。
私ごときが理解できるレベルではないでした。
現実にはありそうな処理ですが
実際のコードはもっと複雑で、テストしております。
結果が出たらまた報告させて頂きます。
今回は解決とさせて頂きます。
ありがとうございました。

編集    削除
Mr.XRAY  2013-09-13 21:07:32  No: 45248  IP: [192.*.*.*]

>環境はWindows7  Delphi6Personalです。

Windows 7 で JPEG 画像を表示するんですよね.
Windows フォトビューワ が起動していると思います.

ShellExecute の引数を以下のようにして,Windows フォトビューワを指定して起動してみてください.

var
  ViewerdllPath : String;
  ImagePath     : String;
begin
  ViewerdllPath := 'C:\Windows\system32\shimgvw.dll, ImageView_Fullscreen ';
  ImagePath     := Trim(Edit1.Text);

  ShellExecute(Handle,
               'OPEN',
               'Rundll32.exe',
               PChar(ViewerdllPath + ImagePath),
               nil,
               SW_SHOWNORMAL);

  Sleep(300);
  SetForegroundWindow(Handle);
  
動作確認は Windows 7 U64(SP1) + Delphi 7 Pro です.
Delphi 6 は現在使えない状態なので.
(質問のレス用に,正常に起動できないテストをして,そのままなので)

確実にやるには,ShellExecuteEx か CreateProcess で起動して,
Windows フォトビューワが完全に起動完了したのを確認してから
SetForegroundWindow(Handle); を実行するようにします.

しかし,Windows 7 で Delphi 6 は厳しいですね.

>私ごときが理解できるレベルではないでした。

理解できるできないに関わらず,やってみることだと思いますよ.
でなければ永遠に理解できませんからね.
もし,上のコードが理解できないからやらない,というのであれば,無視してください.
他の方にも参考にはなると思いますのでレスしておきます.

編集    削除
横井  2013-09-18 01:54:24  No: 45249  IP: [192.*.*.*]

テストの結果を報告させて頂きます。

deldel さん。
ほぼ完璧でした、使わせて頂きます。
ただキーのチャタリング防止のSleep(300);はあった方がよいようなきがしました。
    Sleep(300);
    ShellExecute(Handle, 'OPEN', PChar(trim(Edit1.Text)+#0),nil, nil, SW_SHOWNORMAL);
    Sleep(300);

Harry さん、ありがとうございました。
おっしゃるとおりMsgHandlerでメッセージをつかまえ
外部アプリを起動後に、フォーカスを取り戻すのがテーマでした。
ので目的が違いました。

Mr.XRAY さん、ありがとうございました。
起動したForm1を画像が表示されるだろう場所に移動して実行すると
  Sleep(300);
  SetForegroundWindow(Handle);
では、少なくとも私の環境では、Form1が画像の後面になりキーも効きませんでした。

以上報告させて頂きました。
おかげで解決しました。ありがとうございました。

編集    削除
Mr.XRAY  2013-09-18 03:32:37  No: 45250  IP: [192.*.*.*]

>起動したForm1を画像が表示されるだろう場所に移動して実行すると
>  Sleep(300);
>  SetForegroundWindow(Handle);
>では、少なくとも私の環境では、Form1が画像の後面になりキーも効きませんでした。

え !?
質問された方が動作すれば,コードは何でもいいのですが.
フォトビューアの起動が重たい (時間がかかる,遅い) のかな ?
でも,スレッドアタッチでは 300 ms で動作しているんだから ....
う〜む.困った.

いえ,横井さんには関係ないけど,個人的に悩みが増えました.

編集    削除