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

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

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

既存アプリにショートカットキーを投げたい

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

■92170 / inTopicNo.1)  既存アプリにショートカットキーを投げたい
  
□投稿者/ こまお (4回)-(2019/08/30(Fri) 14:08:54)

分類:[.NET 全般] 

こんにちは。

自作アプリから既存アプリを起動しそれを操作したいです。
とりあえずショートカットキーで出来る程度が目標です。

下記の様にしてメモ帳を起動、あるいは終了させて見ているのですが、
終了側(ショートカットキー)がうまくいきません。

# lparamは0にしているサンプルが複数見つかるので、0でいいのかなと思っていますがどうなのでしょう。

とりあえず終了できるようにしたいのですが、何が足りないのでしょうか。
あと、WM_ナントカとかVK_ナントカとか、C#の何処かで定義してないでしょうか。

よろしくおねがいします。

public partial class MainWindow : Window {
  private Process notepad;

  private void Button_Click_1(object sender, RoutedEventArgs e) {
    notepad = Process.Start("notepad.exe");
    notepad.WaitForInputIdle();
  }

  [DllImport("user32.dll", SetLastError = true)]
  private static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

  UInt16 WM_KEYDOWN = 0x0100;
  UInt16 WM_KEYUP = 0x0101;
  UInt16 WM_SYSKEYDOWN = 0x0104;
  UInt16 WM_SYSKEYUP = 0x0105;
  UInt16 VK_MENU = 0x12; //alt
  UInt16 VK_F4 = 0x73;

  private void Button_Click_2(object sender, RoutedEventArgs e) {
    var hWnd = notepad.MainWindowHandle;
    PostMessage(hWnd, WM_SYSKEYDOWN, VK_MENU, 0);
    PostMessage(hWnd, WM_SYSKEYDOWN, VK_F4, 0);
    PostMessage(hWnd, WM_SYSKEYUP, VK_F4, 0);
    PostMessage(hWnd, WM_SYSKEYUP, VK_MENU, 0);
  }
}

引用返信 編集キー/
■92174 / inTopicNo.2)  Re[1]: 既存アプリにショートカットキーを投げたい
□投稿者/ 魔界の仮面弁士 (2340回)-(2019/08/30(Fri) 14:24:18)
No92170 (こまお さん) に返信
> 自作アプリから既存アプリを起動しそれを操作したいです。
> とりあえずショートカットキーで出来る程度が目標です。

UIAutomation を使ってみるのはどうでしょう。
あるいは Codeer.Friendly も便利かも。



> private void Button_Click_2(object sender, RoutedEventArgs e) {
>  var hWnd = notepad.MainWindowHandle;
>  PostMessage(hWnd, WM_SYSKEYDOWN, VK_MENU, 0);
>  PostMessage(hWnd, WM_SYSKEYDOWN, VK_F4, 0);
>  PostMessage(hWnd, WM_SYSKEYUP, VK_F4, 0);
>  PostMessage(hWnd, WM_SYSKEYUP, VK_MENU, 0);
> }
メモ帳の終了だけなら、notepad.CloseMainWindow(); で良い気がします。
引用返信 編集キー/
■92187 / inTopicNo.3)  Re[2]: 既存アプリにショートカットキーを投げたい
□投稿者/ こまお (5回)-(2019/08/30(Fri) 16:35:35)
魔界の仮面弁士さんありがとうございます。

>メモ帳の終了だけなら、notepad.CloseMainWindow(); で良い気がします。

いや、キーボードショートカットでやりたかったので。

>UIAutomation を使ってみるのはどうでしょう。

良さそうなのを教えていただきありがとうございます。早速サンプルを漁っているのですが、
キーボードのエミュレーションみたいなのが見当たりません。おすすめのURLってありますか?

せめて1文字入らないかと↓とやってみたのですがやっぱり入りませんでした。orz

PostMessage(hWnd, WM_KEYDOWN, ’A’, 0);
PostMessage(hWnd, WM_KEYUP, 'A', 0);
引用返信 編集キー/
■92192 / inTopicNo.4)  Re[3]: 既存アプリにショートカットキーを投げたい
□投稿者/ とっちゃん (624回)-(2019/08/30(Fri) 18:26:20)
No92187 (こまお さん) に返信
> せめて1文字入らないかと↓とやってみたのですがやっぱり入りませんでした。orz
>
> PostMessage(hWnd, WM_KEYDOWN, ’A’, 0);
> PostMessage(hWnd, WM_KEYUP, 'A', 0);

SendKeys クラスの利用を検討してみてもいいと思います。
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.sendkeys?view=netframework-4.8

キー入力のエミュレーションは、WM_KEYDOWN/KEYUP ではできません。
これらは、キー入力の「結果」として生成される副産物メッセージです。
もちろん、ショートカットも同様。

引用返信 編集キー/
■92193 / inTopicNo.5)  Re[3]: 既存アプリにショートカットキーを投げたい
□投稿者/ 魔界の仮面弁士 (2344回)-(2019/08/30(Fri) 19:19:53)
2019/08/30(Fri) 19:31:23 編集(投稿者)

No92187 (こまお さん) に返信
>> UIAutomation を使ってみるのはどうでしょう。
> 良さそうなのを教えていただきありがとうございます。早速サンプルを漁っているのですが、
> キーボードのエミュレーションみたいなのが見当たりません。おすすめのURLってありますか?

Codeer.Friendly だとこんな感じ。
https://www.kompira.jp/column/operate_windows_gui/

UIAutomation だとこのあたり。
https://docs.microsoft.com/ja-jp/dotnet/framework/ui-automation/ui-automation-text-pattern-how-to-topics



private Process notepad;
private void Button_Click_1(object sender, RoutedEventArgs e)
{
  this.notepad = Process.Start("notepad.exe");
  this.notepad.WaitForInputIdle();
}
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
  // メモ帳のテキスト部に「魔界の仮面弁士」と書き込む
  var elmNotepad = AutomationElement.FromHandle(this.notepad.MainWindowHandle);
  var elmEditBox = elmNotepad.FindFirst(TreeScope.Children, new AndCondition(new OrCondition(
    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document)),
    new PropertyCondition(AutomationElement.ClassNameProperty, "Edit")));
  object patValue;
  if (elmEditBox.TryGetCurrentPattern(ValuePattern.Pattern, out patValue))
  {
    ((ValuePattern)patValue).SetValue("魔界の仮面弁士");
  }
  else
  {
    elmEditBox.SetFocus();
    await Task.Delay(100);
    SendKeys.SendWait("魔界の仮面弁士");
  }
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
  // メモ帳のテキスト部に書かれている文字列を取得する
  var elmNotepad = AutomationElement.FromHandle(this.notepad.MainWindowHandle);
  var elmEditBox = elmNotepad.FindFirst(TreeScope.Children, new AndCondition(new OrCondition(
    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document)),
    new PropertyCondition(AutomationElement.ClassNameProperty, "Edit")));
  var patText = (TextPattern)elmEditBox.GetCurrentPattern(TextPattern.Pattern);
  textBlock1.Text = patText.DocumentRange.GetText(-1);
}
private void Button_Click_4(object sender, RoutedEventArgs e)
{
  // メモ帳のタイトルバーの「閉じる」ボタンをクリック
  var elmNotepad = AutomationElement.FromHandle(this.notepad.MainWindowHandle);
  var elmTitleBar = elmNotepad.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TitleBar));
  var elmCloseButton = elmTitleBar.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "閉じる"));
  var patInvoke = (InvokePattern)elmCloseButton.GetCurrentPattern(InvokePattern.Pattern);
  patInvoke.Invoke();
}
引用返信 編集キー/
■92212 / inTopicNo.6)  Re[4]: 既存アプリにショートカットキーを投げたい
□投稿者/ こまお (6回)-(2019/09/02(Mon) 12:56:57)
みなさんありがとうございます。

とりあえずSendKeyクラスを試そうとしたのですが
VSが名前を確認しろと言ってきました。
多分環境が.NET Framework 4.6.1なのが原因と思います。

別の手を探さないとorz
引用返信 編集キー/
■92214 / inTopicNo.7)  Re[5]: 既存アプリにショートカットキーを投げたい
□投稿者/ 魔界の仮面弁士 (2348回)-(2019/09/02(Mon) 13:08:55)
2019/09/02(Mon) 18:07:57 編集(投稿者)

