/******************************************************************
 *
 * Título: SgaLib
 *   Tipo: Módulo de Implementação
 *
 * Autor: Eduardo Melo Pacheco
 * Data: 04/11/2003
 *
 * Descrição: Módulo que implementa funções para utilizar serviços
 *            do sistema operacional Windows, nas versões NT 4, 2K
 *            e XP. Estes serviços são de obtenção de dados de
 *            hardware, monitoramento de desempenho, disparo
 *            de processos e monitoramento e gerenciamento dos mesmos.
 *            As funções são exportadas para LUA 5 e encapsuladas na
 *            tabela global servermanager. O módulo não disponibiliza
 *            acesso à nenhuma função fora de um contexto LUA 5.
 *
 ******************************************************************/

#include <windows.h>
#include <map>
#include <list>

extern "C"
{
  #include <lua.h>
  #include <lualib.h>
  #include <lauxlib.h>
}

#include "sgautils.h"

using namespace std;

#define TOTALBYTES     100*1024  // Tamanho Inicial do Buffer para dados
                                 // de desempenho
#define BYTEINCREMENT  10*1024   // Incremento do Buffer para dados de desempenho
#define NS_TO_S        10000000  // Fator de conversão da unidade de timer
                                 // do Windows

// Objetos do WMI
#define SYSTEM_OBJECT_INDEX     2   // 'System' object
#define PROCESSOR_OBJECT_INDEX  238 // 'Processor' object
#define PROCESS_OBJECT_INDEX    230 // 'Process' object
#define DISK_OBJECT_INDEX       234 // 'Disk' object
#define NETWORK_OBJECT_INDEX    510 // 'Network' object

// Contadores do WMI
#define TOTAL_PROCESSOR_TIME_COUNTER_INDEX 240  // '% Total processor time' counter (Para WinNT no 'System' object)
#define PROCESSOR_TIME_COUNTER_INDEX       6    // '% processor time' counter (para Win2K/XP)
#define PROCESS_PID_COUNTER_INDEX          784  // PID
#define PROCESS_PPID_COUNTER_INDEX         1410 // Creating Process ID
#define PROCESS_WORKINGSET_COUNTER_INDEX   180  // Proces's Working Set em Bytes
#define ELAPSED_TIME_COUNTER_INDEX         684  // Elapsed Time counter
#define PROCESS_SWAPMEMORY_COUNTER_INDEX   184  // Virtual Bytes Counter
#define PROCESS_USERTIME_COUNTER_INDEX     142  // % User Time
#define PROCESS_KERNELTIME_COUNTER_INDEX   144  // % Privileged Time
#define PROCESS_VIRTUALBYTES_COUNTER_INDEX 174  // Process virtual memory
#define DISK_READBYTESSEC_COUNTER_INDEX    220  // Disk read rate per second
#define DISK_WRITEBYTESSEC_COUNTER_INDEX   222  // Disk write rate per second
#define NETWORK_BYTESRECVSEC_COUNTER_INDEX 264  // Network bytes received per second
#define NETWORK_BYTESSENTSEC_COUNTER_INDEX 506  // Network bytes sent per second

#define RUNNING        0
#define NOT_RESPONDING 1
#define WAITING        2
#define FINISHED       3

#define LITTLE_ENDIAN  0
#define BIG_ENDIAN     1

// Estrutura de dados que contém as versões do Windows
// para determinar qual contador pegar.
typedef enum
{
 WINNT, WIN2K_XP, WIN9X, UNKNOWN
} PLATFORM ;

// Estrutura que guarda tempos de processos, utilizados
// para cálculo de uso de CPU.
typedef struct _PROCESSTIMES PROCESSTIMES, * PPROCESSTIMES;

struct _PROCESSTIMES
{
  ULARGE_INTEGER execTime ;
  LARGE_INTEGER eTime ;
} ;

// Estrutura para guardar handles de processos, necessários
// para obter dados dos comandos disparados. A cada handle
// é associado um PID para busca.
typedef struct _COMMAND COMMAND , * PCOMMAND ;

struct _COMMAND
{
  DWORD pid ;
  LPCTSTR CommandId ;
  HANDLE hName ;
  HANDLE hProcess ;
  HANDLE hStdIn ;
  HANDLE hStdOut ;
  HANDLE hStdError ;
} ;

// Estrutura de dados para guardar dados referentes à processos.
typedef struct _PROCESS
{
  DWORD PID ;
  DWORD PPID ;
  double MemoryUsed ;
  double SwapMemoryUsed ;
  double CPU_PERC;
  double KernelTime ;
  double UserTime ;
  double WallTime ;
  double VirtualBytes ;
  double DiskBytesRead ;
  double DiskBytesWrite ;
  double BytesIn ;
  double BytesOut ;
}  PROCESS , *PPROCESS ;

// Estrutura de dados para guardar dados referentes a E/S.
typedef struct _IO
{
  double DiskBytesRead ;
  double DiskBytesWrite ;
  double BytesIn ;
  double BytesOut ;
}  IODATA;

// Tipos definidos para facilitar a manipulação dos índices
typedef map<DWORD,double> MapCPU ;
typedef map<DWORD,unsigned long> MapProcess ;
typedef multimap<DWORD,unsigned long> MapChildren ;
typedef list<DWORD> ListProcess ;

typedef pair<DWORD,unsigned long> Process_Pair ;
typedef pair<DWORD,double> CPU_Pair;


typedef struct _PROCESSCONTROL
{
  double TimeStamp ;        // Time stamp da útlima vez em que os dados de processo foram atualizados
  unsigned long NumProcesses ;
  PPROCESS aProcessData ;
  MapChildren children ;    // Guarda o mapeamento dos filhos de um processo.
  MapProcess index ;        // Facilita a busca a um processo.
  MapCPU cpu1 ;             // cpu1 e cpu2 guardam os valores dos percentuais
  MapCPU cpu2 ;             // de CPU antigos e atuais.
  MapCPU *oldCPU ;          // oldCPU e currCPU apontam para cpu1 e cpu2 alternadamente
  MapCPU *currCPU ;         // (evita gerencia de memória).
}  PROCESSCONTROL ;

// Variável global para guardar controle de atualização e
// dados de processos
static PROCESSCONTROL Processes ;

// Armazena o número de CPUs da máquina
static DWORD numberOfCpus = 0 ;

// Armazena os últimos dados de E/S coletados
IODATA IOData;

// Variável global que indica se histórico deve ser ativado
BOOLEAN enableHistoric;

/******************************************************************
 *
 *   Função GetPlatform:
 *    Função utilizada para descobrir a versão do Windows.
 *
 *   Parâmetros:
 *      A função não recebe parâmetros.
 *
 *   Valor de retorno:
 *      Tipo: Platform
 *      Descrição: Contém a versão do sistema operacional.
 *
 ******************************************************************/

static PLATFORM GetPlatform()
{
  // Estrutura que contém dados sobre a versão
  OSVERSIONINFO osvi ;
  osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );

  // Chamada à função da API para descobrir a versão
  if ( !GetVersionEx( &osvi ) )
    return UNKNOWN;
  switch ( osvi.dwPlatformId )
  {
  case VER_PLATFORM_WIN32_WINDOWS:
    return WIN9X ;
  case VER_PLATFORM_WIN32_NT :
    if ( osvi.dwMajorVersion == 4)
      return WINNT ;
    else
      return WIN2K_XP ;
  }
  return UNKNOWN ;
}

/*****************************************************************
 *
 * Funções utilizadas para navegar pelos dados retornados pelo WMI
 *
 *****************************************************************/

/******************************************************************
 *
 *   Função FirstObject:
 *    Função utilizada para saber o endereço do primeiro objeto
 *      retornado pela consulta ao WMI, que retorna um bloco de dados.
 *
 *   Parâmetros:
 *   - PerfData:
 *      Tipo: PPERF_DATA_BLOCK definido na API do Windows.
 *      Descrição: Bloco de dados retornado pela consulta aos
 *               dados de performance do WMI.
 *
 *   Valor de retorno:
 *      Tipo: PPERF_DATA_BLOCK definido na API do Windows.
 *      Descrição: Ponteiro para o primeiro objeto retornado no bloco
 *                 de dados de performance do WMI.
 *
 ******************************************************************/


static PPERF_OBJECT_TYPE FirstObject( PPERF_DATA_BLOCK PerfData )
{
  return( (PPERF_OBJECT_TYPE) ( ( PBYTE ) PerfData +
    PerfData->HeaderLength ) ) ;
}

/******************************************************************
 *
 *   Função NextObject:
 *    Função utilizada para saber o endereço do próximo objeto,
 *      dado um objeto no bloco de dados retornado pela consulta
 *    ao WMI,
 *
 *   Parâmetros:
 *   - PerfObj:
 *      Tipo: PPERF_OBJECT_TYPE, definido na API do Windows.
 *      Descrição: Objeto de performance retornado no bloco de
 *               dados de performance do WMI.
 *
 *   Valor de retorno:
 *      Tipo: PPERF_OBJECT_TYPE, definido na API do Windows.
 *      Descrição: Próximo objeto de performance retornado no
 *                 bloco de dados de performance do WMI.
 *
 ******************************************************************/

static PPERF_OBJECT_TYPE NextObject( PPERF_OBJECT_TYPE PerfObj )
{
  return( ( PPERF_OBJECT_TYPE )( ( PBYTE ) PerfObj +
    PerfObj->TotalByteLength ) ) ;
}

/******************************************************************
 *
 *   Função FirstInstance:
 *    Função utilizada para saber o endereço da primeira instância
 *      de um dado objeto do WMI.
 *
 *   Parâmetros:
 *   - PerfObj:
 *      Tipo: PPERF_OBJECT_TYPE, definido na API do Windows.
 *      Descrição: Objeto de performance retornado no bloco de
 *               dados de performance do WMI.
 *
 *   Valor de retorno:
 *      Tipo: PPERF_INSTANCE_DEFINITION,
 *           definido na API do Windows.
 *      Descrição: Primeira instância de um dado objeto retornado
 *                 no bloco de dados de performance do WMI.
 *
 ******************************************************************/

static PPERF_INSTANCE_DEFINITION FirstInstance( PPERF_OBJECT_TYPE PerfObj )
{
    return( ( PPERF_INSTANCE_DEFINITION )( ( PBYTE )PerfObj +
        PerfObj->DefinitionLength ) ) ;
}

/******************************************************************
 *
 *   Função NextInstance:
 *    Função utilizada para saber o endereço da próxima instância,
 *   dada uma instância de um dado objeto do WMI.
 *
 *   Parâmetros:
 *   - PerfInst:
 *      Tipo: PPERF_INSTANCE_DEFINITION,
 *            definido na API do Windows.
 *      Descrição: Instância de um dado objeto retornado
 *               no bloco de dados de performance do WMI.
 *
 *   Valor de retorno:
 *      Tipo: PPERF_INSTANCE_DEFINITION,
 *            definido na API do Windows.
 *      Descrição: Próxima instância de uma dado Objeto do WMI
 *
 ******************************************************************/

static PPERF_INSTANCE_DEFINITION NextInstance( PPERF_INSTANCE_DEFINITION PerfInst )
{
  PPERF_COUNTER_BLOCK PerfCntrBlk;

  PerfCntrBlk = ( PPERF_COUNTER_BLOCK ) ( ( PBYTE ) PerfInst +
    PerfInst->ByteLength ) ;

  return( ( PPERF_INSTANCE_DEFINITION )( ( PBYTE ) PerfCntrBlk +
    PerfCntrBlk->ByteLength ) ) ;
}

/******************************************************************
 *
 *   Função FirstCounter:
 *    Função utilizada para saber o endereço do primeiro contador
 *      de um dado objeto do WMI.
 *
 *   Parâmetros:
 *   - PerfObj:
 *      Tipo: PPERF_OBJECT_TYPE, definido na API do Windows.
 *      Descrição: Objeto de performance retornado no bloco de
 *                 dados de performance do WMI.
 *
 *   Valor de retorno:
 *      Tipo: PPERF_COUNTER_DEFINITION, definido na API do Windows.
 *      Descrição: Primeiro contador de um dado objeto retornado
 *               no bloco de dados de performance do WMI.
 *
 ******************************************************************/

static PPERF_COUNTER_DEFINITION FirstCounter( PPERF_OBJECT_TYPE PerfObj )
{
  return( ( PPERF_COUNTER_DEFINITION ) ( ( PBYTE ) PerfObj +
    PerfObj->HeaderLength ) ) ;
}

/******************************************************************
 *
 *   Função NextCounter:
 *    Função utilizada para saber o endereço do próximo contador,
 *      dado um contador de um dado objeto do WMI.
 *
 *   Parâmetros:
 *   - PerfCntr:
 *      Tipo: PPERF_COUNTER_DEFINITION,
 *            definido na API do Windows.
 *      Descrição: Contador de performance retornado em um
 *                 objeto no bloco de dados de performance do WMI.
 *
 *   Valor de retorno:
 *      Tipo: PPERF_COUNTER_DEFINITION,
 *            definido na API do Windows.
 *      Descrição: Próximo contador de um dado objeto retornado
 *               no bloco de dados de performance do WMI.
 *
 ******************************************************************/

static PPERF_COUNTER_DEFINITION NextCounter( PPERF_COUNTER_DEFINITION PerfCntr )
{
  return( ( PPERF_COUNTER_DEFINITION )( ( PBYTE )PerfCntr +
    PerfCntr->ByteLength ) ) ;
}

