So fahren Sie den Computer von C # herunter

138

Was ist der beste Weg, um den Computer über ein C # -Programm herunterzufahren?

Ich habe ein paar Methoden gefunden, die funktionieren - ich werde sie unten veröffentlichen -, aber keine davon ist sehr elegant. Ich suche etwas, das einfacher und nativer .net ist.

roomaroo
quelle

Antworten:

171

Funktioniert ab Windows XP und ist in Win 2000 oder niedriger nicht verfügbar:

Dies ist der schnellste Weg:

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

Verwenden Sie andernfalls P / Invoke oder WMI, wie andere gesagt haben.

Bearbeiten: So vermeiden Sie das Erstellen eines Fensters

var psi = new ProcessStartInfo("shutdown","/s /t 0");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
Process.Start(psi);
Pop Catalin
quelle
2
Dies scheint auch von Diensten aus zu funktionieren (zumindest in den Szenarien, mit denen ich mich befasse). Ich konnte die WMI- oder ExitWindowsEx-Methoden nie von einem Dienst zum Laufen bringen.
James
1
@ James Es liegt daran, dass ein Dienst normalerweise nicht die Berechtigungen dafür hat.
AK_
Der Stromverbrauchszustand der Maschine ist nach dieser Verwendung anders als nach Verwendung des herkömmlichen Dialogfelds zum Herunterfahren. Durch Drücken des Netzschalters zum Hochfahren werden etwa 80-85 Milliampere anstelle des Standard-300 + erzeugt. Werde hier wieder posten, wenn ich herausfinde warum. Dies sollte die meisten Benutzer nicht betreffen.
Samuelesque
Dies funktioniert hervorragend, mit der Ausnahme, dass in WPF für den Bruchteil einer Sekunde ein Konsolenfenster angezeigt wird, das nicht gerade professionell aussieht.
Dustin Jensen
79

Entnommen aus: einem Geekpedia-Beitrag

Diese Methode verwendet WMI zum Herunterfahren von Fenstern.

Sie müssen Ihrem Projekt einen Verweis auf System.Management hinzufügen, um dies zu verwenden.

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
quelle
3
Die Verwendung von WMI erleichtert das Verfolgen von Fehlern. Was passiert, wenn der Befehl zum Herunterfahren aus irgendeinem Grund nicht funktioniert?
Rob Walker
2
Ich verwende diese Methode, um Windows herunterzufahren, und zwei von drei Mal wird mir mitgeteilt, dass mir die Berechtigungen fehlen, aber beim dritten Mal wird der Computer trotzdem "aufgegeben" und neu gestartet. Was ist damit?
DTI-Matt
1
Diese Lösung funktioniert bei mir nicht. Ich erhalte die Ausnahme "Berechtigung nicht gehalten", auch wenn ich das Programm unter Administratorbenutzer ausführe.
Fanda
@roomaroo Diese Methode funktioniert nicht. Es wird eine Ausnahme ausgelöst: Verwaltungsausnahme, Berechtigung nicht gehalten.
etwas Etwas
Wenn Sie zwangsweise herunterfahren möchten, sollten Sie mboShutdownParams ["Flags"] = "5" verwenden. Wert 5 bedeutet erzwungenes Herunterfahren.
SaneDeveloper
32

Dieser Thread enthält den erforderlichen Code: http://bytes.com/forum/thread251367.html

aber hier ist der relevante Code:

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

Verwendung:

DoExitWin( EWX_SHUTDOWN );

oder

DoExitWin( EWX_REBOOT );
Stephen Wrighton
quelle
Lesen Sie hier, was die anderen EWX_-Kandidaten tun: msdn.microsoft.com/en-us/library/windows/desktop/…
TripleAntigen
1
Wenn Sie numerische Konstanten nach C # portieren, empfiehlt es sich, eine Aufzählung zu verwenden. Dafür ist eine Aufzählung gedacht. Es bietet eine starke Typisierung um numerische Konstanten, unterstützt optional Flags / Bitmasken und wandelt sich leicht hin und her in den zugrunde liegenden numerischen Typ.
Andrew Rondeau
26

Verschiedene Methoden:

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

B. Windows-Verwaltungsinstrumentierung (WMI)

C. System.Runtime.InteropServices Pinvoke

D. Systemverwaltung

Nachdem ich eingereicht habe, habe ich so viele andere gesehen, die auch gepostet haben ...

Lakshmanaraj
quelle
2
B und D sind die gleiche Methode (WMI)
Lucas
E. Powershell führen Skript aus Code blogs.msdn.microsoft.com/kebab/2014/04/28/…
user1785960
14

Die hässliche Methode der alten Schule. Verwenden Sie die ExitWindowsExFunktion aus der Win32-API.

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

