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

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

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

Re[12]: C#でSendMessageとホスティングプロセス


(過去ログ 16 を表示中)

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

■5726 / inTopicNo.1)  C#でSendMessageとホスティングプロセス
  
□投稿者/ ゆりうす (1回)-(2007/07/21(Sat) 19:59:40)

分類:[C#] 

はじめまして,現在C#でアプリケーションを開発しています.

OS:WindowsXP
開発環境:VS2005 C#

その中で,APIのSendMessageを用いてファンクションキーを送信するような
ことを行いたいのですが,上手く行きません.
ソースコードは次のような感じです.

====
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private extern static int SendMessage(IntPtr hwnd, IntPtr wMsg, IntPtr wParam, ref IntPtr lParam);

private const int VK_F8 = 0x77;
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;

public void SendKey(int handle){
IntPtr param = IntPtr.Zero;
SendMessage((IntPtr)handle, (IntPtr)WM_KEYDOWN, (IntPtr)VK_F8, ref param);
SendMessage((IntPtr)handle, (IntPtr)WM_KEYUP, (IntPtr)VK_F8, ref param);
}
====

このSendKeyメソッドで送信しようとしています.
上手く行かない現象として,開発環境から立ち上げたところ,上手く送信されるのですが,
コンパイルしたものを立ち上げてみると,どのようなキーを送っても「e」が送信されてしまいます.

そこで開発環境で,ホスティングプロセスの使用を切ってみたところ,開発環境からでも同じ現象に
なりました.

このような現象なのですが,どなたか解決方法をご存知ないでしょうか.
よろしくお願いします.
引用返信 編集キー/
■5737 / inTopicNo.2)  Re[1]: C#でSendMessageとホスティングプロセス
□投稿者/ れい (14回)-(2007/07/22(Sun) 06:19:59)
No5726 (ゆりうす さん) に返信
> その中で,APIのSendMessageを用いてファンクションキーを送信するような
> ことを行いたいのですが,上手く行きません.

今ためす時間がないのですが、
PostMessageを使ってもだめですか?

SendMessageだとSendKeyをよぶ際に
キューに入ってるメッセージによってはよっては
うまく動きません。

引用返信 編集キー/
■5743 / inTopicNo.3)  Re[2]: C#でSendMessageとホスティングプロセス
□投稿者/ ゆりうす (2回)-(2007/07/22(Sun) 12:57:38)
No5737 (れい さん) に返信

お返事ありがとうございます.

> 今ためす時間がないのですが、
> PostMessageを使ってもだめですか?

試してみましたが,やはり同じ結果のようです.

====
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private extern static int PostMessage(IntPtr hwnd, IntPtr wMsg, IntPtr wParam, ref IntPtr lParam);

public void SendKey(int handle){
IntPtr param = IntPtr.Zero;
PostMessage((IntPtr)handle, (IntPtr)WM_KEYDOWN, (IntPtr)VK_F8, ref param);
PostMessage((IntPtr)handle, (IntPtr)WM_KEYUP, (IntPtr)VK_F8, ref param);
}
====

上記のようにPostMessgeを宣言して利用してみました.
色々実験をしてみたのですが,VB6で作成したアプリケーションに対して送信して値を確認してみると,
環境実行,EXE実行に関わらず正しく遅れているようでした.
しかし,私が送信したいアプリに対して送信を行うと,やはりお伝えした症状になってしまいます.

後何回か実行をしていると「F8」を送信しているのに,「r」が送信されたり,「F9」が送信されたり,と
なぜかばらつくことがあるようです.
その際は,なんのキーを送信してもそれらの値のみが受信されています.