/******************************************************************
 *
 *   Função UnicodeToASCII:
 *    Função utilizada para converter strings com codificação
 *    UNICODE para codificação ASCII.
 *
 *   Parâmetros:
 *   - UString:
 *      Tipo: wchar_t *
 *      Descrição: Vetor de wchar_t, que contém a string
 *                 com codificação Unicode a ser convertida.
 *   - ASCIIString:
 *      Tipo: char *
 *      Descrição: Vetor de char, que receberá a string convertida
 *                 para codificação ASCII.
 *
 *   Valor de retorno:
 *      A função não retorna nada.
 *
 ******************************************************************/

static void UnicodeToASCII ( const wchar_t * UString , char * ASCIIString )
{
  unsigned int StringSize = wcslen( UString ) ;
  unsigned int i ;

  for ( i = 0 ; i < StringSize ; i++  )
  {
    ASCIIString[ i ] = ( char ) __toascii( UString[ i ] ) ;
  }
  ASCIIString[ StringSize ] = '\0' ;
  return ;
}

/******************************************************************
 *
 *   Função QueryPerfomanceData:
 *  Função utilizada para alocar espaço em memória e receber
 *  dados de performance da máquina local utilizando a interface
 *  de registro do WMI
 *
 *   Parâmetros:
 *
 *
 *   Valor de retorno:
 *      Tipo: PPERF_DATA_BLOCK
 *      Descrição: Bloco de dados de performance do WMI
 *
 ******************************************************************/

static PPERF_DATA_BLOCK QueryPerformanceData ( )
{
  DWORD BufferSize = TOTALBYTES ;
  DWORD cbData;
  DWORD dwRet;
  char objects[255];
  // Aloca memória para receber dados de performance do WMI.
  PPERF_DATA_BLOCK PerfData = ( PPERF_DATA_BLOCK ) malloc( BufferSize ) ;
  if (PerfData == NULL) {
     return NULL;
  }
  cbData = BufferSize;
  sprintf(objects, "%d %d %d %d %d\0", SYSTEM_OBJECT_INDEX,
    PROCESSOR_OBJECT_INDEX, PROCESS_OBJECT_INDEX, DISK_OBJECT_INDEX,
    NETWORK_OBJECT_INDEX);
  dwRet = RegQueryValueEx( HKEY_PERFORMANCE_DATA, // Chave do registro referente a dados de performance
                           objects,               // Objetos a serem consultados
                           NULL,
                           NULL,
                           (LPBYTE) PerfData,     // Ponteiro que reberá os dados
                           &cbData
                         );
  while( dwRet == ERROR_MORE_DATA ) {
     // Aumentar o tamanho do buffer até que seja grande o suficiente
     BufferSize += BYTEINCREMENT ;
     PerfData = ( PPERF_DATA_BLOCK ) realloc ( PerfData, BufferSize ) ;
     if (PerfData == NULL) {
        return NULL;
     }
     cbData = BufferSize;
     dwRet = RegQueryValueEx( HKEY_PERFORMANCE_DATA, // Chave do registro referente a dados de performance
        objects,           // Objetos a serem consultados
        NULL,
        NULL,
        (LPBYTE) PerfData, // Ponteiro que reberá os dados
        &cbData );
  }
  if( dwRet != ERROR_SUCCESS ) {
    free(PerfData);
    return NULL;
  }
  return PerfData ;
}

/*****************************************************************
 *
 * Funções utilizadas para pegar valores de contadores do WMI
 *
 *****************************************************************/

/******************************************************************
 *
 *   Função GetObjectFromIndex
 *    Função utilizada para recuperar o endereço de um determinado
 *  objeto dentro de um bloco de performance retornado pelo WMI.
 *
 *   Parâmetros:
 *  - pPerfData:
 *    Tipo: PPERF_DATA_BLOCK
 *    Descrição: Bloco de dados de performance retornado pelo WMI.
 *  - dwObjectIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do objeto de performance no bloco de
 *               performance retornado pelo WMI
 *
 *   Valor de retorno:
 *      Tipo: PPERF_OBJECT_TYPE
 *      Descrição: Ponteiro para o objeto de índice passado como
 *                 parâmetro.
 *
 ******************************************************************/

static PPERF_OBJECT_TYPE GetObjectFromIndex ( PPERF_DATA_BLOCK pPerfData , unsigned long dwObjectIndex )
{
  PPERF_OBJECT_TYPE pPerfObj = NULL;

  // Primeiro objeto
  pPerfObj = FirstObject( pPerfData );

  // Procura pelo objeto de índice recebido como parâmetro
  for( unsigned long i=0; i < pPerfData->NumObjectTypes; i++ )
  {
    if (pPerfObj->ObjectNameTitleIndex == dwObjectIndex)
    {
      return pPerfObj;
    }

    pPerfObj = NextObject( pPerfObj );
  }
  return NULL;
}

/******************************************************************
 *
 *   Função GetULLCounterValueFromObject:
 *    Função utilizada para recuperar o valor de um contador de
 *    um determinado objeto de performance do WMI. Há a de se
 *    passar uma instância como parâmetro.
 *
 *
 *   Parâmetros:
 *  - pPerfObj:
 *    Tipo: PPERF_OBJECT_TYPE
 *    Descrição: Objeto contendo contadores de performance do WMI.
 *  - dwCounterIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do contador no objeto de performance.
 *  - pInstanceName:
 *    Tipo:LPCTSTR, string
 *    Descrição: String contendo o nome da instância do objeto da
 *               qual se deseja recuperar o dado. Se não houverem
 *               instâncias no objeto, o valor do contador no
 *               objeto é retornardo.
 *
 *   Valor de retorno:
 *      Tipo: ULONGLONG
 *      Descrição: Valor contendo o contador desejado no objeto
 *                 recebido como parâmetro.
 *
 ******************************************************************/

static ULONGLONG GetULLCounterValueFromObject( PPERF_OBJECT_TYPE pPerfObj ,
                                               unsigned long dwCounterIndex ,
                                               char * szInstanceName )
{
  PPERF_COUNTER_DEFINITION pPerfCntr = NULL ;
  PPERF_INSTANCE_DEFINITION pPerfInst = NULL ;
  PPERF_COUNTER_BLOCK pCounterBlock = NULL ;
  if ( pPerfObj != NULL )
  {
    // Descobre referência para o primeiro contador do objeto
    pPerfCntr = FirstCounter( pPerfObj ) ;
    // Procura pelo índice recebido como parâmetro
    for( unsigned long j=0; j < pPerfObj->NumCounters; j++ )
    {
      if (pPerfCntr->CounterNameTitleIndex == dwCounterIndex)
          break ;
      // Vai para o próximo contador
      pPerfCntr = NextCounter( pPerfCntr ) ;
    }
    if( pPerfObj->NumInstances == PERF_NO_INSTANCES )
    {
      pCounterBlock = ( PPERF_COUNTER_BLOCK ) ( ( LPBYTE ) pPerfObj + pPerfObj->DefinitionLength ) ;
    }
    else
    {
      pPerfInst = FirstInstance( pPerfObj );
      // Procura pela instância do objeto recebido como parâmetro
      char szInstance[256] ;
      char szInputInstance[256] ;
      strncpy(   szInputInstance , szInstanceName, 255 ) ;
      for( int k=0 ; k < pPerfObj->NumInstances ; k++ )
      {
        UnicodeToASCII( ( wchar_t * ) ( ( PBYTE )pPerfInst + pPerfInst->NameOffset ) , szInstance ) ;
        if (!strcmp( szInstance, szInputInstance ) )
        {
          pCounterBlock = ( PPERF_COUNTER_BLOCK ) ( ( LPBYTE ) pPerfInst + pPerfInst->ByteLength ) ;
          break;
        }
        // Próxima instância.
        pPerfInst = NextInstance( pPerfInst ) ;
      }
    }
    if ( pCounterBlock )
    {
      ULONGLONG * lnValue  ;
      lnValue = ( ULONGLONG * )( ( LPBYTE ) pCounterBlock + pPerfCntr->CounterOffset ) ;
      return * lnValue ;
    }
    return 0 ;
  }
  else
  {
    return 0 ;
  }
}

/******************************************************************
 *
 *   Função GetCounterValueFromInstance:
 *    Função utilizada para recuperar o valor de um contador de
 *  uma determinada instância de um objeto de performance do WMI.
 *
 *   Parâmetros:
 *  - pPerfObj:
 *    Tipo: PPERF_OBJECT_TYPE
 *    Descrição: Objeto contendo contadores de performance do WMI.
 *  - dwCounterIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do contador no objeto de performance.
 *  - pPerfInst:
 *    Tipo:PPERF_INSTANCE_DEFINITION
 *    Descrição: Instância do objeto do qual se deseja recuperar
 *               o valor do contador.
 *
 *   Valor de retorno:
 *      Tipo: DWORD
 *      Descrição: Valor contendo o contador desejado no objeto
 *                 recebido como parâmetro.
 *
 ******************************************************************/

static DWORD GetCounterValueFromInstance ( PPERF_OBJECT_TYPE pPerfObj, unsigned long dwCounterIndex, PPERF_INSTANCE_DEFINITION pPerfInst )
{
  PPERF_COUNTER_DEFINITION pPerfCntr = NULL ;
  PPERF_COUNTER_BLOCK pCounterBlock = NULL ;


  pPerfCntr = FirstCounter( pPerfObj ) ;

  for( unsigned long j=0 ; j < pPerfObj->NumCounters ; j++ )
  {
    if (pPerfCntr->CounterNameTitleIndex == dwCounterIndex)
      break ;

    // Pega o próximo contador.
    pPerfCntr = NextCounter( pPerfCntr ) ;
  }

  pCounterBlock = ( PPERF_COUNTER_BLOCK ) ( ( LPBYTE ) pPerfInst + pPerfInst->ByteLength ) ;

  DWORD * lnValue ;
  lnValue = ( DWORD * )( ( LPBYTE ) pCounterBlock + pPerfCntr->CounterOffset ) ;
  return ( *lnValue ) ;
}

/******************************************************************
 *
 *   Função GetLLCounterValueFromInstance:
 *    Função utilizada para recuperar o valor de um contador de
 *  uma determinada instância de um objeto de performance do WMI.
 *
 *   Parâmetros:
 *  - pPerfObj:
 *    Tipo: PPERF_OBJECT_TYPE
 *    Descrição: Objeto contendo contadores de performance do WMI.
 *  - dwCounterIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do contador no objeto de performance.
 *  - pPerfInst:
 *    Tipo:PPERF_INSTANCE_DEFINITION
 *    Descrição: Instância do objeto do qual se deseja recuperar
 *               o valor do contador.
 *
 *   Valor de retorno:
 *      Tipo: LONGLONG
 *      Descrição: Valor contendo o contador desejado no objeto
 *                 recebido como parâmetro.
 *
 ******************************************************************/

static LONGLONG GetLLCounterValueFromInstance ( PPERF_OBJECT_TYPE pPerfObj, unsigned long dwCounterIndex, PPERF_INSTANCE_DEFINITION pPerfInst )
{
  PPERF_COUNTER_DEFINITION pPerfCntr = NULL ;
  PPERF_COUNTER_BLOCK pCounterBlock = NULL ;

  pPerfCntr = FirstCounter( pPerfObj ) ;

  for( unsigned long j=0 ; j < pPerfObj->NumCounters ; j++ )
  {
    if ( pPerfCntr->CounterNameTitleIndex == dwCounterIndex)
      break ;

    // Próximo contados.
    pPerfCntr = NextCounter( pPerfCntr ) ;
   }

  pCounterBlock = ( PPERF_COUNTER_BLOCK ) ( ( LPBYTE ) pPerfInst + pPerfInst->ByteLength ) ;

  LONGLONG * lnValue ;
  lnValue = ( LONGLONG * )( ( LPBYTE ) pCounterBlock + pPerfCntr->CounterOffset ) ;
  return ( * lnValue ) ;
}

/******************************************************************
 *
 *   Função GetCounterValueFromObject:
 *    Função utilizada para recuperar o valor de um contador de
 *  um determinado objeto de performance do WMI. Há a
 *  de se passar uma instância como parâmetro.
 *
 *
 *   Parâmetros:
 *  - pPerfObj:
 *    Tipo: PPERF_OBJECT_TYPE
 *    Descrição: Objeto contendo contadores de performance do WMI.
 *  - dwCounterIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do contador no objeto de performance.
 *  - pInstanceName:
 *    Tipo:LPCTSTR, string
 *    Descrição: String contendo o nome da instância do objeto da
 *               qual se deseja recuperar o dado. Se não houverem
 *               instâncias no objeto, o valor do contador no
 *               objeto é retornardo.
 *
 *   Valor de retorno:
 *      Tipo: DWORD
 *      Descrição: Valor contendo o contador desejado no objeto
 *                 recebido como parâmetro.
 *
 ******************************************************************/

