FABRICACIÓN DE CONTROLES ACTIVEX

 

Los controles ActiveX, pueden ser implementados por cualquier lenguaje que los soporte, como Visual C++, Visual Basic, Visual J++, etc. Los controles utilizados en el proyecto han sido implementados con Visual C++.

 

Para implementar un control ActiveX, el proyecto en Visual C++ consta de tres archivos de código fuente: *App, *PropPag y *Ctrl. El módulo *App permite realizar tareas de mantenimiento elementales, como inicialización del control y reposición de variables. *PropPage, por su parte, suministra una plantilla o modo de cuadro de diálogo que permite a los usuarios del control ActiveX, personalizar sus opciones. El último módulo, *Ctrl, contiene lo sustancial del control ActiveX: código para diseñar el control, mensajes de envío y recepción en Windows, y otros elementos.

 

El módulo Ctrl, es una clase derivada de ColeControl. Esta clase MFC encapsula la función de un control ActiveX y sirve de protección ante las interfaces de distribución OLE.

 

En el módulo Ctrl, se implementan las propiedades y los métodos, que una vez compilado el control, pueden ser accesibles desde cualquier contenedor que use el control.

 

Propiedades de un control ActiveX

 

Además de los tipos básicos, las propiedades pueden utilizar datos especiales, como fechas, monedas y colores. ActiveX se encarga de definir estos tipos, que no pueden ser creados por el usuario.

 

Existen tres grandes categorias de propiedades:

 

 

Normalmente, los controles ActiveX permiten un acceso completo a sus propiedades. Los contenedores pueden leer directamente estas propiedades y modificar cualquiera de sus valores; sin embargo, los controles no pueden intervenir sobre ellas.

 

Pero sí están autorizados a crear funciones de notificación especiales que se invocan siempre que cambia un valor de propiedad. Por ejemplo puede asociarse una función de notificación a la propiedad fecha de un calendario. Esta función tendría por defecto volver a presentar el calendario cuando cambiara la fecha.

 

Aunque las funciones de notificación pueden recibir cualquier nombre, deberían rotularse con arreglo a una etiqueta ActiveX. La convención de nombres obliga a escribir el nombre de la propiedad entre las palabras "On" y "Changed".

 

Aún con la posibilidad de incluir funciones de notificación, las propiedades siguen mostrándose completamente indefensas. El control y su contenedor tienen completa libertad para manipularlas. La arquitectura ActiveX ofrece una solución: proteger la propiedad con métodos Get/Set. El método Get muestra el valor actual de la propiedad, y el método Set lo cambia por otro nuevo. Esta técnica es útil particularmente cuando ha de calcularse una propiedad antes de leerla, o si se precisa validarla antes de escribirla.

 

 

Funciones de intercambio de propiedades

 

Después de añadir una propiedad con el asistente de clases, se debe inicializar manualmente. No se deberá fijar su valor dentro del constructor de clases, como se haría en programas C++ normales. En vez de ello, se inicializará la propiedad en DoPopExchange(), una función miembro de ColeControl que el asistente de controles OLE añade automaticamente.

 

DoPropExchange() tiene un doble propósito. En primer lugar, asigna a cada propiedad un valor por defecto sea cual sea la ocurrencia del control que se esté creando. Además, permite que el contenedor serialice las propiedades. Esta propiedad permite restaurar el estado de un control incluso después de que se haya interrumpido por avería le funcionamiento del sistema.

 

 

Métodos

 

Los métodos de los controles ActiveX son similares a las funciones de miembros C++. Leen parámetros y les asignan un valor. Dado que los métodos obedecen a un estándar binario, cualquier programa compatible con ActiveX puede invocarlos sin necesidad de un código fuente específico.

 

Sucesos

 

Aplicar métodos es una solución sencilla para que un contenedor se comunique con un control ActiveX. Pero, además, esta conversación también puede establecerse en sentido contrario. Al enviar un suceso, el control transmitirá información "de retorno" al contenedor. Los sucesos pueden informar al contenedor de cualquier contingencia producida: la pulsación de una tecla, la terminación de un proceso largo, un mensaje de sincronización, etc. Si fuera necesario, los sucesos pueden manejar información suplementaria en forma de parámetros. Los parámetros de los sucesos son, en gran medida, comparables a los de los métodos; pueden ser números enteros, cadenas de caracteres o cualquier otro tipo de datos ActiveX estándar.

 

 

