En esta página

Creación de servidores ActiveX en Qt

El módulo QAxServer forma parte del framework ActiveQt. Consta de tres clases:

  • QAxFactory define una fábrica para la creación de objetos COM.
  • QAxBindable proporciona una interfaz entre el widget Qt y el objeto COM.
  • QAxAggregated puede subclasificarse para implementar interfaces COM adicionales.

Se proporcionan algunos ejemplos de implementación de controles ActiveX y objetos COM.

Utilización de la biblioteca

Para convertir una aplicación Qt estándar en un servidor COM utilizando la biblioteca QAxServer debe añadir axserver a la variable QT en su archivo .pro.

Un servidor ejecutable fuera de proceso se genera a partir de un archivo .pro como este:

TEMPLATE = app
QT  += axserver

RC_FILE  = qaxserver.rc
...

Para generar un servidor en proceso, utilice un archivo .pro como éste:

TEMPLATE = lib
QT += axserver
CONFIG  += dll

DEF_FILE = qaxserver.def
RC_FILE  = qaxserver.rc
...

Los archivos qaxserver.rc y qaxserver.def forman parte del framework y pueden utilizarse desde su ubicación habitual (especifique una ruta en el archivo .pro ), o copiarse en el directorio del proyecto. Puede modificar estos archivos siempre que incluya cualquier archivo como entrada de biblioteca de tipos, es decir, puede añadir información sobre la versión o especificar un icono de caja de herramientas diferente.

El uso del módulo axserver hará que la herramienta qmake añada los pasos de compilación necesarios al sistema de compilación:

  • Enlazar el binario con qaxserver.lib en lugar de qtmain.lib
  • Llamar a la herramienta idc para generar un archivo IDL para el servidor COM.
  • Compilar el IDL en una biblioteca de tipos utilizando la herramienta MIDL (parte de la instalación del compilador).
  • Adjuntar la biblioteca de tipos resultante como recurso binario al binario del servidor (también con la herramienta idc ).
  • Registrar el servidor. Este paso puede requerir privilegios administrativos y puede omitirse configurando qaxserver_no_register.

Para omitir el paso de post-procesamiento, establezca también la configuración qaxserver_no_postlink.

Además, puede especificar un número de versión utilizando la variable VERSION, por ejemplo

TEMPLATE = lib
VERSION = 2.5
...

El número de versión especificado se utilizará como versión de la biblioteca de tipos y del servidor al registrarse.

Fuera de proceso vs. Dentro de proceso

El hecho de que su servidor COM deba ejecutarse como un ejecutable independiente o como una biblioteca compartida en el proceso cliente depende principalmente del tipo de objetos COM que desee proporcionar en el servidor.

Un servidor ejecutable tiene la ventaja de poder ejecutarse como una aplicación independiente, pero añade una sobrecarga considerable a la comunicación entre el cliente COM y el objeto COM. Si el control tiene un error de programación, sólo se bloqueará el proceso del servidor que ejecuta el control, y la aplicación cliente probablemente seguirá ejecutándose. No todos los clientes COM soportan servidores ejecutables.

Un servidor en proceso suele ser más pequeño y tiene un tiempo de arranque más rápido. La comunicación entre el cliente y el servidor se realiza directamente a través de llamadas a funciones virtuales y no introduce la sobrecarga necesaria para las llamadas a procedimientos remotos. Sin embargo, si el servidor se bloquea, es probable que la aplicación cliente también lo haga, y no todas las funciones están disponibles para los servidores en proceso (por ejemplo, el registro en la tabla de objetos en ejecución de COM).

Ambos tipos de servidores pueden usar Qt como una librería compartida o enlazada estáticamente en el binario del servidor.

Errores típicos durante los pasos posteriores a la compilación