static DWORD GetCounterValueFromObject( PPERF_OBJECT_TYPE pPerfObj , unsigned long dwCounterIndex , char * szInstanceName )
{
  PPERF_COUNTER_DEFINITION pPerfCntr = NULL ;
  PPERF_INSTANCE_DEFINITION pPerfInst = NULL ;
  PPERF_COUNTER_BLOCK pCounterBlock = NULL ;

  // Descobre referência para o primeiro contador do objeto
  pPerfCntr = FirstCounter( pPerfObj ) ;

  // Procura pelo índice recebido como parâmetro
  for( unsigned long j=0; j < pPerfObj->NumCounters; j++ )
  {
    if (pPerfCntr->CounterNameTitleIndex == dwCounterIndex)
      break ;

    // Vai para o próximo contador
    pPerfCntr = NextCounter( pPerfCntr ) ;
  }

  if( pPerfObj->NumInstances == PERF_NO_INSTANCES )
  {
    pCounterBlock = ( PPERF_COUNTER_BLOCK ) ( ( LPBYTE ) pPerfObj + pPerfObj->DefinitionLength ) ;
  }
  else
  {
    pPerfInst = FirstInstance( pPerfObj );

    // Procura pela instância do objeto recebido como parâmetro
    char szInstance[256] ;
    char szInputInstance[256] ;
    strncpy( szInputInstance , szInstanceName, 255 ) ;
    for( int k=0 ; k < pPerfObj->NumInstances ; k++ )
    {
      UnicodeToASCII( ( wchar_t * ) ( ( PBYTE )pPerfInst + pPerfInst->NameOffset ) , szInstance ) ;
      if (!strcmp( szInstance, szInputInstance ) )
      {
        pCounterBlock = ( PPERF_COUNTER_BLOCK ) ( ( LPBYTE ) pPerfInst + pPerfInst->ByteLength ) ;
        break;
      }

      // Próxima instância.
      pPerfInst = NextInstance( pPerfInst ) ;
    }
  }

  if ( pCounterBlock )
  {
    DWORD * lnValue ;
    lnValue = ( DWORD * )( ( LPBYTE ) pCounterBlock + pPerfCntr->CounterOffset ) ;
    return ( *lnValue ) ;
  }
  return 0 ;
}

/******************************************************************
 *
 *   Função GetCounterValue:
 *    Função utilizada para recuperar o valor de um contador de
 *  uma determinada instância, se especificada, de um objeto cujo
 *  índice é passado como parâmetro.
 *
 *   Parâmetros:
 *  - pPerfObj:
 *    Tipo: PPERF_DATA_BLOCK
 *    Descrição: Objeto contendo contadores de performance do WMI.
 *  - dwObjectIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do objeto de performance no bloco de
 *               performance retornado pelo WMI
 *  - dwCounterIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do contador no objeto de performance.
 *  - pInstanceName:
 *    Tipo:LPCTSTR, string
 *    Descrição: String contendo nome da instância do objeto do
 *               qual se deseja recuperar o valor do contador.
 *               Caso o objeto não possua instâncias, o contador
 *               no objeto será retornado.
 *
 *   Valor de retorno:
 *      Tipo: DWORD
 *      Descrição: Valor contendo o contador desejado no objeto
 *                 recebido como parâmetro.
 *
 ******************************************************************/

static DWORD GetCounterValue( PPERF_DATA_BLOCK pPerfData, unsigned long dwObjectIndex, unsigned long dwCounterIndex, char * pInstanceName )
{
  PPERF_OBJECT_TYPE pPerfObj = NULL ;
  DWORD lnValue = 0 ;

  // Primeiro Objeto
  pPerfObj = FirstObject( pPerfData ) ;

  // Procuro pelo objeto recebido como parâmetro
  for( unsigned long i=0 ; i < pPerfData->NumObjectTypes ; i++ )
  {
    if ( pPerfObj->ObjectNameTitleIndex == dwObjectIndex )
    {
      lnValue = GetCounterValueFromObject( pPerfObj, dwCounterIndex, pInstanceName ) ;
      break;
    }
      pPerfObj = NextObject( pPerfObj ) ;
   }
   return lnValue ;
}

/******************************************************************
 *
 *   Função GetULLCounterValue:
 *    Função utilizada para recuperar o valor de um contador de
 *  uma determinada instância, se especificada, de um objeto cujo
 *  índice é passado como parâmetro.
 *
 *   Parâmetros:
 *  - pPerfObj:
 *    Tipo: PPERF_DATA_BLOCK
 *    Descrição: Objeto contendo contadores de performance do WMI.
 *  - dwObjectIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do objeto de performance no bloco de
 *               performance retornado pelo WMI
 *  - dwCounterIndex:
 *    Tipo: DWORD, redefinição unsigned long.
 *    Descrição: Índice do contador no objeto de performance.
 *  - pInstanceName:
 *    Tipo:LPCTSTR, string
 *    Descrição: String contendo nome da instância do objeto do
 *               qual se deseja recuperar o valor do contador.
 *               Caso o objeto não possua instâncias, o contador
 *               no objeto será retornado.
 *
 *   Valor de retorno:
 *      Tipo: ULONGLONG
 *      Descrição: Valor contendo o contador desejado no objeto
 *                 recebido como parâmetro.
 *
 ******************************************************************/

static ULONGLONG GetULLCounterValue( PPERF_DATA_BLOCK pPerfData,
                              unsigned long dwObjectIndex,
                              unsigned long dwCounterIndex,
                              char * pInstanceName )
{
  PPERF_OBJECT_TYPE pPerfObj = NULL ;
  ULONGLONG lnValue = 0 ;

  // Primeiro Objeto
  pPerfObj = FirstObject( pPerfData ) ;

  // Procuro pelo objeto recebido como parâmetro

  for( unsigned long i=0 ; i < pPerfData->NumObjectTypes ; i++ )
  {
    if ( pPerfObj->ObjectNameTitleIndex == dwObjectIndex )
    {
       lnValue = GetULLCounterValueFromObject( pPerfObj, dwCounterIndex, pInstanceName ) ;
       break;
    }
    pPerfObj = NextObject( pPerfObj ) ;
  }
  return lnValue ;
}

/*****************************************************************
 *
 * Funções de abertura e fechamento do módulo, CHAMADAS de LUA.
 *
 *****************************************************************/

static int _open( lua_State * L )
{
  lua_pushnumber( L , 1 ) ;
  lua_pushnil( L ) ;
  return 2 ;
}

static int _close( lua_State * L )
{
  RegCloseKey( HKEY_PERFORMANCE_DATA ) ;
  return 0 ;
}

/*****************************************************************
 *
 * Funções utilizadas para pegar dados de Hardware da máquina.
 *
 *****************************************************************/

/******************************************************************
 *
 *   Função _getStaticMemoryInfo
 *    Função utilizada para recuperar a quantidade de memória física
 *    instalada e o tamanho da memória de Swap.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    uma tabela na qual o campo ram é o valor de memória física
 *    instalada e o campo swap é o tamanho de memória swap. Também
 *    é inserido na pilha o valor nil, que é a descrição do erro.
 *    A API do Windows não retorna erros para esta função.
 *
 ******************************************************************/

static int _getStaticMemoryInfo( lua_State * L )
{
  // Estrutura que receberá os dados de memória
  MEMORYSTATUSEX MemStatus ;
  MemStatus.dwLength = sizeof(MemStatus);
  // Chamada à API WIndows para solicitar os dados
  GlobalMemoryStatusEx( &MemStatus ) ;
  DWORDLONG PhysicalMem = MemStatus.ullTotalPhys ;
  DWORDLONG SwapMem = MemStatus.ullTotalPageFile - PhysicalMem;

  // Exportação para a pilha de LUA
  lua_newtable( L ) ;
  lua_pushstring( L , "ram\0" ) ;
  lua_pushnumber( L , (lua_Number) PhysicalMem ) ;
  lua_rawset( L , - 3 ) ;
  lua_pushstring( L , "swap\0" ) ;
  lua_pushnumber( L , (lua_Number) SwapMem ) ;
  lua_rawset( L , - 3 ) ;
  lua_pushnil( L ) ;
  return 2 ;
}

/******************************************************************
 *
 *   Função _getNumberOfCpus
 *    Função utilizada para recuperar o número de processadores.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o número de processadores instalados na máquina. Também é
 *    inserido na pilha o valor nil, que é a descrição do erro.
 *    A API do Windows não retorna erros para esta função.
 *
 ******************************************************************/

static int _getNumberOfCpus( lua_State * L )
{
  lua_pushnumber( L , numberOfCpus ) ;
  lua_pushnil( L ) ;

  return 2 ;
}

/******************************************************************
 *
 *   Função _getByteOrderType
 *    Função utilizada para recuperar a ordenação de bytes.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    a ordenação de bytes na máquina. Em caso de erro, o valor
 *    retornado é nil e é inserida na pilha a descrição do erro.
 *    Em caso de sucesso o valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _getByteOrderType( lua_State * L )
{
  PPERF_DATA_BLOCK PerfData = QueryPerformanceData( ) ;
  if ( PerfData != NULL )
  {
    if( PerfData->LittleEndian == 0 )
    {
      free(PerfData);
      lua_pushnumber( L , BIG_ENDIAN ) ;
      lua_pushnil( L ) ;
      return 2 ;
    }
    else
    {
      free(PerfData);
      lua_pushnumber( L , LITTLE_ENDIAN ) ;
      lua_pushnil( L ) ;
      return 2 ;
    }
  }
  else
  {
    lua_pushnil( L ) ;
    lua_pushstring( L , "Erro ao acessar dados do WMI\0" ) ;
    return 2 ;
  }
}

/*****************************************************************
 *
 * Funções utilizadas para disparar e gerenciar processos .
 *
 *****************************************************************/

/******************************************************************
 *
 *   Função NeedToRefresh
 *    Função utilizada para saber se é necessário atualizar dados
 *    de processos, baseando-se em um time stamp e uma "idade"
 *    máxima para os dados. Esta função não é exportada para LUA,
 *    sendo de uso interno do módulo.
 *
 *   Parâmetros:
 *  - MaxOld:
 *    Tipo: double
 *    Descrição: Idade máxima para os dados de processo, em segundos.
 *
 *
 *   Valor de retorno:
 * - Tipo: BOOLEAN
 *   - Caso o tempo decorrido entre a última atualização dos dados e
 *   o momento em que essa função é chamada seja menor que MaxOld,
 *   retorna TRUE. Caso contrário retorna FALSE.
 *
 ******************************************************************/

static BOOLEAN NeedToRefresh( double MaxOld )
{
  FILETIME now ;
  GetSystemTimeAsFileTime( &now ) ;

  LARGE_INTEGER aux ;
  aux.LowPart = now.dwLowDateTime ;
  aux.HighPart = now.dwHighDateTime ;

  double NewTimeStamp = ( double ) aux.QuadPart ;
  double ProcessesDataAge = ( NewTimeStamp - Processes.TimeStamp ) / NS_TO_S ;

  if( ProcessesDataAge > MaxOld )
  {
    return TRUE ;
  }
  else
  {
    return FALSE ;
  }
}

/******************************************************************
 *
 *   Função RefreshIOInfo
 *    Função utilizada para recuperar informações de entrada/saída
 *    da máquina. Esta função é de uso interno do módulo e não é
 *    exportada para o ambiente LUA. Um intervalo mínimo de 10s
 *    entre as chamadas é necessário para que os dados sejam atualizados.
 *
 *   Parâmetros:
 *   - PerfData
 *     Tipo: PPERF_DATA_BLOCK
 *     Descrição: Dados de desempenho obtidos pelo WMI.
 *
 *   Valor de retorno:
 *   - A função não tem retorno.
 *
 ******************************************************************/

static void RefreshIOInfo ( PPERF_DATA_BLOCK PerfData )
{
  PPERF_OBJECT_TYPE DiskObject = NULL ;
  PPERF_OBJECT_TYPE NetworkObject = NULL ;
  PPERF_INSTANCE_DEFINITION OneDisk = NULL ;
  PPERF_INSTANCE_DEFINITION OneNetwork = NULL ;
  unsigned long i;

  DiskObject = GetObjectFromIndex( PerfData, DISK_OBJECT_INDEX ) ;
  NetworkObject = GetObjectFromIndex( PerfData, NETWORK_OBJECT_INDEX ) ;
  if ( DiskObject == NULL || NetworkObject == NULL)
  {
    printf("Erro: GetObjectFromIndex\n");
    return;
  }

  // Variável utilizada para capturar os valores de escrita/leitura de todos os
  // discos (instância _Total)
  OneDisk = FirstInstance( DiskObject );

  IOData.DiskBytesRead = (double) GetCounterValueFromInstance( DiskObject, DISK_READBYTESSEC_COUNTER_INDEX , OneDisk ) ;
  IOData.DiskBytesWrite = (double) GetCounterValueFromInstance( DiskObject, DISK_WRITEBYTESSEC_COUNTER_INDEX , OneDisk ) ;

  unsigned long NumNetworks = NetworkObject->NumInstances ;
  // Variável utilizada para percorrer os vetores de interfaces de rede. Como
  // podem existir múltiplas interfaces e não há uma instância do tipo _Total
  // tal como acontece no disco, é preciso acumular os valores de entrada e
  // saída de rede.
  OneNetwork = FirstInstance( NetworkObject );

  IOData.BytesIn = 0;
  IOData.BytesOut = 0;

  for ( i = 0 ; i < NumNetworks ; i++ )
  {
    IOData.BytesIn += (double) GetCounterValueFromInstance( NetworkObject, NETWORK_BYTESRECVSEC_COUNTER_INDEX , OneNetwork ) ;
    IOData.BytesOut += (double) GetCounterValueFromInstance( NetworkObject, NETWORK_BYTESSENTSEC_COUNTER_INDEX , OneNetwork ) ;

    OneNetwork = NextInstance( OneNetwork );
  }

  return;
}

/******************************************************************
 *
 *   Função RefreshAllProcessesInfo
 *    Função utilizada para recuperar número de processos em
 *      execução na máquina e atualizar os dados de processos. Esta
 *    função é de uso interno do módulo e não é exportada para o
 *    ambiente LUA. Um intervalo mínimo de 10s entre as chamadas é
 *    necessário para que os dados sejam atualizados.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: ambiente Lua usado para colocar as informações
 *               dos processos.
 *
 *   Valor de retorno:
 * - Tipo: unsigned long
 *   - Retorna o número de processos em execução. Em caso de erro
 *   retorna zero e libera o vetor que continha os dados de
 *   processos.
 *
 ******************************************************************/

