Red de conocimiento informático - Problemas con los teléfonos móviles - Cómo escribir componentes com en VC8

Cómo escribir componentes com en VC8

1. Debe estar registrado correctamente bajo el valor de clave HKEY_CLASSES_ROOT\CLSID en el registro.

2. Se debe generar la función DllGetClassObject().

Este es el requisito mínimo para que se ejecute un servidor en proceso. Se debe crear una clave en la clave HKEY_CLASSES_ROOT\CLSID en el registro, utilizando el GUID del servidor como nombre de clave. Esta clave debe contener dos listas de claves, una es la ubicación del servidor y la otra es el modelo de subproceso del servidor. La biblioteca COM llama a la función DllGetClassObject() en la API CoCreateInstance().

Hay otras tres funciones que normalmente se generan:

o DllCanUnloadNow(): Llamada por la biblioteca COM para comprobar si el servidor se ha descargado de la memoria.

o DllRegisterServer(): Lo llama una utilidad de instalación como RegSvr32 para registrar el servidor.

o DllUnregisterServer(): Lo llama la utilidad de desinstalación para eliminar la entrada de registro creada por DllRegisterServer().

Además, no basta con exportar la función correcta: también debe seguir la especificación COM para que las bibliotecas COM y los programas cliente puedan utilizar el servidor.

Vida del servidor y su gestión

Un aspecto distintivo de los servidores DLL es el control sobre cuándo se cargan. Las DLL "estándar" son pasivas y se cargan/descargan aleatoriamente a medida que las aplicaciones las utilizan. Técnicamente hablando, los servidores DLL también son pasivos, ya que después de todo siguen siendo DLL, pero la biblioteca COM proporciona un mecanismo que permite a un servidor ordenarle a COM que lo descargue. Esto se logra mediante la función de salida DllCanUnloadNow(). El prototipo de esta función es el siguiente:

HRESULT DllCanUnloadNow();

Cuando una aplicación cliente llama a la API COM CoFreeUnusedLibraries(), generalmente durante su procesamiento inactivo, la biblioteca COM atraviesa el cliente La aplicación cliente ha cargado todos los servidores DLL y consulta cada uno de ellos llamando a su función DllCanUnloadNow(). Por otro lado, si un servidor determina que ya no necesita residir en la memoria, puede devolver S_OK y dejar que COM lo descargue.

El servidor utiliza un recuento de referencias simple para determinar si se puede descargar. La siguiente es la implementación de DllCanUnloadNow():

extern UINT g_uDllRefCount; // Recuento de referencias del servidor

HRESULT DllCanUnloadNow()

{

return (g_uDllRefCount gt; 0) ? S_FALSE: S_OK;

}

Cómo manejar el recuento de referencias se analizará en la siguiente sección cuando se trate de código específico.

Implementación de interfaces, a partir de IUnknown

Es necesario recuperar todas las interfaces derivadas de IUnknown. Porque IUnknown contiene dos características básicas de los objetos COM: recuento de referencias y consulta de interfaz. Cuando escribe una clase de objeto componente (coclase), también necesita escribir una implementación IUnknown que satisfaga sus necesidades. Tome una clase de objeto componente que implemente la interfaz IUnknown como ejemplo; el siguiente ejemplo puede ser la clase de objeto componente más simple que jamás haya escrito. Implementaremos IUnknown en una clase C llamada CUnknownImpl.

La siguiente es la declaración de esta clase:

class CUnknownImpl: public IUnknown

{

public:

// Constructor y destructor Dispositivo

CUnknownImpl();

virtual ~CUnknownImpl();

// Método IUnknown

ULONG AddRef();

p>

Lanzamiento ULONG)();

HRESULT QueryInterface( REFIID riid, void** ppv);

protegido:

UINT m_uRefCount; / /Recuento de referencias del objeto

};

Constructores y destructores

Los constructores y destructores gestionan el recuento de referencias del servidor:

CUnknownImpl::CUnknownImpl()

{

m_uRefCount = 0;

g_uDllRefCount

}

CUnknownImpl::~CUnknownImpl()

{

g_uDllRefCount--;

}

Al crear un nuevo objeto COM, el constructor se llama, lo que incrementa el recuento de referencias del servidor para mantener el servidor residente en la memoria. También inicializa el recuento de referencias del objeto a cero. Cuando se destruye este objeto COM, disminuye el recuento de referencias del servidor.

AddRef() y Release()

Estos dos métodos controlan el ciclo de vida de los objetos COM. AddRef() es simple:

ULONG CUnknownImpl::AddRef()

{

return m_uRefCount;

}

AddRef() simplemente incrementa el recuento de referencias del objeto y devuelve el recuento actualizado.

Release() es más simple:

ULONG CUnknownImpl::Release()

{

ULONG uRet = --m_uRefCount;

if ( 0 == m_uRefCount ) // ¿Se publicó la última referencia?

eliminar esto;

devolver uRet;

}

Además de disminuir el recuento de referencias del objeto, Release() destruirá el objeto si no hay otras referencias explícitas. Release() también devuelve el recuento de referencias actualizado. Tenga en cuenta que la implementación de Release() supone que el objeto COM se crea en el montón. Si crea un objeto con pegamento global, surgirán problemas cuando el objeto intente eliminarse a sí mismo.

¡Ahora deberías entender por qué es tan importante llamar correctamente a AddRef() y Release() en las aplicaciones cliente! Si no hace esto correctamente, los objetos que utilice se destruirán muy rápidamente, lo que rápidamente desbordará la memoria en todo el servidor y provocará que la aplicación falle la próxima vez que acceda al código del servidor.

Si escribe una aplicación de subprocesos múltiples, es posible que desee utilizar amp para reemplazar los problemas de seguridad de subprocesos de InterlockedIncrement() e InterlockedDecrement().

- Es seguro de usar con servidores de un solo subproceso, porque incluso si la aplicación cliente tiene múltiples subprocesos y realiza llamadas a métodos desde diferentes subprocesos, la biblioteca COM realizará llamadas a métodos del servidor en secuencia. Es decir, una vez que se inicia una llamada a un método, todos los demás subprocesos que intenten llamar al método se bloquearán hasta que regrese el primer método. La propia biblioteca COM garantiza que más de un subproceso a la vez no pueda acceder al servidor.

QueryInterface()

QueryInterface() se conoce como QI(). El programa cliente llama a esta función para solicitar diferentes interfaces del objeto COM. Dado que solo implementamos una interfaz en el código de ejemplo, QI() será fácil de usar. QI() tiene dos parámetros: uno es el IID de la interfaz solicitada y el otro es el tamaño del búfer del puntero. Si la consulta tiene éxito, QI() almacena la dirección del puntero de la interfaz en este puntero del búfer.

HRESULT CUnknownImpl::QueryInterface (REFIID riid, void** ppv)

{

HRESULT hrRet = S_OK;