Implementación de los controles del proyecto. EASYGA.OCX Y CONTROLGA.OCX

 

Los dos controles implementados, EasyGA.ocx y ControlGA.ocx, ejecutan un algoritmo genético usando las librerias de algoritmos genéticos EO, implementa-das por el tutor del proyecto Juan Julián Merelo Guervós.

 

  La implementación del control se ha hecho en Visual C++, por dos motivos básicos, en primer lugar, por que las librerías de algoritmos genéticos con las que hemos trabajado, se encuentran implementadas en C++, y por tanto su integración es inmediata, y en segundo lugar, por que Visual C++ es la herramienta más desarrollada para la implementación de controles ActiveX.

 

El control genera aleatoriamente una población de cromosomas, en un rango fijado por el usuario del control. El control usa un algorimo genético implementado en las librerías EO, para maximizar una función de evaluación, en este caso la sumatoria de todos los genes del cromosoma.

 

Con el objeto de que el usuario del control sea quién determine los paráme-tros del algoritmo genético, se crean las propiedades Get/Set siguientes:

 

 

Se ha implementado el método GetFitness, que tiene como parámetros individuo y generación, y te devuelve el fitness que el algoritmo genético ha conseguido para ese individuo en esa generación.

 

El control ControlGA.ocx es similar al control EasyGA.ocx. Las diferencias estriban, en que con ControlGA se puede ejecutar dos funciones de evaluación distintas, la sumatoria y la suma potencia. Las propiedades de este control ActiveX son las siguientes

 

 

Como métodos tiene implementados los métodos:

 

 

Como ejemplo de implementación de uu control ActiveX en Visual C++, se muestran a continuación los ficheros ControlGACtl.h y ControlGACtl.cpp, que contienen el código esencial de un control ActiveX.

 

El fichero ControlGACtl.h tiene el siguiemte código:

 

#if !defined(AFX_CONTROLGACTL_H__0E12C874_2E36_11D3_B0EA_EE4C2C44F238__INCLUDED_)
#define AFX_CONTROLGACTL_H__0E12C874_2E36_11D3_B0EA_EE4C2C44F238__INCLUDED_

#if _MSC_VER = 1000
#pragma once
#endif // _MSC_VER = 1000

// ControlGACtl.h : Declaration of the CControlGACtrl ActiveX Control class.

/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl : See ControlGACtl.cpp for implementation.

class CControlGACtrl : public COleControl
{
	DECLARE_DYNCREATE(CControlGACtrl)

// Constructor
public:
	CControlGACtrl();

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CControlGACtrl)
	public:
	virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
	virtual void DoPropExchange(CPropExchange* pPX);
	virtual void OnResetState();
	//}}AFX_VIRTUAL

// Implementation
protected:
	~CControlGACtrl();

	DECLARE_OLECREATE_EX(CControlGACtrl)    // Class factory and guid
	DECLARE_OLETYPELIB(CControlGACtrl)      // GetTypeInfo
	DECLARE_PROPPAGEIDS(CControlGACtrl)     // Property page IDs
	DECLARE_OLECTLTYPE(CControlGACtrl)		// Type name and misc status

// Message maps
	//{{AFX_MSG(CControlGACtrl)
		// NOTE - ClassWizard will add and remove member functions here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()

// Dispatch maps
	//{{AFX_DISPATCH(CControlGACtrl)
	afx_msg short GetSize();
	afx_msg void SetSize(short nNewValue);
	afx_msg short GetPopSize();
	afx_msg void SetPopSize(short nNewValue);
	afx_msg short GetRange();
	afx_msg void SetRange(short nNewValue);
	afx_msg short GetGenerations();
	afx_msg void SetGenerations(short nNewValue);
	afx_msg void sumatoria();
	afx_msg void sumaPotencia();
	afx_msg float GetFitness(short generacion, short individuo);
	//}}AFX_DISPATCH
	DECLARE_DISPATCH_MAP()

	afx_msg void AboutBox();

