Integración de los controles EasyGA Y ControlGA en aplicaciones implementadas en Visual C++


Aplicación EasyGAVC.exe


EasyGAVC es una aplicación implementada en Visual C++, que hace uso del control ActiveX EasyGA.ocx. La aplicación recibe los párametros que necesita el control para funcionar, y tras la ejecución de éste, devuelve los resultados del fitness.

 

Integración del control


Para integrar un control en una aplicación Visual C++, en primer lugar el control en concreto debe estar registrado en el sistema. Cualquier control registrado, puede ser usado por aplicaciones Visual C++.

Con el ClassWizard se hace una integración del control automática. Se incluye una nueva clase el proyecto, que es la clase que contiene el control. En esta clase, se encuentran todas las propiedades y métodos que permiten interaccionar con el control. En el proyecto se crea una nueva clase, llamada CEasyga, que incluye las propiedades y métodos del control. Para permitirlo, en el proyecto se van a incluir dos fichero más, que son easyga.h y easyga.cpp, donde se encuentra implementado el control.

La clase que representa al control dentro del proyecto en Visual C++, se encuentra declarada en el fichero easyga.h, de la siguiente forma:

class CEasyga : public CWnd
{
protected:
	DECLARE_DYNCREATE(CEasyga)
public:
	CLSID const& GetClsid()
	{
		static CLSID const clsid
			= { 0x83db1c69, 0xfc94, 0x11d2, { 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38 } };
		return clsid;
	}
	virtual BOOL Create(LPCTSTR lpszClassName,
		LPCTSTR lpszWindowName, DWORD dwStyle,
		const RECT& rect,
		CWnd* pParentWnd, UINT nID,
		CCreateContext* pContext = NULL)
	{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); }

    BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
		const RECT& rect, CWnd* pParentWnd, UINT nID,
		CFile* pPersist = NULL, BOOL bStorage = FALSE,
		BSTR bstrLicKey = NULL)
	{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID,
		pPersist, bStorage, bstrLicKey); }

// Attributes
public:
	short GetSize();
	void SetSize(short);
	short GetPopsize();
	void SetPopsize(short);
	short GetRange();
	void SetRange(short);
	short GetGenerations();
	void SetGenerations(short);
	BOOL GetCalculo();
	void SetCalculo(BOOL);

// Operations
public:
	float GetFitness(short generacion, short individuo);
	void AboutBox();
};

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

#endif // !defined(AFX_EASYGA_H__3629B1EF_06F6_11D3_B0EA_EE4C2C44F238__INCLUDED_)


Como se puede apreciar, aparecen todos las propiedades y métodos del control, los cuales podemos utilizar en nuestra aplicación. Sin embargo, con los controles ActiveX no se reutiliza código fuente, lo que se hace es una reutilización "en binario". Podemos invocar métodos, podemos modificar el valor de una propiedad, pero no podemos acceder al código fuente del control. El código fuente del control permanece encapsulado y no podemos acceder a él. El fichero de código del control, easyga.cpp contiene la implementación de las propiedades y métodos del control.

// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

// NOTE: Do not modify the contents of this file.  If this class is regenerated by
//  Microsoft Visual C++, your modifications will be overwritten.


#include "stdafx.h"
#include "easyga.h"

/////////////////////////////////////////////////////////////////////////////
// CEasyga

IMPLEMENT_DYNCREATE(CEasyga, CWnd)

/////////////////////////////////////////////////////////////////////////////
// CEasyga properties

short CEasyga::GetSize()
{
	short result;
	GetProperty(0x1, VT_I2, (void*)&result);
	return result;
}

void CEasyga::SetSize(short propVal)
{
	SetProperty(0x1, VT_I2, propVal);
}

short CEasyga::GetPopsize()
{
	short result;
	GetProperty(0x2, VT_I2, (void*)&result);
	return result;
}

void CEasyga::SetPopsize(short propVal)
{
	SetProperty(0x2, VT_I2, propVal);
}

short CEasyga::GetRange()
{
	short result;
	GetProperty(0x3, VT_I2, (void*)&result);
	return result;
}

void CEasyga::SetRange(short propVal)
{
	SetProperty(0x3, VT_I2, propVal);
}

short CEasyga::GetGenerations()
{
	short result;
	GetProperty(0x4, VT_I2, (void*)&result);
	return result;
}

void CEasyga::SetGenerations(short propVal)
{
	SetProperty(0x4, VT_I2, propVal);
}

BOOL CEasyga::GetCalculo()
{
	BOOL result;
	GetProperty(0x5, VT_BOOL, (void*)&result);
	return result;
}

void CEasyga::SetCalculo(BOOL propVal)
{
	SetProperty(0x5, VT_BOOL, propVal);
}

/////////////////////////////////////////////////////////////////////////////
// CEasyga operations

float CEasyga::GetFitness(short generacion, short individuo)
{
	float result;
	static BYTE parms[] =
		VTS_I2 VTS_I2;
	InvokeHelper(0x6, DISPATCH_PROPERTYGET, VT_R4, (void*)&result, parms,
		generacion, individuo);
	return result;
}

