C# と .Net Framework で 他の Windows アプリを操作するアプリ
簡単にですが作りました。
経緯
最近、C# を学び始めて .Net Framework
を使うようになったのですが、これがけっこう便利で楽しくて、
ふと、Windows の API なら ハンドル取ってこれそうだなと思い、調べるとすでにやってる人がいたので、
マネをしてみました。
目的
アプリ一つ一つに割り当てられているハンドル(ウィンドウハンドル)を取得して、
外部のアプリからハンドル先に値を送ることでアプリを操作することが目的です。
まだ可能かどうかは分かりませんが、ゲームのテストや同じ操作の繰り返しをプログラムで
制御できればいいなと思って作りました。
こちらを参考にしたので、試したい方はこちらを見た方が早いかと思います。
普通、アプリだと複数のウィンドウやボタンがあるので、操作をするのは難しいのですが、 自分の場合は、ゲームの操作が目的だったので、ハンドルを取ってしまえばあとはコントローラの キーにあたる値を送ることで操作することが可能です。
操作するためのキーの値はこちらを見ればいいかと
Virtual-Key Codes (Windows)
環境
環境は以下です。
- Windows 10
- VisualStudio 2017
以下は、今回使う言語やフレームワーク、その他出てくる技術です。
もし読んでて分からないところがあれば、以下のキーワードを加えて検索するといいかも……?
- C#
- .Net Framework 4.0 以上
- WPF
- Win32API
GUI の作成
WPF で GUI を作ります。 重要な部分ではないので飛ばします。以下のように作りました。
各ボタンの処理
Get Handle
というボタンは、隣にある Process Name
の入力内容を元に関係するアプリを探して、ウィンドウハンドルを取得します。Process Name
は、タスクマネージャを開き、詳細タブに並んでいる .exe
を除いたアプリの名前を入力します。
ボタン入力時の処理は以下です。
private void GetHandleButton_Click(object sender, RoutedEventArgs e) { process = System.Diagnostics.Process.GetProcessesByName(ProcessName.Text); foreach (System.Diagnostics.Process ps in process) { LogBox.Text += ps.Id + ps.MainWindowTitle + ps.MainWindowHandle + "\n"; } }
GetProcessesByName
でアプリのハンドルを取得します。
取得したら、内容をテキストボックスに出力します(これは確認用)。
Button
というボタンは、Message
の内容をハンドル先に送ります。つまり、Message
に操作用の値を書き、
Button
を押すことでアプリを操作します。が、これはまだ未実装です。現状は、予め用意した値を送るようにしています。
IntPtr hWnd = process[0].MainWindowHandle; LogBox.Text += SendMessage(hWnd, 0x0100, 0x20, 0x00);
SendMessage()
で、どう操作したいかを指示しています。その後、確認用にテキストボックスに出力しています。
SendMessage(ハンドル, イベント, 内容1, 内容2)
のように指定します。
イベントは、キーが押された
やキーが離された
、マウスのボタンがクリックされた
などです。内容1,2はイベントに合わせて指定します。何もない場合は 0x00
でいいと思います。
上記だと、hWnd
に、スペースキー
が押された
という情報を送ります。
SendMessage
は、.Net Framework
の API ではなく、Win32API
の API です。これは、以下のように宣言することで使えるようになります。
[System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
DllImport
という属性(Attribute)
を使うことで、外部のライブラリを使えるようにしています。
ここら辺は、以下を参照してください。(正直、自分はちゃんと理解出来ていません……)
@IT:.NET TIPS Win32 APIやDLL関数を呼び出すには? - C#
キーワード:Attribute, Reflection, Annotation
これだけのコードで、別のアプリにプログラムで好きなキー入力を行うことができます。
コード
XAML 側のコードがないので、これだけでは動かないのですが、一応全文載せておきます。
using System; using System.Windows; namespace GetHandle { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { System.Diagnostics.Process[] process; public MainWindow() { InitializeComponent(); } private void GetHandleButton_Click(object sender, RoutedEventArgs e) { process = System.Diagnostics.Process.GetProcessesByName(ProcessName.Text); foreach (System.Diagnostics.Process ps in process) { LogBox.Text += ps.Id + ps.MainWindowTitle + ps.MainWindowHandle + "\n"; } } private void MessageButton_Click(object sender, RoutedEventArgs e) { IntPtr hWnd = process[0].MainWindowHandle; LogBox.Text += SendMessage(hWnd, 0x0100, 0x20, 0x00); } [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam); } }
デモ
ウィンドウハンドル取得して、キー入力をハンドル先に送るアプリを作ったらそのままUE4でも使えた。動画は、スペースキーの値を送ってる #UE4 #UE4Study pic.twitter.com/rdBUnvPXyA
— 漬茶漬け (@tauto_otya) 2017年3月25日