No92212 (こまお さん) に返信
> とりあえずSendKeyクラスを試そうとしたのですが
> VSが名前を確認しろと言ってきました。

参照設定に System.Windows.Forms を加えてください。


> 多分環境が.NET Framework 4.6.1なのが原因と思います。

リファレンスに依存情報が記されていますよ。
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.sendkeys.sendwait?view=netframework-4.8


>> SendKeys.SendWait(String) Method
>>
>> 名前空間:
>>  System.Windows.Forms
>> Assembly:
>>  System.Windows.Forms.dll
>>
>> 適用対象
>>  .NET Core
>>    3.0 Preview 8
>>  .NET Framework
>>    4.8, 4.7.2, 4.7.1, 4.7, 4.6.2, 4.6.1, 4.6, 4.5.2, 4.5.1, 4.5, 4.0, 3.5, 3.0, 2.0, 1.1


# .NET Framework 欄のカンマがコピーできなかったので、手動で追記。
引用返信 編集キー/
■92268 / inTopicNo.8)  Re[6]: 既存アプリにショートカットキーを投げたい
□投稿者/ こまお (7回)-(2019/09/06(Fri) 13:35:36)
レスポンス悪くてすみません。

using System.Windows.Forms;といれると、Formsにアンダーラインが出ます。
System.Windows.Forms.SendKeys.Send()とやっても同様でした。

VS2017Expressだから、とか?

引用返信 編集キー/
■92270 / inTopicNo.9)  Re[7]: 既存アプリにショートカットキーを投げたい
□投稿者/ 魔界の仮面弁士 (2361回)-(2019/09/06(Fri) 14:20:18)
No92268 (こまお さん) に返信
> VS2017Expressだから、とか?

参照設定に System.Windows.Forms アセンブリを追加していないからでしょう。

『参照設定』と『名前空間』は別物ですよ。



引用返信 編集キー/
■92272 / inTopicNo.10)  Re[8]: 既存アプリにショートカットキーを投げたい
□投稿者/ こまお (8回)-(2019/09/06(Fri) 14:56:46)
https://www.peliphilo.net/archives/42

で判りました。でさっそく

var hWnd = notepad.MainWindowHandle;
SetActiveWindow(hWnd);
SendKeys.Send("%{F4}"); //閉じよメモ帳!

とやってみたのですが例外が飛びました。

|System.InvalidOperationException
| HResult=0x80131509
| Message=SendKeys は、Windows のメッセージをハンドルしないため、このアプリケーションの中で実行できません。 アプリケーションがメッセージをハンドルするように変更するか、または SendKeys.SendWait メソッドを使用してください。
| Source=System.Windows.Forms
| スタック トレース:
| 場所 System.Windows.Forms.SendKeys.Send(String keys, Control control, Boolean wait)
| 場所 System.Windows.Forms.SendKeys.Send(String keys)

引用返信 編集キー/
■92273 / inTopicNo.11)  Re[9]: 既存アプリにショートカットキーを投げたい
□投稿者/ こまお (9回)-(2019/09/06(Fri) 15:04:08)
1歩前進。

例外がSendWaitを使えって言ってるのに気が付いて

SendKeys.SendWait("%{F4}");

とやったら、メモ帳じゃなくて自分が閉じました。

でも、誤爆ながらAlt-F4を投げることには成功した様です:-)

あとはメモ帳にフォーカスを移し替えればいいのかなと思います。


引用返信 編集キー/
■92274 / inTopicNo.12)  Re[10]: 既存アプリにショートカットキーを投げたい
□投稿者/ こまお (10回)-(2019/09/06(Fri) 15:30:56)
いけました!!

|[DllImport("USER32.DLL")]
|public static extern bool SetForegroundWindow(IntPtr hWnd);
|
|private void Button_Click_2(object sender, RoutedEventArgs e) {
| var hWnd = notepad.MainWindowHandle;
| SetForegroundWindow(hWnd);
| SendKeys.SendWait("%{F4}");
|}

魔界の仮面弁士さん、とっちゃんさん、ありがとうございました。

これにて閉じさせていただきます!


解決済み
引用返信 編集キー/

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


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

このトピックに書きこむ