void CEasyga::AboutBox()
{
	InvokeHelper(0xfffffdd8, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}


Como se aprecia, el código fuente del control, que ha sido implementado en Visual C++, permanece encapsulado, no podemos acceder a él, y por tanto no podemos saber como ha sido implementado.

 

Una vez que tenemos esta nueva clase en el proyecto, definimos en el módulo CEasygaVCDlg, la variable m_easyga, de tipo CEasyGA. Con esta variable, tenemos una instancia del control ActiveX, y a través de ella accedemos a las propiedades y métodos del control. Para ello, el método que responde a la pulsación del botón Ejecutar Algoritmo Genético, OnEjecutaAG(), y método que te devuelve el fitness de un individuo en una generacion determinada OnButtonFitness(), tras la pulsación del botón Fitness>>, tienen el siguiente código.

void CEasygaVCDlg::OnEjecutarAg() 
{
	UpdateData(TRUE);
	m_easyga.SetSize(m_size);
	m_easyga.SetPopsize(m_popsize);
	m_easyga.SetRange(m_range);
	m_easyga.SetGenerations(m_generacion);
	m_easyga.SetCalculo(TRUE);
	UpdateData(FALSE);
}
 
void CEasygaVCDlg::OnButtonFitness() 
{
	UpdateData(TRUE);
	m_fitness = m_easyga.GetFitness(m_fitness_generacion,m_fitness_individuo);
	UpdateData(FALSE);
}
 

Como se aprecia, la integración de controles ActiveX en una aplicación VisualC++, es bastante simple utilizando el ClassWizard.

 


Aplicación ControlGAVC.exe

Esta aplicación es similar a la anterior, la diferencia estriba, en el hecho de que el algoritmo genético admite varias funciones de evaluación, y por tanto, el control tiene algún método más y la aplicación, por tanto varia un poco.

 

El control que utiliza es el control ControlGA.ocx. El código del fichero controlga.h es el siguiente:

 #if !defined(AFX_CONTROLGA_H__FFA10ECF_2FA9_11D3_B0EA_EE4C2C44F238__INCLUDED_)
#define AFX_CONTROLGA_H__FFA10ECF_2FA9_11D3_B0EA_EE4C2C44F238__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

// NOTE: Do not modify the contents of this file.  If this class is regenerated by
//  Microsoft Visual C++, your modifications will be overwritten.

/////////////////////////////////////////////////////////////////////////////
// CControlGA wrapper class

class CControlGA : public CWnd
{
protected:
	DECLARE_DYNCREATE(CControlGA)
public:
	CLSID const& GetClsid()
	{
		static CLSID const clsid
			= { 0xe12c866, 0x2e36, 0x11d3, { 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38 } };
		return clsid;
	}
	virtual BOOL Create(LPCTSTR lpszClassName,
		LPCTSTR lpszWindowName, DWORD dwStyle,
		const RECT& rect,
		CWnd* pParentWnd, UINT nID,
		CCreateContext* pContext = NULL)
	{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); }

    BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
		const RECT& rect, CWnd* pParentWnd, UINT nID,
		CFile* pPersist = NULL, BOOL bStorage = FALSE,
		BSTR bstrLicKey = NULL)
	{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID,
		pPersist, bStorage, bstrLicKey); }

// Attributes
public:
	short GetSize();
	void SetSize(short);
	short GetPopSzie();
	void SetPopSzie(short);
	short GetRange();
	void SetRange(short);
	short GetGenerations();
	void SetGenerations(short);

// Operations
public:
	float GetFitness(short generacion, short individuo);
	void sumatoria();
	void sumaPotencia();
	void AboutBox();
};

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

#endif // !defined(AFX_CONTROLGA_H__FFA10ECF_2FA9_11D3_B0EA_EE4C2C44F238__INCLUDED_)


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

// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

// NOTE: Do not modify the contents of this file.  If this class is regenerated by
//  Microsoft Visual C++, your modifications will be overwritten.


#include "stdafx.h"
#include "controlga.h"

/////////////////////////////////////////////////////////////////////////////
// CControlGA

IMPLEMENT_DYNCREATE(CControlGA, CWnd)

/////////////////////////////////////////////////////////////////////////////
// CControlGA properties

short CControlGA::GetSize()
{
	short result;
	GetProperty(0x1, VT_I2, (void*)&result);
	return result;
}

void CControlGA::SetSize(short propVal)
{
	SetProperty(0x1, VT_I2, propVal);
}

short CControlGA::GetPopSzie()
{
	short result;
	GetProperty(0x2, VT_I2, (void*)&result);
	return result;
}

void CControlGA::SetPopSzie(short propVal)
{
	SetProperty(0x2, VT_I2, propVal);
}

short CControlGA::GetRange()
{
	short result;
	GetProperty(0x3, VT_I2, (void*)&result);
	return result;
}

void CControlGA::SetRange(short propVal)
{
	SetProperty(0x3, VT_I2, propVal);
}

short CControlGA::GetGenerations()
{
	short result;
	GetProperty(0x4, VT_I2, (void*)&result);
	return result;
}

void CControlGA::SetGenerations(short propVal)
{
	SetProperty(0x4, VT_I2, propVal);
}

/////////////////////////////////////////////////////////////////////////////
// CControlGA operations

float CControlGA::GetFitness(short generacion, short individuo)
{
	float result;
	static BYTE parms[] =
		VTS_I2 VTS_I2;
	InvokeHelper(0x7, DISPATCH_PROPERTYGET, VT_R4, (void*)&result, parms,
		generacion, individuo);
	return result;
}

void CControlGA::sumatoria()
{
	InvokeHelper(0x5, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}

void CControlGA::sumaPotencia()
{
	InvokeHelper(0x6, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}

void CControlGA::AboutBox()
{
	InvokeHelper(0xfffffdd8, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
Como pasaba con el control EasyGA.ocx, cuando integras un control ActiveX en una aplicación Visual C++, el código fuente permanece oculto, pero puedes utilizar sin ningún problema los métodos y propiedades del control, no puedes modificar el código fuente, pero puedes integrar el control en tu aplicación, sin necesidad de que el código haya sido escrito en el mismo lenguaje que tu aplicación.