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

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

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

C# キー入力シミュレート PostMessageについて

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

■82919 / inTopicNo.1)  C# キー入力シミュレート PostMessageについて
  
□投稿者/ telracs (1回)-(2017/02/20(Mon) 02:34:12)

分類:[C#] 

環境: win10 64bit VisualStudio 2015comm
言語: C# (.NET Framework)

タイトルに書いた通り、他アプリケーションにキー入力を送信したく、
PostMessageによる物を実装しました

シミュレートしたいのはCtrl + S
上書き保存のショートカットキーですね。

メニューのハンドル取得でもいいのですが、対象のアプリケーションが不特定で、あるアプリケーションに限ったものではない(伝わりにくい)、メインウィンドウハンドル取得からポストで動くしいいんじゃねぇのみたいな感じで実装しました。

そこで、なんですが、 自分が実装しましたプログラムでは32bitアプリケーションにはしっかりポストされ、上書き保存も出来ています。
しかし、64bitのアプリケーションに送るとポストはされても無反応、つまり上書き保存がされないのです。
Spy++でログも確認済です。
LParamについてなんですが、
ctrl down 0x001D0001
s    down 0x001F0001
ctrl up      0xC01D0001
s    up      0xC01F0001
でnew IntPtrしてたんですけど、色々サイト見てるとIntPtr.Zeroが多かったのでこっちにしました。

SendKeyでは上書き保存ができました。スキャンコード?みたいなのは00でなってたのでDirectInputではないと思います(自分の知識が間違ってたらごめんなさい)

ログはすべてメインウィンドウハンドルで確認しました。
自分でCtrl + Sした時とPostMessageした時のログはほぼ一緒で何が違うのかさっぱりわかりませんでした。
違うのはLparamとWM_CHARが生成されることくらいですが、LParamも全く同じにしてポストした時も上書き出来ませんでした。


文章が分かりにくい部分もあるかと思いますが、
何が違うか、または送信先のアプリケーション側の問題なのか
解決策を教えてください。お願いします。

実装コードの一部

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr PostMessage(IntPtr hWnd, IntPtr Msg, IntPtr wParam, IntPtr lParam);

public IntPtr WM_KEYDOWN = new IntPtr(0x0100);
public IntPtr WM_KEYUP = new IntPtr(0x0101);

public IntPtr VK_Ctrl = new IntPtr(0x11);
public IntPtr VK_S = new IntPtr(0x53);

private void button2_Click(object sender, EventArgs e)
{
    /*
     *  GetProcessByNameでメインウィンドウハンドルを取得
     */
    PostMessage(mainWindowHandle, WM_KEYDOWN, VK_Ctrl, IntPtr.Zero);
    PostMessage(mainWindowHandle, WM_KEYDOWN, VK_S, IntPtr.Zero);
    PostMessage(mainWindowHandle, WM_KEYUP, VK_S, IntPtr.Zero);
    PostMessage(mainWindowHandle, WM_KEYUP, VK_Ctrl, IntPtr.Zero);
}

引用返信 編集キー/
■82920 / inTopicNo.2)  Re[1]: C# キー入力シミュレート PostMessageについて
□投稿者/ 魔界の仮面弁士 (1132回)-(2017/02/20(Mon) 08:21:27)
No82919 (telracs さん) に返信
> しかし、64bitのアプリケーションに送るとポストはされても無反応、つまり上書き保存がされないのです。

x64 ビルドにした上で、管理者実行してみた場合はどうなりますか? もしも
if( Marshal.GetLastWin32Error() == ERROR_ACCESS_DENIED /* 5 */ )
なのであれば、UIPI が原因かもしれません。(当方未検証)
https://msdn.microsoft.com/ja-jp/windows/dd871146.aspx
引用返信 編集キー/
■82923 / inTopicNo.3)  Re[1]: C# キー入力シミュレート PostMessageについて
□投稿者/ Hongliang (500回)-(2017/02/20(Mon) 08:56:35)
それが原因かどうかは分かりませんが、PostMessageの第二引数MsgはUINTであり、C#ではint/uintに相当します。
引用返信 編集キー/
■82924 / inTopicNo.4)  Re[2]: C# キー入力シミュレート PostMessageについて
□投稿者/ telracs (2回)-(2017/02/20(Mon) 09:00:11)
だめでした...ポストテストしてたアプリケーションが管理者権限だったので普通の権限で起動させてポストしても
ポストはされても無反応です...

以下Spy++のログ
(黄色がアプリケーションで直接押したやつ、赤で区切って上がSendkeyによるもの、下がPostMessage)
LParamを一緒にしても無反応です。

http://i.imgur.com/kl9oQKn.png

