Controles ActiveX MFC: Temas avanzados
En este artículo se tratan temas avanzados relacionados con el desarrollo de controles ActiveX. Entre ellas se incluyen las siguientes:
Importante
ActiveX es una tecnología heredada que no se debe usar para el nuevo desarrollo. Para más información sobre las tecnologías modernas que reemplazan a ActiveX, vea Controles ActiveX.
Uso de clases de base de datos en controles ActiveX
Dado que las clases de control ActiveX forman parte de la biblioteca de clases, puede aplicar los mismos procedimientos y reglas para usar clases de base de datos en una aplicación MFC estándar para desarrollar controles ActiveX que usan las clases de base de datos MFC.
Para información general sobre las clases de base de datos de MFC, consulte Clases de base de datos de MFC (DAO y ODBC). En el artículo se presentan las clases ODBC de MFC y las clases DAO de MFC y se le dirige a más detalles sobre cualquiera de las dos.
Nota:
DAO se admite mediante Office 2013. DAO 3.6 es la versión final y se considera obsoleta. El entorno y los asistentes de Visual C++ no admiten DAO (aunque se incluyen las clases DAO y todavía se pueden usar). Microsoft recomienda usar plantillas OLE DB o bien ODBC y MFC para proyectos nuevos. Solo debe usar DAO para mantener las aplicaciones existentes.
Implementación de una propiedad parametrizada
Una propiedad parametrizada (a veces denominada matriz de propiedades) es un método para exponer una colección homogénea de valores como una sola propiedad del control. Por ejemplo, puede usar una propiedad parametrizada para exponer una matriz o un diccionario como una propiedad. En Visual Basic, se obtiene acceso a esta propiedad mediante notación de matriz:
x = o.Array(2, 3) ' gets element of 2D array
o.Array(2, 3) = 7 ' sets element of 2D array
Use el Asistente para agregar propiedades para implementar una propiedad parametrizada. El Asistente para agregar propiedades implementa la propiedad agregando un par de funciones Get/Set que permiten al usuario de control tener acceso a la propiedad mediante la notación anterior o de forma estándar.
De forma similar a los métodos y las propiedades, las propiedades parametrizadas también tienen un límite en cuanto al número de parámetros permitidos. En el caso de las propiedades parametrizadas, el límite es de 15 parámetros (con un parámetro reservado para almacenar el valor de propiedad).
El procedimiento siguiente agrega una propiedad parametrizada, denominada Array, a la que se puede tener acceso como una matriz bidimensional de enteros.
Para agregar una propiedad parametrizada mediante el Asistente para agregar propiedades, siga estos pasos:
Cargue el proyecto del control.
En la vista de clases, expanda el nodo de biblioteca del control.
Haga clic con el botón derecho en el nodo de interfaz del control (el segundo nodo del nodo de biblioteca) para abrir el menú contextual.
En el menú contextual, haga clic en Agregar y después en Agregar propiedad.
En el cuadro Nombre de propiedad, escriba
Array
.En el cuadro Tipo de propiedad, seleccione
short
.En Tipo de implementación, haga clic en Métodos Get/Set.
En los cuadros Función Get y Función Set, escriba nombres únicos para las funciones Get y Set o acepte los nombres predeterminados.
Agregue un parámetro denominado row (tipo short), mediante los controles Nombre de parámetro y Tipo de parámetro.
Agregue un segundo parámetro denominado column (tipo short).
Haga clic en Finalizar
Cambios realizados por el Asistente para agregar propiedades
Al agregar una propiedad personalizada, el Asistente para agregar propiedades realiza cambios en los archivos de encabezado (.H) e implementación (.CPP) de la clase de control.
Las líneas siguientes se agregan al archivo .H de clase de control:
SHORT GetArray(SHORT row, SHORT column);
void SetArray(SHORT row, SHORT column, SHORT newVal);
Este código declara dos funciones llamadas GetArray
y SetArray
que permiten al usuario solicitar una fila y una columna específicas al acceder a la propiedad.
Además, el Asistente para agregar propiedades agrega las líneas siguientes al mapa de distribución de controles, ubicado en el archivo de implementación de la clase de control (.CPP):
DISP_PROPERTY_PARAM_ID(CMyAxUICtrl, "Array", dispidArray, GetArray, SetArray, VT_I2, VTS_I2 VTS_I2)
Por último, las implementaciones de las funciones GetArray
y SetArray
se agregan al final del archivo .CPP. En la mayoría de los casos, modificará la función Get para devolver el valor de la propiedad. La función Set normalmente contendrá código que se debe ejecutar, ya sea antes o después de que la propiedad cambie.
Para que esta propiedad sea útil, puede declarar una variable miembro de matriz bidimensional en la clase de control, de tipo short
, para almacenar valores para la propiedad parametrizada. Después, podría modificar la función Get para devolver el valor almacenado en la fila y la columna adecuadas, como se indica en los parámetros, y modificar la función Set para actualizar el valor al que hacen referencia los parámetros de fila y columna.
Control de errores en el control ActiveX
Si se producen condiciones de error en el control, es posible que tenga que notificar el error al contenedor de controles. Hay dos métodos para notificar errores, dependiendo de la situación en la que se produzca el error. Si el error se produce dentro de la función Get o Set de una propiedad, o dentro de la implementación de un método de automatización OLE, el control debe llamar a COleControl::ThrowError, que indica al usuario del control que se ha producido un error. Si el error se produce en cualquier otro momento, el control debe llamar a COleControl::FireError, que desencadena un evento de error de existencias.
Para indicar el tipo de error que se ha producido, el control debe pasar un código de error a ThrowError
o FireError
. Un código de error es un código de estado OLE, que tiene un valor de 32 bits. Cuando sea posible, elija un código de error del conjunto estándar de códigos definidos en el archivo de encabezado OLECTL.H. Estos códigos se resumen en la tabla siguiente.
Códigos de error de los controles ActiveX
Error | Descripción |
---|---|
CTL_E_ILLEGALFUNCTIONCALL | Llamada de función no válida |
CTL_E_OVERFLOW | Desbordamiento |
CTL_E_OUTOFMEMORY | No hay memoria suficiente |
CTL_E_DIVISIONBYZERO | División por cero |
CTL_E_OUTOFSTRINGSPACE | Espacio de cadena insuficiente |
CTL_E_OUTOFSTACKSPACE | Espacio de pila insuficiente |
CTL_E_BADFILENAMEORNUMBER | Número o nombre de archivo incorrecto |
CTL_E_FILENOTFOUND | Archivo no encontrado |
CTL_E_BADFILEMODE | Modo de archivo incorrecto |
CTL_E_FILEALREADYOPEN | Archivo ya abierto |
CTL_E_DEVICEIOERROR | Error de E/S del dispositivo |
CTL_E_FILEALREADYEXISTS | El archivo ya existe |
CTL_E_BADRECORDLENGTH | Longitud de registro incorrecta |
CTL_E_DISKFULL | Disco lleno |
CTL_E_BADRECORDNUMBER | Número de registro incorrecto |
CTL_E_BADFILENAME | Modo de archivo incorrecto |
CTL_E_TOOMANYFILES | Demasiados archivos |
CTL_E_DEVICEUNAVAILABLE | Dispositivo no disponible |
CTL_E_PERMISSIONDENIED | Permiso denegado |
CTL_E_DISKNOTREADY | Disco no preparado |
CTL_E_PATHFILEACCESSERROR | Error de acceso a la ruta o al archivo |
CTL_E_PATHNOTFOUND | No se encuentra la ruta de acceso |
CTL_E_INVALIDPATTERNSTRING | Cadena de patrón no válida |
CTL_E_INVALIDUSEOFNULL | Uso no válido de NULL |
CTL_E_INVALIDFILEFORMAT | Formato de archivo no válido |
CTL_E_INVALIDPROPERTYVALUE | Valor de propiedad no válido |
CTL_E_INVALIDPROPERTYARRAYINDEX | Índice de matriz de propiedades no válido |
CTL_E_SETNOTSUPPORTEDATRUNTIME | No se admite Set en tiempo de ejecución |
CTL_E_SETNOTSUPPORTED | No se admite Set (propiedad de solo lectura). |
CTL_E_NEEDPROPERTYARRAYINDEX | Se necesita un índice de matriz de propiedades |
CTL_E_SETNOTPERMITTED | No se permite establecer |
CTL_E_GETNOTSUPPORTEDATRUNTIME | No se admite Get en tiempo de ejecución |
CTL_E_GETNOTSUPPORTED | No se admite Get (propiedad de solo escritura) |
CTL_E_PROPERTYNOTFOUND | Propiedad no encontrada |
CTL_E_INVALIDCLIPBOARDFORMAT | Formato de Portapapeles no válido |
CTL_E_INVALIDPICTURE | Imagen no válida |
CTL_E_PRINTERERROR | Error en la impresora |
CTL_E_CANTSAVEFILETOTEMP | No se puede guardar el archivo en TEMP |
CTL_E_SEARCHTEXTNOTFOUND | No se encuentra el texto de la búsqueda |
CTL_E_REPLACEMENTSTOOLONG | Los reemplazos son demasiado largos |
Si es necesario, use la macro CUSTOM_CTL_SCODE para definir un código de error personalizado para una condición que no esté cubierta por uno de los códigos estándar. El parámetro de esta macro debe ser un entero entre 1000 y 32767, ambos incluidos. Por ejemplo:
#define MYCTL_E_SPECIALERROR CUSTOM_CTL_SCODE(1000)
Si va a crear un control ActiveX para reemplazar un control VBX existente, defina los códigos de error del control ActiveX con los mismos valores numéricos que usa el control VBX para asegurarse de que los códigos de error son compatibles.
Control de teclas especiales en el control
En algunos casos, es posible que quiera controlar ciertas combinaciones de pulsaciones de teclas de una manera especial; por ejemplo, insertar una nueva línea cuando se presione la tecla ENTRAR en un control de cuadro de texto de varias líneas o moverse entre un grupo de controles de edición cuando se presione un identificador de tecla direccional.
Si la clase base del control ActiveX es COleControl
, puede invalidar CWnd::P reTranslateMessage para controlar los mensajes antes de que el contenedor los procese. Al usar esta técnica, siempre se devuelve TRUE si el mensaje se controla en la invalidación de PreTranslateMessage
.
En el ejemplo de código siguiente se muestra una manera posible de controlar los mensajes relacionados con las teclas direccionales.
BOOL CMyAxUICtrl::PreTranslateMessage(MSG* pMsg)
{
BOOL bHandleNow = FALSE;
switch (pMsg->message)
{
case WM_KEYDOWN:
switch (pMsg->wParam)
{
case VK_UP:
case VK_DOWN:
case VK_LEFT:
case VK_RIGHT:
bHandleNow = TRUE;
break;
}
if (bHandleNow)
{
OnKeyDown((UINT)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam));
}
break;
}
return bHandleNow;
}
Para más información sobre cómo controlar las interfaces de teclado para un control ActiveX, consulte la documentación del SDK de ActiveX.
Acceso a controles de cuadro de diálogo que son invisibles en tiempo de ejecución
Puede crear controles de cuadro de diálogo que no tengan ninguna interfaz de usuario y que sean invisibles en tiempo de ejecución. Si agrega un control ActiveX invisible en tiempo de ejecución a un cuadro de diálogo y usa CWnd::GetDlgItem para acceder al control, el control no funcionará correctamente. En su lugar, debe usar una de las técnicas siguientes para obtener un objeto que represente el control:
Con el Asistente para agregar variables miembro, seleccione Variable de control y, luego, elija el identificador del control. Escriba un nombre de variable miembro y seleccione la clase contenedora del control en Tipo de control.
o bien
Declare una variable local y una subclase como elemento de cuadro de diálogo. Inserte código similar al siguiente (
CMyCtrl
es la clase contenedora, IDC_MYCTRL1 es el identificador del control):CCirc myCirc; myCirc.SubclassDlgItem(IDC_CIRCCTRL2, this); // ... use myCirc ... myCirc.UnsubclassWindow();