static unsigned long RefreshAllProcessesInfo ( lua_State* L )
{
  PPERF_DATA_BLOCK PerfData = NULL ;
  PPERF_OBJECT_TYPE ProcessObject = NULL ;
  PPERF_INSTANCE_DEFINITION OneProcess = NULL ;
  static LARGE_INTEGER OldPoolingTime = { 0 } ;

  // Lê os processos do Cygwin
  lua_getglobal(L, "collectWinPID");
  if( lua_pcall(L, 0, 0, 0) ) {
    // retira a mensagem de erro da pilha
    const char* str = lua_tostring(L, -1);
    printf("Erro: collectWinPID %s\n", str);
    lua_pop(L, 1);
    return 0;
  }

  // Lê os dados do Windows
  PerfData = QueryPerformanceData( ) ;

  if ( PerfData == NULL )
  {
    printf("Erro: QueryPerformanceData\n");
    return 0 ;
  }

  if(enableHistoric == TRUE) {
    RefreshIOInfo(PerfData);
  }

  ProcessObject = GetObjectFromIndex( PerfData, PROCESS_OBJECT_INDEX ) ;
  if ( ProcessObject == NULL )
  {
    free( PerfData ) ;
    printf("Erro: GetObjectFromIndex\n");
    return 0 ;
  }

  // Novo timer do sistema.
  LARGE_INTEGER NewPoolingTime = PerfData->PerfTime100nSec ;

  // Tempo decorrido entre as chamadas. Mínimo de 10s para atualização de dados.
  double deltaPooling = (double) ( NewPoolingTime.QuadPart - OldPoolingTime.QuadPart ) ;

  // Número de processos em execução durante a última chamada.
  unsigned long OldNumProcesses = Processes.NumProcesses ;

  if  ( Processes.aProcessData != NULL )
  {
    free ( Processes.aProcessData ) ;
    Processes.index.clear();
    Processes.children.clear();
  }

  //A instância _Total de process não entra
  unsigned long NumProcesses = ProcessObject->NumInstances - 1 ;

  Processes.aProcessData = ( PPROCESS ) malloc ( NumProcesses * sizeof( PROCESS ) ) ;
  if (Processes.aProcessData == NULL) {
    printf("Erro: malloc\n");
    return 0;
  }

  // Variáveis utilizadas para percorrer os vetores de processos.
  MapCPU::const_iterator cpuIter ;
  unsigned long i;
  OneProcess = FirstInstance( ProcessObject );

  for ( i = 0 ; i < NumProcesses ; i++ )
  {
    LONGLONG Freq = ProcessObject->PerfFreq.QuadPart ;
    LONGLONG Time = ProcessObject->PerfTime.QuadPart ;
    LONGLONG Counter = GetLLCounterValueFromInstance( ProcessObject, ELAPSED_TIME_COUNTER_INDEX , OneProcess ) ;
    double tmpCPUPerc = (double) GetCounterValueFromInstance( ProcessObject, PROCESSOR_TIME_COUNTER_INDEX, OneProcess ) ;

    Processes.aProcessData[ i ].PID = ( DWORD ) GetCounterValueFromInstance( ProcessObject, PROCESS_PID_COUNTER_INDEX, OneProcess);
    Processes.aProcessData[ i ].PPID = ( DWORD ) GetCounterValueFromInstance( ProcessObject, PROCESS_PPID_COUNTER_INDEX, OneProcess);
    Processes.aProcessData[ i ].MemoryUsed = ( double ) ( GetCounterValueFromInstance( ProcessObject, PROCESS_WORKINGSET_COUNTER_INDEX, OneProcess) );
    Processes.aProcessData[ i ].SwapMemoryUsed = ( double )  GetCounterValueFromInstance( ProcessObject, PROCESS_SWAPMEMORY_COUNTER_INDEX , OneProcess ) ;
    Processes.aProcessData[ i ].UserTime = ( double ) GetLLCounterValueFromInstance( ProcessObject, PROCESS_USERTIME_COUNTER_INDEX, OneProcess ) / NS_TO_S ;
    Processes.aProcessData[ i ].KernelTime = ( double ) GetLLCounterValueFromInstance( ProcessObject, PROCESS_KERNELTIME_COUNTER_INDEX, OneProcess ) / NS_TO_S ;
    Processes.aProcessData[ i ].WallTime = ( double )( ( Time - Counter ) / Freq ) ;
    Processes.aProcessData[ i ].VirtualBytes = (double) GetCounterValueFromInstance( ProcessObject, PROCESS_VIRTUALBYTES_COUNTER_INDEX , OneProcess ) ;
    Processes.aProcessData[ i ].DiskBytesRead = IOData.DiskBytesRead;
    Processes.aProcessData[ i ].DiskBytesWrite = IOData.DiskBytesWrite;
    Processes.aProcessData[ i ].BytesIn = IOData.BytesIn;
    Processes.aProcessData[ i ].BytesOut = IOData.BytesOut;

    OneProcess = NextInstance( OneProcess );

    // Verifica se o processo existia na coleta anterior
    cpuIter = Processes.oldCPU->find( Processes.aProcessData[ i ].PID );
    if( cpuIter != Processes.oldCPU->end() )
    {
      // Percentual normalizado pelo número de CPUs
      Processes.aProcessData[ i ].CPU_PERC = ( ((tmpCPUPerc - cpuIter->second) / deltaPooling ) / (double)numberOfCpus) * 100;
    }
    else {
      Processes.aProcessData [ i ].CPU_PERC = 0 ;
    }

    // Cria um indice para os processos
    Processes.index.insert( Process_Pair( Processes.aProcessData[ i ].PID, i ));

    // XXX Um processo no Windows pode ser pai dele mesmo?!?
    if( Processes.aProcessData[ i ].PPID != Processes.aProcessData[ i ].PID )
      Processes.children.insert( Process_Pair( Processes.aProcessData[ i ].PPID, i ));

    // Guarda o valor da CPU para ser usada na próxima coleta
    Processes.currCPU->insert( CPU_Pair( Processes.aProcessData[ i ].PID, tmpCPUPerc ));
  }

  // Descarta valores antigos da CPU
  Processes.oldCPU->clear();

  // Guarda os valores atuais para a próxima chamada
  MapCPU *tmpCPU = Processes.oldCPU;
  Processes.oldCPU = Processes.currCPU;
  Processes.currCPU = tmpCPU;

  Processes.NumProcesses = NumProcesses ;
  OldPoolingTime = NewPoolingTime ;
  Processes.TimeStamp = ( double ) NewPoolingTime.QuadPart ;

  free( PerfData ) ;
  return NumProcesses ;
}

/******************************************************************
 *
 *   Função _getProcessesByPID
 *    Função utilizada para recuperar o PID dos filhos de um dado
 *    processo.
 *
 * -  L:
 *    Tipo: lua_State
 *    Descrição: ambiente Lua usado para colocar as informações
 *               dos processos.
 * -  pid:
 *    Tipo: DWORD
 *    Descrição: PID do pai dos processos a serem recuperados.
 *
 * -  children:
 *    Tipo: DWORD**
 *    Descrição: Retorna o PID dos processos filho.
 *
 * -  size:
 *    Tipo: DWORD*
 *    Descrição: Retorna o número de processos filho.
 *
 *   Valor de retorno:
 *   -  Retorna TRUE em caso normal e FALSE caso haja erro.
 *      No caso de erro, a pilha Lua conterá 'nil' e a mensagem de erro.
 *
 ******************************************************************/

static BOOL _getProcessesByPID( lua_State* L, DWORD pid , DWORD** procs , unsigned long* size )
{
  unsigned long i = 0;
  DWORD proc = 0;

  // Busca a lista de processos filhos no Cygwin
  lua_getglobal( L, "getWinPID" );
  lua_pushnumber( L, pid );
  if( lua_pcall(L, 1, 1, 0) != 0 ) {
    lua_pushnil( L );
    lua_pushstring( L, "Erro ao ler informações sobre os processos.");
    return FALSE ;
  }

  // PID não encontrado
  if( lua_isnil(L, -1) ) {
    lua_pushstring(L, "Processo não encontrado.");
    return FALSE;
  }

  // Número de processos encontrados (o PID do pai pode estar incluso)
  *size = (DWORD) luaL_getn( L, -1 );
  if( (*size) == 0 ) {
    return TRUE;
  }

  // Aloca espaço para os PIDs
  *procs = ( DWORD * ) malloc( (*size) * sizeof( DWORD ) ) ;
  if ((*procs) == NULL) {
    lua_pushnil( L );
    lua_pushstring( L, "Erro: memória insuficiente.");

    return FALSE;
  }

  // Coloca os PIDs no vetor
  for( i = 0 ; i < (*size) ; i++ ) {
    lua_pushnumber( L, i+1 );
    lua_gettable( L, -2 );

    proc = (DWORD) lua_tonumber( L, -1 );
    (*procs)[ i ] = proc ;
    lua_pop(L, 1);
  }

   return TRUE;
}

/******************************************************************
 *
 *   Função _collectChildrenInfo
 *    Função utilizada para recuperar as informações sobre um
 *    processo. Esta função é de uso interno do módulo e NÃO é
 *    exportada para o ambiente LUA.
 *
 * -  L:
 *    Tipo: lua_State
 *    Descrição: ambiente Lua usado para colocar as informações
 *               dos processos. No topo da pilha fica a tabela
 *               que conterá as informações sobre o processo.
 * -  pid:
 *    Tipo: DWORD
 *    Descrição: PID do pai dos processos a serem recuperados.
 *
 *   Valor de retorno:
 *   -  Retorna FALSE caso o processo não foi localizado. Caso
 *      contrário, TRUE.
 *
 ******************************************************************/

static bool _collectProcessInfo(lua_State *L, DWORD pid)
{
  unsigned long idx;
  MapProcess::const_iterator processIter;

  // Busca o PID
  processIter = Processes.index.find( (DWORD) pid );

  // Como a coleta de Lua é em um momento diferente da coleta do
  // Windows, um processo pode não aparecer.
  if( processIter == Processes.index.end() )
    return FALSE;

  // Posição do processo no vetor
  idx = processIter->second;

  // Prepara o índice para os dados do processo
  lua_newtable( L ) ;

  // Preenche a tabela do processo
  lua_pushstring( L, "pid" ) ;
  lua_pushnumber( L, Processes.aProcessData[ idx ].PID );
  lua_rawset( L, -3 );

  lua_pushstring( L, "ppid" );
  lua_pushnumber( L, Processes.aProcessData[ idx ].PPID );
  lua_rawset( L, -3 );

  lua_pushstring(L, "memoryRamSizeMb");
  lua_pushnumber(L, Processes.aProcessData[ idx ].MemoryUsed / (1024 * 1024));
  lua_rawset(L, -3);

  lua_pushstring(L, "memorySwapSizeMb");
  lua_pushnumber(L, Processes.aProcessData[ idx ].SwapMemoryUsed / (1024 * 1024));
  lua_rawset(L, -3);

  lua_pushstring(L, "CPUTimeSec");
  lua_pushnumber(L, Processes.aProcessData[ idx ].UserTime +
                   Processes.aProcessData[ idx ].KernelTime );
  lua_rawset(L, -3);

  lua_pushstring(L, "wallTimeSec");
  lua_pushnumber(L, Processes.aProcessData[ idx ].WallTime );
  lua_rawset(L, -3);

  lua_pushstring(L, "CPUPerc");
  lua_pushnumber(L, Processes.aProcessData[ idx ].CPU_PERC );
  lua_rawset(L, -3);

  lua_pushstring(L, "userTimeSec");
  lua_pushnumber(L, Processes.aProcessData[ idx ].UserTime );
  lua_rawset(L, -3);

  lua_pushstring(L, "systemTimeSec");
  lua_pushnumber(L, Processes.aProcessData[ idx ].KernelTime );
  lua_rawset(L, -3);

  lua_pushstring(L, "virtualMemorySizeMB");
  lua_pushnumber(L, Processes.aProcessData[ idx ].VirtualBytes );
  lua_rawset(L, -3);

  lua_pushstring(L, "diskBytesReadKB");
  lua_pushnumber(L, Processes.aProcessData[ idx ].DiskBytesRead / 1024);
  lua_rawset(L, -3);

  lua_pushstring(L, "diskBytesWriteKB");
  lua_pushnumber(L, Processes.aProcessData[ idx ].DiskBytesWrite / 1024);
  lua_rawset(L, -3);

  lua_pushstring(L, "bytesInKB");
  lua_pushnumber(L, Processes.aProcessData[ idx ].BytesIn / 1024);
  lua_rawset(L, -3);

  lua_pushstring(L, "bytesOutKB");
  lua_pushnumber(L, Processes.aProcessData[ idx ].BytesOut / 1024);
  lua_rawset(L, -3);

  lua_pushstring(L, "state");
  lua_pushstring(L, "RUNNING" );
  lua_rawset(L, -3);

  lua_pushstring(L, "processorId");
  lua_pushnumber(L, 0);
  lua_rawset(L, -3);

  lua_pushstring(L, "command");
  lua_pushstring(L, "unknown" );
  lua_rawset(L, -3);

  lua_pushstring(L, "execHost");
  lua_pushstring(L, "unknown" );
  lua_rawset(L, -3);

  return TRUE;
}

