Cara mematikan komputer dari C #

138

Apa cara terbaik untuk mematikan komputer dari program C #?

Saya telah menemukan beberapa metode yang berfungsi - saya akan mempostingnya di bawah ini - tetapi tidak ada satupun yang sangat elegan. Saya mencari sesuatu yang sederhana dan asli. Net.

roomaroo
sumber

Jawaban:

171

Bekerja dimulai dengan windows XP, tidak tersedia di win 2000 atau lebih rendah:

Ini adalah cara tercepat untuk melakukannya:

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

Kalau tidak, gunakan P / Invoke atau WMI seperti yang dikatakan orang lain.

Sunting: cara menghindari membuat jendela

var psi = new ProcessStartInfo("shutdown","/s /t 0");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
Process.Start(psi);
Pop Catalin
sumber
2
Tampaknya ini juga berfungsi dari layanan (setidaknya dalam skenario yang saya perhatikan). Saya tidak pernah bisa mendapatkan metode WMI atau ExitWindowsEx untuk bekerja dari layanan.
James
1
@ James Itu karena sebuah layanan biasanya tidak memiliki izin untuk itu.
AK_
Keadaan konsumsi daya mesin berbeda setelah menggunakan ini, daripada setelah menggunakan jendela dialog shutdown tradisional. Menekan tombol daya untuk mem-boot up membutuhkan sekitar 80-85 miliamp, daripada standar 300+. Akan dikirim kembali ke sini jika saya mengetahui alasannya. Ini seharusnya tidak mempengaruhi sebagian besar pengguna.
samuelesque
Ini bekerja dengan baik, kecuali kenyataan bahwa jika Anda berada di WPF, ini akan memunculkan jendela konsol untuk sepersekian detik, tidak terlihat profesional.
Dustin Jensen
79

Diambil dari: sebuah posting Geekpedia

Metode ini menggunakan WMI untuk mematikan windows.

Anda harus menambahkan referensi ke System.Management ke proyek Anda untuk menggunakan ini.

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
sumber
3
Menggunakan WMI memudahkan untuk melacak kesalahan. Apa yang terjadi jika perintah penutupan tidak berfungsi karena suatu alasan?
Rob Walker
2
Saya menggunakan metode ini untuk mematikan windows, dan dua dari tiga kali ini akan memberi tahu saya bahwa saya tidak memiliki izin, tetapi yang ketiga, itu karena "menyerah" dan menghidupkan kembali komputer. Ada apa dengan itu?
DTI-Matt
1
Solusi ini tidak berfungsi untuk saya. Saya mendapatkan "Privilege not holding" exception bahkan jika saya menjalankan program di bawah administrator pengguna.
Fanda
@ roomaroo Metode ini tidak berfungsi. Itu melempar pengecualian: Pengecualian manajemen, hak istimewa tidak dimiliki.
somethingSomething
Jika Anda ingin mematikan secara paksa, Anda harus menggunakan mboShutdownParams ["Flags"] = "5"; Nilai 5 berarti pematian paksa.
SaneDeveloper
32

Utas ini menyediakan kode yang diperlukan: http://bytes.com/forum/thread251367.html

tapi ini kode yang relevan:

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

Pemakaian:

DoExitWin( EWX_SHUTDOWN );

atau

DoExitWin( EWX_REBOOT );
Stephen Wrighton
sumber
Anda dapat membaca tentang apa yang dilakukan oleh para kontestan EWX_ lainnya di sini: msdn.microsoft.com/en-us/library/windows/desktop/…
TripleAntigen
1
Saat porting konstanta numerik ke C #, praktik terbaik adalah dengan menggunakan enum. Itulah yang harus dilakukan oleh enum. Ini memberikan pengetikan yang kuat di sekitar konstanta numerik, opsional mendukung flags / bitmasks, dan mudah dilemparkan bolak-balik ke tipe numerik yang mendasarinya.
Andrew Rondeau
26

Metode yang berbeda:

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

B. Instrumentasi Manajemen Windows (WMI)

C. System.Runtime.InteropServices Pinvoke

D. Manajemen Sistem

Setelah saya kirim, saya telah melihat begitu banyak orang lain juga telah diposting ...

lakshmanaraj
sumber
2
B dan D adalah metode yang sama (WMI)
Lucas
E. Powershell mengeksekusi script dari kode blogs.msdn.microsoft.com/kebab/2014/04/28/...
user1785960
14

Metode jelek jadul. Gunakan ExitWindowsExfungsi dari 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);

