Em alguns projetos de automação, quiosques de autoatendimento (totens) ou sistemas de monitoramento em Delphi, é necessário ter o controle total sobre o sistema operacional, incluindo a capacidade de desligar ou reiniciar o computador diretamente pelo software.
No Windows moderno (Windows 10 e Windows 11), para realizar essas ações de forma segura e sem travamentos, precisamos interagir diretamente com a API do Windows (as famosas funções da WinAPI) e solicitar privilégios específicos de encerramento para a aplicação.
Neste artigo prático, você vai aprender a criar uma rotina robusta em Delphi para desligar, reiniciar ou fazer logoff no Windows de forma totalmente compatível com as versões atuais do sistema.
🔑 O Segredo dos Privilégios no Windows
O Windows protege o sistema contra desligamentos acidentais por softwares de terceiros. Por isso, antes de enviar o comando de desligamento, nossa aplicação precisa solicitar e obter o privilégio de segurança chamado SE_SHUTDOWN_NAME.
Se você tentar apenas disparar o comando sem essa validação de privilégios, a função falhará silenciosamente em sistemas modernos devido às restrições de controle de conta de usuário (UAC).
💻 O Código Definitivo (Compatível com Windows 7, 10 e 11)
Para implementar, crie uma função genérica. Ela utilizará as units nativas Winapi.Windows e System.SysUtils.
Adicione no seu código a seguinte procedure:
procedure ControlarEnergiaWindows(const Acao: Word);
var
HandleToken: THandle;
TokenPrivileges: TTokenPrivileges;
RetornoComprimento: DWord;
begin
// 1. Solicita o Token de Acesso para este processo para ajustar os privilégios
if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, HandleToken) then
begin
try
// Obtém o LUID local para o privilégio de desligamento
if LookupPrivilegeValue(nil, 'SeShutdownPrivilege', TokenPrivileges.Privileges[0].Luid) then
begin
TokenPrivileges.PrivilegeCount := 1; // Quantidade de privilégios a alterar
TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
// Aplica o novo privilégio de desligamento ao nosso processo
AdjustTokenPrivileges(HandleToken, False, TokenPrivileges, SizeOf(TTokenPrivileges), TokenPrivileges, RetornoComprimento);
end;
finally
// Sempre fecha o handle de segurança aberto
CloseHandle(HandleToken);
end;
end;
// 2. Executa a ação desejada na API do Windows
case Acao of
1: // DESLIGAR (Force)
ExitWindowsEx(EWX_SHUTDOWN or EWX_FORCE, SHTDN_REASON_MAJOR_OTHER);
2: // REINICIAR (Force)
ExitWindowsEx(EWX_REBOOT or EWX_FORCE, SHTDN_REASON_MAJOR_OTHER);
3: // LOGOFF (Force)
ExitWindowsEx(EWX_LOGOFF or EWX_FORCE, SHTDN_REASON_MAJOR_OTHER);
end;
end;
🛠️ Como Usar no Seu Formulário
Com a procedure declarada no seu código, basta chamá-la associando aos eventos de cliques dos seus botões:
🔹 Para Desligar o Computador:
procedure TForm1.BtnDesligarClick(Sender: TObject);
begin
if MessageDlg('Deseja realmente desligar o computador?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
ControlarEnergiaWindows(1);
end;
end;
🔹 Para Reiniciar o Computador:
procedure TForm1.BtnReiniciarClick(Sender: TObject);
begin
if MessageDlg('Deseja realmente reiniciar o computador?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
ControlarEnergiaWindows(2);
end;
end;
🔹 Para Fazer Logoff (Trocar Usuário):
procedure TForm1.BtnLogoffClick(Sender: TObject);
begin
ControlarEnergiaWindows(3);
end;
💡 Cuidados com o parâmetro "EWX_FORCE"
No código fornecido, utilizamos a diretiva EWX_FORCE junto com as ações. Essa flag força o encerramento de todos os aplicativos ativos no Windows que estejam travados ou com documentos não salvos.
Se o seu software roda em um ambiente corporativo, certifique-se de avisar o usuário para salvar o trabalho antes de disparar o comando, pois o Windows encerrará tudo sem exibir diálogos de confirmação externos.
💬 Participe da discussão!
Em qual tipo de sistema você utiliza esse controle de energia (totens, automação comercial, etc.)? Já teve problemas com o controle de privilégios em versões recentes do Windows?
Deixe seu comentário abaixo para que possamos trocar experiências!
Nenhum comentário:
Postar um comentário