AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

VOICEROID+ 結月ゆかり EXにsendMessageするには

 前回、VOICEROIDに文字送信することでコントロールしましたが、あれはアクティブウインドウに送信するものなので、なにか作業してる時にプログラムが動くと誤動作します。
 従って、プロセス間通信をきちんと行いたいと思います。
 プロセス番号、ウインドウハンドラなどは取得できたのですが、FindWindowExAがうまく動かせません。
 要するに、Windowsアプリ上のテキストボックスのクラス番号が無いとsendMessageできない仕様のようです。
 はてどうするか?
 調べると、.netアプリでは、SPY++というMSのアプリでツリー構造が調べられるようです。
 また、旧VOICEROID+の「東北ずん子」を制御するHSPサンプルも見つけました。
【HSP3】VOICEROID+ 東北ずん子をHSPから制御するモジュール Ver 0.01 | Codetter(こーどったー)β
 ↑素晴らしいです。
 どうやらリッチテキストコントロールを使ってる模様です。
 まず、これのアプリ名を結月ゆかりに変更しました。
 しかし、

// ボイスロイドのテキストボックスを取得
#defcfunc GetZunkoTextBoxV
		FindWindowExA GetZunkoTopWindowV(), 0, zunkomainclass, 0
		hChild = stat
		FindWindowExA hChild, 0, zunkomainclass, 0		// その子を取得(長男)
		FindWindowExA hChild, stat, zunkomainclass, 0	// 2番目(次男)
			hChild = stat
			FindWindowExA hChild, 0, zunkomainclass, 0		// 2番目の兄弟の孫(長男)を取得
			FindWindowExA stat, 0, zunkomainclass, 0
			FindWindowExA stat, 0, zunkomainclass, 0
			FindWindowExA stat, 0, zunkomainclass, 0
				hChild = stat
				FindWindowExA hChild, 0, zunkoeditclass, 0
return stat

 これが正しい値を返しません。+から+EXになってますのでUI変更により、ツリー構造が違うようです。
 クラス名も違いますが。
 ツリー構造をわざわざ辿らないでも、SPY++を使えば直接ハンドラ値が分かります。

msg="東京特許許可局"
sendmsg $d03b2, 0x000C/*WM_SETTEXT*/, 0, varptr(msg)

これで、リッチテキストコントロールに直接コピペできました。
しかし、この$d03b2は動的な値で、アプリを起動し直すと変わります。
やはりツリーを都度調べる必要があるようです。

#deffunc zunko_init
	// ウィンドウ名とかクラス名とか
	zunkowname1 = "VOICEROID+ 結月ゆかり EX*"
	zunkowname2 = "VOICEROID+ 結月ゆかり EX"
	zunkomainclass = "WindowsForms10.Window.8.app.0.378734a"
	zunkoeditclass = "WindowsForms10.RichEdit20W.app.0.378734a"
	zunkobuttonclass = "WindowsForms10.BUTTON.app.0.378734a"
return

// ボイスロイドのテキストボックスを取得
#defcfunc GetZunkoTextBoxV
		FindWindowExA GetZunkoTopWindowV(), 0, zunkomainclass, 0
		hChild = stat
		FindWindowExA stat, 0, zunkomainclass, 0
		FindWindowExA hChild, stat, zunkomainclass, 0
		FindWindowExA stat, 0, zunkomainclass, 0
		FindWindowExA stat, 0, zunkomainclass, 0
		FindWindowExA stat, 0, zunkomainclass, 0
		FindWindowExA stat, 0, zunkomainclass, 0
		FindWindowExA stat, 0, zunkomainclass, 0
		FindWindowExA stat, 0, zunkoeditclass, 0
return stat

msg="東京特許許可局"
sendmsg GetZunkoTextBoxV(), 0x000C/*WM_SETTEXT*/, 0, varptr(msg)

これで、メッセージ送信できました。無事リッチテキストコントロールに東京特許許可局が入りました。

とりあえずテキストボックスと再生ボタンが取れればOKでしょ

// ボイスロイドのテキストボックスを取得
#defcfunc GetZunkoTextBoxV
		FindWindowExA GetZunkoTopWindowV(), 0, zunkomainclass, 0
		 hChild = stat
		 FindWindowExA stat, 0, zunkomainclass, 0
		 FindWindowExA hChild, stat, zunkomainclass, 0
		  FindWindowExA stat, 0, zunkomainclass, 0
		   FindWindowExA stat, 0, zunkomainclass, 0
		    FindWindowExA stat, 0, zunkomainclass, 0
		     FindWindowExA stat, 0, zunkomainclass, 0
		      FindWindowExA stat, 0, zunkomainclass, 0
		       FindWindowExA stat, 0, zunkoeditclass, 0
return stat
// ボイスロイドの再生ボタンを取得
#defcfunc GetZunkoPlayButtonV
		FindWindowExA GetZunkoTopWindowV(), 0, zunkomainclass, 0
		hChild = stat
		 FindWindowExA stat, 0, zunkomainclass, 0
		 FindWindowExA hChild, stat, zunkomainclass, 0
		  FindWindowExA stat, 0, zunkomainclass, 0
		   FindWindowExA stat, 0, zunkomainclass, 0
		    FindWindowExA stat, 0, zunkomainclass, 0
		     FindWindowExA stat, 0, zunkomainclass, 0
		     hChild = stat
		      FindWindowExA stat, 0, zunkomainclass, 0
	          FindWindowExA hChild, stat, zunkomainclass, 0
			   FindWindowExA stat, 0, zunkobuttonclass, 0
return stat

以下のように同期処理もできました

ZunkoSetTextV "東京特許許可局"
ZunkoPlayTextV

repeat
	await 100
    if(IsZunkoPlayingV()==1) : break //再生が終わるまで待つ
loop

ZunkoSetTextV "東京特許許可局2"
ZunkoPlayTextV


動的な探索は、これでだいたいできたんですが、ボタンの区別がわからないなどでお蔵入りしました。
あとHSPの仕様もよくわからないし(local宣言しないと局所変数にならないなど解りにくい)

// search tree
#defcfunc SearchTree int phw,int height,local hw
	if(height>=10) : return 0
	data="             "
	hw=0
	repeat 10
		FindWindowExA phw, hw, targetClass, 0
		if(stat!=0) {
		 	hw=stat
		 	mes strmid(data, 0, height)+strf("%x", hw)+" found!"
		} else {
		 	FindWindowExA phw, hw, zunkomainclass, 0
		 	hw=stat
			if(hw==0) :break
		 	mes strmid(data, 0, height)+strf("%x", hw)
		}
		res=SearchTree(hw,height+1)
	loop
	return hw