No82920 (魔界の仮面弁士 さん) に返信
> ■No82919 (telracs さん) に返信
>>しかし、64bitのアプリケーションに送るとポストはされても無反応、つまり上書き保存がされないのです。
>
> x64 ビルドにした上で、管理者実行してみた場合はどうなりますか? もしも
> if( Marshal.GetLastWin32Error() == ERROR_ACCESS_DENIED /* 5 */ )
> なのであれば、UIPI が原因かもしれません。(当方未検証)
> https://msdn.microsoft.com/ja-jp/windows/dd871146.aspx
引用返信 編集キー/
■82927 / inTopicNo.5)  Re[2]: C# キー入力シミュレート PostMessageについて
□投稿者/ telracs (4回)-(2017/02/20(Mon) 10:04:44)
uintやintでも無反応でした

No82923 (Hongliang さん) に返信
> それが原因かどうかは分かりませんが、PostMessageの第二引数MsgはUINTであり、C#ではint/uintに相当します。
引用返信 編集キー/
■82928 / inTopicNo.6)  Re[3]: C# キー入力シミュレート PostMessageについて
□投稿者/ 魔界の仮面弁士 (1135回)-(2017/02/20(Mon) 10:13:35)
2017/02/20(Mon) 10:47:19 編集(投稿者)

No82924 (telracs さん) に返信
> だめでした...ポストテストしてたアプリケーションが管理者権限だったので普通の権限で起動させてポストしても
> ポストはされても無反応です...

PostMessage 直後の GetLastWin32Error は何を返してきますか?
※要 SetLastError 指定


追記:x64 の Release Build にした場合に、動作が変わりますか?
https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/5283d1ba-74f9-42dd-aea9-9e142d989e02/changewindowmessagefilterex0x0049?forum=vcgeneralja
引用返信 編集キー/
■82929 / inTopicNo.7)  Re[3]: C# キー入力シミュレート PostMessageについて
□投稿者/ 魔界の仮面弁士 (1136回)-(2017/02/20(Mon) 10:23:06)
No82927 (telracs さん) に返信
> uintやintでも無反応でした
>
> ■No82923 (Hongliang さん) に返信
>>それが原因かどうかは分かりませんが、PostMessageの第二引数MsgはUINTであり、C#ではint/uintに相当します。

ついでに戻り値は BOOL 型(32bit)なので、
C# 的には bool ですね。[return: MarshalAs(UnmanagedType.Bool)]
引用返信 編集キー/
■82930 / inTopicNo.8)  Re[4]: C# キー入力シミュレート PostMessageについて
□投稿者/ telracs (5回)-(2017/02/20(Mon) 10:40:51)
それぞれのPostMessageのあとに
int error = Marshal.GetLastWin32Error();
MessageBox.Show(error.ToString());

で見てみましたが、全部0表示でした

No82928 (魔界の仮面弁士 さん) に返信
> 2017/02/20(Mon) 10:14:39 編集(投稿者)
>
> ■No82924 (telracs さん) に返信
>>だめでした...ポストテストしてたアプリケーションが管理者権限だったので普通の権限で起動させてポストしても
>>ポストはされても無反応です...
>
> PostMessage 直後の GetLastWin32Error は何を返してきますか?
> ※要 SetLastError 指定
引用返信 編集キー/
■82931 / inTopicNo.9)  Re[5]: C# キー入力シミュレート PostMessageについて
□投稿者/ 魔界の仮面弁士 (1137回)-(2017/02/20(Mon) 10:53:26)
No82930 (telracs さん) に返信
>>PostMessage 直後の GetLastWin32Error は何を返してきますか?
>>※要 SetLastError 指定
> それぞれのPostMessageのあとに
> int error = Marshal.GetLastWin32Error();
> MessageBox.Show(error.ToString());
> で見てみましたが、全部0表示でした

DllImportAttribute.SetLastError フィールドは true になっていますか?
(最初の投稿では false でしたよね)


また、受信側アプリで ChangeWindowMessageFilter を
あらかじめ呼んでおいた場合はどうなりますか?
(WM_COPYGLOBALDATA も呼んだ方が良いらしいですが、裏付ける資料が見当たらず)
http://d.hatena.ne.jp/tekk/20091018/1255881871
引用返信 編集キー/
■82933 / inTopicNo.10)  Re[6]: C# キー入力シミュレート PostMessageについて
□投稿者/ telracs (6回)-(2017/02/20(Mon) 11:59:54)
DLLImportにTrueに設定しました。
Changeなんとかは受信側でコード書かないとダメなんですかね?
受信側は私が作成したものではないプログラムになってまして...


