Yo soy Ubik. Antes de que el universo existiera yo existía. Yo hice los soles y los mundos. Yo creé las vidas y los espacios en que habitan. Yo las cambio de lugar a mi antojo. Van donde yo dispongo y hacen lo que yo les ordeno. Yo soy el verbo, y mi nombre no puede ser pronunciado. Es el nombre que nadie conoce. Me llaman Ubik, pero Ubik no es mi nombre. Yo soy. Yo seré siempre.

sábado, 19 de mayo de 2007

Monitorizar la finalizacion de aplicaciones externas

No se vosotros pero seguro que nos hemos encontrado con una aplicacion que hemos desarrollado que sin saber muy bien porque acaba finalizando de forma inesperada, o bien por un error de la aplicacion o bien por la propia logica del programa.
Mi caso concreto es una aplicacion que siempre tiene que estar ejecutandose, en un servidor, sin intervencion de ningun usuario. Como siempre ocurre, la urgencia por terminar el programa cuanto antes provoca que seguramente haya cosas mal programadas, o no lo suficientemente 'seguras'. En la practica, estas imperfecciones se traducen en finalizaciones inesperadas de la aplicacion, con su consiguiente ventanita de error. Cuando se trabaja con aplicaciones de red y con threads, mas se corre el riesgo de estos 'crashhh'.
Yo parto de la idea que todos cometemos errores al programar o que simplemente desconocemos los entresijos del complicado mundo de la programacion en windows, a estos niveles de Visual C++, asi que estas utilidades las veo mas que necesarias.
Bueno, seguire con la introduccion del problema que me ocurrio a mi. Como os decia, la aplicacion debia de correr las 24 horas en un servidor. De vez en cuando ocurria algun error que provocaba la ventanita de error y la finalizacion del mismo.
La solucion, ... hacer un programa que esta a la escucha del evento de finalizacion del exe en cuestion y cuando detecta la finalizacion, lo vuelve a ejectuar. Por su parte la aplicacion monitorizada se configura de forma que cuando finalice de forma anomala no informe al usuario con la tipica ventanita de assertion o error.
Teniendo este programa 'controlador' te da mas 'tiempo' para encontrar donde estan los errores y corregirlo. Pero miestras tanto, ya tienes tu aplicacion en produccion.


  • Si creamos una aplicacion de dialogo con la MFC, es aconsejable crearse una 'hebra de trabajo' que se encargue de esta tarea, y asi no dejamos muerta al dialogo y puede seguir recibiendo los mensajes.



UINT Hebra(LPVOID pV)
{

CControladorDlg *pPal=(CControladorDlg*)pV;



while(!pPal->m_bFinHebra)
{
int ret=0;


RunProcessAndWait(
sCmdLine,
sRunningDir,
&ret);


}
return 0;
}


BOOL RunProcessAndWait(CString sCmdLine,

CString sRunningDir,

int *nRetValue)
{
int nRetWait;

int nError;

DWORD dwTimeout = INFINITE;


STARTUPINFO stInfo;
PROCESS_INFORMATION prInfo;
BOOL bResult;

ZeroMemory( &stInfo, sizeof(stInfo) );


stInfo.cb = sizeof( stInfo );
stInfo.lpReserved = NULL;

stInfo.dwFlags = 0;
stInfo.cbReserved2 = 0;

stInfo.lpReserved2 = NULL;
stInfo.lpDesktop = NULL;

stInfo.lpTitle = NULL;
stInfo.dwX = 100;

stInfo.dwY = 100;
stInfo.dwXSize = 0;

stInfo.dwYSize = 0;
stInfo.dwXCountChars = 0;

stInfo.dwYCountChars = 0;
stInfo.dwFillAttribute = 0;

stInfo.dwFlags = STARTF_USEPOSITION;
stInfo.wShowWindow = 0;

stInfo.hStdInput = NULL;
stInfo.hStdOutput = NULL;

stInfo.hStdError = NULL;

bResult = CreateProcess(
NULL,

(LPSTR)(LPCSTR)sCmdLine,

NULL,
NULL,

TRUE,
DETACHED_PROCESS

NORMAL_PRIORITY_CLASS,

NULL,

(LPCSTR)sRunningDir,
&stInfo,

&prInfo);

*nRetValue = nError = GetLastError();

if (!bResult) return FALSE;

nRetWait = WaitForSingleObject(prInfo.hProcess,dwTimeout);

*nRetValue = nError = GetLastError();

CloseHandle(prInfo.hThread);

CloseHandle(prInfo.hProcess);


if (nRetWait == WAIT_TIMEOUT) return FALSE;
return TRUE;
}


  • De esta forma conseguimos 'monitorizar' indefinidamente el estado del proceso que acabamos de crear. El proceso en cuestion es la aplicacion nuestra.

  • Por su parte, en la aplicacion debemos poner esto, para que no muestre los mensajes de errores:



SetErrorMode(SEM_FAILCRITICALERRORS SEM_NOGPFAULTERRORBOX SEM_NOOPENFILEERRORBOX);




Y con todo esto, ya tenemos finalizado, nuestro sistema para monitorizar nuestras aplicaciones. Espero que os sirva.


Slds.