引用返信 編集キー/
■5744 / inTopicNo.4)  Re[3]: C#でSendMessageとホスティングプロセス
□投稿者/ HIRO (59回)-(2007/07/22(Sun) 13:20:14)
HIRO さんの Web サイト
No5743 (ゆりうす さん) に返信
> ■No5737 (れい さん) に返信
>
> お返事ありがとうございます.
>
>>今ためす時間がないのですが、
>>PostMessageを使ってもだめですか?
>
> 試してみましたが,やはり同じ結果のようです.
>
> ====
> [DllImport("user32.dll", CharSet=CharSet.Auto)]
> private extern static int PostMessage(IntPtr hwnd, IntPtr wMsg, IntPtr wParam, ref IntPtr lParam);
>
> public void SendKey(int handle){
> IntPtr param = IntPtr.Zero;
> PostMessage((IntPtr)handle, (IntPtr)WM_KEYDOWN, (IntPtr)VK_F8, ref param);
> PostMessage((IntPtr)handle, (IntPtr)WM_KEYUP, (IntPtr)VK_F8, ref param);
> }
> ====
>
> 上記のようにPostMessgeを宣言して利用してみました.
> 色々実験をしてみたのですが,VB6で作成したアプリケーションに対して送信して値を確認してみると,
> 環境実行,EXE実行に関わらず正しく遅れているようでした.
> しかし,私が送信したいアプリに対して送信を行うと,やはりお伝えした症状になってしまいます.
>
> 後何回か実行をしていると「F8」を送信しているのに,「r」が送信されたり,「F9」が送信されたり,と
> なぜかばらつくことがあるようです.
> その際は,なんのキーを送信してもそれらの値のみが受信されています.
>


こちらは参考になりませんか?
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23085&forum=7
引用返信 編集キー/
■5748 / inTopicNo.5)  Re[4]: C#でSendMessageとホスティングプロセス
□投稿者/ れい (18回)-(2007/07/22(Sun) 16:46:55)
No5744 (HIRO さん) に返信
>>上記のようにPostMessgeを宣言して利用してみました.
>>色々実験をしてみたのですが,VB6で作成したアプリケーションに対して送信して値を確認してみると,

あれ。
他のプロセスに送っていたのですか。
自ウィンドウかと思いました。
じゃあPostでも関係ないですね。

引用返信 編集キー/
■5760 / inTopicNo.6)  Re[4]: C#でSendMessageとホスティングプロセス
□投稿者/ ゆりうす (3回)-(2007/07/23(Mon) 11:33:41)
2007/07/23(Mon) 11:35:26 編集(投稿者)
2007/07/23(Mon) 11:34:54 編集(投稿者)

No5744 (HIRO さん) に返信
返事が遅くなってしまい申し訳ありません.

> こちらは参考になりませんか?
> http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23085&forum=7

教えていただいたページを拝見させていただきました.
lParamの文字列が文字化けするのと同じ現象が起こっているのかと考えてみましたが,
wParamの型にIntptrを利用しており,渡しているので,恐らく正しいのではと思っています.

wParamの型をintに変更したりして試してみましたが,やはり上手く飛ばないようです.
またビルドを変えると,「ESC」が飛んでしまったりするようです・・・.
引用返信 編集キー/
■5764 / inTopicNo.7)  Re[5]: C#でSendMessageとホスティングプロセス
□投稿者/ 魔界の仮面弁士 (352回)-(2007/07/23(Mon) 12:05:34)
No5760 (ゆりうす さん) に返信
> wParamの型をintに変更したりして試してみましたが,やはり上手く飛ばないようです.

lparam の方の型は何にしていますか?
ここには 32bit 整数を値渡しすることになるでしょうから、「ref」はマズイと思いますが…。
引用返信 編集キー/
■5795 / inTopicNo.8)  Re[6]: C#でSendMessageとホスティングプロセス
□投稿者/ ゆりうす (4回)-(2007/07/23(Mon) 22:54:14)
No5764 (魔界の仮面弁士 さん) に返信

> lparam の方の型は何にしていますか?
> ここには 32bit 整数を値渡しすることになるでしょうから、「ref」はマズイと思いますが…。

lparamはIntPtrの参照型にしておりました.
ここをただのintやIntPtrにすると,まったくメッセージが送られなくなってしまうのです.
これは,どこか根本的なところが間違っているのでしょうか・・・
引用返信 編集キー/
■5802 / inTopicNo.9)  Re[7]: C#でSendMessageとホスティングプロセス
□投稿者/ teja (1回)-(2007/07/24(Tue) 08:28:14)

 別の掲示板で、"VK_F*"は、"WM_KEYDOWN"でなく"WM_SYSKEYDOWN"を使うような事が
書いてありました。

 WM_SYSKEYDOWN = &H104

