|
|
|
@ -32,6 +32,8 @@ static void OnDisconnect(struct etcpmon_app* app); |
|
|
|
static void OnConnectionSelect(struct etcpmon_app* app); |
|
|
|
static void OnConnectionSelect(struct etcpmon_app* app); |
|
|
|
static void OnTimer(struct etcpmon_app* app); |
|
|
|
static void OnTimer(struct etcpmon_app* app); |
|
|
|
static void UpdateUIState(struct etcpmon_app* app); |
|
|
|
static void UpdateUIState(struct etcpmon_app* app); |
|
|
|
|
|
|
|
static void AddTooltip(HWND hTip, HWND hCtrl, const char* text); |
|
|
|
|
|
|
|
static void CreateTooltips(struct etcpmon_app* app); |
|
|
|
/* Callback functions for client events */ |
|
|
|
/* Callback functions for client events */ |
|
|
|
static void on_connected(void* user_data); |
|
|
|
static void on_connected(void* user_data); |
|
|
|
static void on_disconnected(void* user_data); |
|
|
|
static void on_disconnected(void* user_data); |
|
|
|
@ -139,7 +141,8 @@ HWND etcpmon_gui_create_window(struct etcpmon_app* app) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CreateControls(app); |
|
|
|
CreateControls(app); |
|
|
|
|
|
|
|
CreateTooltips(app); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { |
|
|
|
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { |
|
|
|
app->hGraphPens[i] = CreatePen(PS_SOLID, 2, graph_colors[i]); |
|
|
|
app->hGraphPens[i] = CreatePen(PS_SOLID, 2, graph_colors[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -695,6 +698,205 @@ static void CreateControls(struct etcpmon_app* app) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void AddTooltip(HWND hTip, HWND hCtrl, const char* text) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!hTip || !hCtrl || !text) return; |
|
|
|
|
|
|
|
TOOLINFOA ti; |
|
|
|
|
|
|
|
memset(&ti, 0, sizeof(ti)); |
|
|
|
|
|
|
|
ti.cbSize = sizeof(ti); |
|
|
|
|
|
|
|
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; |
|
|
|
|
|
|
|
ti.hwnd = GetParent(hCtrl); |
|
|
|
|
|
|
|
ti.uId = (UINT_PTR)hCtrl; |
|
|
|
|
|
|
|
ti.lpszText = (LPSTR)text; |
|
|
|
|
|
|
|
SendMessageA(hTip, TTM_ADDTOOL, 0, (LPARAM)&ti); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
static void CreateTooltips(struct etcpmon_app* app) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!app || !app->hWndMain) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app->hToolTip = CreateWindowExA( |
|
|
|
|
|
|
|
WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL, |
|
|
|
|
|
|
|
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, |
|
|
|
|
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, |
|
|
|
|
|
|
|
app->hWndMain, NULL, app->hInstance, NULL |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!app->hToolTip) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SendMessageA(app->hToolTip, TTM_SETMAXTIPWIDTH, 0, 400); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ETCP Metrics */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpRttLast, |
|
|
|
|
|
|
|
"etcp.rtt_last / ETCP Connection\r\nВремя приема-передачи последнего пакета (RTT), единицы 0.1 мс"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpRttAvg10, |
|
|
|
|
|
|
|
"etcp.rtt_avg_10 / ETCP Connection\r\nСредний RTT за последние 10 пакетов, единицы 0.1 мс"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpRttAvg100, |
|
|
|
|
|
|
|
"etcp.rtt_avg_100 / ETCP Connection\r\nСредний RTT за последние 100 пакетов, единицы 0.1 мс"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpJitter, |
|
|
|
|
|
|
|
"etcp.jitter / ETCP Connection\r\nРазброс RTT (макс - мин), единицы 0.1 мс"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpBytesSent, |
|
|
|
|
|
|
|
"etcp.bytes_sent_total / ETCP Connection\r\nОбщий объем отправленных байт за все время"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpRetrans, |
|
|
|
|
|
|
|
"etcp.retrans_count / ETCP Connection\r\nКоличество ретрансляций (повторных отправок пакетов)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpAcks, |
|
|
|
|
|
|
|
"etcp.ack_count / ETCP Connection\r\nКоличество полученных ACK-пакетов (подтверждений)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpInflight, |
|
|
|
|
|
|
|
"etcp.unacked_bytes / ETCP Connection\r\nБайт в полете: отправлено, но еще не подтверждено"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditEtcpLinks, |
|
|
|
|
|
|
|
"etcp.links_count / ETCP Connection\r\nКоличество активных линков (физических соединений)"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* TUN Metrics */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTunReadBytes, |
|
|
|
|
|
|
|
"tun.bytes_read / TUN Interface\r\nВсего байт прочитано из TUN-интерфейса"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTunWriteBytes, |
|
|
|
|
|
|
|
"tun.bytes_written / TUN Interface\r\nВсего байт записано в TUN-интерфейс"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTunReadPkts, |
|
|
|
|
|
|
|
"tun.packets_read / TUN Interface\r\nВсего пакетов прочитано из TUN-интерфейса"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTunWritePkts, |
|
|
|
|
|
|
|
"tun.packets_written / TUN Interface\r\nВсего пакетов записано в TUN-интерфейс"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTunReadErrs, |
|
|
|
|
|
|
|
"tun.read_errors / TUN Interface\r\nОшибок чтения из TUN-интерфейса"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTunWriteErrs, |
|
|
|
|
|
|
|
"tun.write_errors / TUN Interface\r\nОшибок записи в TUN-интерфейс"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Routing Metrics */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtRouted, |
|
|
|
|
|
|
|
"tun.routed_packets / Routing\r\nКоличество успешно маршрутизированных пакетов"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtDropped, |
|
|
|
|
|
|
|
"tun.dropped_packets / Routing\r\nКоличество отброшенных (не маршрутизированных) пакетов"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtTunInQPkts, |
|
|
|
|
|
|
|
"tun.tun_in_q_packets / Routing\r\nПакетов во входной очереди TUN"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtTunInQBytes, |
|
|
|
|
|
|
|
"tun.tun_in_q_bytes / Routing\r\nБайт во входной очереди TUN"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtTunOutQPkts, |
|
|
|
|
|
|
|
"tun.tun_out_q_packets / Routing\r\nПакетов в выходной очереди TUN"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtTunOutQBytes, |
|
|
|
|
|
|
|
"tun.tun_out_q_bytes / Routing\r\nБайт в выходной очереди TUN"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtCount, |
|
|
|
|
|
|
|
"tun.rt_count / Routing\r\nОбщее количество записей в таблице маршрутизации"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtLocal, |
|
|
|
|
|
|
|
"tun.rt_local / Routing\r\nЛокальных (статических) маршрутов"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtLearned, |
|
|
|
|
|
|
|
"tun.rt_learned / Routing\r\nИзученных (динамических/BGP) маршрутов"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtBgpSenders, |
|
|
|
|
|
|
|
"tun.rt_bgp_senders / Routing BGP\r\nКоличество BGP-отправителей в списке"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditRtBgpNodes, |
|
|
|
|
|
|
|
"tun.rt_bgp_nodes / Routing BGP\r\nКоличество BGP-узлов"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Queue Metrics */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQInQBytes, |
|
|
|
|
|
|
|
"etcp.input_queue_bytes / ETCP Queue\r\nБайт во входной очереди (принято от TUN, ожидает отправки)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQInQPkts, |
|
|
|
|
|
|
|
"etcp.input_queue_packets / ETCP Queue\r\nПакетов во входной очереди"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQInSendBytes, |
|
|
|
|
|
|
|
"etcp.input_send_q_bytes / ETCP Queue\r\nБайт в очереди отправки (готовы к отправке по линкам)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQInSendPkts, |
|
|
|
|
|
|
|
"etcp.input_send_q_packets / ETCP Queue\r\nПакетов в очереди отправки"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQWaitAckBytes, |
|
|
|
|
|
|
|
"etcp.input_wait_ack_bytes / ETCP Queue\r\nБайт в очереди ожидания ACK (отправлено, ждем подтверждения)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQWaitAckPkts, |
|
|
|
|
|
|
|
"etcp.input_wait_ack_packets / ETCP Queue\r\nПакетов в очереди ожидания ACK"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQWaitAckOptInfl, |
|
|
|
|
|
|
|
"etcp.optimal_inflight / ETCP Congestion Control\r\nЦелевое (оптимальное) окно перегрузки в байтах"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQAckBytes, |
|
|
|
|
|
|
|
"etcp.ack_q_bytes / ETCP Queue\r\nБайт в очереди ACK (подтверждения, готовы к отправке)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQAckPkts, |
|
|
|
|
|
|
|
"etcp.ack_q_packets / ETCP Queue\r\nПакетов в очереди ACK"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQRecvBytes, |
|
|
|
|
|
|
|
"etcp.recv_q_bytes / ETCP Queue\r\nБайт в очереди приема (принято, ожидает доставки в TUN)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQRecvPkts, |
|
|
|
|
|
|
|
"etcp.recv_q_packets / ETCP Queue\r\nПакетов в очереди приема"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQOutBytes, |
|
|
|
|
|
|
|
"etcp.output_queue_bytes / ETCP Queue\r\nБайт в выходной очереди (готовы к записи в TUN)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditQOutPkts, |
|
|
|
|
|
|
|
"etcp.output_queue_packets / ETCP Queue\r\nПакетов в выходной очереди"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Error Counters */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditErrReinit, |
|
|
|
|
|
|
|
"etcp.reinit_count / ETCP Errors\r\nСчетчик реинициализаций соединения"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditErrReset, |
|
|
|
|
|
|
|
"etcp.reset_count / ETCP Errors\r\nСчетчик сбросов (reset) соединения"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditErrPktFmt, |
|
|
|
|
|
|
|
"etcp.pkt_format_errors / ETCP Errors\r\nОшибок формата пакета (невалидные заголовки)"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Timer Flags */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTimerRetrans, |
|
|
|
|
|
|
|
"etcp.retrans_timer_active / ETCP Timers\r\nАктивен ли таймер ретрансляции (ON/OFF)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTimerAckResp, |
|
|
|
|
|
|
|
"etcp.ack_resp_timer_active / ETCP Timers\r\nАктивен ли таймер отложенных ACK"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* WaitAck queue state */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditWaitAckSuspend, |
|
|
|
|
|
|
|
"etcp.wait_ack_cb_suspended / ETCP WaitAck\r\nCallback приостановлен (ожидание ACK блокирует передачу)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditWaitAckCb, |
|
|
|
|
|
|
|
"etcp.wait_ack_cb_set / ETCP WaitAck\r\nCallback установлен (есть обработчик ожидания ACK)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditWaitAckTimer, |
|
|
|
|
|
|
|
"etcp.wait_ack_resume_timeout / ETCP WaitAck\r\nТаймер возобновления передачи активен"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ID Metrics */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditIdNextTx, |
|
|
|
|
|
|
|
"etcp.next_tx_id / ETCP Sequence\r\nСледующий ID для передачи (Sequence Number TX)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditIdLastRx, |
|
|
|
|
|
|
|
"etcp.last_rx_id / ETCP Sequence\r\nПоследний принятый ID (Sequence Number RX)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditIdLastDel, |
|
|
|
|
|
|
|
"etcp.last_delivered_id / ETCP Sequence\r\nПоследний доставленный ID (в TUN)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditIdRxAckTill, |
|
|
|
|
|
|
|
"etcp.rx_ack_till / ETCP Sequence\r\nДо какого ID подтвержден прием (ACK от получателя)"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Normalizer */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormInPkts, |
|
|
|
|
|
|
|
"etcp.norm_input_pkts / Packet Normalizer\r\nПакетов на входе нормализатора (текущие)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormInBytes, |
|
|
|
|
|
|
|
"etcp.norm_input_bytes / Packet Normalizer\r\nБайт на входе нормализатора (текущие)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormOutPkts, |
|
|
|
|
|
|
|
"etcp.norm_output_pkts / Packet Normalizer\r\nПакетов на выходе нормализатора (текущие)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormOutBytes, |
|
|
|
|
|
|
|
"etcp.norm_output_bytes / Packet Normalizer\r\nБайт на выходе нормализатора (текущие)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormAllocErr, |
|
|
|
|
|
|
|
"etcp.norm_alloc_errors / Packet Normalizer\r\nОшибок выделения памяти в нормализаторе"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormLogicErr, |
|
|
|
|
|
|
|
"etcp.norm_logic_errors / Packet Normalizer\r\nЛогических ошибок в нормализаторе"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormFragSize, |
|
|
|
|
|
|
|
"etcp.norm_frag_size / Packet Normalizer\r\nРазмер текущего фрагмента"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormDataPtr, |
|
|
|
|
|
|
|
"etcp.norm_data_ptr / Packet Normalizer\r\nУказатель на данные в буфере"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormDataSize, |
|
|
|
|
|
|
|
"etcp.norm_data_size / Packet Normalizer\r\nРазмер данных в буфере"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormInTotPkts, |
|
|
|
|
|
|
|
"etcp.norm_in_total_pkts / Packet Normalizer\r\nВсего пакетов обработано на входе (накопительно)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormInTotBytes, |
|
|
|
|
|
|
|
"etcp.norm_in_total_bytes / Packet Normalizer\r\nВсего байт обработано на входе (накопительно)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormOutTotPkts, |
|
|
|
|
|
|
|
"etcp.norm_out_total_pkts / Packet Normalizer\r\nВсего пакетов обработано на выходе (накопительно)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditNormOutTotBytes, |
|
|
|
|
|
|
|
"etcp.norm_out_total_bytes / Packet Normalizer\r\nВсего байт обработано на выходе (накопительно)"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ACK Debug counters */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditAckHitInf, |
|
|
|
|
|
|
|
"etcp.cnt_ack_hit_inf / ETCP ACK Debug\r\nACK попал в inflight-окно (ожидаемый ACK)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditAckHitSndq, |
|
|
|
|
|
|
|
"etcp.cnt_ack_hit_sndq / ETCP ACK Debug\r\nACK попал в send-очередь"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditAckMiss, |
|
|
|
|
|
|
|
"etcp.cnt_ack_miss / ETCP ACK Debug\r\nACK не найден (неожиданный ACK)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditCntLinkWait, |
|
|
|
|
|
|
|
"etcp.cnt_link_wait / ETCP ACK Debug\r\nСчетчик ожидания линка"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditTxState, |
|
|
|
|
|
|
|
"etcp.tx_state / ETCP ACK Debug\r\nСостояние передачи (битовая маска)"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Debug counters */ |
|
|
|
|
|
|
|
for (int i = 0; i < 8; i++) { |
|
|
|
|
|
|
|
char buf[256]; |
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), |
|
|
|
|
|
|
|
"etcp.debug[%d] / ETCP Debug\r\nОтладочное поле (зависит от версии)", i); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditDebug[i], buf); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* System resources */ |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditActiveTimeouts, |
|
|
|
|
|
|
|
"etcp.active_timeouts / System Resources\r\nАктивных таймаутов в системе (async)"); |
|
|
|
|
|
|
|
AddTooltip(app->hToolTip, app->hEditBusyMemory, |
|
|
|
|
|
|
|
"etcp.busy_memory_blocks / System Resources\r\nЗанятых блоков памяти (memory pool)"); |
|
|
|
|
|
|
|
} |
|
|
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { |
|
|
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { |
|
|
|
struct etcpmon_app* app = NULL; |
|
|
|
struct etcpmon_app* app = NULL; |
|
|
|
|
|
|
|
|
|
|
|
@ -918,10 +1120,15 @@ int etcpmon_gui_run(struct etcpmon_app* app) { |
|
|
|
} |
|
|
|
} |
|
|
|
void etcpmon_gui_cleanup(struct etcpmon_app* app) { |
|
|
|
void etcpmon_gui_cleanup(struct etcpmon_app* app) { |
|
|
|
if (!app) return; |
|
|
|
if (!app) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (app->hToolTip) { |
|
|
|
|
|
|
|
DestroyWindow(app->hToolTip); |
|
|
|
|
|
|
|
app->hToolTip = NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { |
|
|
|
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { |
|
|
|
if (app->hGraphPens[i]) DeleteObject(app->hGraphPens[i]); |
|
|
|
if (app->hGraphPens[i]) DeleteObject(app->hGraphPens[i]); |
|
|
|
}
|
|
|
|
} |
|
|
|
if (app->client) { |
|
|
|
if (app->client) { |
|
|
|
etcpmon_client_cleanup(app->client); |
|
|
|
etcpmon_client_cleanup(app->client); |
|
|
|
free(app->client); |
|
|
|
free(app->client); |
|
|
|
|