Im Produktionscode sollten Sie die Rückgabewerte der API-Aufrufe überprüfen, aber ich habe das weggelassen, um das Beispiel klarer zu machen.

roomaroo
quelle
12

Kurz und bündig. Rufen Sie ein externes Programm auf:

    using System.Diagnostics;

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

Hinweis: Dies ruft das Windows-Programm Shutdown.exe auf, sodass es nur funktioniert, wenn dieses Programm verfügbar ist. Möglicherweise treten Probleme unter Windows 2000 (wo shutdown.exe nur im Resource Kit verfügbar ist) oder XP Embedded auf .

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

Sollte arbeiten.

Zum Neustart ist es / r

Dadurch wird die PC-Box direkt und sauber ohne Dialogfelder neu gestartet.

Micah Vertal
quelle
Dies ist die perfekte Antwort auf moderne (2015+) Systeme.
Fattie
danke, kannst du erklären, was die / s und die / t 0 tun?
Vladimir verleg
1
@ Peterverleg Sicher. Das Argument "/ s" weist den Computer an, herunterzufahren, und das Argument "/ t" weist den Computer an, vor dem Herunterfahren x Sekunden zu warten. Ich weiß aus eigener Erfahrung, dass das Argument "/ t" in Windows 8.1 nichts bewirkt, aber es funktioniert mit Sicherheit in 7. Sie können diese Funktionen auch verwenden: shutdown /s /t 0 //For shutdown shutdown /r /t 0 //For restart shutdown /h /t 0 //For hibernateVersuchen Sie außerdem, sie für dasselbe Ergebnis in CMD einzugeben.
Micah Vertal
6

Sie können den Herunterfahrvorgang starten:

  • shutdown -s -t 0 - Herunterfahren
  • shutdown -r -t 0 - Neustart
RichS
quelle
6

Beachten Sie, dass dies shutdown.exenur ein Wrapper ist InitiateSystemShutdownEx, der einige Feinheiten enthält, die in fehlenExitWindowsEx

unbob
quelle
5

Ich hatte Probleme beim Versuch, die oben akzeptierte WMI-Methode zu verwenden, da ich trotz der Ausführung des Programms als Administrator immer keine Ausnahmen hatte.

Die Lösung bestand darin, dass der Prozess das Privileg für sich selbst anforderte. Ich fand die Antwort unter http://www.dotnet247.com/247reference/msgs/58/292150.aspx, geschrieben von einem Typen namens Richard Hill.

Ich habe meine grundlegende Verwendung seiner Lösung unten eingefügt, falls dieser Link alt wird.

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
quelle
2
Das hat funktioniert, obwohl ich nicht gerne weiß warum. Ich frage mich ehrlich, ob ich nur mit dem Befehl "Herunterfahren" hätte gehen sollen ...
Dan Bailiff
5

Gerade in dem Pop Catalin Antwort, hier ist ein Einzeiler , welche Fährt den Computer ohne Fenster anzuzeigen:

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

Ich habe versucht, mit der WMI-Methode von roomaroo Windows 2003 Server herunterzufahren, aber es würde nicht funktionieren, bis ich der Main () - Deklaration "[STAThread]" (dh das Threading-Modell " Single Threaded Apartment ") hinzugefügt habe :

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

Ich habe dann versucht, einen Thread herunterzufahren, und um das zum Laufen zu bringen, musste ich auch den "Apartment State" des Threads auf STA setzen:

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

Ich bin ein C # Noob, daher bin ich mir nicht ganz sicher, welche Bedeutung STA-Threads für das Herunterfahren des Systems haben (selbst nachdem ich den oben veröffentlichten Link gelesen habe). Vielleicht kann jemand anderes näher darauf eingehen ...?

MisterEd
quelle
Tatsächlich muss nur der Thread, der WMI aufruft, ein STA-Thread sein. Wenn das nicht der Haupt-Thread ist, Main()braucht es nicht [STAThread].
SLaks
2

** Ausgearbeitete Antwort ...

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
quelle
1

Verwenden Sie shutdown.exe. Verwenden Sie das PowerShell-Ausführungsskript, um Probleme mit der Übergabe von Argumenten, der komplexen Ausführung und der Ausführung von WindowForms zu vermeiden:

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 sollte unter dem Betriebssystem installiert und in GAC verfügbar sein.

Entschuldigung für mein Englisch.

user1785960
quelle
0

Es gibt keine native .net-Methode zum Ausschalten des Computers. Sie müssen den API-Aufruf ExitWindows oder ExitWindowsEx P / aufrufen.

Ja - dieser Jake.
quelle
0

Wenn Sie den Computer remote herunterfahren möchten, können Sie verwenden

Using System.Diagnostics;

Klicken Sie auf eine beliebige Schaltfläche

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