2022年2月19日土曜日

Win32Apiを呼び出して、外部アプリケーションを操作する

PowerAutomate はとても便利だけど、細かなチェック処理とかしたくて、自前でのPhotoshop自動化ツールを作りました。

(うちのPhotoshopが古い&安いものなので、自動化機能が付いていないだけで、普通の人はバッチ機能付きのPhotoshopで良いと思う)


自作プログラムから他のアプリケーションを操作するってのは、それなりに敷居が高い処理だと思うので、覚書を残しておきます。

慣れない人には、「なんか動く」ものを確認するまでが第一関門だと思うので、そこまでの参考にどうぞ。

ソースはC#で記載していますが、他言語でもだいたい一緒です。


関連記事


メモ帳に自動で文字を入力する

目的はPhotoshopの操作ですが、説明として難しくなるので簡略化したもので検討します。

今回は「メモ帳」を操作します。


こんな機能を実装します。

  1. メモ帳を起動する
  2. メモ帳に文字を入力
  3. メモ帳を保存

これは最小構成のソース見たほうがわかりやすいね

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PhotoshopAuto
{
	public class TestClass
	{
		[DllImport("user32.dll", SetLastError = true)]
		static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildafter, string lpszClass, string lpszWindow);

		[DllImport("user32.dll")]
		public static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, uint lParam);

		public const int WM_KEYDOWN = 0x100;

		public static void TestA()
		{
			// ①メモ帳を起動する
			var proc = Process.Start("notepad");
			proc.WaitForInputIdle();

			// ②メモ帳内の編集ウィンドウを取得する
			IntPtr hWnd = IntPtr.Zero;
			var editWindow = FindWindowEx(proc.MainWindowHandle, hWnd, null, null);

			// ③メモ帳内の編集ウィンドウに「a」を入力する
			PostMessage(editWindow, WM_KEYDOWN, 0x00000041, 0x001E0001);
		}
	}
}

こんな感じです。

1.メモ帳を起動する

これは、簡単。Process.Startメソッドを呼ぶだけ。
メモ帳は「notepad」って文字列で呼び出せますが、実際にはexeのフルパスの指定などが必要になります。
で、メモ帳の起動直後は操作を受け付けるかわからないので、WaitForInputIdle()によって少し待機ています。

2.メモ帳内の編集ウィンドウを取得する

Win32Apiを使用して、メモ帳内の編集ウィンドウ(文字入力する部分)のハンドラを取得します。
ハンドラを探すには「FindWindowEx」メソッドを使用します。
FindWindowExを使用するときは、ソースのサンプルのように「DllImport」部分を記載しておきます。

※今回の例では、編集ウィンドウのハンドラがメインハンドラの直下の最初のウィンドウだと分かっていたので、超単純な例になっています。
では、どうやって編集ウィンドウのハンドラを見つけるのかというと、Spy++を使用しますハンドラの調べ方は別途記事を参照してください。

3.メモ帳内の編集ウィンドウに文字を入力する

Win32Apiを使用して、メモ帳内の編集ウィンドウに「a」と入力します。
キー操作を通知するのでPostMessage(またはSendMessage)を使用します。
PostMessageを使用するときは、ソースのサンプルのように「DllImport」部分を記載しておきます。

※ソース内の WM_KEYDOWN(0x100) はウィンドウメッセージの一覧などで調べることができます。
「0x00000041」や「0x001E0001」について、何を入れるべきかは、ウィンドウメッセージの一覧を調べると、合わせて記載されています。
ただ、単純なプログラムであれば、Spy++でメッセージ確認したほうが早いと思います。