No82931 (魔界の仮面弁士 さん) に返信
> ■No82930 (telracs さん) に返信
> >>PostMessage 直後の GetLastWin32Error は何を返してきますか?
> >>※要 SetLastError 指定
>>それぞれのPostMessageのあとに
>>int error = Marshal.GetLastWin32Error();
>>MessageBox.Show(error.ToString());
>>で見てみましたが、全部0表示でした
>
> DllImportAttribute.SetLastError フィールドは true になっていますか?
> (最初の投稿では false でしたよね)
>
>
> また、受信側アプリで ChangeWindowMessageFilter を
> あらかじめ呼んでおいた場合はどうなりますか?
> (WM_COPYGLOBALDATA も呼んだ方が良いらしいですが、裏付ける資料が見当たらず)
> http://d.hatena.ne.jp/tekk/20091018/1255881871
引用返信 編集キー/
■82934 / inTopicNo.11)  Re[7]: C# キー入力シミュレート PostMessageについて
□投稿者/ 魔界の仮面弁士 (1138回)-(2017/02/20(Mon) 12:10:17)
No82933 (telracs さん) に返信
> Changeなんとかは受信側でコード書かないとダメなんですかね?
> 受信側は私が作成したものではないプログラムになってまして...

原因の切り分けのために、実験用のアプリを用意する、という意味です。

「自分が実装した32bitアプリケーション」にはポストされていた。
「他者が実装した64bitアプリケーション」にはポストできない。

ならば「自分が実装した64bitアプリケーション」ではどうなのか? 自作アプリでも
拒絶されるなら、ユーザー インターフェイス特権の分離 (UIPI) による
影響かどうかを調べてみる…ということです。
管理者起動や ChangeWindowMessageFilter(Ex) の呼び出しはその一環。
引用返信 編集キー/
■82937 / inTopicNo.12)  Re[8]: C# キー入力シミュレート PostMessageについて
□投稿者/ telracs (7回)-(2017/02/20(Mon) 16:19:51)
色々模索した結果、
keybd_eventを追加すると反応がなかったアプリケーションで上書きできました
少々ごり押し気味ですが、狙い通りの動作をしてくれるのでこれで妥協します

色々ありがとうございました!

keybd_event(0x11, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
PostMessage(mainWindowHandle, WM_KEYDOWN, VK_Ctrl, IntPtr.Zero);
PostMessage(mainWindowHandle, WM_KEYDOWN, VK_S, IntPtr.Zero);
await Task.Delay(1000);
keybd_event(0x11, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);


No82934 (魔界の仮面弁士 さん) に返信
> ■No82933 (telracs さん) に返信
>>Changeなんとかは受信側でコード書かないとダメなんですかね?
>>受信側は私が作成したものではないプログラムになってまして...
>
> 原因の切り分けのために、実験用のアプリを用意する、という意味です。
>
> 「自分が実装した32bitアプリケーション」にはポストされていた。
> 「他者が実装した64bitアプリケーション」にはポストできない。
>
> ならば「自分が実装した64bitアプリケーション」ではどうなのか? 自作アプリでも
> 拒絶されるなら、ユーザー インターフェイス特権の分離 (UIPI) による
> 影響かどうかを調べてみる…ということです。
> 管理者起動や ChangeWindowMessageFilter(Ex) の呼び出しはその一環。
解決済み
引用返信 編集キー/
■82938 / inTopicNo.13)  Re[1]: C# キー入力シミュレート PostMessageについて
□投稿者/ 魔界の仮面弁士 (1139回)-(2017/02/20(Mon) 17:58:07)
以下、補足情報。
解決済みチェックはつけたままにしておきます。

No82919 (telracs さん) に返信
> SendKeyでは上書き保存ができました。

SendKey…
SendKeys でしょうか?

SendKeys は、.NET 3.0 以降において、 Vista 以降の UIPI 対策がなされていますね。
https://msdn.microsoft.com/ja-jp/library/system.windows.forms.sendkeys.aspx

既定の動作では、ジャーナルフックをまずは試してみて、それが拒絶された場合にのみ
SendInput に切り替える、という実装になっているようです。

この動作を変更する場合は、app.settings に
<add key="SendKeys" value="JournalHook"/>
<add key="SendKeys" value="SendInput"/>
のいずれかを指定する事になります。


ジャーナルフックの概要についてはこのあたり。

https://msdn.microsoft.com/ja-jp/library/aa480152.aspx
》WH_JOURNALPLAYBACK と WH_JOURNALRECORD は本質的に
》プロセス間で実行されるため、最高の権限レベルが必要です。
》多くの場合にすべての UI 権限が必要なわけではない SendInput() API を
》ジャーナル フックの代わりに使用することができます。


SendKeys の内部実装についてはこのあたり。
https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/SendKeys.cs,c16b3cbcd61cbe78


ちなみに VB6 / VBA の SendKeys も同様の改修が入っています。
http://support.microsoft.com/kb/931136/ja
https://tunemicky.blogspot.jp/2012/08/windows7-vb6-vba-sendkeys-70.html


また、今回利用されたという keybd_event API については、
現在は SendInput API を使うようにとアナウンスされています。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646304.aspx
https://msdn.microsoft.com/ja-jp/library/cc364822.aspx
》Note This function has been superseded. Use SendInput instead.
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


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

このトピックに書きこむ