C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[11]: SendKeys.Sendメソッドについて


(過去ログ 115 を表示中)

[トピック内 16 記事 (1 - 16 表示)]  << 0 >>

■67915 / inTopicNo.1)  SendKeys.Sendメソッドについて
  
□投稿者/ なお (1回)-(2013/09/10(Tue) 00:26:48)

分類:[C#] 

2013/09/10(Tue) 00:29:42 編集(投稿者)

用言語:Visual Studio 2010 C#、使用PC:Windows 7

1つのアプリケーション(APP1)から別のアプリケーション(APP2)を操作しています。
詳細コードは割愛しますが、APP1のボタン実行後、SendKeys.Sendメソッドを使用してAPP2を操作しています。
Windows 7やXPのPCのほとんどは問題なく操作出来ているのですが、一部のXPのPCでAPP2が正しく操作出来ないことがあります。
(APP1のボタンを何度か押せばAPP2は動作することがある。⇒APP1のボタンを押してもAPP2が反応しないことがある。)

そのため、Application.DoEventsメソッドをSendKeys.Sendメソッドの後に入れ、メッセージキューにあるWindowsメッセージをすべて処理してから
APP1のボタンを実行するたびにAPP2が動作すると思いましたが、不具合は解消されません。

使用PCによって、別のアプリケーションが操作出来ないことが発生することはあるのでしょうか?またその解消法をご存知の方、ご教示お願い致します。
引用返信 編集キー/
■67916 / inTopicNo.2)  Re[1]: SendKeys.Sendメソッドについて
□投稿者/ daive (15回)-(2013/09/10(Tue) 06:38:33)
2013/09/10(Tue) 07:01:42 編集(投稿者)
2013/09/10(Tue) 06:54:36 編集(投稿者)

MSの該当文書(非推奨)が、見つからないので、参考程度の書込みです。
(記憶の限り、VB4の頃には非推奨だったはず、うろ覚え。
 .NETでもサポートされているのは、要望が多いからなんだろうなぁ。)
.NET Framework の SendKeys.Send メソッド(1.1〜4.5迄資料あり)
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.sendkeys.send(v=vs.110).aspx
 【4.5版抜粋】
SendKeys クラスはタイミングに関する問題の影響を受けやすく、
一部の開発者はこれを回避する必要がありました。 更新された実装では、
まだタイミングに関する問題の影響を受けやすい状態ですが、若干高速になるため、
回避策の変更が必要な場合があります。 SendKeys クラスは、最初に以前の実装を使用し、
それに失敗した場合に新しい実装を使用します。 したがって、SendKeys クラスの動作は、
オペレーティング システムによって異なる場合があります。
また、SendKeys クラスが新しい実装を使用する場合は、SendWait メソッドは、
メッセージが別のプロセスに対して送信されたときに、そのメッセージが処理されるまで待機しません。
アプリケーションがオペレーティング システムに関係なく一定の動作に依存する場合、
app.config ファイルに次のアプリケーション設定を追加することで
SendKeys クラスに新しい実装を強制的に使用させることができます。

SendKeys自体は、古いWindows3.1迄で使われた機能で、
Windows95/WindowsNT 以後では、
操作が、SendKeys以外では出来ない場合にのみ、使う機能だと思っています。
SendKeysは、アクティブなウィンドへ、キーストローク相当のデータを送信します。
アクティブなウィンドが、変わり得るマルチタスク環境では、支障が出るのは当然かも。
例えば、
メモ帳を操作をしようとする場合は、
メモ帳互換アプリが公開されているので、
それを使う方が簡単。
Shell "NotePad.exe"
Shell "Calc.exe"
で、Sendkeysで操作
なんて解説している、本、サンプルは、古すぎ。

APP1、APP2が自前アプリであれば、
1.操作用のIFを付ける。
  ⇒古くは、操作用ファイルを作ってとかやりましたけど、今は、色々な方法が取れます。