引用返信 編集キー/
■5803 / inTopicNo.10)  Re[7]: C#でSendMessageとホスティングプロセス
□投稿者/ 魔界の仮面弁士 (357回)-(2007/07/24(Tue) 09:07:15)
No5795 (ゆりうす さん) に返信
> ここをただのintやIntPtrにすると,まったくメッセージが送られなくなってしまうのです.
当方では Int32 の値渡しにして、VB6 に対してキーイベントを発生させる事ができました。

> これは,どこか根本的なところが間違っているのでしょうか・・・
キー押下をシミュレートするなら、SendInput では?
引用返信 編集キー/
■5858 / inTopicNo.11)  Re[8]: C#でSendMessageとホスティングプロセス
□投稿者/ ゆりうす (5回)-(2007/07/24(Tue) 23:45:37)
No5803 (魔界の仮面弁士 さん) に返信

皆様色々なアドバイスありがとうございます.

>別の掲示板で、"VK_F*"は、"WM_KEYDOWN"でなく"WM_SYSKEYDOWN"を使うような事が
>書いてありました。

WM_SYSKEYDOWNを試してみましたが,やはり同じ症状になってしまいます.

> 当方では Int32 の値渡しにして、VB6 に対してキーイベントを発生させる事ができました。

私の方でも試してみましたところ,テスト用に作成したVB6のアプリでは受信することができていました.

> キー押下をシミュレートするなら、SendInput では?

SendInputも試してみましたが,テキストボックス?のようなものにフォーカスが当たっているときのみに反応しまして,
その他では反応しないといった症状が起こりました.


今回,上手く行かない原因としては,やはり送信先が問題なのでしょうか?
今回送信対象としているアプリが私が作ったものではありません.
ですので,受信側になんらか問題があると思い始めております.

ただ,それならそれで開発環境から実行すれば上手く行って,exe起動だと上手く行かないという点に納得が
行かないのですが・・・・

引用返信 編集キー/
■5861 / inTopicNo.12)  Re[9]: C#でSendMessageとホスティングプロセス
□投稿者/ れい (21回)-(2007/07/25(Wed) 00:28:13)
横槍ですが。

No5858 (ゆりうす さん) に返信
> 皆様色々なアドバイスありがとうございます.
>
> WM_SYSKEYDOWNを試してみましたが,やはり同じ症状になってしまいます.
>

せっかく皆さんがアドバイスしているのですから、
どのアドバイスを適用しチェックを行ったのか、きちんと書かないと
問題と症状と解決案がぐちゃぐちゃです。

まず、

>> ここには 32bit 整数を値渡しすることになるでしょうから、「ref」はマズイと思いますが…。
>lparamはIntPtrの参照型にしておりました.
>ここをただのintやIntPtrにすると,まったくメッセージが送られなくなってしまうのです.
>これは,どこか根本的なところが間違っているのでしょうか・・・

これは直したのですか?
とりあえずrefでは意味不明なlparamが送られてしまいます。

> 今回,上手く行かない原因としては,やはり送信先が問題なのでしょうか?
> 今回送信対象としているアプリが私が作ったものではありません.
> ですので,受信側になんらか問題があると思い始めております.

そうかもしれませんが、
とりあえずSendMessageが明らかに変なので、

> ただ,それならそれで開発環境から実行すれば上手く行って,exe起動だと上手く行かないという点に納得が
> 行かないのですが・・・・

どんな問題があっても「まぁそーゆーこともあるかもね」ぐらいにしか思いません。
そこを直してからまた話を。
引用返信 編集キー/
■5866 / inTopicNo.13)  Re[10]: C#でSendMessageとホスティングプロセス
□投稿者/ ゆりうす (6回)-(2007/07/25(Wed) 02:40:00)
No5861 (れい さん) に返信

> せっかく皆さんがアドバイスしているのですから、
> どのアドバイスを適用しチェックを行ったのか、きちんと書かないと
> 問題と症状と解決案がぐちゃぐちゃです。

大変申し訳ありません.
反省し,現在の状況を纏めて見たいと思います.

■lparamの型に関して
lparamの型をintにして実行してみました.

===
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private extern static int SendMessage(IntPtr hwnd, IntPtr wMsg, IntPtr wParam, int lParam);

private const int VK_F8 = 0x77;

