2026-06-21 13:03:31 +00:00
|
|
|
using AgroBase.Forms.IHM;
|
2024-07-05 18:59:05 +00:00
|
|
|
using AgroBase.Models;
|
2024-04-24 18:01:25 +00:00
|
|
|
using AgroBase.Services;
|
2023-10-09 16:06:23 +00:00
|
|
|
using System;
|
2024-12-13 19:39:31 +00:00
|
|
|
using System.Threading;
|
2023-08-31 11:50:53 +00:00
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
namespace AgroBase.Forms
|
|
|
|
|
{
|
|
|
|
|
public partial class frmInstancial : Form
|
|
|
|
|
{
|
2024-11-27 17:38:56 +00:00
|
|
|
public static AsyncTaskTimerModel tmrVarreduraDispositivos;
|
|
|
|
|
|
2023-08-31 11:50:53 +00:00
|
|
|
public static frmPrincipal frmPrincipal = new frmPrincipal();
|
|
|
|
|
public static frmJoystick frmJoystick = new frmJoystick();
|
2026-06-21 13:03:31 +00:00
|
|
|
public static frmIHM frmIHM = new frmIHM()
|
2023-08-31 11:50:53 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
FormBorderStyle = FormBorderStyle.None,
|
|
|
|
|
//WindowState = FormWindowState.Maximized,
|
|
|
|
|
//TopMost = true
|
|
|
|
|
};
|
2024-12-13 19:39:31 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private static readonly SemaphoreSlim _startupGate =
|
|
|
|
|
new SemaphoreSlim(1, 1);
|
2025-11-06 16:18:32 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private static readonly SemaphoreSlim _shutdownGate =
|
|
|
|
|
new SemaphoreSlim(1, 1);
|
2026-03-05 02:03:31 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private static CancellationTokenSource _appCts;
|
2025-06-06 20:46:08 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private static bool _startupConcluido;
|
|
|
|
|
private static bool _shutdownIniciado;
|
2024-09-24 19:02:54 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private bool _allowClose;
|
2025-06-06 20:46:08 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
public frmInstancial()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
2025-06-30 10:43:54 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
/*
|
|
|
|
|
* O construtor precisa ser leve.
|
|
|
|
|
* Nada de abrir MQTT, Redis, Python, CAN, Livox ou operadores aqui.
|
|
|
|
|
* O WinForms ainda está criando handles e a aplicação ainda não
|
|
|
|
|
* possui lifecycle seguro para aguardar falhas.
|
|
|
|
|
*/
|
|
|
|
|
ThreadPool.SetMinThreads(
|
|
|
|
|
workerThreads: 50,
|
|
|
|
|
completionPortThreads: 50
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-11-05 20:03:46 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private async void frmInstancial_Load(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
try
|
2025-06-06 20:46:08 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
await InicializarServicosAsync();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Load] Falha crítica na inicialização: " +
|
|
|
|
|
ex
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(
|
|
|
|
|
"Falha ao inicializar o sistema:\n\n" +
|
|
|
|
|
ex.Message,
|
|
|
|
|
"AgroBase",
|
|
|
|
|
MessageBoxButtons.OK,
|
|
|
|
|
MessageBoxIcon.Error
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
}
|
2023-08-31 11:50:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void frmInstancial_Shown(object sender, EventArgs e)
|
|
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
2024-07-05 18:59:05 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
if (!Variaveis.Producao)
|
|
|
|
|
{
|
|
|
|
|
frmIHM.FormClosing -= FrmIHM_FormClosing;
|
|
|
|
|
frmPrincipal.FormClosing -= frmPrincipal_FormClosing;
|
|
|
|
|
|
|
|
|
|
frmIHM.FormClosing += FrmIHM_FormClosing;
|
|
|
|
|
frmPrincipal.FormClosing += frmPrincipal_FormClosing;
|
|
|
|
|
|
|
|
|
|
frmPrincipal.Show();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
frmIHM.FormClosing -= frmPrincipal_FormClosing;
|
|
|
|
|
frmIHM.FormClosing += frmPrincipal_FormClosing;
|
|
|
|
|
|
|
|
|
|
frmIHM.Show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Hide();
|
2024-07-05 18:59:05 +00:00
|
|
|
}
|
2026-06-21 13:03:31 +00:00
|
|
|
catch (Exception ex)
|
2024-07-05 18:59:05 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Shown] " + ex
|
|
|
|
|
);
|
2024-07-05 18:59:05 +00:00
|
|
|
}
|
2023-08-31 11:50:53 +00:00
|
|
|
}
|
2024-03-01 19:49:20 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private static async Task InicializarServicosAsync()
|
2024-07-05 18:59:05 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
await _startupGate.WaitAsync()
|
|
|
|
|
.ConfigureAwait(false);
|
2024-11-27 17:38:56 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
2024-11-27 17:38:56 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
if (_startupConcluido)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_shutdownIniciado = false;
|
|
|
|
|
Variaveis.Fechando = false;
|
|
|
|
|
|
|
|
|
|
_appCts?.Dispose();
|
|
|
|
|
_appCts = new CancellationTokenSource();
|
|
|
|
|
|
|
|
|
|
FuncoesGlobais.AddApplicationToStartup();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ordem pensada para campo:
|
|
|
|
|
* 1. limpar processos externos velhos;
|
|
|
|
|
* 2. subir infraestrutura local;
|
|
|
|
|
* 3. subir comunicação MQTT/UDP;
|
|
|
|
|
* 4. iniciar rotinas e operadores;
|
|
|
|
|
* 5. iniciar varredura física.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
PythonService.EncerrarProcessos();
|
|
|
|
|
|
|
|
|
|
RedisService.Iniciar();
|
|
|
|
|
RedisService.LimparDadosIniciais();
|
|
|
|
|
|
2026-06-22 16:46:34 +00:00
|
|
|
GeneralJoystick.IniciarRotinas();
|
|
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
await Variaveis.IniciarMqttAsync(_appCts.Token)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Hoje pode ficar comentado se UDP não for usado no rover,
|
|
|
|
|
* mas o método fica aqui no lugar certo do lifecycle.
|
|
|
|
|
*/
|
2026-06-22 16:46:34 +00:00
|
|
|
Variaveis.IniciarUDP();
|
2026-06-21 13:03:31 +00:00
|
|
|
|
|
|
|
|
APIService.IniciarRotinas();
|
|
|
|
|
VersionamentoService.IniciarRotinas();
|
|
|
|
|
|
|
|
|
|
LivoxManagerProcess.Start();
|
|
|
|
|
|
|
|
|
|
await VariaveisOperacao
|
|
|
|
|
.Operadores
|
|
|
|
|
.IniciarProcessamento(false)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
AudioAlertaService.SelecionarVoz(
|
|
|
|
|
VariaveisEquipamento.VozAlerta
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IniciarTimerVarreduraDispositivos();
|
|
|
|
|
|
|
|
|
|
_startupConcluido = true;
|
|
|
|
|
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial] Inicialização concluída."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
await EncerrarProcessosInternoAsync(
|
|
|
|
|
sairProcesso: false
|
|
|
|
|
).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
throw;
|
2024-11-27 17:38:56 +00:00
|
|
|
}
|
2026-06-21 13:03:31 +00:00
|
|
|
finally
|
2024-11-27 17:38:56 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
_startupGate.Release();
|
2024-11-27 17:38:56 +00:00
|
|
|
}
|
2026-06-21 13:03:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void IniciarTimerVarreduraDispositivos()
|
|
|
|
|
{
|
|
|
|
|
if (tmrVarreduraDispositivos != null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
tmrVarreduraDispositivos =
|
|
|
|
|
new AsyncTaskTimerModel(
|
|
|
|
|
"tmrVarreduraDispositivos",
|
|
|
|
|
tmrVarreduraDispositivos_Tick,
|
|
|
|
|
SerialService.InteraloVerificacao,
|
|
|
|
|
null,
|
|
|
|
|
15000
|
|
|
|
|
);
|
2024-11-27 17:38:56 +00:00
|
|
|
|
|
|
|
|
tmrVarreduraDispositivos.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static async Task tmrVarreduraDispositivos_Tick()
|
|
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
if (Variaveis.Fechando)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
await SerialService
|
|
|
|
|
.RealizarVarreduraPortasUSB()
|
|
|
|
|
.ConfigureAwait(false);
|
2024-07-05 18:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
/*
|
|
|
|
|
* Método mantido para compatibilidade com chamadas antigas.
|
|
|
|
|
* Não é mais chamado no Load, porque o startup correto é
|
|
|
|
|
* Variaveis.IniciarMqttAsync().
|
|
|
|
|
*/
|
2024-07-05 18:59:05 +00:00
|
|
|
private async void IniciarConexaoMqtt()
|
|
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await Variaveis.IniciarMqttAsync();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.IniciarConexaoMqtt] " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-07-05 18:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
public static Task EncerrarProcessos()
|
|
|
|
|
{
|
|
|
|
|
return EncerrarProcessos(sairProcesso: false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async Task EncerrarProcessos(
|
|
|
|
|
bool sairProcesso)
|
|
|
|
|
{
|
|
|
|
|
await _shutdownGate.WaitAsync()
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_shutdownIniciado)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_shutdownIniciado = true;
|
|
|
|
|
|
|
|
|
|
await EncerrarProcessosInternoAsync(
|
|
|
|
|
sairProcesso
|
|
|
|
|
).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_shutdownGate.Release();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static async Task EncerrarProcessosInternoAsync(
|
|
|
|
|
bool sairProcesso)
|
2024-07-05 18:59:05 +00:00
|
|
|
{
|
2025-03-27 11:47:00 +00:00
|
|
|
Variaveis.Fechando = true;
|
2024-07-05 18:59:05 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try { _appCts?.Cancel(); } catch { }
|
2025-11-05 20:03:46 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
/*
|
|
|
|
|
* Primeiro paramos timers para nenhuma rotina reentrar
|
|
|
|
|
* enquanto desmontamos serial, CAN, MQTT e processos.
|
|
|
|
|
*/
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await AsyncTaskTimerModel
|
|
|
|
|
.PararTimersAsync()
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao parar timers: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-11-27 17:38:56 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
tmrVarreduraDispositivos = null;
|
2026-03-05 16:53:30 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await SerialService
|
|
|
|
|
.EncerrarAsync()
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
2024-07-05 18:59:05 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao encerrar SerialService: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
2024-07-05 18:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
/*
|
|
|
|
|
* Tenta avisar dispositivos antes de fechar CAN/MQTT/processos.
|
|
|
|
|
*/
|
|
|
|
|
try
|
2024-07-05 18:59:05 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
foreach (var disp in Variaveis.DispositivosConectados)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
disp.EnviarProtocolosConfiguracao(false);
|
|
|
|
|
disp.SalvarParametros(disp.Dados);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao salvar " +
|
|
|
|
|
disp.Dispositivo + ": " + ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao percorrer dispositivos: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
2024-07-05 18:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
/*
|
|
|
|
|
* Dá uma janela curta para a fila CAN drenar.
|
|
|
|
|
* Usa DateTime aqui só por compatibilidade com o padrão atual,
|
|
|
|
|
* mas sem travar indefinidamente.
|
|
|
|
|
*/
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var timeout = DateTime.Now.AddSeconds(10);
|
|
|
|
|
|
|
|
|
|
while (!CanManager.CanService.FilaLiberada &&
|
|
|
|
|
DateTime.Now < timeout)
|
|
|
|
|
{
|
|
|
|
|
await Task.Delay(200)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro aguardando fila CAN: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-09-24 19:02:54 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
LivoxManagerProcess.Dispose();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao encerrar Livox: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
PythonService.EncerrarProcessos();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao encerrar Python: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-07-05 18:59:05 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Variaveis.StopUdpChannel();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao encerrar UDP: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-09-24 19:02:54 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await GPSService
|
|
|
|
|
.EncerrarAsync()
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao encerrar GPS: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-09-24 19:02:54 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await Variaveis
|
|
|
|
|
.EncerrarMqttAsync()
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.Encerrar] Erro ao encerrar MQTT: " +
|
|
|
|
|
ex.Message
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-07-05 18:59:05 +00:00
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_appCts?.Dispose();
|
|
|
|
|
_appCts = null;
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
|
|
|
|
|
_startupConcluido = false;
|
|
|
|
|
|
|
|
|
|
if (sairProcesso)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Environment.Exit(0);
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void frmPrincipal_FormClosing(
|
|
|
|
|
object sender,
|
|
|
|
|
FormClosingEventArgs e)
|
2024-07-05 18:59:05 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
if (_allowClose)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-07-05 18:59:05 +00:00
|
|
|
e.Cancel = true;
|
2026-06-21 13:03:31 +00:00
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await EncerrarProcessos(
|
|
|
|
|
sairProcesso: false
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
_allowClose = true;
|
|
|
|
|
|
|
|
|
|
BeginInvoke(
|
|
|
|
|
new Action(() =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Variaveis.MostrarLog(
|
|
|
|
|
"[frmInstancial.FormClosing] " + ex
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Environment.Exit(1);
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
}
|
2024-07-05 18:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 13:03:31 +00:00
|
|
|
private void FrmIHM_FormClosing(
|
|
|
|
|
object sender,
|
|
|
|
|
FormClosingEventArgs e)
|
2024-10-04 13:11:23 +00:00
|
|
|
{
|
2026-06-21 13:03:31 +00:00
|
|
|
/*
|
|
|
|
|
* Em modo desenvolvimento, fechar a IHM apenas oculta a janela.
|
|
|
|
|
* Em produção, o evento de fechamento da IHM é associado ao
|
|
|
|
|
* frmPrincipal_FormClosing e faz shutdown real.
|
|
|
|
|
*/
|
2024-10-04 13:11:23 +00:00
|
|
|
e.Cancel = true;
|
|
|
|
|
frmIHM.Hide();
|
|
|
|
|
}
|
2023-08-31 11:50:53 +00:00
|
|
|
}
|
|
|
|
|
}
|