Para que los pasos de post-procesamiento específicos de ActiveQt funcionen, el servidor tiene que cumplir algunos requisitos:

  • Todos los controles expuestos pueden crearse sin más que una instancia de QApplication
  • La vinculación inicial del servidor incluye un recurso de biblioteca de tipos temporal
  • Todas las dependencias necesarias para ejecutar el servidor se encuentran en la ruta del sistema (o en la ruta utilizada por el entorno de llamada; tenga en cuenta que Visual Studio tiene su propio conjunto de variables de entorno que aparecen en el cuadro de diálogo Herramientas|Opciones|Directorios).

Si estos requisitos no se cumplen, es probable que se produzca uno o más de los siguientes errores:

El ejecutable del servidor se bloquea

Para generar el IDL los widgets expuestos como controles ActiveX necesitan ser instanciados (se llama al constructor). En este punto, no existe nada más que un objeto QApplication. El constructor de tu widget no debe depender de ningún otro objeto para ser creado, por ejemplo, debe comprobar si hay punteros nulos.

Para depurar tu servidor ejecútalo con -dumpidl outputfile y comprueba dónde falla.

Tenga en cuenta que no se llama a ninguna función del control.

El ejecutable del servidor no es una aplicación Win32 válida

Adjuntar la librería de tipos corrompió el binario del servidor. Esto es un error de Windows y sólo ocurre con las versiones de lanzamiento.

El primer paso de vinculación tiene que vincular una biblioteca de tipos ficticia en el ejecutable que más tarde puede ser reemplazada por idc. Añada un archivo de recursos con una biblioteca de tipos a su proyecto como se muestra en los ejemplos.

"No se puede localizar la DLL

El sistema de compilación necesita ejecutar el ejecutable del servidor para generar la definición de la interfaz y registrar el servidor. Si una biblioteca de vínculos dinámicos con la que se vincula el servidor no se encuentra en la ruta, puede fallar (por ejemplo, Visual Studio llama al servidor utilizando la configuración de entorno especificada en la opción "Directorios"). Asegúrese de que todas las DLL y plugins que necesita el servidor se encuentran en un directorio que aparece en la ruta tal y como se muestra en el cuadro de mensaje de error (consulte también la Herramienta de implementación de Windows).

"No se puede abrir el archivo ..."

El servidor ActiveX no pudo cerrarse correctamente cuando el último cliente dejó de utilizarlo. Normalmente, la aplicación tarda unos dos segundos en terminar, pero es posible que tenga que utilizar el administrador de tareas para matar el proceso (por ejemplo, cuando un cliente no libera los controles correctamente).

El control no puede ser instanciado

En este caso, puede ayudar registrar el servidor como Administrador.

Implementación de Controles

Para implementar un objeto COM con Qt, cree una subclase de QObject o cualquier subclase existente de QObject. Si la clase es una subclase de QWidget, el objeto COM será un control ActiveX.

#include <QWidget>

class MyActiveX : public QWidget
{
    Q_OBJECT

La macro Q_OBJECT es necesaria para proporcionar la información metaobjeto sobre el widget al framework ActiveQt.

Q_CLASSINFO("ClassID", "{1D9928BD-4453-4bdd-903D-E525ED17FDE5}")
Q_CLASSINFO("InterfaceID", "{99F6860E-2C5A-42ec-87F2-43396F4BE389}")
Q_CLASSINFO("EventsID", "{0A3E9F27-E4F1-45bb-9E47-63099BCCD0E3}")

Utilice la macro Q_CLASSINFO() para especificar los identificadores COM para el objeto COM. ClassID y InterfaceID son obligatorios, mientras que EventsID sólo es necesaria cuando su objeto tiene señales. Para generar estos identificadores, utilice herramientas del sistema como uuidgen o guidgen.

Puede especificar atributos adicionales para cada una de sus clases; consulte Información y ajuste de clases para obtener más detalles.

Q_PROPERTY(int value READ value WRITE setValue)

Utilice la macro Q_PROPERTY() para declarar propiedades para el control ActiveX.

Declare un constructor estándar que tome un objeto padre, y funciones, señales y ranuras como para cualquier subclase de QObject.

public:
    MyActiveX(QWidget *parent = 0)
    ...

    int value() const;

public slots:
    void setValue(int v);
    ...

signals:
    void valueChange(int v);
    ...

};