/******************************************************************
 *
 *   Função _getCommandAllInfo
 *    Função utilizada para recuperar uma lista de todos os filhos
 *    de um processo e suas respectivas infomações.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 *
 * - MaxOld:
 *   Tipo: number
 *   Descrição: "Idade" máxima que a informação pode ter.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha uma tabela contendo os processos
 *      filhos e seus dados de CPU, memória, etc.
 *
 ******************************************************************/

static int _getCommandAllInfo(lua_State *L)
{
   MapProcess::const_iterator processIter;
   DWORD *procs = NULL;
   unsigned long nProcs = 0;
   unsigned long count = 0;
   unsigned long idx = 0;
   unsigned long i = 0;

   // Recebe "idade" máxima para dados de processos
   double MaxOld = lua_tonumber( L , -1 ) ;

   // Teste para saber se é necessário atualizar dados de processos
   if( NeedToRefresh( MaxOld ) == TRUE )
   {
      if ( RefreshAllProcessesInfo( L ) == 0 )
      {
         lua_pushnil( L ) ;
         lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
         return 2 ;
      }
   }

   // Procura pelo uso de cpu do processo e retorna
   if ( lua_isuserdata( L, -2 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , -2 ) ;

      // Recupera os processos do Cygwin
      if( !_getProcessesByPID(L, CommandHandle->pid, &procs, &nProcs) ) {
         // Em caso de erro, este já está na pilha Lua
         return 2;
      }

      // Tabela de resposta que conterá a lista de informações sobre
      // os processos.
      lua_newtable( L );
      idx = lua_gettop( L );

      if( nProcs == 0 ) {
         return 1;
      }

      // Coleta as informações do filho
      count = 1;
      for( i = 0; i < nProcs; i++ ) {
         lua_pushnumber(L, count);
         // Salva na tabela 'idx' as informações sobre o processo
         if( _collectProcessInfo(L, procs[i]) ) {
            lua_rawset(L, idx);
            count++;
         }
         else {
            lua_pop(L, 1);
         }
      }

      free( procs );

      return 1;
   }

   // Caso o Handle seja inválido, retorna o erro
   lua_pushnil( L ) ;
   lua_pushstring( L , "Handle de comando inválido.\0" ) ;
   return 2 ;
}


/******************************************************************
 *
 *   Função _getProcessCpuLoad
 *    Função utilizada para recuperar o uso de CPU de um processo
 *    cujo o handle é passado na pilha como parâmetro. Esta função
 *    é registrada como getcommandcpuload na tabela servermanager,
 *    global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 * - MaxOld:
 *   Tipo: number
 *   Descrição: "Idade" máxima que a informação pode ter.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o uso de cpu do comando. Em caso de erro, o valor retornado
 *    é nil e é inserida na pilha a descrição do erro. Em caso de
 *    sucesso o valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _getProcessCpuLoad( lua_State * L )
{
   // Recebe "idade" máxima para dados de processos
   double MaxOld = lua_tonumber( L , -1 ) ;

   // Teste para saber se é necessário atualizar dados de processos
   if( NeedToRefresh( MaxOld ) == TRUE )
   {
      if ( RefreshAllProcessesInfo( L ) == 0 )
      {
         lua_pushnil( L ) ;
         lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
         return 2 ;
      }
   }

   // Procura pelo uso de cpu do processo e retorna
   if ( lua_isuserdata( L, -2 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , -2 ) ;

      DWORD PID = CommandHandle->pid ;
      // Procura no índice de processos
      MapProcess::const_iterator iter = Processes.index.find(PID) ;
      if( iter != Processes.index.end() ) {
         lua_pushnumber( L , Processes.aProcessData[ iter->second ].CPU_PERC ) ;
         lua_pushnil( L ) ;
         return 2 ;
      }

      // Caso não tenha achado o processo em questão, retorna o erro
      lua_pushnil( L ) ;
      lua_pushstring( L , "Comando não está executando.\0" ) ;
      return 2 ;
   }
   // Caso o Handle seja inválido, retorna o erro
   else
   {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Handle de comando inválido.\0" ) ;
      return 2 ;
   }
}

/******************************************************************
 *
 *   Função _getProcessMemoryLoad
 *    Função utilizada para recuperar o uso de memória de um
 *    processo cujo o handle é passado na pilha como parâmetro.
 *    Esta  função é registrada como getcommandmemoryload na tabela
 *    servermanager, global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 * - MaxOld:
 *   Tipo: number
 *   Descrição: Tempo máximo que a informação pode ter. Não é
 *              utilizado.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o uso de memória do comando. Este uso é inserido em uma
 *    tabela contendo os campos "ram" e "swap". Em caso de erro,
 *    o valor retornado é nil e é inserida na pilha a descrição do
 *    erro. Em caso de sucesso o valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _getProcessMemoryLoad( lua_State *L )
{
   // Recebe "idade" máxima para dados de processos
   double MaxOld = lua_tonumber( L , -1 ) ;

   // Teste para saber se é necessário atualizar dados de processos
   if( NeedToRefresh( MaxOld ) == TRUE )
   {
      if ( RefreshAllProcessesInfo( L ) == 0 )
      {
         lua_pushnil( L ) ;
         lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
         return 2 ;
      }
   }

   // Procura pelo uso de memória do processo e retorna
   if ( lua_isuserdata( L, -2 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , -2 ) ;

      DWORD PID = CommandHandle->pid ;
      // Procura no índice de processos
      MapProcess::const_iterator iter = Processes.index.find(PID) ;
      if( iter != Processes.index.end() )
      {
         lua_newtable( L ) ;

         lua_pushstring( L , "ram\0" ) ;
         lua_pushnumber( L , Processes.aProcessData[ iter->second ].MemoryUsed ) ;
         lua_rawset( L , - 3 ) ;

         lua_pushstring( L , "swap\0" ) ;
         lua_pushnumber( L , Processes.aProcessData[ iter->second ].SwapMemoryUsed ) ;
         lua_rawset( L , - 3 ) ;

         lua_pushnil( L ) ;

         return 2 ;
      }

      // Caso não tenha achado o processo em questão, retorna o erro
      lua_pushnil( L ) ;
      lua_pushstring( L , "Comando não está executando.\0" ) ;
      return 2 ;
   }
   else
   {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Handle de comando inválido\0" ) ;
      return 2 ;
   }
}

/******************************************************************
 *
 *   Função _getJobsInfo
 *    Esta função é registrada como getjobsinfo
 *    na tabela servermanager, global no ambiente Lua.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para Lua na tabela
 *               servermanager, é necessário saber qual o State.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o valor nil sinalizando que, por enquanto, não foi definido
 *    qual o comportamento que essa função deve ter no Windows.
 ******************************************************************/

static int _getJobsInfo( lua_State * L )
{
  lua_pushnil( L ) ;

  return 1 ;
}


/******************************************************************
 *
 *   Função _getNumberOfJobs
 *    Função utilizada para obter o número de jobs em
 *    execução no servidor.
 *    Esta  função é registrada como getnumberofjobs
 *    na tabela servermanager, global no ambiente Lua.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para Lua na tabela
 *               servermanager, é necessário saber qual o State.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o número de jobs em execução no servidor.
 ******************************************************************/

static int _getNumberOfJobs( lua_State * L )
{
	   int count = 0;
	   // Recebe "idade" máxima para dados de processos
	   double MaxOld = lua_tonumber( L , -1 ) ;

	   // Teste para saber se é necessário atualizar dados de processos
	   if( NeedToRefresh( MaxOld ) == TRUE )
	   {
	      if ( RefreshAllProcessesInfo( L ) == 0 )
	      {
	         lua_pushnil( L ) ;
	         lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
	         return 2 ;
	      }
	   }

	   //coloca a tabela global que armazena
	   //os Comandos de lua no topo da pilha
	   lua_getglobal( L, "COMMAND" ) ;

	   //coloca no topo da pilha o array que
	   //que possui o registro de todos os comandos
	   lua_getfield( L, -1, "array" ) ;

	   lua_pushnil( L ) ;
	   //itera por todos os comandos
	   while (lua_next( L, -2 ) != 0){

		   count = count + 1;

		   //remove o valor do comando e mantem a chave
		   //para a iteração continuar
		   lua_pop( L, 1 );
	   }

	   lua_pushnumber( L , count);
	   lua_pushnil( L );

	   return 2 ;
}


/******************************************************************
 *
 *   Função _getProcessTimes
 *    Função utilizada para recuperar os tempos de um processo cujo
 *    o handle é passado na pilha como parâmetro. Esta  função é
 *    registrada como getcommandtimeusage na tabela servermanager,
 *    global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 * - MaxOld:
 *   Tipo: number
 *   Descrição: Tempo máximo que a informação pode ter. Não é
 *              utilizado.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    os tempos do comando. Estes tempos são inserido em uma
 *    tabela contendo os campos "user", "system" e "elapsed". Em
 *    caso de erro, o valor retornado é nil e é inserida na pilha
 *    a descrição do erro. Em caso de sucesso o valor de erro nil
 *    é inserido na pilha.
 *
 ******************************************************************/

static int _getProcessTimes( lua_State * L )
{
   // Recebe "idade" máxima para dados de processos
   double MaxOld = lua_tonumber( L , -1 ) ;

   // Teste para saber se é necessário atualizar dados de processos
   if( NeedToRefresh( MaxOld ) == TRUE )
   {
      if ( RefreshAllProcessesInfo( L ) == 0 )
      {
         lua_pushnil( L ) ;
         lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
         return 2 ;
      }
   }

   // Procura pelo uso de memória do processo e retorna
   if ( lua_isuserdata( L, -2 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , -2 ) ;

      DWORD PID = CommandHandle->pid ;
      // Procura no índice de processos
      MapProcess::const_iterator iter = Processes.index.find(PID) ;
      if( iter != Processes.index.end() )
      {
         lua_newtable( L ) ;

         lua_pushstring( L , "user\0" ) ;
         lua_pushnumber( L , Processes.aProcessData[ iter->second ].UserTime ) ;
         lua_rawset( L , - 3 ) ;

         lua_pushstring( L , "system\0" ) ;
         lua_pushnumber( L , Processes.aProcessData[ iter->second ].KernelTime ) ;
         lua_rawset( L , - 3 ) ;

         lua_pushstring( L , "elapsed\0" ) ;
         lua_pushnumber( L , Processes.aProcessData[ iter->second ].WallTime ) ;
         lua_rawset( L , - 3 ) ;

         lua_pushnil( L ) ;
         return 2 ;
      }
      // Caso não esteja mais rodando, retorna os tempos finais do processo

      // Estrutras passadas para a função da API do Windows
      // para pegar tempos dos processos.
      FILETIME ftUser ;
      FILETIME ftKernel ;
      FILETIME ftCreation ;
      FILETIME ftExit ;

      // Variável utilizada para derivar os dados
      // recebidos da API para segundos
      LARGE_INTEGER auxTime , auxTime1 ;

      double UserTime , KernelTime , WallTime ;

      // Chamada à API do Windows para obter os tempos do processo terminado.
      // É necessário converter os tempos para segundos.
      if ( GetProcessTimes( CommandHandle->hProcess , &ftCreation , &ftExit , &ftKernel , &ftUser ) == TRUE )
      {
         auxTime.HighPart = ftUser.dwHighDateTime ;
         auxTime.LowPart = ftUser.dwLowDateTime ;
         UserTime = ( double ) auxTime.QuadPart / NS_TO_S ;


         auxTime.HighPart = ftKernel.dwHighDateTime ;
         auxTime.LowPart = ftKernel.dwLowDateTime ;
         KernelTime = ( double ) auxTime.QuadPart / NS_TO_S ;

         auxTime.HighPart = ftCreation.dwHighDateTime ;
         auxTime.LowPart = ftCreation.dwLowDateTime ;
         auxTime1.HighPart = ftExit.dwHighDateTime ;
         auxTime1.LowPart = ftExit.dwLowDateTime ;

         WallTime = ( double )  ( auxTime1.QuadPart - auxTime.QuadPart ) / NS_TO_S ;

         // Retorna os tempos
         lua_newtable( L ) ;
         lua_pushstring( L , "user\0" ) ;
         lua_pushnumber( L , UserTime ) ;
         lua_rawset( L , - 3 ) ;
         lua_pushstring( L , "system\0" ) ;
         lua_pushnumber( L , KernelTime ) ;
         lua_rawset( L , - 3 ) ;
         lua_pushstring( L , "elapsed\0" ) ;
         lua_pushnumber( L , WallTime ) ;
         lua_rawset( L , - 3 ) ;
         lua_pushnil( L ) ;
         return 2 ;
      }
      // Caso haja falha na aquisição dos tempos finais, retorna o erro
      else
      {
         lua_pushnil( L ) ;
         lua_pushstring( L , "Erro ao recuperar tempos finais do comando.\0" ) ;
         return 2 ;
      }
   }
   else
   {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Handle de comando inválido.\0" ) ;
      return 2 ;
   }
}

/******************************************************************
 *
 *   Função _getProcessStatus
 *    Função utilizada para recuperar o status de um processo cujo
 *    o handle é passado na pilha como parâmetro. Esta  função é
 *    registrada como getcommandstatus na tabela servermanager,
 *    global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 * - MaxOld:
 *   Tipo: number
 *   Descrição: Tempo máximo que a informação pode ter. Não é
 *              utilizado.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o status do comando. Este status pode possuir o valor RUNNING
 *    ou FINISHED. Em caso de erro, o valor retornado é nil e é
 *    inserida na pilha a descrição do erro. Em caso de sucesso o
 *    valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _getProcessStatus( lua_State *L )
{
   // Recebe "idade" máxima para dados de processos
   double MaxOld = lua_tonumber( L , -1 ) ;

   // Teste para saber se é necessário atualizar dados de processos
   if( NeedToRefresh( MaxOld ) == TRUE )
   {
      if ( RefreshAllProcessesInfo( L ) == 0 )
      {
         lua_pushnil( L ) ;
         lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
         return 2 ;
      }
   }

   // Procura pelo uso de memória do processo e retorna
   if ( lua_isuserdata( L, -2 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , -2 ) ;

      DWORD PID = CommandHandle->pid ;
      // Procura no índice de processos
      MapProcess::const_iterator iter = Processes.index.find(PID) ;
      if( iter != Processes.index.end() )
      {
         lua_pushnumber( L , RUNNING ) ;
         lua_pushnil( L ) ;
         return 2 ;
      }

      // Processo não está rodando
      lua_getglobal(L, "_checkforerror");
      lua_pushlightuserdata( L , ( void * ) CommandHandle ) ;
      lua_pcall(L, 1, 0, 0);

      lua_pushnumber( L , FINISHED ) ;
      lua_pushnil( L ) ;
      return 2 ;
   }
   else
   {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Handle de comando inválido\0" ) ;
      return 2 ;
   }
}

/******************************************************************
 *
 *   Função _getProcessExecHost
 *    Função utilizada para recuperar o host de um processo cujo
 *    o handle é passado na pilha como parâmetro. Esta  função é
 *    registrada como getcommandexechost na tabela servermanager,
 *    global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o host que está executando o comando.
 *    Em caso de erro, o valor retornado é nil e é
 *    inserida na pilha a descrição do erro. Em caso de sucesso o
 *    valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _getProcessExecHost( lua_State *L )
{
   if ( lua_isuserdata( L, -2 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , -2 ) ;

      HANDLE hName = CommandHandle->hName ;

      if (hName) {
        lua_pushstring( L , (const char*) hName ) ;
      }
      else {
        lua_pushstring( L , "unknown" ) ; // XXX - Nao podemos usar gethostname?
      }
      lua_pushnil( L ) ;
      return 2 ;
   }

   lua_pushnil( L ) ;
   lua_pushstring( L , "Handle de comando inválido\0" ) ;
   return 2 ;
}


/******************************************************************
 *
 *      Função _getProcessParentPid
 *      Função utilizada para recuperar o PID do pai de um processo
 *    cujo o handle é passado na pilha como parâmetro. Esta  função é
 *    registrada como getcommandstatus na tabela servermanager,
 *    global no ambiente LUA.
 *
 *      Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 * - MaxOld:
 *   Tipo: number
 *   Descrição: Tempo máximo que a informação pode ter.
 *
 *      Valor de retorno:
 *      -  A função retorna, na pilha do state passado como parâmetro,
 *    o PID do pai do processo. Em caso de erro, o valor retornado
 *    é nil e é inserida na pilha a descrição do erro. Em caso de
 *    sucesso o valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _getProcessParentPid( lua_State *L )
{
   // Recebe "idade" máxima para dados de processos
   double MaxOld = lua_tonumber( L , 2 ) ;

   // Teste para saber se é necessário atualizar dados de processos
   if( NeedToRefresh( MaxOld ) == TRUE )
   {
      if ( RefreshAllProcessesInfo( L ) == 0 )
      {
         lua_pushnil( L ) ;
         lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
         return 2 ;
      }
   }

   // Procura pelo PPID do processo e retorna
   if ( lua_isuserdata( L, 1 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , 1 ) ;

      DWORD PID = CommandHandle->pid ;

      // Procura no índice de processos
      MapProcess::const_iterator iter = Processes.index.find(PID) ;
      if( iter != Processes.index.end() )
      {
         lua_pushnumber( L , Processes.aProcessData[ iter->second ].PPID ) ;
         lua_pushnil( L ) ;
         return 2 ;
      }

      // Processo não está rodando
      lua_pushnil( L ) ;
      lua_pushstring( L , "Processo terminado.\0" ) ;
      return 2 ;
   }
   else
   {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Handle de comando invalido\0" ) ;
      return 2 ;
   }
}

/******************************************************************
 *
 *   Função _retrievecommandhandle
 *      Função utilizada para criar um handle a partir de dados
 *    persistentes do processo. Função registrada como
 *    retrievecommandhandle na tabela servermanager, global no
 *    ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - pdata:
 *   Tipo: tabela
 *   Descrição: Esta função pega na pilha de LUA a tabela criada
 *              pela função _getcommandpersistentdata
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    um handle para o comando. Em caso de erro, o valor retornado
 *    é nil e é inserida na pilha a descrição do erro. Em caso de
 *    sucesso o valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _retrievecommandhandle( lua_State * L )
{
  DWORD pid ;
  HANDLE hProcess ;
  PCOMMAND ProcessData ;
  FILETIME ftCreation ;
  FILETIME dummy ;
  FILETIME auxTime ;
  if( lua_istable( L , 1 ) )
  {
    lua_rawgeti ( L, 1 , 1 ) ;
    pid = (DWORD) lua_tonumber( L , - 1 ) ;
    lua_rawgeti ( L, 1 , 2 ) ;
    auxTime.dwLowDateTime =  (unsigned long)lua_tonumber( L , -1 ) ;
    lua_rawgeti ( L, 1 , 3 ) ;
    auxTime.dwHighDateTime =  (unsigned long)lua_tonumber( L , -1 ) ;

    hProcess = OpenProcess( PROCESS_ALL_ACCESS , FALSE , pid ) ;
    if( !hProcess )
    {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Falha ao recuperar handle para o processo.\0" ) ;
      return 2 ;
    }

    if ( GetProcessTimes( hProcess , &ftCreation , &dummy , &dummy , &dummy ) == TRUE )
    {
      if( (auxTime.dwHighDateTime == ftCreation.dwHighDateTime) &&
          (auxTime.dwLowDateTime == ftCreation.dwLowDateTime))
      {
        //Sem erros, retorna o handle
        // Desaloca em releasecommandinfo
        ProcessData = ( PCOMMAND ) malloc( sizeof( COMMAND ) ) ;
        if (ProcessData == NULL) {
           lua_pushnil( L ) ;
           lua_pushstring( L , "Falha ao alocar memória para novo handle.\0" ) ;
           return 2 ;
        }
        ProcessData->pid = pid ;
        ProcessData->CommandId = NULL;
        ProcessData->hStdIn = NULL;
        ProcessData->hStdOut = NULL;
        ProcessData->hStdError = NULL;
        ProcessData->hName = NULL ;
        ProcessData->hProcess = hProcess ;
        lua_pushlightuserdata( L , ( void * ) ProcessData ) ;
        lua_pushnil( L ) ;
        return 2 ;
      }
      else
      {
        lua_pushnil( L ) ;
        lua_pushstring( L , "Processos diferem na criacao.\0" ) ;
        return 2 ;
      }
    }
    else
    {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Erro ao recuperar data de criacao do processo.\0" ) ;
      return 2 ;
    }
  }
  else
  {
    lua_pushnil( L ) ;
    lua_pushstring( L , "Tabela invalida para recuperar handle.\0" ) ;
    return 2 ;
  }
}

/******************************************************************
 *
 *   Função _getcommandpersistentdata
 *      Função utilizada para guardar dados de um processo cujo
 *    o handle é passado na pilha como parâmetro. Com estes dados,
 *    deve ser possível se refazer o handle do comando. Esta  função
 *    é registrada como getcommandpersistentdata na tabela
 *    servermanager, global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    uma tabela com os campos pid e data de criação. Em caso de erro,
 *    o valor retornado é nil e é inserida na pilha a descrição do
 *    erro. Em caso de sucesso o valor de erro nil é inserido na
 *    pilha.
 *
 ******************************************************************/

static int _getcommandpersistentdata( lua_State *L )
{
   DWORD pid ;
   HANDLE pHandle ;
   FILETIME ftCreation ;
   FILETIME dummy ;

   // Procura pelo uso de memória do processo e retorna
   if ( lua_isuserdata( L, 1 ) )
   {
      // Pega o Handle do comando na pilha
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , 1 ) ;

      pid = CommandHandle->pid ;
      pHandle = CommandHandle->hProcess ;

      if ( GetProcessTimes( pHandle , &ftCreation , &dummy , &dummy , &dummy ) == TRUE )
      {
        //Sem erros, retorna a tabela
        lua_newtable( L ) ;
        lua_pushnumber( L , 1 ) ;
        lua_pushnumber( L , pid ) ;
        lua_rawset( L , - 3 ) ;
        lua_pushnumber( L , 2 ) ;
        lua_pushnumber( L , ftCreation.dwLowDateTime ) ;
        lua_rawset( L , - 3 ) ;
        lua_pushnumber( L , 3 ) ;
        lua_pushnumber( L , ftCreation.dwHighDateTime ) ;
        lua_rawset( L , - 3 ) ;
        lua_pushnil( L ) ;
        return 2 ;
      }
      else
      {
        lua_pushnil( L ) ;
        lua_pushstring( L , "Falha ao obter data de criacao do processo.\0" ) ;
        return 2 ;
      }
   }
   else
   {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Handle de comando inválido.\0" ) ;
      return 2 ;
   }
}

/******************************************************************
 *
 *   Função setStartupHandles
 *      Função utilizada para abrir os arquivos que redefinem as
 *    saídas e entrada padrão de um processo e preencher os respectivos
 *    campos na estrutura STARTUPINFO.
 *
 *   Parâmetros:
 * -  si:
 *    Tipo: STARTUPINFO*
 *    Descrição: Estrutura que informa os dados para inicialização
 *               do novo processo.
 * - inFileName:
 *   Tipo: string
 *   Descrição: Nome do arquivo que redefine a entrada padrão do
 *              processo. Pode conter NULL ou "\0".
 *
 * - outFileName:
 *   Tipo: string
 *   Descrição: Nome do arquivo que redefine a saída padrão do
 *              processo. Pode conter NULL ou "\0".
 *
 * - errorFileName:
 *   Tipo: string
 *   Descrição: Nome do arquivo que redefine a saída de erro do
 *              processo. Pode conter NULL ou "\0".
 *
 *   Valor de retorno:
 *   -  Em caso de erro, uma string com mensagem indicativa do erro.
 *      Em caso de sucesso, NULL.
 *
 ******************************************************************/

static char* setStartupHandles (STARTUPINFO *si, const char *inFileName,
  const char *outFileName, const char *errorFileName ) {

  HANDLE hInFile = GetStdHandle(STD_INPUT_HANDLE) ;
  HANDLE hOutFile = GetStdHandle(STD_OUTPUT_HANDLE) ;
  HANDLE hErrorFile = GetStdHandle(STD_ERROR_HANDLE) ;
  SECURITY_ATTRIBUTES fileHandlesSecurity ;
  fileHandlesSecurity.bInheritHandle = TRUE ;
  fileHandlesSecurity.lpSecurityDescriptor = NULL ;
  fileHandlesSecurity.nLength = sizeof( SECURITY_ATTRIBUTES ) ;

  if (( inFileName != NULL ) && ( strlen( inFileName ) > 0 )) {
    hInFile = CreateFile( inFileName , // Nome do arquivo
      FILE_WRITE_DATA | FILE_READ_DATA , // Permissões de
      FILE_SHARE_READ | FILE_SHARE_WRITE , // Permissões d
      &fileHandlesSecurity , // Security, com herança de h
      OPEN_EXISTING , // Abre um arquivo existente
      FILE_ATTRIBUTE_NORMAL , // Atributos do arquivo
      NULL // Template
      ) ;
    if( hInFile == INVALID_HANDLE_VALUE )
    {
      printf("Could not open %s file, error %d\n", inFileName, GetLastError());
      return "Erro ao abrir arquivo de Input para o comando."
        " Comando Abortado.\0" ;
    }
   }

   if ( ( outFileName != NULL ) && ( strlen( outFileName ) > 0 ) ) {
      hOutFile = CreateFile( outFileName , // Nome do arquivo
                             FILE_WRITE_DATA | FILE_READ_DATA , // Permissões de
                             FILE_SHARE_READ | FILE_SHARE_WRITE , // Permissões d
                             &fileHandlesSecurity , // Security, com herança de h
                             CREATE_ALWAYS , // Abre um arquivo existente
                             FILE_ATTRIBUTE_NORMAL , // Atributos do arquivo
                             NULL // Template
                            ) ;
      if( hOutFile == INVALID_HANDLE_VALUE )
      {
        printf("Could not open %s file, error %d\n", outFileName, GetLastError());
        return "Erro ao abrir arquivo de Output para o comando."
          " Comando Abortado.\0" ;
      }
   }

   if ( ( errorFileName != NULL ) && ( strlen( errorFileName ) > 0 ) ) {
      if ( ( outFileName == NULL ) ||
        (strcmp( errorFileName , outFileName ) != 0 ))
        {
        hErrorFile = CreateFile( errorFileName , // Nome do arquivo
                            FILE_WRITE_DATA | FILE_READ_DATA , // Permissões de
                            FILE_SHARE_READ | FILE_SHARE_WRITE , // Permissões d
                            &fileHandlesSecurity , // Security, com herança de h
                            CREATE_ALWAYS , // Abre um arquivo existente
                            FILE_ATTRIBUTE_NORMAL , // Atributos do arquivo
                            NULL // Template
                          ) ;
hErrorFile = INVALID_HANDLE_VALUE;
       if( hErrorFile == INVALID_HANDLE_VALUE )
       {
         printf("Could not open %s file, error %d\n", errorFileName, GetLastError());
         return "Erro ao abrir arquivo de Error para o comando."
                            " Comando Abortado.\0" ;
       }
     }
     else {
       hErrorFile = hOutFile ;
     }
  }

  si->hStdOutput = hOutFile ;
  si->hStdInput = hInFile ;
  si->hStdError = hErrorFile ;
  return NULL;
}