Dalam kode produksi Anda harus memeriksa nilai kembali panggilan API, tetapi saya mengabaikannya untuk membuat contoh lebih jelas.

roomaroo
sumber
12

Pendek dan manis. Panggil program eksternal:

    using System.Diagnostics;

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

Catatan: Ini menyebut program Windows Shutdown.exe, jadi itu hanya akan berfungsi jika program itu tersedia. Anda mungkin memiliki masalah pada Windows 2000 (di mana shutdown.exe hanya tersedia di kit sumber daya) atau XP Embedded .

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

Harus bekerja

Untuk restart, ini / r

Ini akan memulai ulang kotak PC secara langsung dan bersih, tanpa dialog.

Micah Vertal
sumber
Ini adalah jawaban sempurna untuk sistem modern (2015+).
Fattie
terima kasih, bisakah Anda menjelaskan apa yang dilakukan oleh / s dan / t 0?
Vladimir verleg
1
@Peterverleg Sure. Argumen "/ s" memberi tahu komputer untuk mematikan dan "/ t" memberi tahu komputer untuk menunggu x detik sebelum mematikan. Saya tahu dari pengalaman pribadi bahwa argumen "/ t" tidak melakukan apa pun di Windows 8.1, tapi pasti berhasil di 7. Anda dapat menggunakan fungsi-fungsi ini juga: shutdown /s /t 0 //For shutdown shutdown /r /t 0 //For restart shutdown /h /t 0 //For hibernateJuga, coba ketikkan ke CMD untuk hasil yang sama.
Micah Vertal
6

Anda dapat meluncurkan proses mematikan:

  • shutdown -s -t 0 - Mematikan
  • shutdown -r -t 0 - Mengulang kembali
Kekayaan
sumber
6

Perhatikan bahwa shutdown.exeini hanyalah pembungkus saja InitiateSystemShutdownEx, yang menyediakan beberapa barang hilangExitWindowsEx

unbob
sumber
5

Saya mengalami kesulitan mencoba menggunakan metode WMI yang diterima di atas karena saya selalu mendapat hak istimewa tidak memegang pengecualian meskipun menjalankan program sebagai administrator.

Solusinya adalah proses meminta hak istimewa itu untuk dirinya sendiri. Saya menemukan jawabannya di http://www.dotnet247.com/247reference/msgs/58/292150.aspx ditulis oleh seorang pria bernama Richard Hill.

Saya telah menempelkan penggunaan dasar saya atas solusinya di bawah jika tautannya menjadi tua.

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
sumber
2
Ini berhasil, meskipun saya tidak suka tidak tahu mengapa. Jujur saya bertanya-tanya apakah saya seharusnya hanya pergi dengan perintah "shutdown" ...
Dan Bailiff
5

Hanya untuk menambah jawaban Pop Catalin, berikut adalah satu liner yang mematikan komputer tanpa menampilkan jendela apa pun:

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

Saya mencoba metode WMI roomaroo untuk mematikan Windows 2003 Server, tetapi tidak akan berfungsi sampai saya menambahkan `[STAThread] '(yaitu model threading " Single Threaded Apartment ") ke deklarasi Main ():

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

Saya kemudian mencoba untuk mematikan dari utas, dan untuk membuatnya berfungsi saya harus mengatur "Apartemen Negara" dari utas ke STA juga:

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

Saya seorang C # noob, jadi saya tidak sepenuhnya yakin akan pentingnya thread STA dalam hal mematikan sistem (bahkan setelah membaca tautan yang saya posting di atas). Mungkin orang lain bisa menguraikan ...?

MisterEd
sumber
Sebenarnya, hanya utas yang memanggil WMI yang perlu utas STA. Jika itu bukan utas utama, Main()tidak perlu [STAThread].
SLaks
2

** Jawaban Terinci ...

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

Gunakan shutdown.exe. Untuk menghindari masalah dengan melewatkan argumen, eksekusi kompleks, eksekusi dari WindowForms menggunakan skrip eksekusi 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 harus diinstal pada OS dan tersedia di GAC.

Maaf untuk bahasa Inggris saya.

pengguna1785960
sumber
0

Tidak ada metode .net asli untuk mematikan komputer. Anda perlu P / Panggil panggilan API ExitWindows atau ExitWindowsEx.

Ya - Jake itu.
sumber
0

Jika Anda ingin mematikan komputer dari jarak jauh maka Anda dapat menggunakannya

Using System.Diagnostics;

pada tombol apa saja klik

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