// Event maps
	//{{AFX_EVENT(CControlGACtrl)
	//}}AFX_EVENT
	DECLARE_EVENT_MAP()

// Dispatch and event IDs
public:
	short popsize;
	short size;
	short generations;
	short range;
	enum {
	//{{AFX_DISP_ID(CControlGACtrl)
	dispidSize = 1L,
	dispidPopSzie = 2L,
	dispidRange = 3L,
	dispidGenerations = 4L,
	dispidFitness = 7L,
	dispidSumatoria = 5L,
	dispidSumaPotencia = 6L,
	//}}AFX_DISP_ID
	};
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CONTROLGACTL_H__0E12C874_2E36_11D3_B0EA_EE4C2C44F238__INCLUDED)



El código del fichero ControlGACtl.cpp es el siguiente:

// ControlGACtl.cpp : Implementation of the CControlGACtrl ActiveX Control class.

#include "stdafx.h"
#include "ControlGA.h"
#include "ControlGACtl.h"
#include "ControlGAPpg.h"

#include 
#include 				
#include 				
#include 
#include  
#include 

using namespace std;

#include <stdlib.h
#include <stdio.h
#include <time.h

#include <generic/EOVector.h
#include <generic/EOGOps.h
#include <generic/EOEvalAll.h
#include <generic/EOselect/EOSteadyState.h
#include <specific/EOSIntOps.h 
#include <generic/EOGenTerm.h
#include <generic/EOselect/EOReplacers.h
#include <generic/EOEasyGA.h
#include <ADT/EOAlgo.h
#include <ADT/EOFitness.h      
#include <ADT/EOSelector.h    
#include <ADT/EOTerm.h		
#include <ADT/EOEvalFunc.h
#include "evaluacion.h"


 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

float fitness_inicial[200];
float fitness_final[200];


IMPLEMENT_DYNCREATE(CControlGACtrl, COleControl)


/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CControlGACtrl, COleControl)
	//{{AFX_MSG_MAP(CControlGACtrl)
	// NOTE - ClassWizard will add and remove message map entries
	//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG_MAP
	ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit)
	ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// Dispatch map

BEGIN_DISPATCH_MAP(CControlGACtrl, COleControl)
	//{{AFX_DISPATCH_MAP(CControlGACtrl)
	DISP_PROPERTY_EX(CControlGACtrl, "size", GetSize, SetSize, VT_I2)
	DISP_PROPERTY_EX(CControlGACtrl, "popSzie", GetPopSize, SetPopSize, VT_I2)
	DISP_PROPERTY_EX(CControlGACtrl, "range", GetRange, SetRange, VT_I2)
	DISP_PROPERTY_EX(CControlGACtrl, "generations", GetGenerations, SetGenerations, VT_I2)
	DISP_FUNCTION(CControlGACtrl, "sumatoria", sumatoria, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CControlGACtrl, "sumaPotencia", sumaPotencia, VT_EMPTY, VTS_NONE)
	DISP_PROPERTY_PARAM(CControlGACtrl, "fitness", GetFitness, SetNotSupported, VT_R4, VTS_I2 VTS_I2)
	//}}AFX_DISPATCH_MAP
	DISP_FUNCTION_ID(CControlGACtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()


/////////////////////////////////////////////////////////////////////////////
// Event map

BEGIN_EVENT_MAP(CControlGACtrl, COleControl)
	//{{AFX_EVENT_MAP(CControlGACtrl)
	// NOTE - ClassWizard will add and remove event map entries
	//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_EVENT_MAP
END_EVENT_MAP()


/////////////////////////////////////////////////////////////////////////////
// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CControlGACtrl, 1)
	PROPPAGEID(CControlGAPropPage::guid)
END_PROPPAGEIDS(CControlGACtrl)


/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CControlGACtrl, "CONTROLGA.ControlGACtrl.1",
	0xe12c866, 0x2e36, 0x11d3, 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38)


/////////////////////////////////////////////////////////////////////////////
// Type library ID and version