2.メモリーマップドファイルなどで、メモリー共有をする。
3.WCFで、、、(.NET Remotingと呼ばれた機能の更新版)
自前アプリでなく、Windowsアプリであれば、
4.SPY++などで、ウィンドハンドル、コントロールを調べて、、
WEBが対象であれば、
5.ウェッブブラウザーコントロールから、サンプルを作って、、、
   対象ブラウザを決めて、、、、
フラッシュが対象であれば、
6.アプリの操作情報が解らないと、、、

OFFICEなどは、interop サポートがある製品、無い製品、、
createobject で扱える場合、、、
引用返信 編集キー/
■67918 / inTopicNo.3)  Re[2]: SendKeys.Sendメソッドについて
□投稿者/ kiku (21回)-(2013/09/10(Tue) 09:33:44)
すでに回答されているdaiveさんの通りなのですが、
わたしの場合、送る前に、ちょっとだけsleep入れると動いたりしていました。
PCの性能などによって調整するパラメータとして対応しました。
参考まで。

引用返信 編集キー/
■67935 / inTopicNo.4)  Re[3]: SendKeys.Sendメソッドについて
□投稿者/ なお (2回)-(2013/09/11(Wed) 10:36:05)
2013/09/11(Wed) 10:50:32 編集(投稿者)

daive-san,kiku-san

ご回答有難う御座いました。内容は理解致しました。
対処としてAPP2のWindowハンドルを取得して、Postmessageにてキー入力を試みようと思います。
詳細は割愛しますが、Bまでは問題なく目的のWindowハンドルを取得出来ました。(hWndWorkPtr)
しかし、PostMessageの第1引数にそのハンドルが格納されません。何故でしょうか?
因みに目的のWindowハンドルはtoolstripsでその中のボタン(F8実行)を実行しようとしています。

private const int VK_F5 = 0x74;
private const int WM_KEYDOWN = 0x100;
--------------------------------------------------------------------------------------
@ hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 子ウインドウ //
A hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 2番目孫ウインドウ //
B hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 1番目孫ウインドウ //

C PostMessage(hWndWorkPtr, WM_KEYDOWN, VK_F5, 0);

お手数おかけ致しますが、ご確認のほど宜しくお願い致します。

引用返信 編集キー/
■67936 / inTopicNo.5)  Re[4]: SendKeys.Sendメソッドについて
□投稿者/ Hongliang (96回)-(2013/09/11(Wed) 11:30:35)
> 詳細は割愛しますが、(3)までは問題なく目的のWindowハンドルを取得出来ました。(hWndWorkPtr)
> しかし、PostMessageの第1引数にそのハンドルが格納されません。何故でしょうか?

「第1引数にハンドルが格納されない」というのはどういうことをさしているのでしょうか?
(3)の後で、hWndWorkPtrに目的のハンドルが格納されたのは確認されているのですよね?
それを引数に渡すだけで、格納されないも何もないと思うのですが……。
受け取る側は自作関数でもないので、仮引数に格納されたかどうかなんて確認しようはないですし。
引用返信 編集キー/
■67937 / inTopicNo.6)  Re[5]: SendKeys.Sendメソッドについて
□投稿者/ なお (3回)-(2013/09/11(Wed) 11:37:05)
2013/09/11(Wed) 11:40:01 編集(投稿者)

Hongliang-san

ご回答有難う御座います。

Hongliang-san ご指摘のとおり、以下の内容は確認が取れています。
> (3)の後で、hWndWorkPtrに目的のハンドルが格納されたのは確認されているのですよね?

そこから単に引数に渡すだけで良いと私も思っていたんですがBからCへステップインすると、
Bで取得したハンドル(hWndWorkPtr)がCで0になってしまうんです。

理由が分からずに困っています。さきほどのBからCの間に何か特別なことが必要なのでしょうか?

因みにPostmesseageの宣言は以下のようにしています。
[DllImport("User32.dll", EntryPoint = "PostMessage")] //
public static extern int PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); //
引用返信 編集キー/
■67938 / inTopicNo.7)  Re[6]: SendKeys.Sendメソッドについて
□投稿者/ 魔界の仮面弁士 (331回)-(2013/09/11(Wed) 12:15:45)
No67937 (なお さん) に返信
> そこから単に引数に渡すだけで良いと私も思っていたんですがBからCへステップインすると、
> Bで取得したハンドル(hWndWorkPtr)がCで0になってしまうんです。

a = …
b = GetWindow(a, GW_CHILD);
c = GetWindow(b, GW_HWNDNEXT);
d = GetWindow(c, GW_CHILD);
e = d
ret = PostMessage(e, WM_KEYDOWN, VK_F5, 0);

のようにした場合、e と d の両方が IntPtr.Zero になるのでしょうか?


> [DllImport("User32.dll", EntryPoint = "PostMessage")] //
> public static extern int PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); //
今回は AnyCPU ビルドでは無く、x86 ビルドなのでしょうか?
(LPARAM/WPARAM/LRESULT は本来、IntPtr のサイズになります)
引用返信 編集キー/
■67939 / inTopicNo.8)  Re[7]: SendKeys.Sendメソッドについて
□投稿者/ Hongliang (97回)-(2013/09/11(Wed) 12:18:45)
// かぶったので返答は略。

> 今回は AnyCPU ビルドでは無く、x86 ビルドなのでしょうか?
> (LPARAM/WPARAM/LRESULT は本来、IntPtr のサイズになります)

PostMessageだから返値はLRESULTじゃなくてBOOLです。
引用返信 編集キー/
■67941 / inTopicNo.9)  Re[7]: SendKeys.Sendメソッドについて
□投稿者/ なお (4回)-(2013/09/11(Wed) 13:17:02)
2013/09/11(Wed) 13:17:18 編集(投稿者)

魔界の仮面弁士さん、Hongliangさん

ご回答ありがとうございます。
e と d の両方が IntPtr.Zero になります。尚、x86ビルドです。

すみません。
混乱してきたのですが、Postmessegeの宣言と使い方は下記、間違いに対してどのようにしたら宜しいのでしょうか?
ご教示頂いた上で理解を深めようと思います。お手数おかけ致しますが、ご回答宜しくお願い致します。


[DllImport("User32.dll", EntryPoint = "PostMessage")] //
public static extern int PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); //
--------------------------------------------------------------------------------------
private const int VK_F5 = 0x74;
private const int WM_KEYDOWN = 0x100;
--------------------------------------------------------------------------------------
I
ntPtr hWndWorkPtr, a;
@ hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 子ウインドウ //
A hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 2番目孫ウインドウ //
B hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 1番目孫ウインドウ //

a = hWndWorkPtr

C PostMessage(a, WM_KEYDOWN, VK_F5, 0);

引用返信 編集キー/
■67942 / inTopicNo.10)  Re[8]: SendKeys.Sendメソッドについて
□投稿者/ 魔界の仮面弁士 (332回)-(2013/09/11(Wed) 13:28:23)
No67939 (Hongliang さん) に返信
>>今回は AnyCPU ビルドでは無く、x86 ビルドなのでしょうか?
>>(LPARAM/WPARAM/LRESULT は本来、IntPtr のサイズになります)
> PostMessageだから返値はLRESULTじゃなくてBOOLです。

PostMessage で使う型に関していえば、気にするべきは 戻り値では無く引数の方です。

戻り値はその通り BOOL なので、本来の型に合わせるなら
 [return : MarshalAs(UnmanagedType.Bool)] public static extern bool
といったところですが、4バイト固定であるため int でも構いません。


>>(LPARAM/WPARAM/LRESULT は本来、IntPtr のサイズになります)
これは PostMessage で LRESULT が使われているという意味で書いたものでは無く、
LPARAM や WPARAM、それに LRESULT や各種 HANDLE といった型については、
プラットフォームによってサイズが異なるので注意しましょう、という程度の意図でした。
(一方で、HRESULT などは 32bit 固定ですね)

typedef BYTE BOOLEAN;
typedef short VARIANT_BOOL;
typedef int BOOL;
typedef long LONG;

typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
typedef LONG_PTR LRESULT;
typedef LONG HRESULT;

http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx


# 投稿してから、誤解を与える書き方だったかな…とは思ったのですが、
# そのまま放置してしまいました。フォローありがとうございます。
引用返信 編集キー/
■67944 / inTopicNo.11)  Re[9]: SendKeys.Sendメソッドについて
□投稿者/ なお (5回)-(2013/09/11(Wed) 13:41:39)
2013/09/11(Wed) 13:42:14 編集(投稿者)

魔界の仮面弁士 さん

ご丁寧に有難う御座いました。Postmessage使用方法は理解出来ましたが、以下の件は何が理由なのでしょうか?

a = …
b = GetWindow(a, GW_CHILD);
c = GetWindow(b, GW_HWNDNEXT);
d = GetWindow(c, GW_CHILD);
e = d
ret = PostMessage(e, WM_KEYDOWN, VK_F5, 0);

のようにした場合、e と d の両方が IntPtr.Zero になる。


引用返信 編集キー/
■67947 / inTopicNo.12)  Re[10]: SendKeys.Sendメソッドについて
□投稿者/ 魔界の仮面弁士 (333回)-(2013/09/11(Wed) 14:26:41)
2013/09/11(Wed) 14:33:04 編集(投稿者)

No67935 (なお さん) に返信
> Postmessageにてキー入力を試みようと思います。

No67937 (なお さん) に返信
> 因みにPostmesseageの宣言は以下のようにしています。

No67941 (なお さん) に返信
> Postmessegeの宣言と使い方は下記、間違いに対してどのようにしたら宜しいのでしょうか?

No67947 (なお さん) に返信
> ご丁寧に有難う御座いました。Postmessage使用方法は理解出来ましたが、以下の件は何が理由なのでしょうか?

PostMessage を Postmessage と呼ぶことには違和感があります。
Win16 は、API 名の大文字小文字を区別しませんが、Win32/Win64 は区別されるので。


> [DllImport("User32.dll", EntryPoint = "PostMessage")] //
> public static extern int PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); //

第一引数は ref では無いのに、hWnd が書き換わると言うのも奇妙ですね。
InAttribute を付与したり、さらに HandleRef に変更してみるのは如何でしょうか。


ところで、戻り値は成否いずれを返していましたか?
失敗だとしたら、そのときの Marshal.GetLastWin32Error は何でしょうか?
親ウィンドウ、Childウィンドウ、Nextウィンドウにポストした場合はどうでしたか?

> のようにした場合、e と d の両方が IntPtr.Zero になる。
d と e は、非ゼロから Zero に書き換わるとの事でしたが、
a, b, c については、PostMessage 後も同じ値なのですね?
引用返信 編集キー/
■67948 / inTopicNo.13)  Re[8]: SendKeys.Sendメソッドについて
□投稿者/ Hongliang (99回)-(2013/09/11(Wed) 14:49:07)
ええと、単に
GetWindow(c, GW_CHILD);
が失敗している(cが子ウィンドウを持っていないなど)ってだけでは……。
引用返信 編集キー/
■67949 / inTopicNo.14)  Re[9]: SendKeys.Sendメソッドについて
□投稿者/ 魔界の仮面弁士 (334回)-(2013/09/11(Wed) 15:12:25)
2013/09/11(Wed) 15:16:48 編集(投稿者)

No67948 (Hongliang さん) に返信
> ええと、単に
> GetWindow(c, GW_CHILD);
> が失敗している(cが子ウィンドウを持っていないなど)ってだけでは……。

自分もそう思いましたが、 No67935 の段階にて、
 「Bまでは問題なく目的のWindowハンドルを取得出来ました。」
と書かれているのですよね…。

元のコードは「p = GetWindow(p, …)」の構文になっているので、
もしも各行の実行前に変数値を確認するというミスをしていると
誤解を生みそうだと思ったので、 No67938 では変数名を逐次変更して
「p2 = GetWindow(p1, …)」の形で実行するよう提案しても
みましたが、その結果も同じだったようですし。


