Delphi11 VCLでUIAutomationを使った機能を開発しております。
とあるアプリケーションにダイアログを開くボタンがあります。
このボタンをUIAutomationのInvokeでクリックすると、ダイアログが開くのですが
ダイアログを閉じるまで入力待機状態になってしまい処理が停止してしまいます。
Invokeの先でこのようにダイアログを開くような場合は入力待機になるのがUIAutomationの仕様のようですが、
ここをうまく切り抜けてこの開いたダイアログに対して、手入力なしで続けてUIAutomationでアクセスしたいのですが
現状、うまくいきません。
まず行ったのは以下のようなソースです。
var
UIAElem: IUIAutomationElement;
Interf: IInterface;
InvokePtn: IUIAutomationInvokePattern;
////////////////////////////////////////////////////
//UIAElemにはボタンのIUIAutomationElementが設定されています
UIAElem.GetCurrentPattern(UIA_InvokePatternId,Interf);
if Assigned(Interf) then
begin
if Interf.QueryInterface(IID_IUIAutomationInvokePattern,InvokePtn) = S_OK then
begin
InvokePtn.Invoke; <--ここで入力待機状態になりダイアログを閉じるまで停止
end;
end;
これだとInvokeでダイアログが開いた状態で入力待機なりました。
次に、別スレッドでInvokeを実行してみました。
var
ThreadInv: TThread;
////////////////////////////////////////////////////
//UIAElemにはボタンのIUIAutomationElementが設定されています
UIAElem.GetCurrentPattern(UIA_InvokePatternId,Interf);
if Assigned(Interf) then
begin
if Interf.QueryInterface(IID_IUIAutomationInvokePattern,InvokePtn) = S_OK then
begin
//別スレッドで実行
ThreadInv := TThread.CreateAnonymousThread(
procedure()
begin
InvokePtn.Invoke;
end);
ThreadInv.FreeOnTerminate := False;
ThreadInv.Start;
end;
end;
Invokeで停止はしなくなりましたが、入力待機状態でビジーなのか、その状態でUIAutomationを使ったアクセス
(UIAutomationのElementFromPointでマウス下のコントロールを取得)をそのボタンがあるWindow向けに行うと
アクセス違反が発生するようになりました。
Invokeのスレッド実行後に強引に
TerminateThread(ThreadInv.Handle, 0);
といった事を行ってみましたが入力待機は続いているようで事象解消の効果は無く・・・
キレイにInvokeを抜けるにはどうしたら良いのでしょうか?
どなたかお助けくださいませ。
UIAutomationは全く詳しくないのですが、このようなケースではmouse_eventやkeybd_eventで回避するのが常道のようですね…
>HFUKUSHIさん
返信ありがとうございます。
はい、マウスやキーボードイベントだと問題ないのですがUIAutomationで行う必要がありまして、、
代替え案として、Invokeで開いたダイアログ上でElementFromPointを行ってもハングしてエラーにならなければ良さそうですが
(エラーになりそうな対象だったらElementFromPointを行わない)これも対象Windowが入力待ち状態である事の調べ方にたどり着けず、、
Invokeについて調べていたところ
https://learn.microsoft.com/ja-jp/windows/win32/winauto/uiauto-implementinginvoke#required-members-for-iinvokeprovider
もしかしたらUIA_Invoke_InvokedEventIdというものを投げれば・・・とも考えましたが投げる前に失敗してしまってます。
function UiaHostProviderFromHwnd(hwnd: HWND; provider: IRawElementProviderSimple): LRESULT; stdcall; external 'UIAutomationCore.dll' name 'UiaHostProviderFromHwnd';
function UiaRaiseAutomationEvent(provider: IRawElementProviderSimple; eventId: SYSINT): LRESULT; stdcall; external 'UIAutomationCore.dll' name 'UiaRaiseAutomationEvent';
var
pWHndl: Pointer;
EelemPv: IRawElementProviderSimple;
////////////////////////////////////////////////////
//UIA_Invoke_InvokedEventIdを発生させてみようと試みましたがUiaHostProviderFromHwndがうまくいかず・・・
UIAElem.Get_CurrentNativeWindowHandle(pWHndl);
if HWND(pWHndl) <> 0 then
begin
iResult := UiaHostProviderFromHwnd(HWND(pWHndl),EelemPv); <--iResultはオブジェクトが見つからないエラーが返り、EelemPvはnilのまま
if iResult = S_OK then
begin
UiaRaiseAutomationEvent(EelemPv, UIA_Invoke_InvokedEventId);
end;
end;
藁をもすがる思いで色々と試しておりまして、そもそもアプローチが間違っている可能性が大きいのですが
なんとかスッキリとした解決方法にたどり着きたく、何かしらヒントでもいただければ幸いです。
ツイート | ![]() |