他のアプリケーションのeditフォームに対してテキストを送信するには?

解決


はげ山  2006-03-12 18:44:48  No: 20463

いつも拝見しております。
他のアプリケーションの複数のeditフォームに対して左上から順番にテキストを送信したいと考えております。
過去ログを参照しましたがsendmessageがつかえそうなのですが送信先アプリケーションeditフォームの順番が指定できません。
クラスの名前がすべて[edit]となっているためです。
どなたかよいお知恵を拝借できませんでしょうか?


キヲツケ前に習え  2006-03-12 19:22:55  No: 20464

それらのEDITが整然と配置されているなら、GetWindowRectで位置を取得すれば順番がつけられるはず。


はげ山  2006-03-12 20:17:49  No: 20465

早速のレスありがとうございます
GetWindowRectというものを使ってみましたが、すいませんさっぱり
わかりません。具体的には
var
  WinHnd   :  HWND;   //ウィンドウのハンドル
  EdtHnd   :  HWND;   //子ウィンドウのハンドル
  RT : TRect;
begin
 WinHnd   :=    FindWindow('TFormX', nil);
 SetForegroundWindow(WinHnd);
  GetWindowRect(EdtHnd,RT);
  //テキストを送信
  SendMessage(EdtHnd,WM_SETTEXT,0,LPARAM(PChar(Edit1.Text)));
end;
非常に汚いソースですが、どなたか解決策はお持ちでしょうか?
方法としては
①最初に一番左上のEDITを見つけ出しテキストデータを送信
その後、TABキーを送信しまたテキストデータを送信

②なにかしらの方法ですべてのEDITのハンドルを探し出し
1つずつ指定して送信
を考えています


2個↑  2006-03-12 22:45:26  No: 20466

EnumChildWindowあたりで子ウインドウをすべて列挙して、
GetWindowRectで位置を確認し、順番をつけろってことかと。

> ②なにかしらの方法ですべてのEDITのハンドルを探し出し
の回答ね。


はげ山  2006-03-12 23:31:52  No: 20467

EnumChildWindowを検索してみました。
EnumChildProcというコールバック関数(?)とセットになっている
ということは分かりましたが・・・
具体的な使い方がよく分かりません。
イメージ的には
①  FindWindowで目的のウィンドウを検索
②  SetForegroundWindowで目的のウィンドウを全面に
③  EnumChildWindowでそのウィンドウ内のハンドルを列挙?
④  GetWindowRectで位置を確認し、順番をつける?
⑤  あとは順番通りにsendmessageを送信
という感じでしょうか?
なにかサンプルソースでもあれば・・・
馬鹿でもうしわけありません


Mr.XRAY  URL  2006-03-13 01:22:33  No: 20468

状況の確認ですが,

>他のアプリケーションの複数のeditフォームに対して左上.
>クラスの名前がすべて[edit]となっているためです。
となっています.これは同じアプリを複数起動しているということですか? 
また

>WinHnd   :=    FindWindow('TFormX', nil);
こちらでは,クラス名はTFormXとなっていますが,このクラスの名前がeditと
いうのとはどういう関係なのでしょうか.
一つのFromに複数のEditコントロールが配置してあるということでしょうか.

そして,この「他のアプリ」というのは,Delphi製なのでしょうか.Delphi製
の場合,はげ山さんが作成したもの,ソースコードがあり,修正が可能な状
態なのでしょうか.あるいははげ山さんが作成したものでなくても,修正が
可能なのでしょうか.
開発に使用しているDelphiと開発実行環境のWindowsのバージョンは?

--------------------------
想定質問内容(丸に数字の文字は使用しない)

(1) Delphiで作成したアプリがある.ソースコードあり修正可能
(2) ここにTEditの入力コントロールが複数配置してある
(3) このTEditに,別のDelphiのアプリから文字列をセットしたい
(4) この時,左上のEditから順番にセットしたい
    (Tabオーダーは左上から順番になっているので,その順番)
(5) Dephi7 Pro ,WindowsXP で開発中
--------------------------
ということでよろしいでしょうか.
もし,以上の内容でしたら,方法はいつくか考えられます.


はげ山  2006-03-13 01:36:16  No: 20469