/******************************************************************
 *
 *   Função _luaCreateProcess
 *    Função utilizada para recuperar o status de um processo cujo
 *    o handle é passado na pilha como parâmetro. Esta  função é
 *    registrada como executecommand na tabela servermanager,
 *    global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - id:
 *   Tipo: string
 *   Descrição: Esta função pega na pilha de LUA a string que
 *              identifica o comando a ser executado
 * - command:
 *   Tipo: string
 *   Descrição: Esta função pega na pilha de LUA a linha de
 *              comando a ser executada.
 * - infile:
 *   Tipo: string
 *   Descrição: Esta função pega na pilha de LUA o nome do arquivo
 *              de input para o processo. Caso este arquivo seja
 *              inexistente, o processo não é disparado e este erro
 *              é retornado na pilha.
 * - outfile:
 *   Tipo: string
 *   Descrição: Esta função pega na pilha de LUA o nome do arquivo
 *              de output para o processo. Caso este arquivo exista,
 *              a função sobrescreve este arquivo. Caso não consiga
 *              criar o arquivo, este erro é retornado na pilha.
 * - errorfile:
 *   Tipo: string
 *   Descrição: Esta função pega na pilha de LUA o nome do arquivo
 *              de output de erro para o processo. Caso este arquivo
 *              exista, a função sobrescreve este arquivo. Caso não
 *              consiga criar o arquivo, este erro é retornado na pilha.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o status do comando. Este status pode possuir o valor RUNNING
 *    ou FINISHED. Em caso de erro, o valor retornado é nil e é
 *    inserida na pilha a descrição do erro. Em caso de sucesso o
 *    valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _luaCreateProcess( lua_State * L )
{
  char* BashPattern;
  char* BashCommandLine;
  LPCTSTR CommandId = NULL;
  LPCTSTR CommandLine = NULL ;
  LPCTSTR inFileName = NULL ;
  LPCTSTR outFileName = NULL ;
  LPCTSTR errorFileName = NULL ;
  LPCTSTR Error = NULL ;
  HANDLE hName = NULL ;
  BOOL defFiles = FALSE ;
  int  countFiles = 0;

  // Settings de segurança para redirecionamento de I/O
  SECURITY_ATTRIBUTES processHandlesSecurity ;
  processHandlesSecurity.bInheritHandle = TRUE ;
  processHandlesSecurity.lpSecurityDescriptor = NULL ;
  processHandlesSecurity.nLength = sizeof( SECURITY_ATTRIBUTES ) ;

  SECURITY_ATTRIBUTES threadHandlesSecurity ;
  threadHandlesSecurity.bInheritHandle = TRUE ;
  threadHandlesSecurity.lpSecurityDescriptor = NULL ;
  threadHandlesSecurity.nLength = sizeof( SECURITY_ATTRIBUTES ) ;

  if ( lua_isstring( L , 1 ) )
  {
    CommandId = lua_tostring( L , 1 ) ;
  }
  else
  {
    lua_pushnil( L ) ;
    lua_pushstring( L , "Identificador de comando não fornecido.\0" ) ;
    return 2 ;
  }
  if ( lua_isstring( L , 2 ) )
  {
    CommandLine = lua_tostring( L , 2 ) ;
  }
  else
  {
    lua_pushnil( L ) ;
    lua_pushstring( L , "Linha de comando não fornecida.\0" ) ;
    return 2 ;
  }
  if ( lua_isstring( L , 3 ) )
  {
    countFiles++;
    inFileName = lua_tostring( L , 3 ) ;
  }
  if ( lua_isstring( L , 4 ) )
  {
    countFiles++;
    outFileName = lua_tostring( L , 4 ) ;
    if (countFiles == 1)
      inFileName = "\0";
  }
  else if (countFiles == 1) {
    outFileName = "\0";
  }
  if ( lua_isstring( L , 5) )
  {
    countFiles++;
    errorFileName = lua_tostring( L , 5) ;
    if (countFiles == 1) {
      inFileName = "\0";
      outFileName = "\0";
    }
  }
  else if (countFiles > 0) {
    errorFileName = "\0";
  }
  if ( lua_isstring( L , 6) )
  {
    hName = (HANDLE) lua_tostring( L , 6) ;
  }

  STARTUPINFO si;
  PROCESS_INFORMATION pi;
  ZeroMemory(&si, sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO);

  if ( ( countFiles > 0 ) && ( countFiles < 3 ) ) {
    /* Não é possível trocar apenas um dos handles default, quando
     * queremos abrir um novo console para a execução do processo que
     * será criado. Por isso, precisamos criar um processo auxiliar
     * que abre a nova console e cria então o processo que realmente
     * desejamos, redefinindo apenas alguns handles dessa nova console.
     */
    BashPattern = "startcmd '%s' '%s' '%s' '%s'" ;
    BashCommandLine = (char*) malloc( sizeof(char) * (strlen(BashPattern) +
      strlen(CommandLine) + strlen(inFileName) + strlen(outFileName) +
      strlen(errorFileName) + 1));
    if (BashCommandLine == NULL) {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Erro ao criar commando para execução.\0" ) ;
      return 2 ;
   }
    sprintf(BashCommandLine, BashPattern, CommandLine, inFileName,
      outFileName, errorFileName);
  }
  else {
    /* Podemos disparar o processo que desejamos diretamente, sem
     * redefinir nenhum handle ou redefinindo os três.
     */
    BashPattern = "bash -c '%s'" ;
    BashCommandLine = (char*) malloc( sizeof(char) * (strlen(BashPattern) +
                                    strlen(CommandLine) + 1));
    if (BashCommandLine == NULL) {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Erro ao criar commando para execução.\0" ) ;
      return 2 ;
    }
    sprintf(BashCommandLine, BashPattern, CommandLine);

    if ( countFiles == 3 ) {
      defFiles = TRUE ;
      si.dwFlags = STARTF_USESTDHANDLES ;
      Error = setStartupHandles( &si, inFileName, outFileName, errorFileName);
      if ( Error ) {
        lua_pushnil( L ) ;
        lua_pushstring( L , Error) ;
        return 2 ;
      }
    }
  }

  if ( CreateProcess( NULL , // Application name, não condiz com linha de comando
                      (LPSTR)BashCommandLine , // Linha de comando a ser executada
                      &processHandlesSecurity , // Com herança de handles de processo
                      &threadHandlesSecurity  , // Com herança de handles de Threads
                      defFiles , // Com herança de handles "herdáveis"
                      CREATE_NEW_CONSOLE , // Flags de criação
                      NULL , // Flags de Ambiente
                      NULL , // Diretório da aplicação
                      &si , // Dados para inicialização de processos
                      &pi // Estrutura a ser preenchida com handles e ids do processo e main thread
                    ) == TRUE )
  {
    // Onde devemos fazer o free??
    free(BashCommandLine);
    // REFRESH!!
    if ( RefreshAllProcessesInfo( L ) == 0 )
    {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
      return 2 ;
    }
    PCOMMAND ProcessData = ( PCOMMAND ) malloc( sizeof( COMMAND ) ) ; // Desaloca em releasecommandinfo
    if (ProcessData == NULL) {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Sem memória para criar handle" ) ;
      return 2 ;
    }
    ProcessData->hStdIn = si.hStdInput ;
    ProcessData->hStdOut = si.hStdOutput ;
    ProcessData->hStdError = si.hStdError ;
    ProcessData->hProcess = pi.hProcess ;
    ProcessData->hName = hName ;
    ProcessData->CommandId = CommandId ;
    ProcessData->pid = pi.dwProcessId ;
    lua_pushlightuserdata( L , ( void * ) ProcessData ) ;
    lua_pushnil( L ) ;
    return 2 ;
  }
  else
  {
    printf("Could not create process %s, error %d\n", BashCommandLine, GetLastError());
    // Onde devemos fazer o free??
    free(BashCommandLine);
    lua_pushnil( L ) ;
    lua_pushstring( L , "Erro ao criar processo\0" ) ;
    return 2 ;
  }
}

/******************************************************************
 *
 *   Função _getCommandId
 *    Função utilizada para recuperar o ID de um comando
 *    disparado pelo programa. Esta  função é registrada como
 *    getcommandid na tabela servermanager, global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o ID do processo em questão.
 *
 ******************************************************************/

static int _getCommandId( lua_State * L )
{
  if ( lua_isuserdata( L, 1 ) )
  {

    PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , 1 ) ;
    if (CommandHandle->CommandId == NULL) {
      lua_pushnil( L );
      lua_pushstring( L , "Id de comando inválido (nulo).\0" ) ;
    }
    else {
      lua_pushstring( L , CommandHandle->CommandId);
      lua_pushnil( L ) ;
    }

    return 2 ;
  }
  else
  {
    lua_pushnil( L ) ;
    lua_pushstring( L , "Handle de comando inválido.\0" ) ;
    return 2 ;
  }
}

/******************************************************************
 *
 *   Função _getProcessPid
 *    Função utilizada para recuperar o PID de uma processo
 *    disparado pelo programa. Esta  função é registrada como
 *    getcommandpid na tabela servermanager, global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    o PID do processo em questão.
 *
 ******************************************************************/

static int _getProcessPid( lua_State * L )
{
  if ( lua_isuserdata( L, 1 ) )
  {

    PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , 1 ) ;
    lua_pushnumber( L , CommandHandle->pid);
    lua_pushnil( L ) ;
    return 2 ;
  }
  else
  {
    lua_pushnil( L ) ;
    lua_pushstring( L , "Handle de comando inválido.\0" ) ;
    return 2 ;
  }
}


/******************************************************************
 *
 *   Função _kill
 *    Função utilizada para recuperar o status de um processo cujo
 *    o handle é passado na pilha como parâmetro. Esta  função é
 *    registrada como killcommand na tabela servermanager, global
 *    no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 *
 *   Valor de retorno:
 *   -  Em caso de sucesso, retorna ok = 1 e error = nil. Em caso de
 *    erro retorna ok = nil e error = descrição do erro na função.
 *
 ******************************************************************/

static int _kill( lua_State *L )
{
   DWORD* procs = NULL;
   unsigned long nProcs = 0 ;
   unsigned long i = 0;
   BOOL retVal = TRUE ;
   HANDLE hProcess ;

   if ( lua_isuserdata( L, 1 ) )
   {
      PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , 1 ) ;

      if ( RefreshAllProcessesInfo( L ) == 0 )
      {
        lua_pushnil( L ) ;
        lua_pushstring( L , "Falha ao atualizar dados de processos.\0" ) ;
        return 2 ;
      }

      // Finaliza os processos
      if( _getProcessesByPID( L, CommandHandle->pid, &procs, &nProcs ) ) {
         for( i = 0 ; i < nProcs ; i++ ) {
            hProcess = OpenProcess( PROCESS_ALL_ACCESS , FALSE , procs[i] );
            retVal = retVal & TerminateProcess( hProcess , 0 ); //verdadeiro caso tenha sucesso
            CloseHandle( hProcess );
         }

         if( nProcs > 0 ) {
            free( procs );
         }

         if( retVal ) {
            lua_pushboolean( L, 1 );
            return 1;
         }
      }

      lua_pushnil( L );
      lua_pushstring( L , "Falha ao finalizar um ou mais processos." );
      return 2;
   }

   lua_pushnil( L );
   lua_pushstring( L , "Handle de comando inválido." );
   return 2 ;
}

/******************************************************************
 *
 *   Função _releasecommandinfo
 *    Função utilizada para liberar recursos alocados no disparo
 *    de um comando. Esta  função é registrada como
 *    releasecommandinfo na tabela servermanager, global no ambiente
 *    LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - Handle:
 *   Tipo: userdata
 *   Descrição: Esta função pega na pilha de LUA o Handle para o
 *              comando que é o mesmo criado quando o processo é
 *              disparado.
 *
 *   Valor de retorno:
 *   -  Em caso de sucesso, retorna ok = 1 e error = nil. Em caso de
 *    erro retorna ok = nil e error = descrição do erro na função.
 *
 ******************************************************************/

static int _releasecommandinfo( lua_State * L )
{
  if ( lua_isuserdata( L, -1 ) )
  {
    PCOMMAND CommandHandle = ( PCOMMAND ) lua_touserdata( L , -1 ) ;
    if( CommandHandle )
    {
      CloseHandle( CommandHandle->hProcess ) ;
      if ( CommandHandle->hStdIn != NULL ) {
        CloseHandle( CommandHandle->hStdIn ) ;
      }
      if ( CommandHandle->hStdOut != NULL ) {
        CloseHandle( CommandHandle->hStdOut ) ;
      }
      if ( CommandHandle->hStdError != NULL ) {
        CloseHandle( CommandHandle->hStdError ) ;
      }
      free( CommandHandle ) ;
      lua_pushnumber( L , 1.0 ) ;
      lua_pushnil( L ) ;
      return 2 ;
    }
    else
    {
      lua_pushnil( L ) ;
      lua_pushstring( L , "Handle de comando inválido\0" ) ;
      return 2 ;
    }
  }
  else
  {
    lua_pushnil( L ) ;
    lua_pushstring( L , "Handle de comando inválido\0" ) ;
    return 2 ;
  }
}

/*****************************************************************
 *
 * Funções utilizadas para monitorar desempenho da máquina.
 *
 *****************************************************************/

/******************************************************************
 *
 *   Função _getCpuUsage
 *    Função utilizada para recuperar o uso de CPU entre 2 chamadas
 *    à esta função. Caso o intervalo de tempo seja menor do que 10s
 *    a função não recalcula o valor e retorna novamente o uso de
 *    CPU calculado anteriormente. Esta  função é registrada como
 *    getcpuload na tabela servermanager, global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - MaxOld:
 *   Tipo: number
 *   Descrição: Tempo máximo que a informação pode ter.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    a carga de cpu na máquina. Em caso de erro, o valor
 *    retornado é nil e é inserida na pilha a descrição do erro.
 *    Em caso de sucesso o valor de erro nil é inserido na pilha.
 *
 ******************************************************************/

static int _getCpuUsage( lua_State * L )
{
  static bool bFirstTime = true;
  static DWORD lnOldValue = 0;
  static LARGE_INTEGER OldPerfTime100nSec = {0};
  static PLATFORM Platform = GetPlatform();
  static double CpuUsage = 0.0 ;

  // Teste para checar se informação precisa ser atualizada
  double MaxOld = lua_tonumber( L , - 1 ) ;

  FILETIME now ;
  GetSystemTimeAsFileTime( &now ) ;

  LARGE_INTEGER aux ;
  aux.LowPart = now.dwLowDateTime ;
  aux.HighPart = now.dwHighDateTime ;

  double NewTimeStamp = ( double ) aux.QuadPart ;
  double CpuLoadAge = ( NewTimeStamp - ( ( double ) OldPerfTime100nSec.QuadPart ) ) / NS_TO_S ;

  if( CpuLoadAge <= MaxOld )
  {
    lua_pushnumber( L , CpuUsage ) ;
    lua_pushnil( L ) ;
    return 2 ;
  }

  PPERF_DATA_BLOCK PerfData = QueryPerformanceData( ) ;
  if (PerfData == NULL) {
    lua_pushnil( L ) ;
    lua_pushstring( L ,"Não foi possível obter dados sobre o processo.\0" ) ;
    return 2;
  }

  char szInstance[256] = {0};

  // Há uma diferença entre os contadores no Windows XP/2k e NT, segundo o artigo
  // Q259390 no MSDN. Por isso é necessário saber qual o sistema operacional.

  unsigned long dwObjectIndex;
  unsigned long dwCpuUsageIndex;
  switch (Platform)
  {
  case WINNT:
    dwObjectIndex = SYSTEM_OBJECT_INDEX;
    dwCpuUsageIndex = TOTAL_PROCESSOR_TIME_COUNTER_INDEX;
    break;
  case WIN2K_XP:
    dwObjectIndex = PROCESSOR_OBJECT_INDEX;
    dwCpuUsageIndex = PROCESSOR_TIME_COUNTER_INDEX;
    strcpy(szInstance,"_Total");
    break;
  default:
    free( PerfData ) ;
    lua_pushnil( L ) ;
    lua_pushstring( L ,"SGA sem suporte à plataforma.\0" ) ;
    return 2;
  }

  LARGE_INTEGER   NewPerfTime100nSec = {0} ;
  NewPerfTime100nSec = PerfData->PerfTime100nSec ;
  DWORD lnNewValue ;
  lnNewValue = GetCounterValue( PerfData, dwObjectIndex, dwCpuUsageIndex, szInstance ) ;

  // Teste para saber se é a primeira chamada à função
  if (bFirstTime)
  {
    bFirstTime = false;
    lnOldValue = lnNewValue;
    OldPerfTime100nSec = NewPerfTime100nSec;
    free(PerfData);
    lua_pushnil( L ) ;
    lua_pushstring( L ,"Mínimo de duas chamadas necessárias para cálculo. Próxima chamada retornará valor correto.\0" ) ;
    return 2;
  }

  double DeltaPerfTime100nSec =
    (double) ( NewPerfTime100nSec.QuadPart - OldPerfTime100nSec.QuadPart ) ;

  LONGLONG lnValueDelta = lnNewValue - lnOldValue ;

  lnOldValue = lnNewValue ;
  OldPerfTime100nSec = NewPerfTime100nSec ;

  CpuUsage = (double)lnValueDelta / DeltaPerfTime100nSec ;

  CpuUsage = ( 1.0 - CpuUsage ) * 100.0 ;
  if ( CpuUsage < 0.0 )
  {
    lua_pushnumber( L , 0 ) ;
    lua_pushnil( L ) ;
    free(PerfData) ;
    return 2 ;
  }
  else
  {
    lua_pushnumber( L , CpuUsage ) ;
    lua_pushnil( L ) ;
    free(PerfData) ;
    return 2 ;
  }
}

/******************************************************************
 *
 *   Função _getMemoryUsage
 *    Função utilizada para recuperar o uso de memória na máquina.
 *    Esta  função é registrada como getmemoryload na tabela
 *    servermanager, global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 * - MaxOld:
 *   Tipo: number
 *   Descrição: Tempo máximo que a informação pode ter. Não é
 *              utilizado nesta função.
 *
 *   Valor de retorno:
 *   -  A função retorna, na pilha do state passado como parâmetro,
 *    uma tabela na qual o campo ram é o valor de memória física
 *    em uso e o campo swap é o tamanho de memória swap em uso.
 *    Também é inserido na pilha o valor nil, que é a descrição do
 *    erro. A API do Windows não retorna erros para esta função.
 *
 ******************************************************************/

static int _getMemoryUsage( lua_State * L )
{
  MEMORYSTATUSEX MemStatus ;
  MemStatus.dwLength = sizeof(MemStatus);
  GlobalMemoryStatusEx( &MemStatus ) ;
  DWORDLONG PhysicalMem = MemStatus.ullTotalPhys - MemStatus.ullAvailPhys ;
  DWORDLONG SwapMem = MemStatus.ullTotalPageFile - MemStatus.ullAvailPageFile ;
  lua_newtable( L ) ;
  lua_pushstring( L , "swap\0" ) ;
  lua_pushnumber( L , (lua_Number) SwapMem ) ;
  lua_rawset( L , - 3 ) ;
  lua_pushstring( L , "ram\0" ) ;
  lua_pushnumber( L , (lua_Number) PhysicalMem ) ;
  lua_rawset( L , - 3 ) ;
  lua_pushnil( L ) ;
  return 2 ;
}

/******************************************************************
 *
 *   Função _sleep
 *    Função utilizada para fazer o sga dormir. Esta  função é
 *    registrada como getmemoryload na tabela servermanager, global
 *    no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 *
 *   Valor de retorno:
 *   -  A função não retorna valores.
 *
 ******************************************************************/

static int _sleep( lua_State * L )
{
  double dtime = lua_tonumber(L, -1 );
  DWORD time = (DWORD) (dtime * 1000);
  Sleep( time );
  return 0;
}

/******************************************************************
 *
 *   Função _now
 *    Função utilizada para saber data do sistema, em segundos.
 *    Esta  função é registrada como now na tabela servermanager,
 *    global no ambiente LUA.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 *
 *   Valor de retorno:
 *   -  Retorna number contendo a data do sistema em segundos.
 *
 ******************************************************************/

static int _now( lua_State * L )
{
  FILETIME now ;
  GetSystemTimeAsFileTime( &now ) ;

  LARGE_INTEGER aux ;
  aux.LowPart = now.dwLowDateTime ;
  aux.HighPart = now.dwHighDateTime ;

  double DateInSeconds = ( double ) aux.QuadPart / NS_TO_S ;
  lua_pushnumber( L , DateInSeconds ) ;
  return 1 ;
}

/**
 * Função _setHistoric
 *  Configura a variável que alimenta o histórico de execução dos algoritmos.
 *
 * Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 *
 * Valor de retorno:
 *  0 : Sucesso
 *  1 : Erro
 */
static int _setHistoric( lua_State * L )
{
  enableHistoric = lua_toboolean(L, -1 );

  return 1;
}

/**
 * Função _getHistoric
 *  Obtém a variável que alimenta o histórico de execução dos algoritmos.
 *
 * Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: Como esta função é exportada para lua na tabela
 *               severmanager, é necessário saber qual o State.
 *
 * Valor de retorno:
 * 0 : Sucesso
 * 1 : Erro
 */
static int _getHistoric( lua_State * L )
{
  // Exportação para a pilha de LUA
  lua_pushboolean( L , enableHistoric ) ;

  return 1 ;
}

/******************************************************************
 *
 *   Função luaopen_sga
 *    Função utilizada para registrar a tabela servermanager.
 *
 *   Parâmetros:
 * -  L:
 *    Tipo: lua_State
 *    Descrição: State no qual a tabela será registrada.
 *
 *   Valor de retorno:
 *   -  A função não retorna valores.
 *
 ******************************************************************/

int luaopen_sga( lua_State * L )
{
  // Inicializa Controle de processos
  Processes.TimeStamp = 0 ;
  Processes.currCPU = &Processes.cpu1;
  Processes.oldCPU = &Processes.cpu2;

  // Guarda estado da pilha para restaurá-la
  int StackState = lua_gettop( L ) ;

  // Cria uma tabela para conter as funções
  lua_newtable( L ) ;

  // Adiciona os métodos a esta tabela
  lua_pushstring( L , "getnumcpus\0" ) ;
  lua_pushcfunction( L , _getNumberOfCpus ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getmemory\0" ) ;
  lua_pushcfunction( L , _getStaticMemoryInfo ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getbyteorder\0" ) ;
  lua_pushcfunction( L , _getByteOrderType ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcpuload\0" ) ;
  lua_pushcfunction( L , _getCpuUsage ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getmemoryload\0" ) ;
  lua_pushcfunction( L , _getMemoryUsage ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "executecommand\0" ) ;
  lua_pushcfunction( L , _luaCreateProcess ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandpersistentdata\0" ) ;
  lua_pushcfunction( L , _getcommandpersistentdata ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandPPID\0" ) ;
  lua_pushcfunction( L , _getProcessParentPid ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "retrievecommandhandle\0" ) ;
  lua_pushcfunction( L , _retrievecommandhandle ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandstatus\0" ) ;
  lua_pushcfunction( L , _getProcessStatus ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandexechost\0" ) ;
  lua_pushcfunction( L , _getProcessExecHost ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandcpuload\0" ) ;
  lua_pushcfunction( L , _getProcessCpuLoad ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandmemoryload\0" ) ;
  lua_pushcfunction( L , _getProcessMemoryLoad ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandtimeusage\0" ) ;
  lua_pushcfunction( L , _getProcessTimes ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandid\0" ) ;
  lua_pushcfunction( L , _getCommandId ) ;
  lua_rawset( L , - 3 ) ;

  lua_pushstring( L , "getcommandpid\0" ) ;
  lua_pushcfunction( L , _getProcessPid ) ;
  lua_rawset( L , - 3 ) ;

  lua_pushstring( L , "killcommand\0" ) ;
  lua_pushcfunction( L , _kill ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "releasecommandinfo\0" ) ;
  lua_pushcfunction( L , _releasecommandinfo ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getcommandallinfo\0" ) ;
  lua_pushcfunction( L , _getCommandAllInfo ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getjobsinfo\0" ) ;
  lua_pushcfunction( L , _getJobsInfo ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getnumberofjobs\0" ) ;
  lua_pushcfunction( L , _getNumberOfJobs ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "sleep\0" ) ;
  lua_pushcfunction( L , _sleep ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "now\0" ) ;
  lua_pushcfunction( L , _now ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "open\0" ) ;
  lua_pushcfunction( L , _open ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "close\0" ) ;
  lua_pushcfunction( L , _close ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "setHistoric\0" ) ;
  lua_pushcfunction( L , _setHistoric ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "getHistoric\0" ) ;
  lua_pushcfunction( L , _getHistoric ) ;
  lua_rawset( L , -3 ) ;

  // Adiciona as constantes a esta tabela
  lua_pushstring( L , "RUNNING\0" ) ;
  lua_pushnumber( L , RUNNING ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "NOT_RESPONDING\0" ) ;
  lua_pushnumber( L , NOT_RESPONDING ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "WAITING\0" ) ;
  lua_pushnumber( L , WAITING ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "FINISHED\0" ) ;
  lua_pushnumber( L , FINISHED ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "LITTLE_ENDIAN\0" ) ;
  lua_pushnumber( L , LITTLE_ENDIAN ) ;
  lua_rawset( L , -3 ) ;

  lua_pushstring( L , "BIG_ENDIAN\0" ) ;
  lua_pushnumber( L , BIG_ENDIAN ) ;
  lua_rawset( L , -3 ) ;

  // Pega a tabela da pilha, já preenchida, e a adiciona
  // à tabela de globais sobre o nome de servermanager.
  lua_setglobal( L , "servermanager\0" ) ;

  // Ajuste de uma variável global para ajustar o pid do próprio sga-daemon
  int sga_pid = GetCurrentProcessId();
  lua_pushnumber(L, sga_pid);
  lua_setglobal(L, "SGA_PID\0");

  // Salva o número de CPUs
  SYSTEM_INFO SysInfo;
  GetSystemInfo( &SysInfo );
  numberOfCpus = SysInfo.dwNumberOfProcessors;

  // Carrega funções auxiliares
  sga_require(L, "lib.Windows");

  // Restaura estado da pilha
  lua_settop( L , StackState ) ;

  return 0;
}