El marco ActiveQt expondrá las propiedades y ranuras públicas como propiedades y métodos ActiveX, y las señales como eventos ActiveX, y convertirá entre los tipos de datos Qt y los tipos de datos COM equivalentes.

Tipos de datos

Los tipos de datos Qt compatibles con las propiedades son los siguientes:

Tipo de datos QtPropiedad COM
boolVARIANT_BOOL
QStringBSTR
intint
uintunsigned int
dobledoble
qlonglongCY
qulonglongCY
QColorOLE_COLOR
QDateFECHA
QDateTimeDATE
QTimeDATE
QFontIFontDisp*
QPixmapIPictureDisp*
QVariantVARIANTE
QVariantList (igual que QList<QVariant>)SAFEARRAY(VARIANT)
QStringListSAFEARRAY(BSTR)
QByteArraySAFEARRAY(BYTE)
QRectTipo definido por el usuario
QSizeTipo definido por el usuario
QPointTipo definido por el usuario

Los tipos de datos Qt admitidos para parámetros en señales y ranuras son:

Tipo de datos QtParámetro COM
bool[in] VARIANT_BOOL
bool&[in, out] VARIANT_BOOL*
QString, const QString&[in] BSTR
QString&[in, out] BSTR*
QString&[in, out] BSTR*
int[in] int
int&[in,out] int
uint[in] unsigned int
uint&[in, out] unsigned int*
doubledouble [in] doble
doble&[in, out] double*
QColorconst QColor&[en] OLE_COLOR
QColor&[in, out] OLE_COLOR*
QDateconst QDate&[in] DATE
QDate&[in, out] DATE*
QDateTimeconst QDateTime&[in] DATE
QDateTime&[in, out] DATE*
QFontconst QFont&[in] IFontDisp*
QFont&[in, out] IFontDisp**
QPixmapconst QPixmap&[en] IPictureDisp*
QPixmap&[in, out] IPictureDisp**
QList<QVariant>, const QList<QVariant>&[in] SAFEARRAY(VARIANT)
QList<QVariant>&[in, out] SAFEARRAY(VARIANT)*
QStringList, const QStringList&[in] SAFEARRAY(BSTR)
QStringList&[in, out] SAFEARRAY(BSTR)*
QByteArrayconst QByteArray&[in] SAFEARRAY(BYTE)
QByteArray&[in, out] SAFEARRAY(BYTE)*
QObject*[in] IDispatch*
QRect& [in, out] struct QRect (definido por el usuario)
QSize&[in, out] struct QSize (definido por el usuario)
QPoint&[in, out] struct QPoint (definido por el usuario)

También se admiten enums y flags exportados (véase Q_ENUM() y Q_FLAG()). Los tipos de parámetros in también se admiten como valores de retorno.

Las propiedades y señales/ranuras que tienen parámetros que utilizan cualquier otro tipo de datos son ignoradas por el framework ActiveQt.

Subobjetos

Los objetos COM pueden tener múltiples subobjetos que pueden representar un subelemento del objeto COM. Un objeto COM que represente una aplicación de hoja de cálculo con múltiples documentos puede, por ejemplo, proporcionar un subobjeto para cada hoja de cálculo.

Cualquier subclase de QObject puede utilizarse como tipo para un subobjeto en ActiveX, siempre y cuando sea conocida por QAxFactory. A continuación, el tipo puede utilizarse en propiedades, o como tipo de retorno o parámetro de una ranura.

Notificación de propiedades

Para que las propiedades sean vinculables para el cliente ActiveX, utilice la herencia múltiple de la clase QAxBindable:

#include <QAxBindable>
#include <QWidget>

