Como desligar o computador de c #

138

Qual é a melhor maneira de desligar o computador a partir de um programa C #?

Encontrei alguns métodos que funcionam - eu os publicarei abaixo - mas nenhum deles é muito elegante. Estou procurando por algo que seja mais simples e nativamente .net.

roomaroo
fonte

Respostas:

171

Funciona a partir do Windows XP, não disponível no Windows 2000 ou inferior:

Esta é a maneira mais rápida de fazer isso:

Process.Start("shutdown","/s /t 0");

Caso contrário, use P / Invoke ou WMI como outros disseram.

Editar: como evitar a criação de uma janela

var psi = new ProcessStartInfo("shutdown","/s /t 0");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
Process.Start(psi);
Pop Catalin
fonte
2
Isso parece funcionar também a partir de serviços (pelo menos nos cenários com os quais estou preocupado). Nunca consegui fazer com que os métodos WMI ou ExitWindowsEx funcionassem em um serviço.
James
1
@ James É porque um serviço geralmente não tem permissões.
AK_
O estado de consumo de energia da máquina é diferente depois de usar isso, e depois de usar a janela de diálogo de desligamento tradicional. Pressionar o botão liga / desliga para inicializar consome cerca de 80 a 85 miliamperes, em vez do padrão 300+. Vou postar de volta aqui se eu descobrir o porquê. Isso não deve afetar a maioria dos usuários.
samuelesque 27/02
Isso funciona muito bem, exceto pelo fato de que, se você estiver no WPF, isso gerará uma janela de console por uma fração de segundo, não exatamente de aparência profissional.
Dustin Jensen
79

Retirado de: a Geekpedia post

Este método usa o WMI para desligar as janelas.

Você precisará adicionar uma referência ao System.Management ao seu projeto para usá-lo.

using System.Management;

void Shutdown()
{
    ManagementBaseObject mboShutdown = null;
    ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
    mcWin32.Get();

    // You can't shutdown without security privileges
    mcWin32.Scope.Options.EnablePrivileges = true;
    ManagementBaseObject mboShutdownParams =
             mcWin32.GetMethodParameters("Win32Shutdown");

     // Flag 1 means we want to shut down the system. Use "2" to reboot.
    mboShutdownParams["Flags"] = "1";
    mboShutdownParams["Reserved"] = "0";
    foreach (ManagementObject manObj in mcWin32.GetInstances())
    {
        mboShutdown = manObj.InvokeMethod("Win32Shutdown", 
                                       mboShutdownParams, null);
    }
}
roomaroo
fonte
3
O uso do WMI facilita o rastreamento de erros. O que acontece se o comando shutdown não funcionar por algum motivo?
Rob Walker
2
Estou usando esse método para desligar as janelas e, em duas de três vezes, ele me diz que não tenho permissões, mas na terceira vez, parece que "desiste" e reinicia o computador de qualquer maneira. O que há com isso?
precisa
1
Esta solução não funciona para mim. Recebo a exceção "Privilégio não retido", mesmo que eu execute o programa no usuário administrador.
Fanda 03/09
@roomaroo Este método não funciona. Ele lança uma exceção: exceção de gerenciamento, privilégio não mantido.
somethingSomething
Se você deseja desligar com força, use mboShutdownParams ["Flags"] = "5"; Valor 5 significa desligamento forçado.
SaneDeveloper
32

Este tópico fornece o código necessário: http://bytes.com/forum/thread251367.html

mas aqui está o código relevante:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct TokPriv1Luid
{
    public int Count;
    public long Luid;
    public int Attr;
}

[DllImport("kernel32.dll", ExactSpelling=true) ]
internal static extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool OpenProcessToken( IntPtr h, int acc, ref IntPtr
phtok );

[DllImport("advapi32.dll", SetLastError=true) ]
internal static extern bool LookupPrivilegeValue( string host, string name,
ref long pluid );

