Cách tắt máy tính từ C #


138

Cách tốt nhất để tắt máy tính từ chương trình C # là gì?

Tôi đã tìm thấy một vài phương pháp hiệu quả - tôi sẽ đăng chúng bên dưới - nhưng không có phương pháp nào thanh lịch. Tôi đang tìm kiếm một cái gì đó đơn giản và tự nhiên .net.

Câu trả lời:


171

Hoạt động bắt đầu với windows XP, không khả dụng trong win 2000 hoặc thấp hơn:

Đây là cách nhanh nhất để làm điều đó:

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

Nếu không, sử dụng P / Gọi hoặc WMI như những người khác đã nói.

Chỉnh sửa: làm thế nào để tránh tạo cửa sổ

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

2
Điều này dường như cũng hoạt động từ các dịch vụ (ít nhất là trong các tình huống tôi quan tâm). Tôi không bao giờ có thể có được các phương thức WMI hoặc ExitWindowsEx để làm việc từ một dịch vụ.
James

1
@James Đó là vì một dịch vụ thường không có quyền cho nó.
AK_

Trạng thái tiêu thụ năng lượng của máy sẽ khác sau khi sử dụng, so với sau khi sử dụng cửa sổ hộp thoại tắt truyền thống. Nhấn nút nguồn để khởi động lại sẽ thu hút khoảng 80-85 milliamp, thay vì 300 + ish tiêu chuẩn. Sẽ đăng lại ở đây nếu tôi tìm hiểu lý do tại sao. Điều này sẽ không ảnh hưởng đến hầu hết người dùng.
samuelesque

Điều này hoạt động rất tốt, ngoại trừ thực tế là nếu bạn đang ở trong WPF, điều này sẽ sinh ra một cửa sổ giao diện điều khiển trong một giây, không chính xác là trông chuyên nghiệp.
Dustin Jensen

79

Lấy từ: một bài Geekpedia

Phương pháp này sử dụng WMI để tắt các cửa sổ.

Bạn sẽ cần thêm một tham chiếu đến System.Man Management vào dự án của bạn để sử dụng cái này.

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
Sử dụng WMI giúp dễ dàng theo dõi lỗi hơn. Điều gì xảy ra nếu lệnh tắt máy không hoạt động vì một số lý do?
Rob Walker

2
Tôi đang sử dụng phương pháp này để tắt các cửa sổ, và hai trong ba lần nó sẽ cho tôi biết tôi thiếu quyền, nhưng lần thứ ba, nó lại "bỏ cuộc" và khởi động lại máy tính. Có chuyện gì thế?
DTI-Matt

1
Giải pháp này không hiệu quả với tôi. Tôi nhận được ngoại lệ "Đặc quyền không được giữ" ngay cả khi tôi chạy chương trình dưới quyền người dùng quản trị viên.
Fanda

@roomaroo Phương pháp này không hiệu quả. Nó ném một ngoại lệ: Ngoại lệ quản lý, đặc quyền không được tổ chức.
một cái gì đó

Nếu bạn muốn tắt máy một cách ép buộc, bạn nên sử dụng mboShutdownParams ["Flags"] = "5"; Giá trị 5 có nghĩa là buộc phải tắt máy.
SaneDeveloper

32

Chủ đề này cung cấp mã cần thiết: http://bytes.com/forum/thread251367.html

nhưng đây là mã có liên quan:

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

Sử dụng:

DoExitWin( EWX_SHUTDOWN );

hoặc là

DoExitWin( EWX_REBOOT );

Bạn có thể đọc về những gì các thành viên EWX_ khác làm tại đây: msdn.microsoft.com/en-us/l
Library / windows / desktop / Lỗi

1
Khi chuyển các hằng số sang C #, cách tốt nhất là sử dụng enum. Đó là những gì một enum được thiết kế để làm. Nó cho phép gõ mạnh xung quanh các hằng số, tùy chọn hỗ trợ cờ / bitmasks và dễ dàng chuyển đổi qua lại với kiểu số cơ bản.
Andrew Rondeau

26

Các phương pháp khác nhau:

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

B. Thiết bị quản lý Windows (WMI)

C. System.R.78.InteropService Pinvoke

D. Quản lý hệ thống

Sau khi tôi gửi, tôi đã thấy rất nhiều người khác cũng đã đăng ...


2
B và D là cùng một phương thức (WMI)
Lucas

E. Powershell thực thi kịch bản từ mã blogs.msdn.microsoft.com/kebab/2014/04/28/...
user1785960

14

Phương pháp cũ xấu xí. Sử dụng ExitWindowsExchức năng từ 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);

