Come spegnere il computer da C #


138

Qual è il modo migliore per spegnere il computer da un programma C #?

Ho trovato alcuni metodi che funzionano - li posterò di seguito - ma nessuno di questi è molto elegante. Sto cercando qualcosa che sia .net più semplice e nativo.

Risposte:


171

Funziona a partire da Windows XP, non disponibile in Windows 2000 o inferiore:

Questo è il modo più veloce per farlo:

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

Altrimenti usa P / Invoke o WMI come altri hanno già detto.

Modifica: come evitare di creare una finestra

var psi = new ProcessStartInfo("shutdown","/s /t 0");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
Process.Start(psi);

2
Questo sembra funzionare anche dai servizi (almeno negli scenari di cui mi occupo). Non sono mai riuscito a far funzionare i metodi WMI o ExitWindowsEx da un servizio.
James,

1
@James È perché un servizio di solito non ha i permessi per esso.
AK_11

Lo stato di consumo energetico della macchina è diverso dopo averlo utilizzato, rispetto a quando si utilizza la finestra di dialogo di spegnimento tradizionale. Premendo il pulsante di accensione per eseguire il backup si ottengono circa 80-85 milliampere, anziché lo standard 300 + ish. Riporterò qui se scopro il perché. Ciò non dovrebbe interessare la maggior parte degli utenti.
samuelesco il

Funziona benissimo, tranne per il fatto che se sei in WPF, questo genererà una finestra della console per una frazione di secondo, non esattamente dall'aspetto professionale.
Dustin Jensen,

80

Tratto da: un post di Geekpedia

Questo metodo utilizza WMI per arrestare Windows.

Per poterlo utilizzare, devi aggiungere un riferimento a System.Management al tuo progetto.

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);
    }
}

3
L'uso di WMI semplifica il monitoraggio degli errori. Cosa succede se il comando shutdown non funziona per qualche motivo?
Rob Walker,

2
Sto usando questo metodo per chiudere Windows, e due volte su tre mi dirà che mi mancano le autorizzazioni, ma la terza volta sorse di "rinunciare" e riavvia comunque il computer. Cosa succede con quello?
DTI-Matt,

1
Questa soluzione non funziona per me. Ottengo l'eccezione "Privilegio non trattenuto" anche se eseguo il programma con l'utente amministratore.
Fanda,

@roomaroo Questo metodo non funziona. Genera un'eccezione: eccezione di gestione, privilegio non mantenuto.
Something

Se si desidera arrestare forzatamente è necessario utilizzare mboShutdownParams ["Flags"] = "5"; Il valore 5 indica l'arresto forzato.
SaneDeveloper il

32

Questo thread fornisce il codice necessario: http://bytes.com/forum/thread251367.html

ma ecco il codice pertinente:

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 );

o

DoExitWin( EWX_REBOOT );

Si può leggere su ciò che gli altri fanno contstants EWX_ qui: msdn.microsoft.com/en-us/library/windows/desktop/...
TripleAntigen

1
Quando si esegue il porting di costanti numeriche su C #, è consigliabile utilizzare un enum. Questo è ciò che un enum è progettato per fare. Fornisce una digitazione forte attorno alle costanti numeriche, opzionalmente supporta flag / maschere di bit e si lancia facilmente avanti e indietro sul tipo numerico sottostante.
Andrew Rondeau,

26

Diversi metodi:

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

B. Strumentazione gestione Windows (WMI)

C. System.Runtime.InteropServices Pinvoke

D. Gestione del sistema

Dopo che ho inviato, ho visto molti altri hanno anche pubblicato ...


2
B e D sono lo stesso metodo (WMI)
Lucas,

E. Powershell esegue lo script dal codice blogs.msdn.microsoft.com/kebab/2014/04/28/…
user1785960

14

Il brutto metodo della vecchia scuola. Utilizzare la ExitWindowsExfunzione dall'API 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);

