註冊自定義屬性、事件和控件模式
在可以使用自定義屬性、事件或控件模式之前,提供者和客戶端必須在運行時間註冊屬性、事件或控件模式。 註冊在應用程式過程中是全域有效的,直到程式關閉或過程中最後一個 Microsoft UI Automation 元素物件(IUIAutomation 或 IRawElementProviderSimple)被釋放之前,註冊會保持有效狀態。
Registation 牽涉到將 GUID 傳遞至 UI 自動化,以及自定義屬性、事件或控件模式的詳細資訊。 嘗試第二次使用相同的信息註冊相同的 GUID 將會成功,但嘗試第二次註冊相同的 GUID,但使用不同的資訊(例如,不同類型的自定義屬性)將會失敗。 未來,如果已接受自定義規格並整合到使用者介面自動化核心中,使用者介面自動化將會驗證自定義註冊資訊,並使用已註冊的程序代碼,而不是「官方」架構實作,藉此將應用程式相容性問題降到最低。 您無法移除已註冊的屬性、事件或控制項模式。
本主題包含下列各節:
註冊自定義屬性和事件
註冊自定義屬性或事件可讓提供者和用戶端取得屬性或事件的標識碼,然後傳遞至採用標識元作為參數的各種 API 方法。
要註冊屬性或事件,請按以下步驟:
- 定義自訂屬性或事件的 GUID。
- 將屬性或事件的相關信息填入 UIAutomationPropertyInfo 或 UIAutomationEventInfo 結構,包括 GUID 和包含自定義屬性或事件名稱的不可區域化字串。 自訂屬性也需要指定屬性的數據類型,例如,屬性是否保存整數或字串。 數據類型必須是由UIAutomationType 列舉中指定的下列類型之一。 自訂屬性不支援其他數據類型。
- UIAutomationType_Bool
- UIAutomationType_Double
- UIAutomationType_Element
- UIAutomationType_Int
- UIAutomationType_Point
- UIAutomationType_String
- 使用 CoCreateInstance 函式來建立 CUIAutomationRegistrar 物件的實例,並擷取物件的 IUIAutomationRegistrar 介面指標。
- 呼叫 IUIAutomationRegistrar::RegisterProperty 或 RegisterEvent 方法,並傳遞 UIAutomationPropertyInfo 結構或 UIAutomationEventInfo 結構的位址。
IUIAutomationRegistrar::RegisterProperty 或 RegisterEvent 方法會傳回屬性標識符或事件標識符,應用程式可以傳遞至任何採用這類標識符做為參數的 UI 自動化方法。 例如,您可以將已註冊的屬性標識符傳遞至 IUIAutomationElement::GetCurrentPropertyValue 方法或 IUIAutomation::CreatePropertyCondition 方法。
下列範例示範如何註冊自定義屬性。
// Declare a variable for holding the custom property ID.
PATTERNID g_MyCustomPropertyID;
// Define a GUID for the custom property.
GUID GUID_MyCustomProperty = { 0x82f383ff, 0x4b4d, 0x40d3,
{ 0x8e, 0xd2, 0x90, 0xb5, 0x25, 0x8e, 0xaa, 0x19 } };
HRESULT RegisterProperty()
{
// Fill the structure with the GUID, name, and data type.
UIAutomationPropertyInfo MyCustomPropertyInfo =
{
GUID_MyCustomProperty,
L"MyCustomProp",
UIAutomationType_String
};
// Create the registrar object and get the IUIAutomationRegistrar
// interface pointer.
IUIAutomationRegistrar * pUIARegistrar = NULL;
CoCreateInstance(CLSID_CUIAutomationRegistrar, NULL, CLSCTX_INPROC_SERVER,
IID_IUIAutomationRegistrar, (void **)&pUIARegistrar);
if (pUIARegistrar == NULL)
return E_NOINTERFACE;
// Register the property and retrieve the property ID.
HRESULT hr = pUIARegistrar->RegisterProperty(&MyCustomPropertyInfo, &g_MyCustomPropertyID);
pUIARegistrar->Release();
return hr;
}
IUIAutomationRegistrar::RegisterProperty 和 RegisterEvent 方法擷取的屬性和事件標識碼只有在擷取它們的應用程式內容中才有效,而且只有在應用程式的存留期內才有效。 註冊方法可以在呼叫相同應用程式的不同運行時間實例時,針對相同的 GUID 傳回不同的整數值。
沒有方法可以取消註冊自定義屬性或事件。 相反地,當釋放最後一個UI自動化物件時,它們會隱含地取消註冊。
重要
如果您的程式代碼是Microsoft Active Accessibility (MSAA) 用戶端,當您變更自定義屬性的值時,您必須呼叫 NotifyWinEvent 函式。
實作自定義控件模式
自定義控制項模式不包含在UI自動化API中,而是由第三方在運行時間提供。 用戶端和提供者應用程式的開發人員必須共同合作來定義自定義控件模式,包括控件模式將支援的方法、屬性和事件。 定義控制項模式之後,用戶端和提供者都必須實作支援的元件物件模型 (COM) 物件,以及程式代碼,以在運行時間註冊控制項模式。 自定義控件模式需要實作兩個 COM 物件:用戶端包裝函式和模式處理程式。
注意
下列主題中的範例說明如何實作自定義控件模式,以複製現有 Value 控件模式的功能。 這些範例僅供指示之用。 實際的自定義控件模式應該提供標準UI自動化控件模式無法使用的功能。
用戶端封裝器和模式處理器
用戶端包裝函式會實作用戶端用來擷取屬性和呼叫自定義控件模式所公開之方法的 API。 API 會實作為 COM 介面,將所有屬性要求和方法呼叫傳遞至 UI 自動化核心,然後將這些要求和呼叫封送至提供者。
註冊自定義控制項模式的程式代碼必須提供UI自動化可用來建立用戶端包裝函式對象的實例的類別處理站。 成功註冊自定義控件模式時,UI 自動化會傳回 IUIAutomationPatternInstance 介面指標,用戶端會用來將屬性要求和方法呼叫轉送至 UI 自動化核心。
在提供者端,使用者介面自動化核心會從用戶端取得屬性要求和方法呼叫,並將其傳遞至模式處理程序物件。 然後,模式處理程式會在自定義控件模式的提供者介面上呼叫適當的方法。
註冊自定義控制模式的程式碼會建立一個模式處理程序物件,並在註冊控制模式時,將物件的 IUIAutomationPatternHandler 介面指標提供給UI自動化。
下圖顯示用戶端屬性要求或方法呼叫如何從用戶端包裝函式,透過UI自動化核心元件流向模式處理程式,然後流向提供者介面。
的流程
實作用戶端包裝函式和模式處理程式介面的對象必須具有自由線程。 此外,使用者介面自動化核心必須能夠直接呼叫物件,而不需要任何中繼封送處理碼。
實作客戶端封裝器
用戶端包裝函式是一個物件,會公開用戶端用來要求自定義控件模式所支援屬性和呼叫方法的IXxxPattern 介面。 介面包含每個支援屬性的一對「取得」方法(get_CurrentXxx 和 get_CachedXxx 方法),以及每個支援方法的「呼叫」方法。 具現化物件時,物件建構函式會接收UI自動化核心所實作之 IUIAutomationPatternInstance 介面的指標。 IXxxPattern 介面的方法會使用 IUIAutomationPatternInstance::GetProperty 和 CallMethod 方法,將屬性要求和方法呼叫轉送至 UI 自動化核心。
下列範例示範如何為支援單一屬性的簡單自定義控件模式實作用戶端包裝函式物件。 如需更複雜的範例,請參閱 自定義控件模式的範例實作。
// Define the client interface.
interface __declspec(uuid("c78b266d-b2c0-4e9d-863b-e3f74a721d47"))
IMyCustomPattern : public IUnknown
{
STDMETHOD (get_CurrentIsReadOnly)(BOOL * pIsReadOnly) = 0;
STDMETHOD (get_CachedIsReadOnly)(BOOL * pIsReadOnly) = 0;
};
// Implement the client wrapper class.
class CMyValuePatternClientWrapper :
public IMyCustomPattern
{
IUIAutomationPatternInstance * _pInstance;
public:
// Get IUIAutomationPatternInstance interface pointer from the
// UI Automation core.
CMyValuePatternClientWrapper(IUIAutomationPatternInstance * pInstance)
: _pInstance(pInstance)
{
_pInstance->AddRef();
}
~CMyValuePatternClientWrapper()
{
_pInstance->Release();
}
// Note: Put standard IUnknown implementation here.
STDMETHODIMP get_CurrentIsReadOnly(BOOL * pIsReadOnly)
{
return _pInstance->GetProperty(0, FALSE, UIAutomationType_Bool, pIsReadOnly);
}
STDMETHODIMP get_CachedIsReadOnly(BOOL * pIsReadOnly)
{
return _pInstance->GetProperty(0, TRUE, UIAutomationType_Bool, pIsReadOnly);
}
};
實作模式處理程式
模式處理程式是實作 IUIAutomationPatternHandler 介面的物件。 此介面有兩種方法:IUIAutomationPatternHandler::CreateClientWrapper 和 Dispatch。 UI 自動化核心會呼叫 CreateClientWrapper 方法,並接收指向 IUIAutomationPatternInstance 介面的指標。 CreateClientWrapper 藉由實例化客戶端包裝物件來回應,並將 IUIAutomationPatternInstance 介面指標傳遞至客戶端包裝物件的建構函式。
UI 自動化核心會使用 Dispatch 方法,將屬性要求和方法呼叫傳遞至自定義控件模式的提供者介面。 參數包括指向提供者介面的指標、屬性 getter 或方法被呼叫時的零起始索引,以及包含要傳遞到提供者的參數的 UIAutomationParameter 陣列結構。 模式處理程式會藉由檢查索引參數來判斷要呼叫的提供者方法,然後呼叫該提供者介面,傳遞包含在 UIAutomationParameter 結構中的參數, 來回應。
在註冊控制項模式之前,模式處理程式物件是由註冊自定義控件模式的相同程式代碼具現化。 程式代碼必須在註冊時將模式處理程序物件的 IUIAutomationPatternHandler 介面指標傳遞至 UI 自動化核心。
下列範例示範如何為支援單一屬性的簡單自定義控件模式實作模式處理程序物件。 如需更複雜的範例,請參閱 自定義控件模式的範例實作。
// Define the provider interface.
interface __declspec(uuid("9f5266dd-f0ab-4562-8175-c383abb2569e"))
IMyValueProvider : public IUnknown
{
STDMETHOD (get_IsReadOnly)(BOOL * pIsReadOnly) = 0;
};
// Index used by IUIAutomationPatternHandler::Dispatch.
const int MyValue_GetIsReadOnly = 0;
// Define the pattern handler class.
class CMyValuePatternHandler : public IUIAutomationPatternHandler
{
public:
// Put standard IUnknown implementation here.
STDMETHODIMP CreateClientWrapper(
IUIAutomationPatternInstance * pPatternInstance,
IUnknown ** pClientWrapper)
{
*pClientWrapper = new CMyValuePatternClientWrapper(pPatternInstance);
if (*pClientWrapper == NULL)
return E_INVALIDARG;
return S_OK;
}
STDMETHODIMP Dispatch (IUnknown * pTarget, UINT index,
const struct UIAutomationParameter *pParams, UINT cParams)
{
switch(index)
{
case MyValue_GetIsReadOnly:
return ((IMyValueProvider*)pTarget)->get_IsReadOnly((BOOL*)pParams[0].pData);
}
return E_INVALIDARG;
}
};
註冊自定義控件模式
使用自定義控制項模式之前,提供者和客戶端都必須註冊自定義控制項模式。 註冊會提供UI自動化核心與控件模式的詳細資訊,並提供提供者或用戶端控件模式標識碼,以及控件模式所支援之屬性和事件的標識碼。 在提供者端,必須在相關聯的控件處理 WM_GETOBJECT 訊息之前或同時,註冊自定義控件模式。
註冊自定義控制項模式時,提供者或用戶端會提供下列資訊:
- 自定義控制項模式的 GUID。
- 包含自訂控制項模式名稱的無法本地化字串。
- 支援自定義控制項模式之提供者介面的 GUID。
- 支援自定義控制項模式之用戶端介面的 GUID。
- 描述自定義控件模式所支援屬性的 UIAutomationPropertyInfo 陣列 結構。 針對每個屬性,必須指定 GUID、屬性名稱和數據類型。
- UIAutomationMethodInfo 結構體陣列,描述自定義控制項模式所支援的方法。 針對每個方法,結構包含下列資訊:方法名稱、參數計數、參數數據類型清單,以及參數名稱的清單。
- UIAutomationEventInfo 陣組 結構,描述自定義控件模式所引發的事件。 針對每個事件,必須指定 GUID 和事件名稱。
- IUIAutomationPatternHandler 模式處理程式物件的介面位址,讓自定義控件模式可供用戶端使用。
若要註冊自定義控制項模式,提供者或用戶端程式代碼必須執行下列步驟:
- 使用上述資訊填入 UIAutomationPatternInfo 結構。
- 使用 CoCreateInstance 函式來建立 CUIAutomationRegistrar 物件的實例,並擷取物件的 IUIAutomationRegistrar 介面指標。
- 呼叫 IUIAutomationRegistrar::RegisterPattern 方法,傳遞 UIAutomationPatternInfo 結構的位址。
RegisterPattern 方法會傳回控件模式識別碼,以及屬性標識碼和事件標識碼的清單。 應用程式可以將這些標識碼傳遞至採用這類標識碼做為參數的任何UI自動化方法。 例如,您可以將已註冊的模式標識符傳遞至 IUIAutomationElement::GetCurrentPattern 方法,以擷取控制模式提供者介面的指標。
沒有方法可以取消註冊自定義控件模式。 而是在釋放最後一個UI自動化物件時隱含地取消註冊。
如需示範如何註冊自定義控件模式的範例,請參閱下一節。
自定義控件模式的範例實作
本節包含範例程式代碼,示範如何實作自定義控件模式的用戶端包裝函式和模式處理程序物件。 此範例會實作以 Value 控件模式為基礎的自定義控件模式。
// Step 1: Define the public provider and client interfaces using IDL. Interface
// definitions are in C here to simplify the example.
// Define the provider interface.
interface __declspec(uuid("9f5266dd-f0ab-4562-8175-c383abb2569e"))
IMyValueProvider : public IUnknown
{
STDMETHOD (get_Value)(BSTR * pValue) = 0;
STDMETHOD (get_IsReadOnly)(BOOL * pIsReadOnly) = 0;
STDMETHOD (SetValue)(LPCWSTR pNewValue) = 0;
STDMETHOD (Reset)() = 0;
};
// Define the client interface.
interface __declspec(uuid("103b8323-b04a-4180-9140-8c1e437713a3"))
IUIAutomationMyValuePattern : public IUnknown
{
STDMETHOD (get_CurrentValue)(BSTR * pValue) = 0;
STDMETHOD (get_CachedValue)(BSTR * pValue) = 0;
STDMETHOD (get_CurrentIsReadOnly)(BOOL * pIsReadOnly) = 0;
STDMETHOD (get_CachedIsReadOnly)(BOOL * pIsReadOnly) = 0;
STDMETHOD (SetValue)(LPCWSTR pNewValue) = 0;
STDMETHOD (Reset)() = 0;
};
// Enumerate the properties and methods starting from 0, and placing the
// properties first.
enum
{
MyValue_GetValue = 0,
MyValue_GetIsReadOnly = 1,
MyValue_SetValue = 2,
MyValue_Reset = 3,
};
// Step 2: Implement the client wrapper class.
class CMyValuePatternClientWrapper :
public IUIAutomationMyValuePattern
{
IUIAutomationPatternInstance * _pInstance;
public:
// Get IUIAutomationPatternInstance interface pointer.
CMyValuePatternClientWrapper(IUIAutomationPatternInstance * pInstance)
{
_pInstance = pInstance;
_pInstance->AddRef();
}
// Put standard IUnknown implementation here.
STDMETHODIMP get_CurrentValue(BSTR * pValue)
{
return _pInstance->GetProperty(MyValue_GetValue, FALSE,
UIAutomationType_String, pValue);
}
STDMETHODIMP get_CachedValue(BSTR * pValue)
{
return _pInstance->GetProperty(MyValue_GetValue, TRUE,
UIAutomationType_String, pValue);
}
STDMETHODIMP get_CurrentIsReadOnly(BOOL * pIsReadOnly)
{
return _pInstance->GetProperty(MyValue_GetIsReadOnly, FALSE,
UIAutomationType_Bool, pIsReadOnly);
}
STDMETHODIMP get_CachedIsReadOnly(BOOL * pIsReadOnly)
{
return _pInstance->GetProperty(MyValue_GetIsReadOnly, TRUE,
UIAutomationType_Bool, pIsReadOnly);
}
STDMETHODIMP SetValue(LPCWSTR pValue)
{
UIAutomationParameter SetValueParams[] =
{ UIAutomationType_String, &pValue };
return _pInstance->CallMethod(MyValue_SetValue, SetValueParams,
ARRAYSIZE(SetValueParams));
}
STDMETHODIMP Reset()
{
return _pInstance->CallMethod(MyValue_Reset, NULL, 0);
}
};
// Step 3: Implement the pattern handler class.
class CMyValuePatternHandler : public IUIAutomationPatternHandler
{
public:
// Put standard IUnknown implementation here.
STDMETHODIMP CreateClientWrapper(
IUIAutomationPatternInstance * pPatternInstance,
IUnknown ** pClientWrapper)
{
*pClientWrapper = new CMyValuePatternClientWrapper(pPatternInstance);
if (*pClientWrapper == NULL)
return E_INVALIDARG;
return S_OK;
}
STDMETHODIMP Dispatch (IUnknown * pTarget, UINT index,
const struct UIAutomationParameter *pParams,
UINT cParams)
{
switch(index)
{
case MyValue_GetValue:
return ((IMyValueProvider*)pTarget)->get_Value((BSTR*)pParams[0].pData);
case MyValue_GetIsReadOnly:
return ((IMyValueProvider*)pTarget)->get_IsReadOnly((BOOL*)pParams[0].pData);
case MyValue_SetValue:
return ((IMyValueProvider*)pTarget)->SetValue(*(LPCWSTR*)pParams[0].pData);
case MyValue_Reset:
return ((IMyValueProvider*)pTarget)->Reset();
}
return E_INVALIDARG;
}
};
CMyValuePatternHandler g_MyValuePatternHandler;
// Step 4: Declare information about the properties and methods supported
// by the custom control pattern.
// Define GUIDs for the custom control pattern and each of its properties
// and events.
static const GUID MyValue_Pattern_Guid = { 0xa49aa3c0, 0xe413, 0x4ecf,
{ 0xa1, 0xc3, 0x37, 0x42, 0xa7, 0x86, 0x67, 0x3f } };
static const GUID MyValue_Value_Property_Guid = { 0xe58f3f67, 0x22c7, 0x44f0,
{ 0x83, 0x55, 0xd8, 0x76, 0x14, 0xa1, 0x10, 0x81 } };
static const GUID MyValue_IsReadOnly_Property_Guid = { 0x480540f2, 0x9829, 0x4acd,
{ 0xb8, 0xea, 0x6e, 0x2a, 0xdc, 0xe5, 0x3a, 0xfb } };
static const GUID MyValue_Reset_Event_Guid = { 0x5b80edd3, 0x67f, 0x4a70,
{ 0xb0, 0x7, 0x4, 0x12, 0x85, 0x11, 0x1, 0x7a } };
// Declare information about the properties, in the same order as the
// previously defined "MyValue_" enumerated type.
UIAutomationPropertyInfo g_MyValueProperties[] =
{
// GUID, name, data type.
{ MyValue_Value_Property_Guid, L"MyValuePattern.Value",
UIAutomationType_String },
{ MyValue_IsReadOnly_Property_Guid, L"MyValuePattern.IsReadOnly",
UIAutomationType_Bool },
};
// Declare information about the event.
UIAutomationEventInfo g_MyValueEvents [] =
{
{ MyValue_Reset_Event_Guid, L"MyValuePattern.Reset" },
};
// Declare the data type and name of the SetValue method parameter.
UIAutomationType g_SetValueParamTypes[] = { UIAutomationType_String };
LPCWSTR g_SetValueParamNames[] = {L"pNewValue"};
// Declare information about the methods.
UIAutomationMethodInfo g_MyValueMethods[] =
{
// Name, focus flag, count of in parameters, count of out parameters, types, parameter names.
{ L"MyValuePattern.SetValue", TRUE, 1, 0, g_SetValueParamTypes, g_SetValueParamNames },
{ L"MyValuePattern.Reset", TRUE, 0, 0, NULL, NULL },
};
// Declare the custom control pattern using the previously defined information.
UIAutomationPatternInfo g_ValuePatternInfo =
{
MyValue_Pattern_Guid,
L"MyValuePattern",
__uuidof(IMyValueProvider),
__uuidof(IUIAutomationMyValuePattern),
ARRAYSIZE(g_MyValueProperties), g_MyValueProperties, // properties
ARRAYSIZE(g_MyValueMethods), g_MyValueMethods, // methods
ARRAYSIZE(g_MyValueEvents), g_MyValueEvents, // events
&g_MyValuePatternHandler
};
// Step 5: Register the custom control pattern and retrieve the control pattern and property
// identifiers.
// Control pattern, property, and event IDs.
PATTERNID g_MyValue_PatternID;
PROPERTYID g_MyValue_Value_PropertyID;
PROPERTYID g_MyValue_IsReadOnly_PropertyID;
EVENTID g_MyValueReset_EventID;
// ID used by the client to determine whether the custom control pattern is available.
PROPERTYID g_IsMyValuePatternAvailable_PropertyID;
HRESULT RegisterPattern()
{
// Create the registrar object and get the IUIAutomationRegistrar interface pointer.
IUIAutomationRegistrar * pUIARegistrar;
CoCreateInstance(CLSID_CUIAutomationRegistrar, NULL, CLSCTX_INPROC_SERVER,
IID_IUIAutomationRegistrar, (void **)&pUIARegistrar);
if (pUIARegistrar == NULL)
return E_NOINTERFACE;
PROPERTYID propIDs[2]; // Array for property IDs.
// Register the control pattern.
HRESULT hr = pUIARegistrar->RegisterPattern(
&g_ValuePatternInfo,
&g_MyValue_PatternID,
&g_IsMyValuePatternAvailable_PropertyID,
ARRAYSIZE(propIDs),
propIDs,
1,
&g_MyValueReset_EventID);
if (hr == S_OK)
{
// Copy the property IDs.
g_MyValue_Value_PropertyID = propIDs[0];
g_MyValue_IsReadOnly_PropertyID = propIDs[1];
}
pUIARegistrar->Release();
return hr;
}
相關主題