class MyActiveX : public QWidget, public QAxBindable
{
    Q_OBJECT

Al implementar las funciones de escritura de propiedades, utilice las funciones requestPropertyChange() y propertyChanged() de la clase QAxBindable para permitir que los clientes ActiveX se vinculen a las propiedades del control.

Servir controles

Para que un servidor COM esté disponible para el sistema COM, debe registrarse en el registro del sistema utilizando cinco identificadores únicos. Estos identificadores son proporcionados por herramientas como guidgen o uuidgen. La información de registro permite a COM localizar el binario que proporciona un control ActiveX solicitado, realizar llamadas a procedimientos remotos al control y leer información de tipo sobre los métodos y propiedades expuestos por el control.

Para crear el objeto COM cuando el cliente lo solicita, el servidor debe exportar una implementación de QAxFactory. La forma más sencilla de hacerlo es utilizar un conjunto de macros:

QAXFACTORY_BEGIN("{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}",
                 "{a8f21901-7ff7-4f6a-b939-789620c03d83}")
    QAXCLASS(MyWidget)
    QAXCLASS(MyWidget2)
    QAXTYPE(MySubType)
QAXFACTORY_END()

Esto exportará MyWidget y MyWidget2 como objetos COM que pueden ser creados por clientes COM, y registrará MySubType como un tipo que puede ser usado en propiedades y parámetros de MyWidget y MyWidget2.

En QAxFactory class documentation se explica cómo utilizar esta macro y cómo implementar y utilizar fábricas personalizadas.

Para servidores ejecutables fuera de proceso puedes implementar una función main() para instanciar un objeto QApplication y entrar en el bucle de eventos como cualquier aplicación Qt normal. Por defecto la aplicación se iniciará como una aplicación Qt estándar, pero si pasas -activex en la línea de comandos se iniciará como un servidor ActiveX. Utilice QAxFactory::isServer() para crear y ejecutar una interfaz de aplicación estándar, o para evitar una ejecución autónoma:

#include <QApplication>
#include <QAxFactory>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    if (!QAxFactory::isServer()) {
        // create and show main window
    }
    return app.exec();
}

Sin embargo, esto no es necesario ya que ActiveQt proporciona una implementación por defecto de una función principal. La implementación por defecto llama a QAxFactory::startServer(), crea una instancia de QApplication y llama a exec().

Para construir el ejecutable del servidor ActiveX ejecute qmake para generar el makefile, y utilice la herramienta make de su compilador como para cualquier otra aplicación Qt. El proceso make también registrará los controles en el registro del sistema llamando al ejecutable resultante con la opción de línea de comandos -regserver.

Si el servidor ActiveX es un ejecutable, se admiten las siguientes opciones de línea de comandos:

OpciónResultado
-regserverRegistra el servidor en el registro del sistema
-regserverperuserRegistra el servidor en el registro del sistema para el usuario actual (desde 5.14)
-unregserverDesregistra el servidor del registro del sistema
-unregserverperuserDesregistra el servidor del registro del sistema para el usuario actual (desde 5.14)
-activexInicia la aplicación como servidor ActiveX
-dumpidl <file> -version x.yEscribe la IDL del servidor en el archivo especificado. La biblioteca de tipos tendrá la versión x.y

Los servidores en proceso pueden registrarse utilizando la herramienta regsvr32 disponible en todos los sistemas Windows.

Problemas típicos de compilación

Los errores de compilador/enlazador listados se basan en los emitidos por el compilador Microsoft Visual C++ 6.0.

"Ninguna función sobrecargada toma 2 parámetros"

Cuando el error se produce en código que utiliza la macro QAXCLASS() o QAXFACTORY_DEFAULT(), la clase widget no tenía ningún constructor que pueda ser utilizado por la fábrica por defecto. Añada un constructor de widget estándar o implemente una fábrica personalizada que no requiera uno.

Cuando el error se produce en código que utiliza la macro QAXFACTORY_EXPORT(), la subclase QAxFactory no tenía un constructor apropiado. Proporcione un constructor de clase pública como

MyFactory(const QUuid &, const QUuid &);

para su clase de fábrica.

"Error de sintaxis: sufijo incorrecto en el número"

Los identificadores únicos no se han pasado como cadenas a la macro QAXFACTORY_EXPORT(), QAXFACTORY_BEGIN() o QAXFACTORY_DEFAULT().

"Símbolo externo no resuelto _ucm_instantiate"