[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool AdjustTokenPrivileges( IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen );

[DllImport("user32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool ExitWindowsEx( int flg, int rea );

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
internal const int EWX_LOGOFF = 0x00000000;
internal const int EWX_SHUTDOWN = 0x00000001;
internal const int EWX_REBOOT = 0x00000002;
internal const int EWX_FORCE = 0x00000004;
internal const int EWX_POWEROFF = 0x00000008;
internal const int EWX_FORCEIFHUNG = 0x00000010;

private void DoExitWin( int flg )
{
    bool ok;
    TokPriv1Luid tp;
    IntPtr hproc = GetCurrentProcess();
    IntPtr htok = IntPtr.Zero;
    ok = OpenProcessToken( hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok );
    tp.Count = 1;
    tp.Luid = 0;
    tp.Attr = SE_PRIVILEGE_ENABLED;
    ok = LookupPrivilegeValue( null, SE_SHUTDOWN_NAME, ref tp.Luid );
    ok = AdjustTokenPrivileges( htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero );
    ok = ExitWindowsEx( flg, 0 );
    }

Uso:

DoExitWin( EWX_SHUTDOWN );

ou

DoExitWin( EWX_REBOOT );
Stephen Wrighton
fonte
Você pode ler sobre o que os outros contstants EWX_ fazer aqui: msdn.microsoft.com/en-us/library/windows/desktop/...
TripleAntigen
1
Ao portar constantes numéricas para C #, a melhor prática é usar uma enumeração. É para isso que um enum foi projetado para fazer. Ele fornece forte digitação em torno de constantes numéricas, opcionalmente suporta sinalizadores / máscaras de bits e transmite facilmente para o tipo numérico subjacente.
Andrew Rondeau
26

Métodos diferentes:

UMA. System.Diagnostics.Process.Start("Shutdown", "-s -t 10");

B. Instrumentação de Gerenciamento do Windows (WMI)

C. System.Runtime.InteropServices Pinvoke

D. Gerenciamento do Sistema

Depois de enviar, vi muitos outros também postarem ...

lakshmanaraj
fonte
2
B e D são o mesmo método (WMI)
Lucas
E. Powershell executa o script a partir do código blogs.msdn.microsoft.com/kebab/2014/04/28/…
user1785960
14

O método feio da velha escola. Use a ExitWindowsExfunção da API do Win32.

using System.Runtime.InteropServices;

void Shutdown2()
{
    const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
    const short SE_PRIVILEGE_ENABLED = 2;
    const uint EWX_SHUTDOWN = 1;
    const short TOKEN_ADJUST_PRIVILEGES = 32;
    const short TOKEN_QUERY = 8;
    IntPtr hToken;
    TOKEN_PRIVILEGES tkp;

    // Get shutdown privileges...
    OpenProcessToken(Process.GetCurrentProcess().Handle, 
          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken);
    tkp.PrivilegeCount = 1;
    tkp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
    LookupPrivilegeValue("", SE_SHUTDOWN_NAME, out tkp.Privileges.pLuid);
    AdjustTokenPrivileges(hToken, false, ref tkp, 0U, IntPtr.Zero, 
          IntPtr.Zero);

    // Now we have the privileges, shutdown Windows
    ExitWindowsEx(EWX_SHUTDOWN, 0);
}

// Structures needed for the API calls
private struct LUID
{
    public int LowPart;
    public int HighPart;
}
private struct LUID_AND_ATTRIBUTES
{
    public LUID pLuid;
    public int Attributes;
}
private struct TOKEN_PRIVILEGES
{
    public int PrivilegeCount;
    public LUID_AND_ATTRIBUTES Privileges;
}

[DllImport("advapi32.dll")]
static extern int OpenProcessToken(IntPtr ProcessHandle, 
                     int DesiredAccess, out IntPtr TokenHandle);

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
    [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
    ref TOKEN_PRIVILEGES NewState,
    UInt32 BufferLength,
    IntPtr PreviousState,
    IntPtr ReturnLength);

[DllImport("advapi32.dll")]
static extern int LookupPrivilegeValue(string lpSystemName, 
                       string lpName, out LUID lpLuid);

[DllImport("user32.dll", SetLastError = true)]
static extern int ExitWindowsEx(uint uFlags, uint dwReason);

No código de produção, você deve verificar os valores de retorno das chamadas de API, mas deixei isso de fora para tornar o exemplo mais claro.

roomaroo
fonte
12

Curto e grosso. Ligue para um programa externo:

    using System.Diagnostics;

    void Shutdown()
    {
        Process.Start("shutdown.exe", "-s -t 00");
    }

Nota: Isso chama o programa Shutdown.exe do Windows, portanto só funcionará se esse programa estiver disponível. Você pode ter problemas no Windows 2000 (onde shutdown.exe está disponível apenas no kit de recursos) ou no XP Embedded .

roomaroo
fonte
9
System.Diagnostics.Process.Start("shutdown", "/s /t 0")

Deveria trabalhar.

Para reiniciar, é / r

Isso reiniciará a caixa do PC de maneira direta e limpa, sem caixas de diálogo.

Micah Vertal
fonte
Esta é a resposta perfeita em sistemas modernos (mais de 2015).
Fattie
obrigado, você poderia explicar o que o / se o / t 0 fazem?
Vladimir verleg
1
@Peterverleg Sure. O argumento "/ s" diz ao computador para desligar e o "/ t" diz ao computador para aguardar x segundos antes de desligar. Sei por experiência pessoal que o argumento "/ t" não faz nada no Windows 8.1, mas funciona no 7, com certeza. Você também pode usar estas funções: shutdown /s /t 0 //For shutdown shutdown /r /t 0 //For restart shutdown /h /t 0 //For hibernateAlém disso, tente digitá-las no CMD para o mesmo resultado.
Micah Vertal
6

Você pode iniciar o processo de desligamento:

  • shutdown -s -t 0 - Desligar
  • shutdown -r -t 0 - Reiniciar
RichS
fonte
6

Observe que shutdown.exe é apenas um invólucro InitiateSystemShutdownEx, que fornece alguns detalhes ausentes noExitWindowsEx

desobstruir
fonte
5

Tive problemas ao tentar usar o método WMI aceito acima, porque sempre obtive o privilégio de não ter exceções, apesar de executar o programa como administrador.

A solução foi o processo solicitar o privilégio para si. Encontrei a resposta em http://www.dotnet247.com/247reference/msgs/58/292150.aspx escrita por um cara chamado Richard Hill.

Eu colei meu uso básico da solução abaixo, caso o link fique velho.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Runtime.InteropServices;
using System.Security;
using System.Diagnostics;

namespace PowerControl
{
    public class PowerControl_Main
    {


        public void Shutdown()
        {
            ManagementBaseObject mboShutdown = null;
            ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
            mcWin32.Get();

            if (!TokenAdjuster.EnablePrivilege("SeShutdownPrivilege", true))
            {
                Console.WriteLine("Could not enable SeShutdownPrivilege");
            }
            else
            {
                Console.WriteLine("Enabled SeShutdownPrivilege");
            }

            // You can't shutdown without security privileges
            mcWin32.Scope.Options.EnablePrivileges = true;
            ManagementBaseObject mboShutdownParams = mcWin32.GetMethodParameters("Win32Shutdown");

            // Flag 1 means we want to shut down the system
            mboShutdownParams["Flags"] = "1";
            mboShutdownParams["Reserved"] = "0";

            foreach (ManagementObject manObj in mcWin32.GetInstances())
            {
                try
                {
                    mboShutdown = manObj.InvokeMethod("Win32Shutdown",
                                                   mboShutdownParams, null);
                }
                catch (ManagementException mex)
                {
                    Console.WriteLine(mex.ToString());
                    Console.ReadKey();
                }
            }
        }


    }


    public sealed class TokenAdjuster
    {
        // PInvoke stuff required to set/enable security privileges
        [DllImport("advapi32", SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        static extern int OpenProcessToken(
        System.IntPtr ProcessHandle, // handle to process
        int DesiredAccess, // desired access to process
        ref IntPtr TokenHandle // handle to open access token
        );

        [DllImport("kernel32", SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        static extern bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int AdjustTokenPrivileges(
        IntPtr TokenHandle,
        int DisableAllPrivileges,
        IntPtr NewState,
        int BufferLength,
        IntPtr PreviousState,
        ref int ReturnLength);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool LookupPrivilegeValue(
        string lpSystemName,
        string lpName,
        ref LUID lpLuid);

        [StructLayout(LayoutKind.Sequential)]
        internal struct LUID
        {
            internal int LowPart;
            internal int HighPart;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct LUID_AND_ATTRIBUTES
        {
            LUID Luid;
            int Attributes;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct _PRIVILEGE_SET
        {
            int PrivilegeCount;
            int Control;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // ANYSIZE_ARRAY = 1
            LUID_AND_ATTRIBUTES[] Privileges;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct TOKEN_PRIVILEGES
        {
            internal int PrivilegeCount;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            internal int[] Privileges;
        }
        const int SE_PRIVILEGE_ENABLED = 0x00000002;
        const int TOKEN_ADJUST_PRIVILEGES = 0X00000020;
        const int TOKEN_QUERY = 0X00000008;
        const int TOKEN_ALL_ACCESS = 0X001f01ff;
        const int PROCESS_QUERY_INFORMATION = 0X00000400;

        public static bool EnablePrivilege(string lpszPrivilege, bool
        bEnablePrivilege)
        {
            bool retval = false;
            int ltkpOld = 0;
            IntPtr hToken = IntPtr.Zero;
            TOKEN_PRIVILEGES tkp = new TOKEN_PRIVILEGES();
            tkp.Privileges = new int[3];
            TOKEN_PRIVILEGES tkpOld = new TOKEN_PRIVILEGES();
            tkpOld.Privileges = new int[3];
            LUID tLUID = new LUID();
            tkp.PrivilegeCount = 1;
            if (bEnablePrivilege)
                tkp.Privileges[2] = SE_PRIVILEGE_ENABLED;
            else
                tkp.Privileges[2] = 0;
            if (LookupPrivilegeValue(null, lpszPrivilege, ref tLUID))
            {
                Process proc = Process.GetCurrentProcess();
                if (proc.Handle != IntPtr.Zero)
                {
                    if (OpenProcessToken(proc.Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                    ref hToken) != 0)
                    {
                        tkp.PrivilegeCount = 1;
                        tkp.Privileges[2] = SE_PRIVILEGE_ENABLED;
                        tkp.Privileges[1] = tLUID.HighPart;
                        tkp.Privileges[0] = tLUID.LowPart;
                        const int bufLength = 256;
                        IntPtr tu = Marshal.AllocHGlobal(bufLength);
                        Marshal.StructureToPtr(tkp, tu, true);
                        if (AdjustTokenPrivileges(hToken, 0, tu, bufLength, IntPtr.Zero, ref ltkpOld) != 0)
                        {
                            // successful AdjustTokenPrivileges doesn't mean privilege could be changed
                            if (Marshal.GetLastWin32Error() == 0)
                            {
                                retval = true; // Token changed
                            }
                        }
                        TOKEN_PRIVILEGES tokp = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(tu,
                        typeof(TOKEN_PRIVILEGES));
                        Marshal.FreeHGlobal(tu);
                    }
                }
            }
            if (hToken != IntPtr.Zero)
            {
                CloseHandle(hToken);
            }
            return retval;
        }

    }
}
m3z
fonte
2
Isso funcionou, embora eu não goste de não saber o porquê. Eu honestamente me pergunto se eu deveria ter acabado com o comando "shutdown" ...
Dan Bailiff
5

Apenas para adicionar à resposta do Pop Catalin, aqui está um liner que desliga o computador sem exibir nenhuma janela:

Process.Start(new ProcessStartInfo("shutdown", "/s /t 0") {
  CreateNoWindow = true, UseShellExecute = false
});
homem
fonte
2

Tentei o método WMI do roomaroo para desligar o Windows 2003 Server, mas ele não funcionaria até que eu adicionasse `[STAThread] '(ou seja, o modelo de encadeamento " Single Threaded Apartment ") à declaração Main ():

[STAThread]
public static void Main(string[] args) {
    Shutdown();
}

Tentei desligar a partir de um thread e, para que isso funcionasse, tive que definir o "Estado do apartamento" do thread como STA:

using System.Management;
using System.Threading;

public static class Program {

    [STAThread]
    public static void Main(string[] args) {
        Thread t = new Thread(new ThreadStart(Program.Shutdown));
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        ...
    }

    public static void Shutdown() {
        // roomaroo's code
    }
}

Eu sou um C # noob, por isso não tenho certeza do significado dos threads STA em termos de desligamento do sistema (mesmo depois de ler o link que eu postei acima). Talvez alguém mais possa elaborar ...?

MisterEd
fonte
Na verdade, apenas o thread que chama WMI precisa ser STA. Se esse não é o segmento principal, Main()não precisa [STAThread].
SLaks
2

** Resposta elaborada ...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
// Remember to add a reference to the System.Management assembly
using System.Management;
using System.Diagnostics;

namespace ShutDown
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnShutDown_Click(object sender, EventArgs e)
        {
            ManagementBaseObject mboShutdown = null;
            ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
            mcWin32.Get();

            // You can't shutdown without security privileges
            mcWin32.Scope.Options.EnablePrivileges = true;
            ManagementBaseObject mboShutdownParams = mcWin32.GetMethodParameters("Win32Shutdown");

            // Flag 1 means we want to shut down the system
            mboShutdownParams["Flags"] = "1";
            mboShutdownParams["Reserved"] = "0";

            foreach (ManagementObject manObj in mcWin32.GetInstances())
            {
                mboShutdown = manObj.InvokeMethod("Win32Shutdown", mboShutdownParams, null);
            }
        }
    }
}
Fazil Mir
fonte
1

Use shutdown.exe. Para evitar problemas com a passagem de argumentos, execução complexa, execução de WindowForms, use o script de execução do PowerShell:

using System.Management.Automation;
...
using (PowerShell PowerShellInstance = PowerShell.Create())
{
    PowerShellInstance.AddScript("shutdown -a; shutdown -r -t 100;");
    // invoke execution on the pipeline (collecting output)
    Collection<PSObject> PSOutput = PowerShellInstance.Invoke();
} 

O System.Management.Automation.dll deve estar instalado no sistema operacional e disponível no GAC.

Desculpe pelo meu Inglês.

user1785960
fonte
0

Não existe um método nativo .net para desligar o computador. Você precisa P / Invocar a chamada da API ExitWindows ou ExitWindowsEx API.

Sim - aquele Jake.
fonte
0

Se você deseja desligar o computador remotamente, poderá usar

Using System.Diagnostics;

em qualquer botão, clique

{
    Process.Start("Shutdown","-i");
}
Jason Plank
fonte