前回、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