Поделиться через


Регистрация пользовательских свойств, событий и шаблонов элементов управления

Перед использованием пользовательского свойства, события или шаблона элемента управления поставщик и клиент должны зарегистрировать свойство, событие или шаблон элемента управления во время выполнения. Регистрация действует глобально в рамках процесса выполнения и остается действующей до закрытия процесса или выпуска последнего элемента объекта автоматизации пользовательского интерфейса Microsoft (IUIAutomation или IRawElementProviderSimple).

Регистрация включает передачу GUID в автоматизацию пользовательского интерфейса, а также подробные сведения о пользовательском свойстве, событии или шаблоне управления. Попытка зарегистрировать один и тот же GUID второй раз с той же информацией будет выполнена успешно, но попытка зарегистрировать тот же GUID второй раз с другой информацией (например, пользовательское свойство другого типа) завершится ошибкой. В будущем, если пользовательская спецификация принимается и интегрирована в ядро автоматизации пользовательского интерфейса, служба автоматизации пользовательского интерфейса проверяет пользовательские сведения о регистрации и использует уже зарегистрированный код вместо реализации официальной платформы, тем самым минимизируя проблемы совместимости приложений. Невозможно удалить свойства, события или шаблоны элементов управления, которые уже зарегистрированы.

В этом разделе содержатся следующие разделы:

Регистрация настраиваемых свойств и событий

Регистрация пользовательского свойства или события позволяет поставщику и клиенту получить идентификатор свойства или события, которые затем можно передать различным методам API, которые принимают идентификаторы в качестве параметров.

Чтобы зарегистрировать свойство или событие:

  1. Определите GUID для пользовательского свойства или события.
  2. Заполните структуру UIAutomationPropertyInfo или UIAutomationEventInfo сведениями о свойстве или событии, включая GUID и нелокализуемую строку, содержащую имя пользовательского свойства или события. Пользовательские свойства также требуют указания типа данных свойства, например, содержит ли свойство целое число или строку. Тип данных должен быть одним из следующих типов, указанных перечислением UIAutomationType. Для пользовательских свойств не поддерживаются другие типы данных.
    • UIAutomationType_Bool
    • UIAutomationType_Double
    • UIAutomationType_Element
    • UIAutomationType_Int
    • UIAutomationType_Point
    • UIAutomationType_String
  3. Используйте функцию CoCreateInstance для создания экземпляра объекта CUIAutomationRegistrar и получения указателя на интерфейс IUIAutomationRegistrar.
  4. Вызовите метод 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, который используется клиентом для передачи запросов свойств и вызовов методов в ядро автоматизации пользовательского интерфейса.

На стороне поставщика ядро автоматизации пользовательского интерфейса принимает запросы свойств и вызовы метода от клиента и передает их в объект обработчика шаблонов. Затем обработчик шаблонов вызывает соответствующие методы в интерфейсе поставщика для пользовательского шаблона элемента управления.

Код, регистрирующий пользовательский шаблон элемента управления, создает объект обработчика шаблонов и при регистрации шаблона элемента управления предоставляет UI Automation указатель на интерфейс IUIAutomationPatternHandler.

На следующей схеме показано, как запрос на свойство клиента или вызов метода выполняется из оболочки клиента, через основные компоненты автоматизации пользовательского интерфейса в обработчик шаблонов, а затем в интерфейс поставщика.

схема , показывающая поток от оболочки клиента к обработчику шаблонов и поставщику

Объекты, реализующие клиентские оболочки и интерфейсы обработчика шаблонов, должны быть многопоточными. Кроме того, ядро автоматизации пользовательского интерфейса должно иметь возможность вызывать объекты напрямую без какого-либо промежуточного кода маршалинга.

Реализация оболочки клиента

Оболочка клиента — это объект, предоставляющий интерфейс IXxXPattern, который клиент использует для запроса свойств и вызовов методов, поддерживаемых шаблоном пользовательского элемента управления. Интерфейс состоит из пары методов получения для каждого поддерживаемого свойства (методы get_CurrentXxx и get_CachedXxx) и метода вызова для каждого поддерживаемого метода. При создании экземпляра объекта конструктор объекта получает указатель на интерфейс 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 конструктору оболочки клиента.

Метод Dispatch используется системой автоматизации пользовательского интерфейса для передачи запросов свойств и вызовов методов в интерфейс поставщика для кастомного шаблона элемента управления. Параметры включают указатель на интерфейс поставщика, отсчитываемый от нуля индекс вызываемого свойства 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 объекта обработчика шаблонов, который делает шаблон пользовательского элемента управления доступным для клиентов.

Чтобы зарегистрировать шаблон пользовательского элемента управления, поставщик или клиентский код должен выполнить следующие действия:

  1. Заполните структуру UIAutomationPatternInfo приведенными выше сведениями.
  2. Используйте функцию CoCreateInstance для создания экземпляра объекта CUIAutomationRegistrar и получения указателя на интерфейс IUIAutomationRegistrar.
  3. Вызовите метод IUIAutomationRegistrar::RegisterPattern, передав адрес структуры UIAutomationPatternInfo.

Метод RegisterPattern возвращает идентификатор шаблона элемента управления, а также список идентификаторов свойств и идентификаторов событий. Приложение может передавать эти идентификаторы любому методу автоматизации пользовательского интерфейса, который принимает такой идентификатор в качестве параметра. Например, можно передать зарегистрированный идентификатор шаблона в метод IUIAutomationElement::GetCurrentPattern, чтобы получить указатель на интерфейс поставщика для шаблона управления.

Нет метода, который отменяет регистрацию шаблона пользовательского элемента управления. Вместо этого он неявно отменяется при выпуске последнего объекта автоматизации пользовательского интерфейса.

Пример, показывающий, как зарегистрировать шаблон пользовательского элемента управления, см. в следующем разделе.

Пример реализации пользовательского шаблона элемента управления

В этом разделе содержится пример кода, демонстрирующий реализацию объектов оболочки клиента и обработчика шаблонов для пользовательского шаблона элемента управления. В этом примере реализуется пользовательский шаблон управления, основанный на шаблоне управления значения.

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

концептуальные

проектирование настраиваемых свойств, событий и шаблонов элементов управления

Обзор свойств автоматизации пользовательского интерфейса

Обзор событий автоматизации пользовательского интерфейса

Обзор шаблонов управления автоматизацией пользовательского интерфейса