UIAutomationのInvokeを使いボタンをクリックした際に入力待機になるのを防ぎたい


sun  2023-12-25 10:06:49  No: 151311  IP: 192.*.*.*

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を抜けるにはどうしたら良いのでしょうか?
どなたかお助けくださいませ。

編集 削除
HFUKUSHI  2023-12-25 23:52:19  No: 151312  IP: 192.*.*.*

UIAutomationは全く詳しくないのですが、このようなケースではmouse_eventやkeybd_eventで回避するのが常道のようですね…

編集 削除
sun  2023-12-26 02:00:02  No: 151313  IP: 192.*.*.*

>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;

藁をもすがる思いで色々と試しておりまして、そもそもアプローチが間違っている可能性が大きいのですが
なんとかスッキリとした解決方法にたどり着きたく、何かしらヒントでもいただければ幸いです。

編集 削除