Nel codice di produzione dovresti controllare i valori di ritorno delle chiamate API, ma l'ho lasciato fuori per rendere più chiaro l'esempio.


12

Breve e dolce Chiama un programma esterno:

    using System.Diagnostics;

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

Nota: questo chiama il programma Shutdown.exe di Windows, quindi funzionerà solo se quel programma è disponibile. Potresti avere problemi su Windows 2000 (dove shutdown.exe è disponibile solo nel kit di risorse) o XP Embedded .


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

Dovrebbe funzionare.

Per il riavvio, è / r

Questo riavvierà la scatola del PC direttamente e in modo pulito, senza finestre di dialogo.


Questa è la risposta perfetta su sistemi moderni (2015+).
Fattie l'

grazie, potresti spiegare cosa fanno i / s e / t 0?
Vladimir verleg,

1
@Peterverleg Certo. L'argomento "/ s" dice al computer di spegnersi e "/ t" dice al computer di attendere x secondi prima di spegnersi. So per esperienza personale che l'argomento "/ t" non fa nulla in Windows 8.1, ma funziona sicuramente in 7. Puoi anche usare queste funzioni: shutdown /s /t 0 //For shutdown shutdown /r /t 0 //For restart shutdown /h /t 0 //For hibernateInoltre, prova a digitarle in CMD per lo stesso risultato.
Micah Vertal,

6

È possibile avviare il processo di spegnimento:

  • shutdown -s -t 0 - Spegnimento
  • shutdown -r -t 0 - Ricomincia


5

Ho avuto problemi a provare a utilizzare il metodo WMI accettato in precedenza perché ho sempre ottenuto il privilegio di non avere eccezioni nonostante l'esecuzione del programma come amministratore.

La soluzione era che il processo richiedesse il privilegio per se stesso. Ho trovato la risposta su http://www.dotnet247.com/247reference/msgs/58/292150.aspx scritta da un ragazzo chiamato Richard Hill.

Ho incollato il mio uso di base della sua soluzione di seguito nel caso in cui quel link invecchi.

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;
        }

    }
}

2
Questo ha funzionato, anche se non mi piace non sapere il perché. Onestamente mi chiedo se avrei dovuto semplicemente seguire il comando "shutdown" ...
Dan Bailiff il

5

Giusto per aggiungere alla risposta di Pop Catalin, ecco una linea che spegne il computer senza visualizzare alcuna finestra:

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

2

Ho provato il metodo WMI di roomaroo per arrestare Windows 2003 Server, ma non avrebbe funzionato fino a quando non avessi aggiunto `[STAThread] '(ovvero il modello di threading " Single Threaded Apartment ") alla dichiarazione Main ():

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

Ho quindi provato a chiudere un thread e per farlo funzionare ho dovuto impostare anche lo "Stato appartamento" del thread su 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
    }
}

Sono un noob C #, quindi non sono del tutto sicuro del significato dei thread STA in termini di spegnimento del sistema (anche dopo aver letto il link che ho postato sopra). Forse qualcun altro può elaborare ...?


In realtà, solo il thread che chiama WMI deve essere thread STA. Se questo non è il thread principale, Main()non è necessario [STAThread].
SLaks

2

** Risposta elaborata ...

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);
            }
        }
    }
}

1

Usa shutdown.exe. Per evitare problemi con il passaggio degli arg, l'esecuzione complessa, l'esecuzione da WindowForms usa lo script di esecuzione di 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();
} 

System.Management.Automation.dll deve essere installato sul sistema operativo e disponibile in GAC.

Mi scusi per il mio inglese.


0

Non esiste un metodo nativo .net per spegnere il computer. È necessario P / Richiamare la chiamata API ExitWindows o ExitWindowsEx.


0

Se si desidera spegnere il computer in remoto, è possibile utilizzare

Using System.Diagnostics;

su qualsiasi pulsante fare clic

{
    Process.Start("Shutdown","-i");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.