El servidor no exporta una implementación de QAxFactory. Utilice la macro QAXFACTORY_EXPORT() en uno de los archivos de implementación del proyecto para instanciar y exportar una fábrica, o utilice la macro QAXCLASS() o QAXFACTORY_DEFAULT() para utilizar la fábrica predeterminada.

"_ucm_initialize ya está definido en ..."

El servidor exporta más de una implementación de un QAxFactory, o exporta la misma implementación dos veces. Si utiliza la fábrica por defecto, la macro QAXFACTORY_BEGIN() o QAXFACTORY_DEFAULT() sólo debe utilizarse una vez en el proyecto. Utilice una implementación personalizada de QAxFactory y la macro QAXFACTORY_EXPORT() si el servidor proporciona varios controles ActiveX.

Distribución de los binarios de QAxServer

Los servidores ActiveX escritos con Qt pueden usar Qt como una biblioteca compartida, o tener Qt enlazado estáticamente en el binario. En ambos casos, los paquetes son bastante grandes (o bien el propio binario del servidor es grande, o bien hay que distribuir la DLL de Qt).

Instalación de servidores independientes

Si su servidor ActiveX también puede ejecutarse como una aplicación independiente, ejecute el ejecutable del servidor con el parámetro de línea de comandos -regserver después de instalar el ejecutable en el sistema de destino. A partir de ese momento, los controles proporcionados por el servidor estarán disponibles para los clientes ActiveX.

Instalación de servidores en proceso

Si el servidor ActiveX forma parte de un paquete de instalación, utilice la herramienta regsvr32 proporcionada por Microsoft para registrar los controles en el sistema de destino. Si esta herramienta no está presente, cargue la DLL en su proceso de instalación, resuelva el símbolo DllRegisterServer y llame a la función:

HMODULE dll = LoadLibrary("myserver.dll");
typedef HRESULT(__stdcall *DllRegisterServerProc)();
DllRegisterServerProc DllRegisterServer =
    (DllRegisterServerProc)GetProcAddress(dll, "DllRegisterServer");

HRESULT res = E_FAIL;
if (DllRegisterServer)
    res = DllRegisterServer();
if (res != S_OK)
    // error handling

Distribuir servidores en Internet

Si desea utilizar los controles de su servidor en páginas web, debe hacer que el servidor esté disponible para el navegador utilizado para ver su página, y debe especificar la ubicación del paquete del servidor en su página.

Para especificar la ubicación de un servidor, utilice el atributo CODEBASE en la etiqueta OBJECT de su página web. El valor puede apuntar al propio archivo del servidor, a un archivo INF que enumera otros archivos necesarios para el servidor (por ejemplo, la DLL de Qt) o a un archivo CAB comprimido.

Los archivos INF y CAB están documentados en casi todos los libros disponibles sobre programación ActiveX y COM, así como en la biblioteca MSDN y otros recursos en línea. Los ejemplos incluyen archivos INF que pueden utilizarse para crear archivos CAB:

[version]
    signature="$CHICAGO$"
    AdvancedINF=2.0
 [Add.Code]
    simpleax.exe=simpleax.exe
 [simpleax.exe]
    file-win32-x86=thiscab
    clsid={DF16845C-92CD-4AAB-A982-EB9840E74669}
    RegisterServer=yes

La herramienta CABARC de Microsoft puede generar fácilmente archivos CAB:

cabarc N simpleax.cab simpleax.exe simple.inf

Los archivos INF suponen una compilación estática de Qt, por lo que no aparecen dependencias de otras DLL en los archivos INF. Para distribuir un servidor ActiveX que dependa de DLLs debe añadir las dependencias, y proporcionar los ficheros de librería con el archivo.

Uso de los controles

Para utilizar los controles ActiveX, por ejemplo para incrustarlos en una página web, utilice la etiqueta HTML <object>.

<object ID="MyActiveX1" CLASSID="CLSID:ad90301a-849e-4e8b-9a91-0a6dc5f6461f">
   ...
<\object>

Para inicializar las propiedades del control, utilice