IMPLEMENT_OLETYPELIB(CControlGACtrl, _tlid, _wVerMajor, _wVerMinor)


/////////////////////////////////////////////////////////////////////////////
// Interface IDs

const IID BASED_CODE IID_DControlGA =
		{ 0xe12c864, 0x2e36, 0x11d3, { 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38 } };
const IID BASED_CODE IID_DControlGAEvents =
		{ 0xe12c865, 0x2e36, 0x11d3, { 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38 } };


/////////////////////////////////////////////////////////////////////////////
// Control type information

static const DWORD BASED_CODE _dwControlGAOleMisc =
	OLEMISC_INVISIBLEATRUNTIME |
	OLEMISC_ACTIVATEWHENVISIBLE |
	OLEMISC_SETCLIENTSITEFIRST |
	OLEMISC_INSIDEOUT |
	OLEMISC_CANTLINKINSIDE |
	OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CControlGACtrl, IDS_CONTROLGA, _dwControlGAOleMisc)


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::CControlGACtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CControlGACtrl

BOOL CControlGACtrl::CControlGACtrlFactory::UpdateRegistry(BOOL bRegister)
{
	// TODO: Verify that your control follows apartment-model threading rules.
	// Refer to MFC TechNote 64 for more information.
	// If your control does not conform to the apartment-model rules, then
	// you must modify the code below, changing the 6th parameter from
	// afxRegInsertable | afxRegApartmentThreading to afxRegInsertable.

	if (bRegister)
		return AfxOleRegisterControlClass(
			AfxGetInstanceHandle(),
			m_clsid,
			m_lpszProgID,
			IDS_CONTROLGA,
			IDB_CONTROLGA,
			afxRegInsertable | afxRegApartmentThreading,
			_dwControlGAOleMisc,
			_tlid,
			_wVerMajor,
			_wVerMinor);
	else
		return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::CControlGACtrl - Constructor

CControlGACtrl::CControlGACtrl()
{
	InitializeIIDs(&IID_DControlGA, &IID_DControlGAEvents);

	// TODO: Initialize your control's instance data here.
}


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::~CControlGACtrl - Destructor

CControlGACtrl::~CControlGACtrl()
{
	// TODO: Cleanup your control's instance data here.
}


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::OnDraw - Drawing function

void CControlGACtrl::OnDraw(
			CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
	// TODO: Replace the following code with your own drawing code.
	pdc-FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
	pdc-Ellipse(rcBounds);
}


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::DoPropExchange - Persistence support

void CControlGACtrl::DoPropExchange(CPropExchange* pPX)
{
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);

	// TODO: Call PX_ functions for each persistent custom property.

}


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::OnResetState - Reset control to default state

void CControlGACtrl::OnResetState()
{
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange
	SetGenerations(10);
	SetPopSize(100);
	SetRange(100);
	SetSize(10);
}


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::AboutBox - Display an "About" box to the user

void CControlGACtrl::AboutBox()
{
	CDialog dlgAbout(IDD_ABOUTBOX_CONTROLGA);
	dlgAbout.DoModal();
}


/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl message handlers

short CControlGACtrl::GetSize() 
{
	return size;
}

void CControlGACtrl::SetSize(short nNewValue) 
{
	size = nNewValue;
	SetModifiedFlag();
}



short CControlGACtrl::GetPopSize() 
{
	return popsize;
}

void CControlGACtrl::SetPopSize(short nNewValue) 
{
	popsize = nNewValue;
	SetModifiedFlag();
}

short CControlGACtrl::GetRange() 
{
	return range;
}

void CControlGACtrl::SetRange(short nNewValue) 
{
	range = nNewValue;
	SetModifiedFlag();
}

short CControlGACtrl::GetGenerations() 
{
	return generations;
}

void CControlGACtrl::SetGenerations(short nNewValue) 
{
	generations = nNewValue;
	SetModifiedFlag();
}

float CControlGACtrl::GetFitness(short generacion, short individuo) 
{
	if (generacion == 1) 
	{
		return fitness_inicial[individuo-1];
	}
	else
		return fitness_final[individuo-1];
}

void CControlGACtrl::sumatoria() 
{
	unsigned size = GetSize();
	unsigned popSize = GetPopSize(); 
	unsigned range = GetRange();
	unsigned numGenerations = GetGenerations();

	unsigned i, j;
	
	srand( (unsigned)time( NULL ) );

	typedef EOVector<int,int eoInt;
	typedef eoInt* ptEoInt;

	EOPop initPop;
	for ( j = 0; j < popSize; j ++ ) 
	{
		ptEoInt EOIA = new eoInt;
		
		for ( i = 0; i < size; i ++ ) 
		{
			EOIA-push_back( rand() % range - range/2 );
		}

		initPop.push_back( *EOIA );	  
		delete EOIA;
	}

	Sumatoria thisEvalFunc;
	EvalAll thisEval( thisEvalFunc );

	// Go ahead to next generation
	float select = (float)0.3;
	EOSteadyState coach( select );

	// Eliminate the worst
	unsigned subPop = (unsigned) floor( select*popSize );
	EOElimWorst popKiller( subPop );

	// And now breed
	EORank chaperon( subPop );

	//Add operators
	EOXOver2 xOver( 1 ); 
	chaperon.addOp( &xOver );

	//More operators
	EODup dupper( 1 );
	chaperon.addOp( &dupper );

	//More operators
	EOKill killer( 1 );
	chaperon.addOp( &killer );

	EOIntArrayMutate mutator( 1 );
	chaperon.addOp( &mutator);
	EOGenTerm ngenerations( numGenerations );
	EOEasyGA 
		thisAlgorithm( thisEval, coach, chaperon, ngenerations, popKiller, true);

	thisEval( initPop );

	for (i=0;i<popSize;i++)
		fitness_inicial[i] = initPop[i].fitness();

	thisAlgorithm( initPop );
	
	for (i=0;i<popSize;i++)
		fitness_final[i] = initPop[i].fitness();

}

void CControlGACtrl::sumaPotencia() 
{
	unsigned size = GetSize();
	unsigned popSize = GetPopSize(); 
	unsigned range = GetRange();
	unsigned numGenerations = GetGenerations();

	unsigned i, j;
	
	// start the algorithm
	srand( (unsigned)time( NULL ) );
	
	// useful typedefs
	typedef EOVector<int,int eoInt;
	typedef eoInt* ptEoInt;

	EOPop initPop;
	for ( j = 0; j < popSize; j ++ ) 
	{
		ptEoInt EOIA = new eoInt;
		for ( i = 0; i < size; i ++ ) 
		{
			EOIA-push_back( rand() % range - range/2 );
		}

		initPop.push_back( *EOIA );	  
		delete EOIA;
		}

	SumaPotencia thisEvalFunc;
	EvalAll thisEval( thisEvalFunc );
	
	// Go ahead to next generation
	float select = (float)0.3;
	EOSteadyState coach( select );

	// Eliminate the worst
	unsigned subPop = (unsigned) floor( select*popSize );
	EOElimWorst popKiller( subPop );

	// And now breed
	EORank chaperon( subPop );

	//Add operators
	EOXOver2 xOver( 1 ); 
	chaperon.addOp( &xOver );

	//More operators
	EODup dupper( 1 );
	chaperon.addOp( &dupper );

	//More operators
	EOKill killer( 1 );
	chaperon.addOp( &killer );

	//Add mutation
	EOIntArrayMutate mutator( 1 );
	chaperon.addOp( &mutator);

	//Termination condition
	EOGenTerm ngenerations( numGenerations );
	
	//And now the population itself
	EOEasyGA 
		thisAlgorithm( thisEval, coach, chaperon, ngenerations, popKiller, true);


	// Evaluate the initial population
	thisEval( initPop );

	for (i=0;i<popSize;i++)
	{
		fitness_inicial[i] = initPop[i].fitness();
	}
	// Apply the genetic algorithm, and generate evolvedPop
	thisAlgorithm( initPop );
	
	for (i=0;i<popSize;i++)
	{
		fitness_final[i] = initPop[i].fitness();
	}

}