Mr.XRAY様  レスありがとうございます。
言葉足らずでもうしわけありません。
状況です
①他のアプリケーションはVB製ですが、ソースなどはありません。
②ここにEdit入力コントロールが複数配置してあります。
③そのEditに別のDelphiアプリから文字列をセットしたいです。
④この時、左上から順番になっているのでその順番です
⑤Delphi6 Pro,WindowsXPで開発中です。

どうぞ、宜しくお願い致します。


想定外なしヨ  2006-03-13 01:58:12  No: 20470

タブオーダーが配置順に並んでいると想定されるなら、クラス名を確認しながら、
GetWindow(hw, GW_HWNDFIRST);
GetWindow(hw, GW_HWNDNEXT);
で順にメッセージを送った方が簡単。


ん?  2006-03-13 02:16:20  No: 20471

参考までに・・・

http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_getwindow.asp
> すべての子ウィンドウを取得する場合、EnumChildWindows 関数を使った方が 
> GetWindow 関数をループ処理で呼び出すよりも信頼性の高い結果が得られます。

本サイトのサンプルプログラムと注意点(?)
http://madia.world.coocan.jp/delphi/Win32API.htm
http://madia.world.coocan.jp/delphi/Win32API/EnumWindows.htm
http://madia.world.coocan.jp/delphi/Win32API/EnumChid.htm
https://www.petitmonte.com/bbs/answers?question_id=901


Mr.XRAY  URL  2006-03-13 02:18:24  No: 20472

これはちょっと難しいです.最初の,つまり一番左上のEditコントロールを
まず知る必要があります.もし,入力フォーカスが,この一番左上にあるもの
と仮定すれば,Tabの移動メッセージを順番に送り,テキストを送るだけで
うまくいくとは思いますが...

そのVBで作られたEditのID値はどうなっていますか.
もし,ID値を調べるものがなければ,以下をDLして調べてみて下さい.

http://homepage2.nifty.com/Mr_XRAY/Halbow/ExeZip/WindowTree.lzh


Mr.XRAY  URL  2006-03-13 02:21:47  No: 20473

もし,ID値が利用できない状況であれば,EnumChildWindowsを使用する
ことになるでしょうね.
(開発時にID値が明示的に設定していなくて,起動ごとに変化する場合)


はげ山  2006-03-13 02:41:04  No: 20474

皆さん、レスありがとうございます!
Mr.XRAY様、IDは可変です。立ち上げるたびに変化しております。


Mr.XRAY  URL  2006-03-13 03:22:32  No: 20475

>IDは可変です。立ち上げるたびに変化しております。

そうすると,手順としては以下のようになるのではないかと思います
(1) 既にレスがあるように,このサイトのサンプルのEnumChildWindows を
    使用して,対象のアプリのフォームのハンドルから,クラスがEditの
    ハンドルを取得する.これが多分一番左上のEditに相当.
    (ただし,他のEditがそのフォームにないと仮定)
(2) SendMessageなどでテキストを送る
(3) 既にレスがある方法で次のコントロールにフォーカス移動する
       SendMessage(H, WM_KEYDOWN, VK_TAB,0);
       SendMessage(H, WM_KEYUP, VK_TAB,0);
    な方法もある(と思う).
(4) Editコントロールの数だけ実行したら終了


ヨコ  2006-03-13 03:55:36  No: 20476

はげ山 さんへ
Mr.XRAYさんが上の方で(丸に数字の文字は使用しない)と書かれていますが
①、②・・・等は機種依存文字ですのでこういう所では使用を控えましょう
「機種依存文字」は検索して調べてみてください


はげ山  2006-03-13 04:53:56  No: 20477

皆さん、ありがとうございます。
Mr.XRAY様の意見を参考にソースを作ってみたいと思います

「機種依存文字」の件、大変失礼しました。
今後気をつけます。
ありがとうございました。


Mr.XRAY  URL  2006-03-13 06:36:14  No: 20478

他にもコーディングの方法があるかも知れませんが,参考のためやってみました.
動作確認は,Delphi7 Pro,WindowwsXP(SP2)で,受け取る側のアプリは,Delphi
で作成したフォームにTEditを6個配置して行いました.
参考になれば幸いです.

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    function GetFocusWindow(hTarget: HWND): HWND;     
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;
  FirstEditHandle : HWND;

implementation

{$R *.DFM}

//var

//=============================================================================
//  子ウィンドウの列挙
//  クラス名がTEditの最後のウィンドウを取得.これがTabオーダーでは最初のコント
//  となる(感覚的に逆)
//=============================================================================
function EnumChildProc(hWnd :integer;lData:LPARAM) : BOOL ;Stdcall;
var
     Name :array[0..MAX_PATH] of Char;
begin
     if IsWindowVisible(hWnd) then begin
       GetClassName(hWnd,Name,MAX_PATH);
       if (Name='TEdit') then begin
         FirstEditHandle:=hWnd;
       end;
     end;
     Result:=True;
end;
//=============================================================================
//  ハンドルがPH上の子ウィンドウのEditに,Tabオーダーの順に文字列をセット
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
     PH  : HWND;
     CH  : HWND;
     Str : String;
     i   : Integer;
begin
     FirstEditHandle:=0;
     PH:=FindWindow('TReceiveForm',nil);
     if PH<>0 then begin
       EnumChildWindows(PH,@EnumChildProc, 0);
       Str:='テスト文字列0';
       CH :=FirstEditHandle;
       Windows.SetFocus(CH);
       SendMessage(CH,WM_SETFOCUS,0,0);
       SendMessage(CH,WM_SETTEXT,0,LPARAM(PChar(Str)));
       //GetFocusWindowの他の方法はクリップボード経由も考えられる
       for i:=1 to 5 do begin
         Str:='テスト'+IntToStr(i);
         //タブオーダーの次のコントロールにフォーカス移動
         SendMessage(PH,WM_NEXTDLGCTL,0,0);
         //そのコントロールのハンドルを取得
         CH:=GetFocusWindow(PH);
         SendMessage(CH,WM_SETTEXT,0,LPARAM(PChar(Str)));
         Application.ProcessMessages;
       end;
     end;
end;
//=============================================================================
//  他アプリケーションのコントロールのハンドルは,コントロールのID値がわかれば
//  ID値から取得できるが,不明の場合はフォーカスのあるコントロールであればこの
//  関数で取得できる.
//  GetForegroundWindowはトップウィンドウの取得,GetFocus単独では他のアプリの
//  場合常に0が返ってくる.AttachThreadInputを使用するとフォーカスのあるウィン
//  ドウ(コントロール)のハンドルを取得できる
//=============================================================================
function TForm1.GetFocusWindow(hTarget: HWND): HWND;
var
     dwTargetID: DWORD;
     dwActiveID: DWORD;
begin

     //操作対象ウィンドウのスレッドを取得
     dwTargetID := GetWindowThreadProcessId(hTarget,nil);
     //現在アクティブなウィンドウ(このアプリ)のスレッドを取得
     dwActiveID := GetCurrentThreadId;

     //hTargetをZオーダのトップにしてアクティブに
     BringWindowToTop(hTarget);
     if AttachThreadInput(dwActiveID,dwTargetID,True) then begin
       //フォーカスウィンドウの取得
       Result:=GetFocus;
       //アタッチを切離す
       AttachThreadInput(dwActiveID,dwTargetID,False);
     end else begin
       Result:=0;
     end;
end;

end.


違いが分かる貴方に…  2006-03-13 07:58:03  No: 20479

GetWindow(hw, GW_HWNDNEXT);
EnumChildWindows(hw, @EnumChildProc, 0);
などでフォーム内のコントロールを列挙する時、その順序は Zオーダーの順になる。この Zオーダーと TABオーダーの間には何の関連もない。
Delphiの IDEでフォームに TEdit(Edit1,Edit2,Edit3を貼りつけていくと、以下のように逆になってしまう。
ただし、すべてのアプリケーションがそうなっているわけではない。
設計の途中変更などでコントロールを追加したり削除したりして、後からTabオーダーの順序だけを整理したとすると、両者の関係はまったくバラバラになる。
通常、このようなことに頓着する必要は無いけれど、このスレッドのケースでは Zオーダーの順だけに頼ってソースを書くと問題となるね。

Control  Tab-Order  Z-Order
Edit1        0          2
Edit2        1          1
Edit3        2          0


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

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






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