<object ID=...>
    <param name="name" value="value">
<\object>

Si el navegador web admite scripts, utilice JavaScript, VBScript y forms para programar el control. Los Ejemplos de ActiveQt incluyen páginas HTML de demostración para los controles de ejemplo.

Clientes ActiveX compatibles y no compatibles

La siguiente información se basa en gran medida en nuestras propias experiencias con controles ActiveX y aplicaciones cliente, y no es en absoluto exhaustiva.

Clientes compatibles

Estas aplicaciones estándar funcionan con controles ActiveX desarrollados con ActiveQt. Tenga en cuenta que algunos clientes sólo admiten controles en proceso.

  • Internet Explorer
  • Contenedor de prueba de controles ActiveX de Microsoft
  • Microsoft Visual Studio 6.0
  • Microsoft Visual Studio.NET/2003
  • Microsoft Visual Basic 6.0
  • Contenedores basados en MFC y ATL
  • Sybase PowerBuilder
  • Contenedores basados en ActiveQt

Las aplicaciones de Microsoft Office son compatibles, pero es necesario registrar los controles como objetos "Insertable". Reimplemente QAxFactory::registerClass para añadir este atributo a la clase COM, o establezca la información de clase "Insertable" para su clase en "sí" utilizando la macro Q_CLASSINFO.

Clientes no compatibles

No hemos conseguido que los objetos COM basados en ActiveQt funcionen con las siguientes aplicaciones cliente.

  • Borland C++ Builder (Versiones 5 y 6)
  • Borland Delphi

Errores típicos en tiempo de ejecución

El servidor no responde

Si el sistema no puede iniciar el servidor (compruebe con el administrador de tareas si el servidor ejecuta un proceso), asegúrese de que no falta en la ruta del sistema ninguna DLL de la que dependa el servidor (por ejemplo, la DLL de Qt). Utiliza un navegador de dependencias para ver todas las dependencias del binario del servidor.

Si el servidor se ejecuta (por ejemplo, el administrador de tareas muestra un proceso), consulte la siguiente sección para obtener información sobre la depuración del servidor.

No se puede crear el objeto

Si el servidor puede ser construido y registrado correctamente durante el proceso de construcción, pero el objeto no puede ser iniciado, por ejemplo, por la aplicación Visor de Objetos OLE/COM, asegúrese de que no falta ninguna DLL de la que dependa el servidor en la ruta del sistema (por ejemplo, la DLL de Qt). Utiliza un navegador de dependencias para ver todas las dependencias del binario del servidor.

Si el servidor se ejecuta, consulta la siguiente sección para obtener información sobre cómo depurar tu servidor.

Fallos al descargar y recargar servidores COM

Si los servidores ActiveQt COM utilizan módulos Qt más allá de los que se encuentran en Qt Base, es necesario activar el servidor COM como un servidor COM fuera de proceso. Si se intenta activar un servidor COM en proceso que incluye módulos como Qt Quick, puede producirse un bloqueo después de descargar el servidor COM.

Bloqueo o comportamiento inesperado durante llamadas COM salientes

Ten en cuenta que un servidor COM fuera de proceso estará procesando su cola de mensajes mientras realiza una llamada saliente al cliente. Esto puede provocar un comportamiento inesperado o un bloqueo si el cliente está llamando al servidor al mismo tiempo. En esta situación, la llamada entrante se ejecutará en el servidor antes de que vuelva la llamada saliente. En particular, si el cliente cierra un control ActiveX mientras el control está volviendo a llamar al cliente, esto puede provocar un bloqueo. Estos problemas de reentrada pueden mitigarse utilizando filtros de mensajes (IMessageFilter y CoRegisterMessageFilter).

Depuración de errores en tiempo de ejecución

Para depurar un servidor en proceso en Visual Studio, establezca el proyecto del servidor como proyecto activo y especifique un cliente "ejecutable para la sesión de depuración" en la configuración del proyecto (por ejemplo, utilice el contenedor de pruebas ActiveX). Puedes establecer puntos de interrupción en tu código, y también entrar en el código de ActiveQt y Qt si has instalado la versión de depuración.