public void SendKey(int handle) {
int param = 0;
SendMessage((IntPtr)handle, (IntPtr)WM_KEYDOWN, (IntPtr)VK_F8, param);
SendMessage((IntPtr)handle, (IntPtr)WM_KEYUP, (IntPtr)VK_F8, param);
}
===

この様にしましたところ,環境実行・exe実行共に受信アプリ側では全く反応がありません.
ただし,自分で適当なアプリをVB6で作成して受信してみたところ,正しい値が来ているようには見えました.

■WM_SYSKEYDOWNの利用
===
private const int WM_SYSKEYDOWN = 0x104;
private const int WM_SYSKEYUP = 0x105;
===

上記のように宣言を行って,WM_KEYDOWNとWM_KEYUPの代わりに用いてみました.
その他のコードは先に記述したものです.
そうしても,症状は変わらず.なにも反応がないままでした.

■SendInputの利用
SendInputを利用すると,環境実行,exe実行に関わらず正しく動作しました.
ただし,受信側画面内のテキスト入力可能な部分にフォーカスが当たっている時のみで,
そこからフォーカスを外すと,反応がなくなります.

これは,私が期待している動作とは異なってしまっております.
どちらかといえば,テキスト入力可能部分にフォーカスが無い時にこそ,反応が起こって欲しいと
考えております.

■現状で起こる症状
・lparamの型をref int もしくは ref IntPtrにした場合
環境実行からだと,正しく送信される.
exeを作成してそれを起動すると何を送信しても「e」が飛んだ時の動作になってしまう.
(ただし,ビルドしなおすを違う文字になることがある(現在起きたのは「ESC」「r」)

環境実行からでも,デバッグオプションで,Visual Studioホスティングプロセスを有効にする,のチェックをはずすと
exe実行と同じ症状になる.

間違っているとのご指摘をいただいておりますが,現状確認のために記載してあります.

・lparamの型をintもしくはIntPtrにした場合
送信側では送信したことになっているが,受信側では全く反応がない(誤作動すらありません).
ただし,VB6で適当なアプリを作って受信してみると正しく送信されている.

以上拙い部分が多いと思いますが,よろしくお願いします.

引用返信 編集キー/
■5872 / inTopicNo.14)  Re[11]: C#でSendMessageとホスティングプロセス
□投稿者/ 魔界の仮面弁士 (363回)-(2007/07/25(Wed) 11:06:39)
No5866 (ゆりうす さん) に返信
> private extern static int SendMessage(IntPtr hwnd, IntPtr wMsg, IntPtr wParam, int lParam);
> SendMessage((IntPtr)handle, (IntPtr)WM_KEYDOWN, (IntPtr)VK_F8, param);
コード的には問題ありませんが、いちいちキャストするのは面倒だとおもいます。
int を渡すことがわかっているなら、宣言側も int の方が便利なのでは。
# hwnd に関しては、handle 側を IntPtr 型で宣言するべきかも知れませんが。


> ただし,受信側画面内のテキスト入力可能な部分にフォーカスが当たっている時のみで,
通常のキー入力は、フォーカスを持つウィンドウに対して行われますし、
SendInput で合成されたキーストロークも、同じ動作になるかと思います。
非アクティブなウィンドウに限定したいなら、この方法では都合が悪そうですね。


> 送信側では送信したことになっているが,受信側では全く反応がない(誤作動すらありません).
> ただし,VB6で適当なアプリを作って受信してみると正しく送信されている.
WM_KEYDOWN を送出することと、キー入力がシミュレートされることは等価ではありません。
相手側のアプリが、どのような実装になっているのかも重要かと思います。

今回のターゲットとなっているアプリケーションの仕様は知りませんが、たとえば
VB6 アプリが F8 キー押下を検出する場合で考えてみると、
 (ア) フォームの KeyDown イベントを使う(KeyPreview = True)
 (イ) サブメニューに、ショートカット F8 を割り当てておき、メニューの Click イベントを使う
 (ウ) DirectInput を用い、GetDeviceStateKeyboard で CONST_DIKEYFLAGS.DIK_F8 のキー状態を得る
 (エ) KB 168795 の方法により、WM_KEYDOWN メッセージを捕らえる