それにその前の No67936 で、Hongliang さんがその件について
確認された際にも、
「Bで取得したハンドル(hWndWorkPtr)がCで0になってしまうんです。」
とあるので、PostMessage 前の d に、非ゼロが設定されていることを
確認しているものと読み取っていました。


あらためて確認しますが、少なくとも PostMessage の直前までには、
a〜d に、それぞれ異なるウィンドウハンドル値(非ゼロ)が
格納されているのですよね? > なおさん
引用返信 編集キー/
■67970 / inTopicNo.15)  Re[10]: SendKeys.Sendメソッドについて
□投稿者/ なお (6回)-(2013/09/12(Thu) 09:52:33)
2013/09/12(Thu) 09:57:34 編集(投稿者)

魔界の仮面弁士さん、Hongliangさん

ご回答有難う御座います。

色々確認してましたが、ポスト先ウィンドウのハンドルを親ウィンドウにするとハンドルは非ゼロ(正しい)で動作しました。
GetWindowで取得した子ウィンドウのハンドルをポスト先にすると、ハンドルが0になります。
尚、そのときのPostMessageの戻り値はTrueにはなっています。

この現象を見る限り、子ウィンドウのハンドルの受け渡しがうまくいってない可能性があります。
但し、以下の件はメールでご回答したとおりの内容になります。PostMessage直前までは非0です。

> あらためて確認しますが、少なくとも PostMessage の直前までには、
> a〜d に、それぞれ異なるウィンドウハンドル値(非ゼロ)が格納されているのですよね? > なおさん

引用返信 編集キー/
■67983 / inTopicNo.16)  Re[11]: SendKeys.Sendメソッドについて
□投稿者/ 魔界の仮面弁士 (343回)-(2013/09/12(Thu) 18:38:09)
No67970 (なお さん) に返信
> 但し、以下の件はメールでご回答したとおりの内容になります。PostMessage直前までは非0です。
手元の環境では、Zero クリアされる現象を再現できていません。
どなたかとメールでやりとりしていた内容があるなら、その情報も共有していただけないでしょうか?


> GetWindowで取得した子ウィンドウのハンドルをポスト先にすると、ハンドルが0になります。
GetWindow してから PostMessage されるまでの間に、ウィンドウが破棄あるいは再生成されているとか…?

だとしても、e はまだしも d まで Zero になる状況になるとは思えないですし。
GW_CHILD で得た値を PostMessage するまでの間に、何か追加の処理を行っていたりはしますか?



> ポスト先ウィンドウのハンドルを親ウィンドウにするとハンドルは非ゼロ(正しい)で動作しました。
対象となるコントロールウィンドウに対してポストすべき場合と、
その親コントロールあるいはトップレベルウィンドウに対して
ポストすべき場合とがあります。
どちらを用いるべきかは、対象アプリの実装次第でしょうね。


// -------------
    public class F : Form {
        private TextBox textBox1 = new TextBox();
        public F() {
            Controls.Add(textBox1);
            textBox1.KeyDown += (object sender, KeyEventArgs e) => {
                if (e.KeyCode == Keys.F5) {
                    Console.WriteLine("F[{0:X}].TextBox[{1:X}].KeyDown", (Int64)this.Handle, (Int64)textBox1.Handle);
                }
            };
            KeyDown += (object sender, KeyEventArgs e) => {
                if (e.KeyCode == Keys.F5) {
                    Console.WriteLine("F[{0:X}].KeyDown", (Int64)this.Handle);
                }
            };
        }
    }
// -------------
    var f1 = new F() { KeyPreview = true , Text = "F1:true"  };
    var f2 = new F() { KeyPreview = false, Text = "F2:false" };
    f1.Show();
    f2.Show();
// -------------
    foreach (IntPtr ptr in new IntPtr[] {
        f1.Handle, f2.Handle, f1.Controls[0].Handle, f2.Controls[0].Handle})
    {
        var ret = PostMessage(ptr, WM_KEYDOWN, (IntPtr)VK_F5, IntPtr.Zero);
        Console.WriteLine("ret={0}, ptr={1}", ret, ptr);
    }

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -