Share via


實作Server-Side 消費者介面自動化提供者

本主題描述如何針對以 C++ 撰寫的自訂控制項實作伺服器端 Microsoft 消費者介面自動化 提供者。 它包含下列區段:

如需示範如何實作伺服器端提供者的程式碼範例,請參閱消費者介面自動化 提供者的操作說明主題

提供者樹狀結構

您必須為每個需要 UIA 用戶端存取的 UI 元素實作 UIA 提供者。

例如,每個元素都必須實作 IRawElementProviderFragment ,而應用程式的根項目必須實作 IRawElementProviderFragmentRoot。 此外,每個提供者元素都應該連結至:

  • 父系 (parent)
  • 先前的提供者元素
  • next provider 元素
  • 第一個提供者子系
  • 最後一個提供者子系

提供者介面

下列元件物件模型 (COM) 介面提供自訂控制項的功能。 若要提供基本功能,每個消費者介面自動化提供者都必須至少實作IRawElementProviderSimple介面。 IRawElementProviderFragmentIRawElementProviderFragmentRoot介面是選擇性的,但應該針對複雜控制項中的元素實作以提供其他功能。

介面 描述
IRawElementProviderSimple 提供視窗裝載之控制項的基本功能,包括控制項模式和屬性的支援。
IRawElementProviderFragment 新增複雜控制項中元素的功能,包括流覽片段、設定焦點,以及傳回專案的周框。
IRawElementProviderFragmentRoot 為複雜控制項中的根項目新增功能,包括在指定的座標尋找子項目,以及設定整個控制項的焦點狀態。

 

注意

在 managed 程式碼的 消費者介面自動化 API 中,這些介面形成繼承階層。 在 C++ 中,這不是完全分開介面的情況。

 

下列介面提供新增的功能,但實作是選擇性的。

介面 描述
IRawElementProviderAdviseEvents 可讓提供者追蹤事件的要求。
IRawElementProviderHwndOverride 啟用在片段消費者介面自動化樹狀結構中重新置放視窗型元素的位置。

 

消費者介面自動化提供者的必要功能

若要與消費者介面自動化通訊,您的控制項必須實作下表中所述的主要功能區域。

功能 實作
將提供者公開至消費者介面自動化。 為了回應傳送至控制視窗 的WM_GETOBJECT 訊息,請傳回實作 IRawElementProviderSimple的物件。 對於片段,這必須是片段根的提供者。
提供屬性值。 實作 IRawElementProviderSimple::GetPropertyValue 以提供或覆寫值。
讓用戶端能夠與控制項互動。 實作支援每個適當控制項模式的介面,例如 IInvokeProvider。 在您的 IRawElementProviderSimple::GetPatternProvider實作中傳回這些控制項模式提供者。
引發事件。 UiaRaiseAutomationEventIProxyProviderWinEventSink的方法。
啟用在片段中巡覽和聚焦。 針對片段內的每個元素實作 IRawElementProviderFragment 。 不屬於片段一部分的專案不需要。
啟用片段中的焦點和尋找子專案。 實作 IRawElementProviderFragmentRoot。 不是片段根目錄的專案不需要。

 

屬性值

自訂控制項的消費者介面自動化提供者必須支援可由消費者介面自動化和用戶端應用程式使用的特定屬性。 對於裝載于視窗的專案,消費者介面自動化可以從預設視窗提供者擷取某些屬性,但必須從自訂提供者取得其他屬性。

一般而言,視窗型控制項的提供者不需要提供 PROPERTYID所識別的下列屬性:

從視窗取得裝載于視窗中之簡單專案或片段根目錄的 RuntimeId 屬性。 不過,根目錄下方的片段元素,例如清單方塊中的清單專案,必須提供自己的識別碼。 如需詳細資訊,請參閱 IRawElementProviderFragment::GetRuntimeId

應該針對裝載于Windows Forms控制項中的提供者傳回 IsKeyboardFocusable 屬性。 在此情況下,預設視窗提供者可能無法擷取正確值。

Name 屬性通常是由主機提供者提供。

來自提供者的事件

UI 自動化提供者應該引發事件,將 UI 狀態中的變更通知用戶端應用程式。 下列函式可用來引發事件。

函式 描述
UiaRaiseAutomationEvent 引發各種事件,包括由控制項模式觸發的事件。
UiaRaiseAutomationPropertyChangedEvent UI 自動化屬性變更後,即會引發事件。
UiaRaiseStructureChangedEvent 藉由移除或加入專案,引發消費者介面自動化樹狀結構變更時的事件。

 

事件的目的是要通知用戶端 UI 中發生的專案。 不論使用者輸入還是用戶端應用程式使用 消費者介面自動化 觸發變更,提供者都應該引發事件。 例如,每當叫用控制項時,或透過直接使用者輸入,或透過呼叫IUIAutomationInvokePattern::Invoke的用戶端應用程式,應該引發UIA_Invoke_InvokedEventId所識別的事件。

若要最佳化效能,提供者可以選擇性地引發事件,或如果沒有註冊任何用戶端應用程式來接收事件,則完全不引發任何事件。 下列 API 元素用於優化。

API 元素 描述
UiaClientsAreListening 此函式會確認任何用戶端應用程式是否已訂閱消費者介面自動化事件。
IRawElementProviderAdviseEvents 在片段根目錄上實作此介面,可讓提供者在用戶端註冊和取消註冊片段上事件的事件處理常式時建議。

 

注意

類似于在 COM 程式設計中實作參考計數,消費者介面自動化提供者必須處理IRawElementProviderAdviseEvents::AdviseEventAddedAdviseEventRemoved方法,例如IUnknown::AddRefIUnknown介面的Release方法。 只要對特定事件或屬性呼叫 建議EventRemoved 多次 提供者應該繼續引發對應的事件,因為某些用戶端仍在接聽中。 或者,消費者介面自動化提供者可以使用UiaClientsAreListening函式來判斷至少有一個用戶端正在接聽,如果是的話,請引發所有適當的事件。

 

提供者導覽

簡單控制項的提供者,例如裝載于視窗中的自訂按鈕,不需要支援消費者介面自動化樹狀結構中的流覽。 從元素巡覽是由主視窗的預設提供者處理,此視窗是在 IRawElementProviderSimple::HostRawElementProvider實作中指定的。 不過,當您實作複雜自訂控制項的提供者時,您必須支援片段的根節點與子系之間的導覽,以及同層級節點之間的導覽。

注意

根以外的片段元素必須從HostRawElementProvider傳回Null,因為它們不會直接裝載在視窗中,而且沒有預設提供者可以支援巡覽。

 

片段的結構取決於您的 IRawElementProviderFragment::Navigate 實作。 對於每個片段的可能方向,此方法會傳回該方向中項目的提供者物件。 如果沒有該方向的專案,方法會傳回 Null

片段根僅支援導覽至子項目。 例如,清單方塊會在NavigateDirection_FirstChild方向時傳回清單中的第一個專案,並在NavigateDirection_LastChild方向時傳回最後一個專案。 片段根目錄不支援流覽至父系或同層級;這是由主機視窗提供者所處理。

不是根的片段項目必須支援導覽至父代,以及導覽至任何同層級和其具有的子系。

指派新父代

快顯視窗實際上是最上層視窗,且預設會顯示在桌面消費者介面自動化樹狀結構中作為子系。 不過,在許多情況下,快顯視窗在邏輯上是一些其他控制項的子系。 例如,下拉式方塊的下拉式清單在邏輯上是下拉式方塊的子系。 同樣地,功能表快顯視窗在邏輯上是功能表的子系。 消費者介面自動化支援將新父代指派給快顯視窗,使其顯示為相關聯控制項的子系。

若要將新父代指派給快顯視窗:

  1. 建立快顯視窗的提供者。 這需要事先知道快顯視窗的類別。
  2. 實作該快顯的所有屬性和控制項模式,就如同它本身的控制項一樣。
  3. 實作 IRawElementProviderSimple::HostRawElementProvider 屬性,以便傳回從 UiaHostProviderFromHwnd取得的值,其中 參數是快顯視窗的視窗控制碼。
  4. 針對快顯視窗和其父系實作 IRawElementProviderFragment::Navigate ,以便從邏輯父代到邏輯子系之間,以及同層級子系之間正確處理流覽。

當 UI 自動化遇到快顯視窗時,它會辨識是否以預設值取代導覽,並在遇到快顯視窗為桌面的子系時,略過快顯視窗。 相反地,節點只能透過片段來連線。

指派新的父代不適用於控制項可以裝載任何類別的視窗的情況。 例如,Rebar 控制項可以在其帶狀區中裝載任何類型的視窗。 若要處理這些案例,消費者介面自動化支援替代形式的視窗重新配置,如下一節所述。

提供者重新置放

消費者介面自動化片段可能包含兩個以上的元素,每個元素都包含在視窗中。 由於每個視窗都有自己的預設提供者,因此會將視窗視為包含視窗的子系,因此預設消費者介面自動化樹狀結構會將視窗顯示為父視窗的子系。 在大部分情況下,這是所需的行為,但有時候,可能會造成混淆,因為它不符合 UI 的邏輯結構。

rebar 控制項就是這種情況的好範例。 Rebar 控制項包含訊號,每個控制項都可以接著包含視窗型控制項,例如工具列、編輯方塊或下拉式方塊。 Rebar 視窗的預設視窗提供者會將訊號控制項視窗視為子系,而 Rebar 提供者會將訊號視為子系。 因為視窗提供者和 Rebar 提供者一起運作,並結合其子系,所以訊號和視窗型控制項都會顯示為 Rebar 控制項的子系。 不過,邏輯上,只有訊號區應該顯示為 Rebar 控制項的子系,而且每個訊號範圍提供者都應該與它所包含的控制項的預設視窗提供者結合。

為了達成此目的,Rebar 控制項的片段根提供者會公開一組代表訊號範圍的子系。 每個訊號都有一個提供者,可能會公開屬性和控制項模式。 在 IRawElementProviderSimple::HostRawElementProvider的實作中,訊號提供者會傳回控制項視窗的預設視窗提供者,其會呼叫 UiaHostProviderFromHwnd,傳入控制項的視窗控制碼 (HWND) 。 最後,Rebar 的片段根提供者會實作 IRawElementProviderHwndOverride 介面,並在其 實作 IRawElementProviderHwndOverride::GetOverrideProviderForHwnd中,它會傳回指定視窗中所含控制項的適當頻段提供者。

中斷提供者連線

應用程式通常會視需要建立控制項,並在之後加以終結。 終結控制項之後,應該呼叫UiaDisconnectProvider來釋放與控制項相關聯的消費者介面自動化提供者資源。

同樣地,應用程式應該使用UiaDisconnectAllProviders函式,在關閉之前釋放應用程式內所有提供者所持有的所有消費者介面自動化資源。

消費者介面自動化提供者程式設計人員指南