Trong mã sản xuất, bạn nên kiểm tra các giá trị trả về của các lệnh gọi API, nhưng tôi đã bỏ qua nó để làm cho ví dụ rõ ràng hơn.


12

Ngắn và ngọt. Gọi một chương trình bên ngoài:

    using System.Diagnostics;

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

Lưu ý: Điều này gọi chương trình Shutdown.exe của Windows, vì vậy nó sẽ chỉ hoạt động nếu chương trình đó khả dụng. Bạn có thể gặp sự cố trên Windows 2000 (trong đó shutdown.exe chỉ khả dụng trong bộ tài nguyên) hoặc XP Embedded .


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

Nên làm việc.

Để khởi động lại, nó / r

Điều này sẽ khởi động lại hộp PC trực tiếp và sạch sẽ, không có hộp thoại.


Đây là câu trả lời hoàn hảo trên các hệ thống hiện đại (2015+).
Fattie

cảm ơn, bạn có thể giải thích những gì / s và / t 0 làm gì không?
Vladimir tuyên bố

1
@Peterverleg Chắc chắn. Đối số "/ s" yêu cầu máy tính tắt máy và "/ t" yêu cầu máy tính đợi x giây trước khi tắt. Tôi biết từ kinh nghiệm cá nhân rằng đối số "/ t" không làm gì trong Windows 8.1, nhưng chắc chắn nó hoạt động trong 7. Bạn cũng có thể sử dụng các chức năng này: shutdown /s /t 0 //For shutdown shutdown /r /t 0 //For restart shutdown /h /t 0 //For hibernateNgoài ra, hãy thử nhập chúng vào CMD để có kết quả tương tự.
Micah Vertal

6

Bạn có thể khởi chạy quá trình tắt máy:

  • shutdown -s -t 0 - Tắt
  • shutdown -r -t 0 - Khởi động lại


5

Tôi gặp khó khăn khi cố gắng sử dụng phương pháp WMI được chấp nhận ở trên vì tôi luôn có quyền riêng tư không có ngoại lệ mặc dù chạy chương trình với tư cách quản trị viên.

Giải pháp là cho quá trình yêu cầu đặc quyền cho chính nó. Tôi đã tìm thấy câu trả lời tại http://www.dotnet247.com/247reference/msgs/58/292150.aspx được viết bởi một chàng trai tên là Richard Hill.

Tôi đã dán cách sử dụng cơ bản giải pháp của anh ấy bên dưới trong trường hợp liên kết đó đã cũ.

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
Điều này làm việc, mặc dù tôi không thích tại sao. Tôi thực sự tự hỏi liệu tôi có nên thực hiện lệnh "tắt máy" không ...
Dan Bailiff

5

Chỉ cần thêm vào câu trả lời của Pop Catalin, đây là một lớp lót tắt máy tính mà không hiển thị bất kỳ cửa sổ nào:

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

2

Tôi đã thử phương pháp WMI của roomaroo để tắt Windows 2003 Server, nhưng nó sẽ không hoạt động cho đến khi tôi thêm `[STAThread] '(tức là mô hình luồng" Căn hộ một luồng ") vào khai báo Main ():

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

Sau đó, tôi đã cố gắng tắt máy từ một luồng và để nó hoạt động, tôi cũng phải đặt "Trạng thái căn hộ" của luồng thành 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
    }
}

Tôi là một C # noob, vì vậy tôi không hoàn toàn chắc chắn về tầm quan trọng của các luồng STA trong việc tắt hệ thống (ngay cả sau khi đọc liên kết tôi đã đăng ở trên). Có lẽ ai đó khác có thể giải thích ...?


Trên thực tế, chỉ có luồng gọi WMI cần phải là luồng STA. Nếu đó không phải là chủ đề chính, Main()không cần [STAThread].
SLaks

2

** Trả lời được xây dựng ...

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

Sử dụng shutdown.exe. Để tránh sự cố khi truyền đối số, thực thi phức tạp, thực thi từ WindowForms sử dụng tập lệnh thực thi 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.Man Quản.Automation.dll nên được cài đặt trên HĐH và có sẵn trong GAC.

Xin lỗi vì tiếng Anh của tôi.


0

Không có phương thức riêng .net để tắt máy tính. Bạn cần P / Gọi lệnh gọi API ExitWindows hoặc ExitWindowsEx.


0

Nếu bạn muốn tắt máy tính từ xa thì bạn có thể sử dụng

Using System.Diagnostics;

trên bất kỳ nút bấm nào

{
    Process.Start("Shutdown","-i");
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.