Para depurar un servidor ejecutable, ejecute la aplicación en un depurador e inicie con el parámetro de línea de comandos -activex. A continuación, inicie su cliente y cree una instancia de su control ActiveX. COM utilizará el proceso existente para el siguiente cliente que intente crear un control ActiveX.

Información y ajuste de clases

Para proporcionar atributos para cada clase COM, utilice la macro Q_CLASSINFO, que forma parte del meta sistema de objetos de Qt.

ClaveSignificado del valor
VersiónLa versión de la clase (1.0 por defecto)
DescripciónCadena que describe la clase.
ClassIDEl ID de la clase. Debe reimplementar QAxFactory::classID si no se especifica.
InterfaceIDEl ID de la interfaz. Debe reimplementar QAxFactory::interfaceID si no se especifica.
ID de eventoEl ID de la interfaz de eventos. No se exponen señales como eventos COM si no se especifica.
DefaultPropertyLa propiedad especificada representa la propiedad por defecto de esta clase. Por ejemplo, la propiedad por defecto de un botón pulsador sería "text".
DefaultSignalLa señal especificada representa la señal por defecto de esta clase. Por ejemplo, la señal por defecto de un botón pulsador sería "clicked".
Clave de licenciaLa creación del objeto requiere la clave de licencia especificada. La clave puede estar vacía para requerir una máquina con licencia. Por defecto las clases no tienen licencia. Véase también la sección siguiente.
StockEventsLos objetos exponen eventos de stock si el valor es "yes". Véase QAxFactory::hasStockEvents()
ToSuperClassLos objetos exponen la funcionalidad de todas las superclases hasta e incluyendo el nombre de la clase en el valor. Véase QAxFactory::exposeToSuperClass()
InsertableSi el valor es "yes", la clase se registra como "Insertable" y aparecerá en los contenedores OLE 2 (por ejemplo, Microsoft Office). Este atributo no está configurado por defecto.
AgregableSi el valor es "no", la clase no admite agregación. Por defecto la agregación está soportada.
CreableSi el valor es "no" la clase no puede ser creada por el cliente, y sólo está disponible a través de la API de otra clase (es decir, la clase es un subtipo).
RegistrarObjetoSi el valor es "yes", los objetos de esta clase se registran con OLE y son accesibles desde la tabla de objetos en ejecución (es decir, los clientes pueden conectarse a una instancia ya en ejecución de esta clase). Este atributo sólo está soportado en servidores fuera de proceso.
MIMEEl objeto puede manejar datos y archivos del formato especificado en el valor. El valor tiene el formato mime:extensión:descripción. Los formatos múltiples se separan con punto y coma.
CoClassAliasEl nombre de clase utilizado en el IDL generado y en el registro. Esto es especialmente útil para clases C++ que viven en un espacio de nombres - por defecto, ActiveQt simplemente elimina el "::" para hacer que la IDL compile.
Categorías implementadasLista de UUID de identificadores de categoría (CATID) separados por comas. Mecanismo genérico para especificar capacidades adicionales del contenedor, además de "control", "insertable", etc. Los CATID típicos incluyen CATID_InternetAware ("{0DE86A58-2BAA-11CF-A229-00AA003D7352}"), CATID_SafeForScripting ("{7DD95801-9882-11CF-9FA9-00AA006C42C4}"), así como valores CATID definidos por el usuario.

Tenga en cuenta que tanto las claves como los valores distinguen entre mayúsculas y minúsculas.

A continuación se declara la versión 2.0 de una clase que sólo expone su propia API y que está disponible en el cuadro de diálogo "Insertar objetos" de las aplicaciones de Microsoft Office.

