註冊自訂屬性、事件和控制項模式
在可以使用自訂屬性、事件或控制項模式之前,提供者和用戶端都必須在執行時間註冊屬性、事件或控制項模式。 註冊會在應用程式進程內全域生效,直到程式關閉或最後一個 Microsoft 消費者介面自動化 元素物件 (IUIAutomation或IRawElementProviderSimple) 發行為止。
Registation 牽涉到將 GUID 傳遞至消費者介面自動化,以及自訂屬性、事件或控制項模式的詳細資訊。 嘗試再次使用相同的資訊註冊相同的 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方法會傳回屬性識別碼或事件識別碼,讓應用程式可以傳遞至任何接受這類識別碼做為參數的消費者介面自動化方法。 例如,您可以將已註冊的屬性識別碼傳遞至 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 的不同整數值。
沒有方法可以取消註冊自訂屬性或事件。 而是在釋放最後一個消費者介面自動化物件時隱含取消註冊。
重要
如果您的程式碼是 Microsoft Active Accessibility (MSAA) 用戶端,當您變更自訂屬性的值時,必須呼叫 NotifyWinEvent 函式。
實作自訂控制項模式
自訂控制項模式不包含在消費者介面自動化 API 中,而是由協力廠商在執行時間提供。 用戶端和提供者應用程式的開發人員必須共同運作,才能定義自訂控制項模式,包括控制項模式將支援的方法、屬性和事件。 定義控制項模式之後,用戶端和提供者都必須實作支援的元件物件模型 (COM) 物件,以及程式碼,以在執行時間註冊控制項模式。 自訂控制項模式需要實作兩個 COM 物件:用戶端包裝函式和模式處理常式。
注意
下列主題中的範例說明如何實作自訂控制項模式,以複製現有 Value 控制項模式的功能。 這些範例僅供指示之用。 實際的自訂控制項模式應該提供無法從標準消費者介面自動化控制項模式取得的功能。
用戶端包裝函式和模式處理常式
用戶端包裝函式會實作用戶端用來擷取屬性和呼叫自訂控制項模式所公開之方法的 API。 API 會實作為 COM 介面,將所有屬性要求和方法呼叫傳遞至消費者介面自動化核心,然後封送處理要求和呼叫提供者。
註冊自訂控制項模式的程式碼必須提供類別處理站,消費者介面自動化可用來建立用戶端包裝函式物件的實例。 成功註冊自訂控制項模式時,消費者介面自動化會傳回用戶端用來轉送屬性要求和方法呼叫至消費者介面自動化核心的IUIAutomationPatternInstance介面指標。
在提供者端,消費者介面自動化核心會從用戶端取得屬性要求和方法呼叫,並將其傳遞至模式處理常式物件。 然後,模式處理常式會在自訂控制項模式的提供者介面上呼叫適當的方法。
註冊自訂控制項模式的程式碼會建立模式處理常式物件,並在註冊控制項模式時,使用物件的IUIAutomationPatternHandler介面指標來提供消費者介面自動化。
下圖顯示用戶端屬性要求或方法呼叫如何從用戶端包裝函式、透過消費者介面自動化核心元件流向模式處理常式,然後流向提供者介面。
實作用戶端包裝函式和模式處理常式介面的物件必須具有自由執行緒。 此外,消費者介面自動化核心必須能夠直接呼叫物件,而不需要任何中繼封送處理常式代碼。
實作用戶端包裝函式
用戶端包裝函式是公開 IXxxPattern 介面的物件,用戶端會使用該介面來要求自訂控制項模式所支援的屬性和呼叫方法。 介面包含每個支援的屬性 (get_CurrentXxx和get_CachedXxx方法) 的一對 「getter」 方法,以及每個支援方法的「caller」 方法。 具現化物件時,物件建構函式會收到IUIAutomationPatternInstance介面的指標,由消費者介面自動化核心實作。 IXxxPattern 介面的方法會使用IUIAutomationPatternInstance::GetProperty和CallMethod方法,將屬性要求和方法呼叫轉送至消費者介面自動化核心。
下列範例示範如何針對支援單一屬性的簡單自訂控制項模式,實作用戶端包裝函式物件。 如需更複雜的範例,請參閱 自訂控制項模式的範例實作。
// 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。 CreateClientWrapper方法是由消費者介面自動化核心呼叫,並接收IUIAutomationPatternInstance介面的指標。 CreateClientWrapper 會藉由具現化用戶端包裝函式物件,並將 IUIAutomationPatternInstance 介面指標傳遞至用戶端包裝函式建構函式來回應。
分派方法是由消費者介面自動化核心用來將屬性要求和方法呼叫傳遞給自訂控制項模式的提供者介面。 參數包括提供者介面的指標、呼叫之屬性 getter 或方法的以零起始的索引,以及包含要傳遞至提供者之參數的 UIAutomationParameter 結構陣列。 模式處理常式會藉由檢查索引參數來判斷要呼叫的提供者方法,然後呼叫該提供者介面,傳遞 UIAutomationParameter 結構中包含的參數來回應。
模式處理常式物件是由註冊自訂控制項模式的相同程式碼具現化,再註冊控制項模式。 程式碼必須在註冊時將模式處理常式物件的IUIAutomationPatternHandler介面指標傳遞至消費者介面自動化核心。
下列範例示範如何針對支援單一屬性的簡單自訂控制項模式實作模式處理常式物件。 如需更複雜的範例,請參閱 自訂控制項模式的範例實作。
// 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;
}
};
註冊自訂控制項模式
使用自訂控制項模式之前,提供者和用戶端都必須註冊自訂控制項模式。 註冊會提供消費者介面自動化核心與控制項模式的詳細資訊,並提供提供者或用戶端的控制項模式識別碼,以及控制項模式所支援之屬性和事件的識別碼。 在提供者端,必須在相關聯的控制項處理 WM_GETOBJECT 訊息之前,或同時註冊自訂控制項模式。
註冊自訂控制項模式時,提供者或用戶端會提供下列資訊:
- 自訂控制項模式的 GUID。
- 包含自訂控制項模式名稱的非當地語系化字串。
- 支援自訂控制項模式之提供者介面的 GUID。
- 支援自訂控制項模式之用戶端介面的 GUID。
- UIAutomationPropertyInfo結構的陣列,描述自訂控制項模式所支援的屬性。 針對每個屬性,必須指定 GUID、屬性名稱和資料類型。
- UIAutomationMethodInfo結構的陣列,描述自訂控制項模式所支援的方法。 針對每個方法,結構包含下列資訊:方法名稱、參數計數、參數資料類型的清單,以及參數名稱的清單。
- UIAutomationEventInfo結構的陣列,描述自訂控制項模式所引發的事件。 針對每個事件,必須指定 GUID 和事件名稱。
- 模式處理常式物件的 IUIAutomationPatternHandler 介面位址,可讓用戶端使用自訂控制項模式。
若要註冊自訂控制項模式,提供者或用戶端程式代碼必須執行下列步驟:
- 使用上述資訊填入 UIAutomationPatternInfo 結構。
- 使用 CoCreateInstance 函式來建立 CUIAutomationRegistrar 物件的實例,並擷取物件的 IUIAutomationRegistrar 介面指標。
- 呼叫 IUIAutomationRegistrar::RegisterPattern 方法,傳遞 UIAutomationPatternInfo 結構的位址。
RegisterPattern方法會傳回控制項模式識別碼,以及屬性識別碼和事件識別碼的清單。 應用程式可以將這些識別碼傳遞至採用這類識別碼作為參數的任何消費者介面自動化方法。 例如,您可以將已註冊的模式識別碼傳遞至 IUIAutomationElement::GetCurrentPattern 方法,以擷取控制項模式提供者介面的指標。
沒有方法可以取消註冊自訂控制項模式。 而是在釋放最後一個消費者介面自動化物件時隱含取消註冊。
如需示範如何註冊自訂控制項模式的範例,請參閱下一節。
自訂控制項模式的範例實作
本節包含範例程式碼,示範如何實作自訂控制項模式的用戶端包裝函式和模式處理常式物件。 此範例會實作以 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;
}
相關主題