Registro de propiedades, eventos y patrones de control personalizados
Antes de que se pueda usar una propiedad personalizada, un evento o un patrón de control, tanto el proveedor como el cliente deben registrar la propiedad, el evento o el patrón de control en tiempo de ejecución. El registro es efectivo globalmente dentro de un proceso de aplicación y permanece efectivo hasta que el proceso se cierra o el último objeto de elemento de Microsoft Automatización de la interfaz de usuario (IUIAutomation o IRawElementProviderSimple) se libera dentro del proceso.
Registation implica pasar un GUID a Automatización de la interfaz de usuario, junto con información detallada sobre la propiedad personalizada, el evento o el patrón de control. Si intenta registrar el mismo GUID una segunda vez con la misma información, se producirá un error al intentar registrar el mismo GUID una segunda vez, pero con información diferente (por ejemplo, se producirá un error en una propiedad personalizada de un tipo diferente). En el futuro, si se acepta e integra la especificación personalizada en el núcleo de Automatización de la interfaz de usuario, Automatización de la interfaz de usuario validará la información de registro personalizada y usará el código ya registrado en lugar de la implementación del marco "oficial", lo que minimiza la aplicación. problemas de compatibilidad. No se pueden quitar propiedades, eventos o patrones de control que ya están registrados.
Este tema contiene las siguientes secciones:
- Registro de propiedades y eventos personalizados
- Implementación de patrones de control personalizados
- Temas relacionados
Registro de propiedades y eventos personalizados
El registro de una propiedad o evento personalizado permite al proveedor y al cliente obtener un identificador para la propiedad o evento, que luego se puede pasar a varios métodos de API que toman identificadores como parámetros.
Para registrar una propiedad o evento:
- Defina un GUID para la propiedad o evento personalizados.
- Rellene una estructura UIAutomationPropertyInfo o UIAutomationEventInfo con información sobre la propiedad o evento, incluido el GUID y una cadena no localizable que contenga el nombre de la propiedad o evento personalizados. Las propiedades personalizadas también requieren que se especifique el tipo de datos de la propiedad, por ejemplo, si la propiedad contiene un entero o una cadena. El tipo de datos debe ser uno de los siguientes tipos especificados por la enumeración UIAutomationType . No se admite ningún otro tipo de datos para las propiedades personalizadas.
- UIAutomationType_Bool
- UIAutomationType_Double
- UIAutomationType_Element
- UIAutomationType_Int
- UIAutomationType_Point
- UIAutomationType_String
- Use la función CoCreateInstance para crear una instancia del objeto CUIAutomationRegistrar y recuperar un puntero a la interfaz IUIAutomationRegistrar del objeto.
- Llame al método IUIAutomationRegistrar::RegisterProperty o RegisterEvent y pase la dirección de la estructura UIAutomationPropertyInfo o la estructura UIAutomationEventInfo .
El método IUIAutomationRegistrar::RegisterProperty o RegisterEvent devuelve un identificador de propiedad o un identificador de evento que una aplicación puede pasar a cualquier método Automatización de la interfaz de usuario que tome este identificador como parámetro. Por ejemplo, puede pasar un identificador de propiedad registrado al método IUIAutomationElement::GetCurrentPropertyValue o al método IUIAutomation::CreatePropertyCondition .
En el ejemplo siguiente se muestra cómo registrar una propiedad personalizada.
// 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;
}
Los identificadores de eventos y propiedades recuperados por los métodos IUIAutomationRegistrar::RegisterProperty y RegisterEvent solo son válidos en el contexto de la aplicación que los recupera y solo durante la duración de la aplicación. Los métodos de registro pueden devolver valores enteros diferentes para el mismo GUID cuando se llama a través de diferentes instancias en tiempo de ejecución de la misma aplicación.
No hay ningún método que anule el registro de una propiedad o evento personalizados. En su lugar, se anulan implícitamente el registro cuando se libera el último objeto Automatización de la interfaz de usuario.
Importante
Si el código es un cliente de Accesibilidad activa de Microsoft (MSAA), debe llamar a la función NotifyWinEvent cuando cambie el valor de una propiedad personalizada.
Implementación de patrones de control personalizados
Un patrón de control personalizado no se incluye en la API de Automatización de la interfaz de usuario, pero lo proporciona un tercero en tiempo de ejecución. Los desarrolladores de aplicaciones cliente y proveedor deben trabajar conjuntamente para definir un patrón de control personalizado, incluidos los métodos, las propiedades y los eventos que admitirá el patrón de control. Después de definir el patrón de control, tanto el cliente como el proveedor deben implementar objetos compatibles con el Modelo de objetos componentes (COM), junto con el código para registrar el patrón de control en tiempo de ejecución. Un patrón de control personalizado requiere la implementación de dos objetos COM: un contenedor de cliente y un controlador de patrones.
Nota
Los ejemplos de los temas siguientes muestran cómo implementar un patrón de control personalizado que duplica la funcionalidad del patrón de control Value existente. Estos ejemplos son solo para fines informativos. Un patrón de control personalizado real debe proporcionar funcionalidad que no está disponible en los patrones de control estándar Automatización de la interfaz de usuario.
Contenedor de cliente y controlador de patrones
El contenedor de cliente implementa la API que usa el cliente para recuperar propiedades y llamar a métodos expuestos por el patrón de control personalizado. La API se implementa como una interfaz COM que pasa todas las solicitudes de propiedad y las llamadas de método al núcleo Automatización de la interfaz de usuario, que a continuación serializa las solicitudes y las llamadas al proveedor.
El código que registra un patrón de control personalizado debe proporcionar un generador de clases que Automatización de la interfaz de usuario puede usar para crear instancias del objeto contenedor de cliente. Cuando se registra correctamente un patrón de control personalizado, Automatización de la interfaz de usuario devuelve un puntero de interfaz IUIAutomationPatternInstance que el cliente usa para reenviar solicitudes de propiedad y llamadas a métodos al núcleo de Automatización de la interfaz de usuario.
En el lado del proveedor, el Automatización de la interfaz de usuario núcleo toma las solicitudes de propiedad y las llamadas de método del cliente y las pasa al objeto de controlador de patrones. A continuación, el controlador de patrones llama a los métodos adecuados en la interfaz del proveedor para el patrón de control personalizado.
El código que registra un patrón de control personalizado crea el objeto de controlador de patrones y, al registrar el patrón de control, proporciona Automatización de la interfaz de usuario con un puntero a la interfaz IUIAutomationPatternHandler del objeto.
En el diagrama siguiente se muestra cómo fluye una llamada de método o solicitud de propiedad de cliente desde el contenedor de cliente, a través de los componentes principales del Automatización de la interfaz de usuario al controlador de patrones y, a continuación, a la interfaz del proveedor.
Los objetos que implementan las interfaces de controlador de patrones y contenedor de cliente deben ser subprocesos libres. Además, el núcleo de Automatización de la interfaz de usuario debe poder llamar a los objetos directamente sin ningún código intermedio de serialización.
Implementación del contenedor de cliente
El contenedor de cliente es un objeto que expone una interfaz IXxxPattern que el cliente usa para solicitar propiedades y llamar a métodos admitidos por el patrón de control personalizado. La interfaz consta de un par de métodos "captadores" para cada propiedad admitida (get_CurrentXxx y método get_CachedXxx) y un método "llamador" para cada método admitido. Cuando se crea una instancia del objeto, el constructor de objetos recibe un puntero a la interfaz IUIAutomationPatternInstance, que implementa el Automatización de la interfaz de usuario núcleo. Los métodos de la interfaz IXxxPattern usan los métodos IUIAutomationPatternInstance::GetProperty y CallMethod para reenviar solicitudes de propiedad y llamadas de método al núcleo Automatización de la interfaz de usuario.
En el ejemplo siguiente se muestra cómo implementar un objeto contenedor de cliente para un patrón de control personalizado sencillo que admita una sola propiedad. Para obtener un ejemplo más complejo, vea Implementación de ejemplo de un patrón de control personalizado.
// 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);
}
};
Implementación del controlador de patrones
El controlador de patrones es un objeto que implementa la interfaz IUIAutomationPatternHandler . Esta interfaz tiene dos métodos: IUIAutomationPatternHandler::CreateClientWrapper y Dispatch. El núcleo Automatización de la interfaz de usuario llama al método CreateClientWrapper y recibe un puntero a la interfaz IUIAutomationPatternInstance. CreateClientWrapper responde creando una instancia del objeto contenedor de cliente y pasando el puntero de interfaz IUIAutomationPatternInstance al constructor contenedor de cliente.
El método Dispatch lo usa el Automatización de la interfaz de usuario núcleo para pasar solicitudes de propiedad y llamadas de método a la interfaz del proveedor para el patrón de control personalizado. Los parámetros incluyen un puntero a la interfaz del proveedor, el índice de base cero del captador de propiedades o el método al que se llama y una matriz de estructuras UIAutomationParameter que contienen los parámetros que se van a pasar al proveedor. El controlador de patrones responde comprobando el parámetro de índice para determinar a qué método de proveedor llamar y, a continuación, llama a esa interfaz de proveedor, pasando los parámetros contenidos en las estructuras UIAutomationParameter .
Se crea una instancia del objeto de controlador de patrones mediante el mismo código que registra el patrón de control personalizado, antes de que se registre el patrón de control. El código debe pasar el puntero de interfaz IUIAutomationPatternHandler del objeto de controlador de patrones al núcleo Automatización de la interfaz de usuario en el momento del registro.
En el ejemplo siguiente se muestra cómo implementar un objeto de controlador de patrones para un patrón de control personalizado simple que admita una sola propiedad. Para obtener un ejemplo más complejo, vea Ejemplo de implementación de un patrón de control personalizado.
// 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;
}
};
Registro de un patrón de control personalizado
Para poder usarse, tanto el proveedor como el cliente deben registrar un patrón de control personalizado. El registro proporciona al núcleo de Automatización de la interfaz de usuario información detallada sobre el patrón de control y proporciona al proveedor o cliente el identificador del patrón de control e identificadores de las propiedades y eventos admitidos por el patrón de control. En el lado del proveedor, el patrón de control personalizado debe registrarse antes de que el control asociado controle el mensaje de WM_GETOBJECT o al mismo tiempo.
Al registrar un patrón de control personalizado, el proveedor o el cliente proporciona la siguiente información:
- GUID del patrón de control personalizado.
- Cadena no localizable que contiene el nombre del patrón de control personalizado.
- GUID de la interfaz del proveedor que admite el patrón de control personalizado.
- GUID de la interfaz de cliente que admite el patrón de control personalizado.
- Matriz de estructuras UIAutomationPropertyInfo que describen las propiedades admitidas por el patrón de control personalizado. Para cada propiedad, se debe especificar el GUID, el nombre de propiedad y el tipo de datos.
- Matriz de estructuras UIAutomationMethodInfo que describen los métodos admitidos por el patrón de control personalizado. Para cada método, la estructura incluye la siguiente información: el nombre del método, un recuento de parámetros, una lista de tipos de datos de parámetros y una lista de los nombres de parámetro.
- Matriz de estructuras UIAutomationEventInfo que describen los eventos generados por el patrón de control personalizado. Para cada evento, se debe especificar el GUID y el nombre del evento.
- Dirección de la interfaz IUIAutomationPatternHandler del objeto de controlador de patrones que hace que el patrón de control personalizado esté disponible para los clientes.
Para registrar el patrón de control personalizado, el proveedor o el código de cliente deben realizar los pasos siguientes:
- Rellene una estructura UIAutomationPatternInfo con la información anterior.
- Use la función CoCreateInstance para crear una instancia del objeto CUIAutomationRegistrar y recuperar un puntero a la interfaz IUIAutomationRegistrar del objeto.
- Llame al método IUIAutomationRegistrar::RegisterPattern y pase la dirección de la estructura UIAutomationPatternInfo .
El método RegisterPattern devuelve un identificador de patrón de control, junto con una lista de identificadores de propiedad e identificadores de evento. Una aplicación puede pasar estos identificadores a cualquier método Automatización de la interfaz de usuario que tome este identificador como parámetro. Por ejemplo, puede pasar un identificador de patrón registrado al método IUIAutomationElement::GetCurrentPattern para recuperar un puntero a la interfaz del proveedor para el patrón de control.
No hay ningún método que anule el registro de un patrón de control personalizado. En su lugar, se anula implícitamente el registro cuando se libera el último objeto Automatización de la interfaz de usuario.
Para obtener un ejemplo que muestra cómo registrar un patrón de control personalizado, consulte la sección siguiente.
Implementación de ejemplo de un patrón de control personalizado
Esta sección contiene código de ejemplo que muestra cómo implementar el contenedor de cliente y los objetos de controlador de patrones para un patrón de control personalizado. En el ejemplo se implementa un patrón de control personalizado basado en el patrón de control 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;
}
Temas relacionados
-
Conceptual
-
Diseño de propiedades personalizadas, eventos y patrones de control
-
Información general acerca de las propiedades de UI Automation
-
Información general acerca de los patrones de control de UI Automation