class MyActiveX : public QWidget
{
    Q_OBJECT
    Q_CLASSINFO("Version", "2.0")
    Q_CLASSINFO("ClassID", "{7a4cffd8-cbcd-4ae9-ae7e-343e1e5710df}")
    Q_CLASSINFO("InterfaceID", "{6fb035bf-8019-48d8-be51-ef05427d8994}")
    Q_CLASSINFO("EventsID", "{c42fffdf-6557-47c9-817a-2da2228bc29c}")
    Q_CLASSINFO("Insertable", "yes")
    Q_CLASSINFO("ToSuperClass", "MyActiveX")
    Q_PROPERTY(...)

public:
    MyActiveX(QWidget *parent = 0);

    ...
};

Desarrollo de componentes con licencia

Si desarrolla componentes, es posible que desee controlar quién puede instanciarlos. Dado que el binario del servidor puede enviarse y registrarse en cualquier máquina cliente, cualquiera puede utilizar esos componentes en su propio software.

El licenciamiento de los componentes puede realizarse mediante diversas técnicas, por ejemplo, el código que crea el control puede proporcionar una clave de licencia, o bien es necesario licenciar la máquina en la que se supone que se ejecutará el control.

Para marcar una clase Qt como licenciada especifique una "LicenseKey" usando la macro Q_CLASSINFO().

class MyLicensedControl : public QWidget
{
    Q_OBJECT
    Q_CLASSINFO("LicenseKey", "<key string>")
    ...
};

La clave es necesaria para poder crear una instancia de MyLicensedControl en una máquina que no tenga licencia propia. El desarrollador con licencia puede ahora redistribuir el binario del servidor con su aplicación, que crea el control utilizando el valor de "LicenseKey", mientras que los usuarios de la aplicación no pueden crear el control sin la clave de licencia.

Si una única clave de licencia para el control no es suficiente (es decir, si desea que diferentes desarrolladores reciban diferentes claves de licencia) puede especificar una clave vacía para indicar que el control requiere una licencia, y reimplementar QAxFactory::validateLicenseKey() para verificar que existe una licencia en el sistema (es decir, a través de un archivo de licencia).

Más interfaces

Los controles ActiveX proporcionados por los servidores ActiveQt soportan un conjunto mínimo de interfaces COM para implementar las especificaciones OLE. Cuando la clase ActiveX hereda de la clase QAxBindable también puede implementar interfaces COM adicionales.

Cree una nueva subclase de QAxAggregated y utilice la herencia múltiple para subclasificar clases de interfaz COM adicionales.

class AxImpl : public QAxAggregated, public ISomeCOMInterface
{
public:
    AxImpl() {}

    long queryInterface(const QUuid &iid, void **iface);

    // IUnknown
    QAXAGG_IUNKNOWN

    // ISomeCOMInterface
    ...
}

Reimplemente la función QAxAggregated::queryInterface() para soportar las interfaces COM adicionales.

long AxImpl::queryInterface(const QUuid &iid, void **iface)
{
    *iface = 0;
    if (iid == IID_ISomeCOMInterface)
        *iface = (ISomeCOMInterface *)this;
    else
        return E_NOINTERFACE;

    AddRef();
    return S_OK;
}

Dado que ISomeCOMInterface es una subclase de IUnknown tendrás que implementar las funciones QueryInterface(), AddRef(), y Release(). Para ello, utiliza la macro QAXAGG_IUNKNOWN en la definición de tu clase. Si implementa las funciones IUnknown manualmente, delegue las llamadas al puntero de interfaz devuelto por la función QAxAggregated::controllingUnknown(), por ejemplo

HRESULT AxImpl::QueryInterface(REFIID iid, void **iface)
{
    return controllingUnknown()->QueryInterface(iid, iface);
}

No admita la interfaz IUnknown en su implementación de queryInterface().

Implemente los métodos de las interfaces COM y utilice QAxAggregated::object() si necesita realizar llamadas a la subclase QObject que implementa el control.

En su subclase QAxBindable, implemente QAxBindable::createAggregate() para devolver un nuevo objeto de la subclase QAxAggregated.

class MyActiveX : public QWidget, public QAxBindable
{
    Q_OBJECT

public:
    MyActiveX(QWidget *parent);

    QAxAggregated *createAggregate()
    {
        return new AxImpl();
    }
};

Véase también ActiveQt Framework.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.