など、幾つかの方法があるかと思いますが……そのすべてが WM_KEYDOWN 送出に反応するわけでは無いかと。
# (ア)と(エ)は反応するでしょうけれども。


> ・lparamの型をref int もしくは ref IntPtrにした場合
lparam の値は、キーリピート情報等を含んだビットフラグであり、それ自体にも意味があります。

IntPtr.Zero を ref で渡した場合、数値 0 ではなく、意図しない値(参照先のアドレス)が
送出されてしまうため、以降の操作に影響を与えてしまうかもしれません。

Spy++(SPYXX.EXE) などを用いて、送出先の WM_KEYDOWN イベントをログに記録してみてください。
異常な値のスキャンコードやリピート数を持った WM_KEYDOWNが Send または Post されてきてはいませんか?


> 環境実行からだと,正しく送信される.
> exeを作成してそれを起動すると何を送信しても「e」が飛んだ時の動作になってしまう.
開発ホストから Release/Debug ビルドを ref 付き/無しで実行した場合と、
exe 単体から Release/Debug ビルドを ref 付き/無しで実行した場合とで、
VK_F8 の送出結果が変化しているかどうかを、Spy++ や実験アプリ等にて確認してみるとか。
引用返信 編集キー/
■5874 / inTopicNo.15)  Re[11]: C#でSendMessageとホスティングプロセス
□投稿者/ れい (22回)-(2007/07/25(Wed) 11:22:31)
No5866 (ゆりうす さん) に返信
> ■lparamの型に関して
> lparamの型をintにして実行してみました.
> この様にしましたところ,環境実行・exe実行共に受信アプリ側では全く反応がありません.
> ただし,自分で適当なアプリをVB6で作成して受信してみたところ,正しい値が来ているようには見えました.

受信アプリも特殊な処理をしてるかもしれません。
問題を切り分けたほうがいいでしょう。

もう一度いいますが、refはダメです。intかintptrで。
これを直したSendMessageを使って、
きちんとVB6にキーを送れるか試したらどうですか?

LPARAMが常に0というのはおかしいです。
MSDNのメッセージの説明に書いてありますが、
少なくともKEYUPにおいては
31、30ビットがたってないといけません。


> ■WM_SYSKEYDOWNの利用
> ===
> private const int WM_SYSKEYDOWN = 0x104;
> private const int WM_SYSKEYUP = 0x105;

これもMSDNに書いてあります。
SYSKEYDOWN/UPはフォーカスがないときにアクティブウィンドウに、
ALTが押されてるときに、
F10が押されたとき等に
送られます。
用途を考えKEYUP/DOWNと使い分けましょう。

引用返信 編集キー/
■5912 / inTopicNo.16)  Re[12]: C#でSendMessageとホスティングプロセス
□投稿者/ ゆりうす (7回)-(2007/07/25(Wed) 23:43:58)
No5874 (れい さん) に返信
魔界の仮面弁士さん,れいさん.
何度もアドバイスを下さりありがとうございます.

> lparam の値は、キーリピート情報等を含んだビットフラグであり、それ自体にも意味があります。
>
> IntPtr.Zero を ref で渡した場合、数値 0 ではなく、意図しない値(参照先のアドレス)が
> 送出されてしまうため、以降の操作に影響を与えてしまうかもしれません。

> Spy++(SPYXX.EXE) などを用いて、送出先の WM_KEYDOWN イベントをログに記録してみてください。
> 異常な値のスキャンコードやリピート数を持った WM_KEYDOWNが Send または Post されてきてはいませんか?

> LPARAMが常に0というのはおかしいです。
> MSDNのメッセージの説明に書いてありますが、
> 少なくともKEYUPにおいては
> 31、30ビットがたってないといけません。

お二方にご指摘いただいたとおり,refの場合はlparamの値に異常なものが入っておりました.
動いていたのは本当にたまたまだったのだと思われます.

Spy++を利用しまして,普通にキーボードを利用したときの値を調べ,その値を値渡しで渡すようにしたところ
正常に動くようになりました.
lparamは0でいいのだと勘違いしていまして,大変お恥ずかしい限りです.
(それを満足に調べることもできませんでした.

今回未熟な自分に対して何度もご指摘いただいた方々に心より感謝いたします.
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -