Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: ShellExecuteで表示された画面が隠れないようにするには?


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 11 - Last Post: Mar 30, 2017 5:10 AM Last Post By: osamu nagao
osamu nagao

Posts: 97
Registered: 3/22/04
ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 24, 2017 10:22 PM
nagaoです。いつも教えて頂きありがとうございます。
下記のテストプログラムでButton1をクリックすると、Yahooの画面が表示されますが、
Form1のFormStyleプロパティをfsStayOnTopにするとForm1の裏に隠れてしまいます。
fsStayOnTopでも隠れなくする方法はないでしょうか?

unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,shellapi, Vcl.StdCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
begin
   ShellExecute(Form1.handle,pchar('open'),
      pchar('http://www.yahoo.co.jp/'), nil,nil,SW_SHOW);
 
end;
 
end.
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 27, 2017 1:45 PM   in response to: osamu nagao in response to: osamu nagao
自己レスです。
裏に隠れてしまうのを防止する直接的な方法がないのであれば、
a)表示されているFormをすべて検知する方法
b)開いたホームページが閉じられたことを検知する方法
はないですか?、
これらの方法があれば、強引ではありますが、次の方法で目的を果たしたいと思います。
1)表示されているすべてのFormをスクリーン外に移動させた後、ホームページを表示させる。
2)その後、Timerでホームページが未だ開けれているか、1秒置きに調べ、閉じられたのであれば、
 すべてのFormを元の位置に戻す。
Atsuya Sakamoto

Posts: 18
Registered: 7/21/07
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 27, 2017 4:59 PM   in response to: osamu nagao in response to: osamu nagao
坂本です。

基本C++でDelphiは使ってないのでソースの例は出せませんが、
WindowsAPIを使うのであれば同じだと思うので、例示としてレスしますね。

a)表示されているFormをすべて検知する方法
EnumWindowsで自分が作成したもの以外も含めて列挙できます。
https://msdn.microsoft.com/ja-jp/library/cc410851.aspx
http://wisdom.sakura.ne.jp/system/winapi/win32/win142.html
特定のWindowを探す方法とてFindWindowという関数もあります。
https://msdn.microsoft.com/ja-jp/library/cc364634.aspx

b)開いたホームページが閉じられたことを検知する方法
上記を定期的に実行し、見つからなければ閉じられた
と認識する事は可能ではあると思います。

あとは、SetWindowPosで、作成したWindowを最前面にする方法もあると思います。
https://msdn.microsoft.com/ja-jp/library/cc411206.aspx

---- A.Sakamoto
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 28, 2017 12:04 AM   in response to: Atsuya Sakamoto in response to: Atsuya Sakamoto
坂本さん、こんにちは。nagaoです。
レス下さいましてありがとうございます。
折角助言頂きましたが、私はWindowsAPIに精通しておりませんので、すぐには役立てることができません。
WindowsAPIを習得するよりも、急ぐ仕事がありますので、本件は勝手ですが、私の後日の宿題とさせていただきます。

追記
このフォーラムは、「私はWindowsAPIに精通していないので、どなたかDelphi言語で私の希望することを達成する方法
を教えて頂けませんでしょうか?」と云った発言も許される場なのでしょうか?

Edited by: osamu nagao on Mar 28, 2017 1:14 AM
igy kk

Posts: 147
Registered: 9/11/03
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 28, 2017 1:45 AM   in response to: osamu nagao in response to: osamu nagao
osamu nagao wrote:
このフォーラムは、「私はWindowsAPIに精通していないので、どなたかDelphi言語で私の希望することを達成する方法
を教えて頂けませんでしょうか?」と云った発言も許される場なのでしょうか?

発言するのは、OKだと思いますよ。

ヒントになりそうな情報は、すでにSakamoto さんから、提供されていますので、
その情報を元に、
 ここまで、やってみましたが、この部分がわかりません
みたいなことでしたら、返信もらえる確率は高くなると思いますし、
質問に興味がある人であれば、調べて教えてくれる人もいるでしょう。

ただ、
WindowsAPIを習得するよりも、急ぐ仕事がありますので、
とか、書くと、「私は忙しくて、手間をかけて調べたくないので、かわりにコードを書いてください。」と
言っているのと同じと、とられる可能性は、ありますね。

あと、

WindowsAPIを習得するより

とのことですが、WindowsAPIは習得するものというより、
(知らないものであれば)調べて、実際にコード書いてみて、希望する動作をするか確認すればよいだけなので、

私はWindowsAPIに精通していないので

というのは、「WindowsAPIを調べる気がないので」と、とられるかもしれませんね。

Edited by: igy kk on Mar 28, 2017 2:55 AM
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 28, 2017 1:41 PM   in response to: igy kk in response to: igy kk
igy kk さん、こんにちは。nagaoです。
レスくださいましてありがとういございます。

ヒントになりそうな情報は、すでにSakamoto さんから、提供されていますので、
その情報を元に、
 ここまで、やってみましたが、この部分がわかりません
みたいなことでしたら、返信もらえる確率は高くなると思いますし、
質問に興味がある人であれば、調べて教えてくれる人もいるでしょう。
今後はそうします。

ただ、
WindowsAPIを習得するよりも、急ぐ仕事がありますので、
とか、書くと、「私は忙しくて、手間をかけて調べたくないので、かわりにコードを書いてください。」と
言っているのと同じと、とられる可能性は、ありますね。
・・・・・・
・・・・・・
・・・・・・
確かにそのような考えをしていた側面もあります。虫のいいことを考えていました。
発言を取り消します。

なお、本件は私が自作しているヘルプ機能で起きている問題であり、ヘルプ文の中に表示されている
URLの文字列をクリックすると、リンクしてそれが表示される部分で起きている問題です。
前面には表示されませんが、裏には表示されていますので、「後でこのソフトを終了してから、
そのURLを見て下さい。」ということで、当面凌ぐことに致します。
今回教えて頂いたことは、大切に記録しておきます。

Edited by: osamu nagao on Mar 28, 2017 3:48 PM
Makoto Saito

Posts: 26
Registered: 12/5/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 29, 2017 2:43 AM   in response to: osamu nagao in response to: osamu nagao
fsStayOnTop というのは,文字通りトップにステイ,つまり,常に最前面に表示するための設定です.
したがって,そのフォームから他のアプリ,ウィンドウを表示しても,最前面に表示できます.
つまり,そのようにしたい場合に利用できるわけです.
基本的に,『裏に隠れてしまう』のではなく『裏に隠したい』時に利用するわけです.

fsStayOnTop のフォームから別のウィンドウを表示した時.別のウィンドウを最前面に表示するには,
そのウィンドウの Z オーダを TOPMOST にすれば可能です.
Delphi の fsStayOnTop は,この TOPMOST の指定と同じです.
別のウィンドウを TOPMOST にすれば,
そのウィンドウと起動した元のフォームのどちらも前面に表示できるようになります.

以下は TOPMOST の簡単なテストコードです.
ほとんど Windows API だけのコードですが,他の方の参考になればと思います.
以下の Windows API を使用しています.

ShellExecute
FindWindow
SetForegroundWindow
SetWindowPos

Windows API に精通していなくても Windows API を使ってもいいと思いますし,使えます.
山に精通していなくても,山登りしてもいいと思いますし,山登りできます.

フォームに TButtton を 2 つ配置して,以下のコードにします.
動作確認は Windows 7 U64(SP1) + Delphi XE(UP1) Pro です.

uses
  ShellAPI;
 
{$R *.dfm}
 
//=============================================================================
//  フォーム生成時の処理
//  このフォームをTOPMOSTのウィンドウにしてみる
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Self.FormStyle := fsStayOnTop;
end;
 
//=============================================================================
//  メモ帳を起動
//  このフォームがメモ帳よりも上に表示される
//  usesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(Handle, '', 'Notepad.exe', nil, nil, SW_SHOW);
end;
 
//=============================================================================
//  メモ帳を最前面に表示
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LHandle : HWND;
  LFlags  : Cardinal;
begin
  LHandle := FindWindow('Notepad', nil);
 
  if LHandle > 0 then begin
    LFlags := SWP_NOSIZE or SWP_NOMOVE or SWP_SHOWWINDOW;
 
    SetForegroundWindow(LHandle);
    SetWindowPos(LHandle, HWND_TOPMOST, 0, 0, 0, 0, LFlags);
  end;
end;


Edited by: Makoto Saito on Mar 29, 2017 2:44 AM
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 29, 2017 1:51 PM   in response to: Makoto Saito in response to: Makoto Saito
Makoto Saitoさん、こんにちは。nagaoです。
レスくださいましてありがとうございます。

フォームに TButtton を 2 つ配置して,以下のコードにします.
・・・・・
・・・・・
教えて頂きましたコードでNotepad.exeの場合は、私の希望するような動作を実現できることを確認しました。
しかし、下記のコードでは、Button2をクリックしても、Yahooのページが前面に出てきません。
FindWindowのAPIを見てもなぜだか分かりません。
どうように修正すればよいのでしょうか?
また、FindWindowを手始めにしてAPIの学習をし、自分でも修正方法が分かるようになりたいと思います。
どのような学習方法がいいのでしょうか?

unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,ShellAPI, Vcl.StdCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  shellexecute(form1.handle,pchar('open'),
              pchar('http://www.yahoo.co.jp/'),
              nil,nil,SW_SHOW);
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
  LHandle : HWND;
  LFlags  : Cardinal;
begin
  LHandle := FindWindow(pchar('http://www.yahoo.co.jp/'), nil);
 
  if LHandle > 0 then begin
    LFlags := SWP_NOSIZE or SWP_NOMOVE or SWP_SHOWWINDOW;
    SetForegroundWindow(LHandle);
    SetWindowPos(LHandle, HWND_TOPMOST, 0, 0, 0, 0, LFlags);
  end;
 
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Self.FormStyle := fsStayOnTop;
 
end;
 
end.
Atsuya Sakamoto

Posts: 18
Registered: 7/21/07
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 29, 2017 6:02 PM   in response to: osamu nagao in response to: osamu nagao
坂本です。

しかし、下記のコードでは、Button2をクリックしても、
Yahooのページが前面に出てきません。
FindWindowのAPIを見てもなぜだか分かりません。
どうように修正すればよいのでしょうか?
FindWindowでは、第1パラメータにクラス名、第2パラメータにウィンドウ名なので、
www.yahoo.co.jpをクラス名に指定しても、左記はURLである為、
ウィンドウを見つける事ができません。
https://msdn.microsoft.com/ja-jp/library/cc364634.aspx

今回の場合、クラス名はnilで、ウィンドウ名にURLを開いているソフトウェア
(WEBブラウザ)のタイトルバー文字列を指定してやればいいと思います。
具体的には、以下のようにします
LHandle=FindWindow(nil,pchar('http://www.yahoo.co.jp/'))

また、FindWindowを手始めにしてAPIの学習をし、
自分でも修正方法が分かるようになりたいと思います。
どのような学習方法がいいのでしょうか?
WindowsAPIの学習について、私はC++Builder1からのユーザで、
WindowsAPIを使わずに10年くらいWindowsのプログラムを作成してきたので、
私も当初はかなり戸惑いました。
理由としては、WindowsAPIの解説で出てくる、使用される変数に、
基本的な型が殆ど無いからです。

ですが、これは実際の所、以下のような感じが殆どです。
※以下は乱暴な例え方で、厳密には違う部分もあります。
※変数名はC言語の例です。
・WORD=ANSIの1Byte文字変数(CHAR)に対する2Byte文字変数
=unsigned int
・DWORD=DOUBLE WORD変数=2倍の2Byte文字変数
=Unicode等の4Byte文字変数=unsigned long
・LPTSTR=文字列のポインタ=char[]=""で作成される文字列のポインタ
・LPVOID=VOID型のポインタ=void*
・WLARAM/LPARAM=OS依存のbit長パラメータ型
16bitOS=unsigned short(16bit)
32bitOS=unsigned long(32bit)
64bitOS=unsigned long long(64bit)
要は、Microsoftが、色々な変数を別の型として個別に呼び名を付けて定義
してるだけで、その実体は今まで使用してきた変数と変わりません。
なので、型が分かれば今までやっている事と特に変わりはないです。

勿論、DelphiからWindowsAPIに変数を渡す場合はキャストは必要ですが、
要はキャストすれば普通にWindowsAPIへDelphiから変数を渡すことも、
WindowsAPIからDelphiへ変数を渡すこともでき、WindowsAPIは動くという事です。

あと、よく出てくる"ウィンドウのハンドル"ですが、
これは、要は、Windowsが管理しているウィンドウ自体のポインタであり、
ウィンドウのポインタをHANDLEとかHWNDという型で定義しているもの
だと考えるのが妥当だと思います。
これらは、RadStudioのTForm等にあるHandle変数と互換があります。
キャストは必要ですが、ウィンドウのハンドルが必要な場合は、Form->Handle
を渡せばいいだけです。

この辺りを理解できれば、あとは、今回使用しようとしているような、
SetWindowPosやFindWindowのような、パラメータを指定してやれば
実行できるWindowsAPIを試してみればいいと思います。

この辺りが普通に気兼ねなく使えるようになったら、もう少し難しい、
EnumWindowsのようなCALLBACK関数を必要とするようなWindowsAPIや、
SendMessageのようなウィンドウメッセージを処理する関数を試してみる
といいと思います。

---- A.Sakamoto
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 29, 2017 8:28 PM   in response to: Atsuya Sakamoto in response to: Atsuya Sakamoto
坂本さん、こんにちは、nagaoです。
レス下さいましてありがとうございます。

具体的には、以下のようにします
LHandle=FindWindow(nil,pchar('http://www.yahoo.co.jp/'))
教えて頂いたことに従い、私のテストプログラムを下記のように変えた上で動作テスト
しましたが、Botton2をクリックしても、ヤフーの画面は隠れたままです。
動作環境は、Window10+Delphi10.1Berlinです。
どこが間違っているのでしょうか?

なお、このこと以外にも色々教えていただいましたが、それらのことは、この問題が
解決してから習得させていただきます。

unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,ShellAPI, Vcl.StdCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  shellexecute(form1.handle,pchar('open'),
              pchar('http://www.yahoo.co.jp/'),
              nil,nil,SW_SHOW);
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
  LHandle : HWND;
  LFlags  : Cardinal;
begin
  LHandle := FindWindow(nil,pchar('http://www.yahoo.co.jp/'));
  //上記ように変えましたが、この行を実行してもFindWindowの返り値は0です。
 
  if LHandle > 0 then begin
    LFlags := SWP_NOSIZE or SWP_NOMOVE or SWP_SHOWWINDOW;
    SetForegroundWindow(LHandle);
    SetWindowPos(LHandle, HWND_TOPMOST, 0, 0, 0, 0, LFlags);
  end;
 
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Self.FormStyle := fsStayOnTop;
 
end;
 
end.
Makoto Saito

Posts: 26
Registered: 12/5/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 29, 2017 8:54 PM   in response to: osamu nagao in response to: osamu nagao
LHandle := FindWindow(pchar('http://www.yahoo.co.jp/'), nil);

と書いていますが,Sakamoto さんが既にレスしているリンク,
https://msdn.microsoft.com/ja-jp/library/cc364634.aspx

では,以下のようになっています.
HWND FindWindow(
  LPCTSTR lpClassName,  // クラス名
  LPCTSTR lpWindowName  // ウィンドウ名
);

第 1 引数は クラス名と書いてあります.
ということは,クラス名は何かを知る必要があるということになります.
http:// で始まる文字列はウェブページのアドレスであって,クラス名ではりません.
また,ウィンドウ名でもありません.

FindWindowのAPIを見てもなぜだか分かりません。

これが本当なら正直言って,あきらめた方がいいと思います.
当然ですが,「見る」のではなく「読む」ことです.
例外はともかくとして,読んですぐ理解できる方はほとんどいないと思います.
たからこそ,ネット上に記事を掲載したり,苦労したので備忘録にして書いている方がいるわけです.

クラス名やウインドウ名とウェブページのアドレスとの区別がつかない段階では無理があります.
これらは,ネット上にいくらでも情報があると思います.
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ShellExecuteで表示された画面が隠れないようにするには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 30, 2017 5:10 AM   in response to: Makoto Saito in response to: Makoto Saito
今回レス下さいました皆様、こんばんわ。nagaoです。

クラス名やウインドウ名とウェブページのアドレスとの区別がつかない段階では無理があります.
これらは,ネット上にいくらでも情報があると思います.
この頂きましたヒントに基づいて、
”デスクトップ上のウインドウのクラス名とタイトルを取得するプログラム”
http://www.gesource.jp/weblog/?p=417
からダウンロードして得たWindowInfo.exeを実行して調べた結果、例えばYahooの
ホームページのクラスはApplicationFrameWindowで、ウインドウのタイトルは
Yahoo! JAPAN と 160 ページ ?- Microsoft Edgeであることが分かりました。

そこで、問題になっていた行を
LHandle := FindWindow(pchar('ApplicationFrameWindow'), nil);
に変更した結果、開いたどのホームページも、表に表示されるようになりました。
これで私の希望することは達成されました。

今回も大変お世話になりました。
Windows APIについては、ほんの少しですが光が見えてきたように思います。
今回教えて頂いたことの殆どは未習得ですので、今後折に触れ読み返してゆこうと
思っています。
ありがとうございました。
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02